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..b8ad1a059825437af4fbd7500e3be03d2ac6c66a 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" |
@@ -33,10 +32,10 @@ type principalServiceImpl struct { |
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.User, error) { |
+ p, err := pImpl.psd.initPrincipal(pImpl.app) |
+ if err != nil { |
+ return nil, err |
} |
token, err := pImpl.psd.getOAuth2Token() |
@@ -44,27 +43,67 @@ 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) |
+ user, err := userFromBlessings(blessings) |
if err != nil { |
return nil, err |
} |
- pImpl.psd.addPrincipal(pImpl.app, &principal{wb, priv}) |
- return newBlessing(wb), nil |
+ p.addUser(user, blessings) |
+ return &user, nil |
+} |
+ |
+func (pImpl *principalServiceImpl) GetUsers() ([]vpkg.User, *vpkg.User, 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(user vpkg.User) (*string, error) { |
+ if p := pImpl.psd.principal(pImpl.app); p != nil { |
+ return p.setCurrentUser(user), 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) GetUser(app *vpkg.AppInstanceName) (*vpkg.User, 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) |
+ } |
+ return p.curr, 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 +122,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) |
gautham
2015/10/26 20:52:01
maybe call it appPrincipalMap
ataly
2015/10/28 21:32:24
I called it 'appPrincipals'. The 'map' is kinda re
|
} |
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 +148,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 +175,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) |
- } |
- // 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, fmt.Errorf("failed to unmarshal response (blessings) from Vanadium Identity Provider: %v", err) |
} |
- 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() { |