Chromium Code Reviews| Index: services/vanadium/security/principal_service.go |
| diff --git a/services/vanadium/security/principal_service.go b/services/vanadium/security/principal_service.go |
| index 07c2e36a407500cca069f7cc0e7c1604545c7efc..d2489e99827963825fda770cc9377cd24e9f878c 100644 |
| --- a/services/vanadium/security/principal_service.go |
| +++ b/services/vanadium/security/principal_service.go |
| @@ -5,7 +5,6 @@ |
| package main |
| import ( |
| - "crypto/ecdsa" |
| "encoding/base64" |
| "encoding/json" |
| "fmt" |
| @@ -26,17 +25,20 @@ import ( |
| //#include "mojo/public/c/system/types.h" |
| import "C" |
| -const blesserURL = "https://dev.v.io/auth/google/bless" |
| +const ( |
| + blesserURL = "https://dev.v.io/auth/google/bless" |
| + tokenInfoURL = "https://www.googleapis.com/oauth2/v1/tokeninfo" |
|
ukode
2015/10/22 20:19:01
Is this URL right. I thought they moved to v2 or v
ataly
2015/10/23 21:14:53
Oh yes, thanks for pointing this out. At the momen
ukode
2015/10/23 22:45:43
Thanks for the clean up.
|
| +) |
| type principalServiceImpl struct { |
| app vpkg.AppInstanceName |
| psd *principalServiceDelegate |
| } |
| -func (pImpl *principalServiceImpl) Login() (*vpkg.Blessing, error) { |
| - if b := pImpl.psd.getBlessing(pImpl.app); b != nil { |
| - // The app has already logged in. |
| - return b, nil |
| +func (pImpl *principalServiceImpl) Login() (*vpkg.UserId, error) { |
| + p, err := pImpl.psd.initPrincipal(pImpl.app) |
| + if err != nil { |
| + return nil, err |
| } |
| token, err := pImpl.psd.getOAuth2Token() |
| @@ -44,27 +46,56 @@ func (pImpl *principalServiceImpl) Login() (*vpkg.Blessing, error) { |
| return nil, err |
| } |
| - pub, priv, err := newPrincipalKey() |
| + blessings, err := pImpl.psd.getBlessings(token, p.publicKey()) |
| if err != nil { |
| return nil, err |
| } |
| - wb, err := pImpl.psd.fetchWireBlessings(token, pub) |
| + id, err := userIdFromBlessings(blessings) |
| if err != nil { |
| return nil, err |
| } |
| - pImpl.psd.addPrincipal(pImpl.app, &principal{wb, priv}) |
| - return newBlessing(wb), nil |
| + p.addUser(id, blessings) |
| + return &id, nil |
| +} |
| + |
| +func (pImpl *principalServiceImpl) GetUsers() ([]vpkg.UserId, *vpkg.UserId, error) { |
| + if p := pImpl.psd.principal(pImpl.app); p != nil { |
| + users, curr := p.users() |
| + return users, curr, nil |
| + } |
| + return nil, nil, fmt.Errorf("no principal available for app %v", pImpl.app) |
| +} |
| + |
| +func (pImpl *principalServiceImpl) SetCurrentUser(id vpkg.UserId) (*string, error) { |
| + if p := pImpl.psd.principal(pImpl.app); p != nil { |
| + return p.setCurrentUser(id), nil |
| + } |
| + str := fmt.Sprintf("no principal available for app %v; please invoke Login()", pImpl.app) |
| + return &str, nil |
| } |
| func (pImpl *principalServiceImpl) Logout() (err error) { |
| - pImpl.psd.deletePrincipal(pImpl.app) |
| - return |
| + if p := pImpl.psd.principal(pImpl.app); p != nil { |
| + p.unsetCurrentUser() |
| + } |
| + return nil |
| } |
| -func (pImpl *principalServiceImpl) GetUserBlessing(app vpkg.AppInstanceName) (*vpkg.Blessing, error) { |
| - return pImpl.psd.getBlessing(app), nil |
| +func (pImpl *principalServiceImpl) GetUserBlessing(app *vpkg.AppInstanceName) (*vpkg.Blessing, error) { |
| + if app == nil { |
| + app = &pImpl.app |
| + } |
| + p := pImpl.psd.principal(*app) |
| + if p == nil { |
| + return nil, fmt.Errorf("no principal available for app %v", pImpl.app) |
| + } |
| + wb := p.currentBlessing() |
| + if wb == nil { |
| + return nil, fmt.Errorf("no blessing available for app %v", pImpl.app) |
| + } |
| + return newBlessing(wb), nil |
| } |
| func (pImpl *principalServiceImpl) Create(req vpkg.PrincipalService_Request) { |
| @@ -83,20 +114,15 @@ func (pImpl *principalServiceImpl) Create(req vpkg.PrincipalService_Request) { |
| }() |
| } |
| -type principal struct { |
| - blessing *wireBlessings |
| - private *ecdsa.PrivateKey |
| -} |
| - |
| type principalServiceDelegate struct { |
| - table map[vpkg.AppInstanceName]*principal |
| - Ctx application.Context |
| - mu sync.Mutex |
| - stubs []*bindings.Stub |
| + Ctx application.Context |
| + mu sync.Mutex |
| + stubs []*bindings.Stub // GUARDED_BY(mu) |
| + principals map[vpkg.AppInstanceName]*principal // GUARDED_BY(mu) |
| } |
| func (psd *principalServiceDelegate) Initialize(context application.Context) { |
| - psd.table = make(map[vpkg.AppInstanceName]*principal) |
| + psd.principals = make(map[vpkg.AppInstanceName]*principal) |
| psd.Ctx = context |
| } |
| @@ -114,6 +140,26 @@ func (psd *principalServiceDelegate) addStubForCleanup(stub *bindings.Stub) { |
| psd.stubs = append(psd.stubs, stub) |
| } |
| +func (psd *principalServiceDelegate) principal(app vpkg.AppInstanceName) *principal { |
| + psd.mu.Lock() |
| + defer psd.mu.Unlock() |
| + return psd.principals[app] |
| +} |
| + |
| +func (psd *principalServiceDelegate) initPrincipal(app vpkg.AppInstanceName) (*principal, error) { |
| + psd.mu.Lock() |
| + defer psd.mu.Unlock() |
| + if p, ok := psd.principals[app]; ok { |
| + return p, nil |
| + } |
| + p, err := newPrincipal() |
| + if err != nil { |
| + return nil, err |
| + } |
| + psd.principals[app] = p |
| + return p, nil |
| +} |
| + |
| func (psd *principalServiceDelegate) getOAuth2Token() (string, error) { |
| authReq, authPtr := auth.CreateMessagePipeForAuthenticationService() |
| psd.Ctx.ConnectToApplication("mojo:authentication").ConnectToService(&authReq) |
| @@ -121,70 +167,49 @@ func (psd *principalServiceDelegate) getOAuth2Token() (string, error) { |
| name, errString, _ := authProxy.SelectAccount(false /*return_last_selected*/) |
| if name == nil { |
| - return "", fmt.Errorf("Failed to select an account for user:%s", errString) |
| + return "", fmt.Errorf("failed to select an account for user:%s", errString) |
| } |
| - |
| token, errString, _ := authProxy.GetOAuth2Token(*name, []string{"email"}) |
| if token == nil { |
| - return "", fmt.Errorf("Failed to obtain OAuth2 token for selected account:%s", errString) |
| + return "", fmt.Errorf("failed to obtain OAuth2 token for selected account:%s", errString) |
| } |
| return *token, nil |
| } |
| -func (psd *principalServiceDelegate) fetchWireBlessings(token string, pub publicKey) (*wireBlessings, error) { |
| +func (psd *principalServiceDelegate) getBlessings(token string, pub publicKey) (*wireBlessings, error) { |
| networkReq, networkPtr := network.CreateMessagePipeForNetworkService() |
| psd.Ctx.ConnectToApplication("mojo:network_service").ConnectToService(&networkReq) |
| networkProxy := network.NewNetworkServiceProxy(networkPtr, bindings.GetAsyncWaiter()) |
| urlLoaderReq, urlLoaderPtr := url_loader.CreateMessagePipeForUrlLoader() |
| if err := networkProxy.CreateUrlLoader(urlLoaderReq); err != nil { |
| - return nil, fmt.Errorf("Failed to create url loader: %v", err) |
| + return nil, fmt.Errorf("failed to create url loader: %v", err) |
| } |
| - urlLoaderProxy := url_loader.NewUrlLoaderProxy(urlLoaderPtr, bindings.GetAsyncWaiter()) |
| + urlLoader := url_loader.NewUrlLoaderProxy(urlLoaderPtr, bindings.GetAsyncWaiter()) |
| req, err := blessingRequestURL(token, pub) |
| if err != nil { |
| return nil, err |
| } |
| - resp, err := urlLoaderProxy.Start(*req) |
| + resp, err := urlLoader.Start(*req) |
| if err != nil || resp.Error != nil { |
| - return nil, fmt.Errorf("Blessings request to Vanadium Identity Provider failed: %v(%v)", err, resp.Error) |
| + return nil, fmt.Errorf("blessings request to Vanadium Identity Provider failed: %v(%v)", err, resp.Error) |
| } |
| res, b := (*resp.Body).ReadData(system.MOJO_READ_DATA_FLAG_ALL_OR_NONE) |
| if res != system.MOJO_RESULT_OK { |
| - return nil, fmt.Errorf("Failed to read response (blessings) from Vanadium Identity Provider. Result: %v", res) |
| + return nil, fmt.Errorf("failed to read response (blessings) from Vanadium Identity Provider. Result: %v", res) |
| } |
| var wb wireBlessings |
| if err := json.Unmarshal(b, &wb); err != nil { |
| - return nil, fmt.Errorf("Failed to unmarshal response (blessings) from Vanadium Identity Provider: %v", err) |
| + return nil, fmt.Errorf("failed to unmarshal response (blessings) from Vanadium Identity Provider: %v", err) |
| } |
| - // TODO(ataly, gauthamt): We should verify all signatures on the certificate chains in the |
| - // wire blessings to ensure that it was not tampered with. |
| - return &wb, nil |
| -} |
| -func (psd *principalServiceDelegate) addPrincipal(app vpkg.AppInstanceName, p *principal) { |
| - psd.mu.Lock() |
| - defer psd.mu.Unlock() |
| - psd.table[app] = p |
| -} |
| - |
| -func (psd *principalServiceDelegate) getBlessing(app vpkg.AppInstanceName) *vpkg.Blessing { |
| - psd.mu.Lock() |
| - defer psd.mu.Unlock() |
| - if p, ok := psd.table[app]; ok { |
| - return newBlessing(p.blessing) |
| - } |
| - return nil |
| -} |
| - |
| -func (psd *principalServiceDelegate) deletePrincipal(app vpkg.AppInstanceName) { |
| - psd.mu.Lock() |
| - defer psd.mu.Unlock() |
| - delete(psd.table, app) |
| + // TODO(ataly, gauthamt): We should verify all signatures on the certificate |
| + // chains in the wire blessings to ensure that it was not tampered with. |
| + return &wb, nil |
| } |
| func (psd *principalServiceDelegate) Quit() { |