| // Copyright 2015 The Vanadium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| // +build mojo |
| |
| // The evolving story of identification and security in syncbase |
| // running in mojo: |
| // (Last Updated: November 5, 2015). |
| // |
| // SHORT STORY: |
| // The syncbase mojo service gets a blessing by exchanging an OAuth2 token for |
| // a blessing. This allows syncbases to identify each other when synchronizing |
| // data between each other and enables basic security policies like "all my |
| // devices sync all my data with each other". However, different mojo "clients" |
| // (that communicate with the local syncbase via mojo IPC) are not isolated |
| // from each other - so each mojo app has complete access to all the data |
| // written to the local syncbase service (modulo any filesystem isolation via |
| // the --root-dir flag). This is something that we intend to change. |
| // |
| // LONGER VERSION: |
| // A "mojo app" consists of a set of interrelated components, accessed by a |
| // URL. Communication between these components is via mojo IPC. One of those |
| // components is syncbase (this package), which is a store that synchronizes |
| // between devices via Vanadium RPCs. See: |
| // https://docs.google.com/a/google.com/document/d/1TyxPYIhj9VBCtY7eAXu_MEV9y0dtRx7n7UY4jm76Qq4/edit?usp=sharing |
| // |
| // Any process communicating via Vanadium RPCs needs to have an identity |
| // represented as a Blessing |
| // (https://vanadium.github.io/concepts/security.html). |
| // |
| // So, the current story is this: |
| // 1 The mojo syncbase app/service fetches an OAuth2 token from the |
| // mojo authentication service |
| // 2 It exchanges this token for a blessing bound to the public |
| // key of the principal associated with this service |
| // (this is essentially a copy of what the mojo principal service |
| // implementation does) |
| // 3 And all RPCs use the blessing obtained above |
| // 4 Other mojo components communicate with their local syncbase via |
| // Mojo IPC (see v.io/x/ref/services/syncbase/server/mojo_call.go) |
| // and DO NOT AUTHENTICATE with it |
| // 5 The resulting security model is that all mojo apps on the same |
| // device have access to whatever is stored in the local syncbase |
| // |
| // Clearly (5) is not ideal. And as this evolves, the plan is likely to be |
| // something involving each "client" of this syncbase mojo service being |
| // identified using the principal service |
| // (https://github.com/domokit/mojo/blob/master/mojo/services/vanadium/security/interfaces/principal.mojom). |
| // But more on that when we get there. |
| |
| package bridge_mojo |
| |
| import ( |
| "fmt" |
| "runtime" |
| |
| "mojo/public/go/application" |
| "mojo/public/go/bindings" |
| "mojo/services/authentication/interfaces/authentication" |
| |
| "v.io/v23/context" |
| "v.io/x/ref/services/syncbase/bridge" |
| ) |
| |
| type selectAccountFailed struct { |
| error |
| } |
| |
| func SetBlessings(v23ctx *context.T, appctx application.Context) error { |
| // Get an OAuth2 token from the mojo authentication service. |
| // At the time of this writing, the mojo authentication |
| // service was implemented only for Android, so in absence |
| // of that abort. Which means that the syncbases cannot |
| // communicate with each other, unless --v23.credentials was |
| // supplied as a flag. |
| if runtime.GOOS != "android" { |
| v23ctx.Infof("Using default blessings for non-Android OS (%v)", runtime.GOOS) |
| return nil |
| } |
| // Get an OAuth2 token from the mojo authentication service. |
| // TODO(ashankar,ataly): This is almost a duplicate of: |
| // https://github.com/domokit/mojo/blob/master/services/vanadium/security/principal_service.go |
| // At some point this needs to be cleared up - the syncbase mojo service |
| // should talk to the principal mojo service. |
| token, err := oauthToken(appctx) |
| if err != nil { |
| if _, ok := err.(selectAccountFailed); ok { |
| // TODO(sadovsky): This behavior is convenient for development, but |
| // probably ought to be disabled in production. |
| v23ctx.Infof("SelectAccount failed; using default blessings") |
| return nil |
| } |
| return err |
| } |
| ctx.Infof("Obtained OAuth2 token, will exchange for blessings") |
| return bridge.SetBlessings(v23ctx, "google", token) |
| } |
| |
| func oauthToken(ctx application.Context) (string, error) { |
| req, ptr := authentication.CreateMessagePipeForAuthenticationService() |
| ctx.ConnectToApplication("mojo:authentication").ConnectToService(&req) |
| proxy := authentication.NewAuthenticationServiceProxy(ptr, bindings.GetAsyncWaiter()) |
| name, errstr, _ := proxy.SelectAccount(true /*return last selected*/) |
| if name == nil || errstr != nil { |
| return "", selectAccountFailed{error: fmt.Errorf("failed to select an account for user: %v", errstr)} |
| } |
| token, errstr, _ := proxy.GetOAuth2Token(*name, []string{"email"}) |
| if token == nil || errstr != nil { |
| return "", fmt.Errorf("failed to obtain an OAuth2 token for %q: %v", *name, errstr) |
| } |
| return *token, nil |
| } |