Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 package main | 5 package main |
| 6 | 6 |
| 7 import ( | 7 import ( |
| 8 "crypto/ecdsa" | |
| 9 "encoding/base64" | 8 "encoding/base64" |
| 10 "encoding/json" | 9 "encoding/json" |
| 11 "fmt" | 10 "fmt" |
| 12 "log" | 11 "log" |
| 13 "net/url" | 12 "net/url" |
| 14 "sync" | 13 "sync" |
| 15 | 14 |
| 16 "mojo/public/go/application" | 15 "mojo/public/go/application" |
| 17 "mojo/public/go/bindings" | 16 "mojo/public/go/bindings" |
| 18 "mojo/public/go/system" | 17 "mojo/public/go/system" |
| 19 "mojo/public/interfaces/network/url_request" | 18 "mojo/public/interfaces/network/url_request" |
| 20 auth "mojo/services/authentication/interfaces/authentication" | 19 auth "mojo/services/authentication/interfaces/authentication" |
| 21 network "mojo/services/network/interfaces/network_service" | 20 network "mojo/services/network/interfaces/network_service" |
| 22 "mojo/services/network/interfaces/url_loader" | 21 "mojo/services/network/interfaces/url_loader" |
| 23 vpkg "mojo/services/vanadium/security/interfaces/principal" | 22 vpkg "mojo/services/vanadium/security/interfaces/principal" |
| 24 ) | 23 ) |
| 25 | 24 |
| 26 //#include "mojo/public/c/system/types.h" | 25 //#include "mojo/public/c/system/types.h" |
| 27 import "C" | 26 import "C" |
| 28 | 27 |
| 29 const blesserURL = "https://dev.v.io/auth/google/bless" | 28 const blesserURL = "https://dev.v.io/auth/google/bless" |
| 30 | 29 |
| 31 type principalServiceImpl struct { | 30 type principalServiceImpl struct { |
| 32 app vpkg.AppInstanceName | 31 app vpkg.AppInstanceName |
| 33 psd *principalServiceDelegate | 32 psd *principalServiceDelegate |
| 34 } | 33 } |
| 35 | 34 |
| 36 func (pImpl *principalServiceImpl) Login() (*vpkg.Blessing, error) { | 35 func (pImpl *principalServiceImpl) Login() (*vpkg.User, error) { |
| 37 » if b := pImpl.psd.getBlessing(pImpl.app); b != nil { | 36 » p, err := pImpl.psd.initPrincipal(pImpl.app) |
| 38 » » // The app has already logged in. | 37 » if err != nil { |
| 39 » » return b, nil | 38 » » return nil, err |
| 40 } | 39 } |
| 41 | 40 |
| 42 token, err := pImpl.psd.getOAuth2Token() | 41 token, err := pImpl.psd.getOAuth2Token() |
| 43 if err != nil { | 42 if err != nil { |
| 44 return nil, err | 43 return nil, err |
| 45 } | 44 } |
| 46 | 45 |
| 47 » pub, priv, err := newPrincipalKey() | 46 » blessings, err := pImpl.psd.getBlessings(token, p.publicKey()) |
| 48 if err != nil { | 47 if err != nil { |
| 49 return nil, err | 48 return nil, err |
| 50 } | 49 } |
| 51 | 50 |
| 52 » wb, err := pImpl.psd.fetchWireBlessings(token, pub) | 51 » user, err := userFromBlessings(blessings) |
| 53 if err != nil { | 52 if err != nil { |
| 54 return nil, err | 53 return nil, err |
| 55 } | 54 } |
| 56 | 55 |
| 57 » pImpl.psd.addPrincipal(pImpl.app, &principal{wb, priv}) | 56 » p.addUser(user, blessings) |
| 57 » return &user, nil | |
| 58 } | |
| 59 | |
| 60 func (pImpl *principalServiceImpl) GetUsers() ([]vpkg.User, *vpkg.User, error) { | |
| 61 » if p := pImpl.psd.principal(pImpl.app); p != nil { | |
| 62 » » users, curr := p.users() | |
| 63 » » return users, curr, nil | |
| 64 » } | |
| 65 » return nil, nil, fmt.Errorf("no principal available for app %v", pImpl.a pp) | |
| 66 } | |
| 67 | |
| 68 func (pImpl *principalServiceImpl) SetCurrentUser(user vpkg.User) (*string, erro r) { | |
| 69 » if p := pImpl.psd.principal(pImpl.app); p != nil { | |
| 70 » » return p.setCurrentUser(user), nil | |
| 71 » } | |
| 72 » str := fmt.Sprintf("no principal available for app %v; please invoke Log in()", pImpl.app) | |
| 73 » return &str, nil | |
| 74 } | |
| 75 | |
| 76 func (pImpl *principalServiceImpl) Logout() (err error) { | |
| 77 » if p := pImpl.psd.principal(pImpl.app); p != nil { | |
| 78 » » p.unsetCurrentUser() | |
| 79 » } | |
| 80 » return nil | |
| 81 } | |
| 82 | |
| 83 func (pImpl *principalServiceImpl) GetUser(app *vpkg.AppInstanceName) (*vpkg.Use r, error) { | |
| 84 » if app == nil { | |
| 85 » » app = &pImpl.app | |
| 86 » } | |
| 87 » p := pImpl.psd.principal(*app) | |
| 88 » if p == nil { | |
| 89 » » return nil, fmt.Errorf("no principal available for app %v", pImp l.app) | |
| 90 » } | |
| 91 » return p.curr, nil | |
| 92 } | |
| 93 | |
| 94 func (pImpl *principalServiceImpl) GetUserBlessing(app *vpkg.AppInstanceName) (* vpkg.Blessing, error) { | |
| 95 » if app == nil { | |
| 96 » » app = &pImpl.app | |
| 97 » } | |
| 98 » p := pImpl.psd.principal(*app) | |
| 99 » if p == nil { | |
| 100 » » return nil, fmt.Errorf("no principal available for app %v", pImp l.app) | |
| 101 » } | |
| 102 » wb := p.currentBlessing() | |
| 103 » if wb == nil { | |
| 104 » » return nil, fmt.Errorf("no blessing available for app %v", pImpl .app) | |
| 105 » } | |
| 58 return newBlessing(wb), nil | 106 return newBlessing(wb), nil |
| 59 } | 107 } |
| 60 | 108 |
| 61 func (pImpl *principalServiceImpl) Logout() (err error) { | |
| 62 pImpl.psd.deletePrincipal(pImpl.app) | |
| 63 return | |
| 64 } | |
| 65 | |
| 66 func (pImpl *principalServiceImpl) GetUserBlessing(app vpkg.AppInstanceName) (*v pkg.Blessing, error) { | |
| 67 return pImpl.psd.getBlessing(app), nil | |
| 68 } | |
| 69 | |
| 70 func (pImpl *principalServiceImpl) Create(req vpkg.PrincipalService_Request) { | 109 func (pImpl *principalServiceImpl) Create(req vpkg.PrincipalService_Request) { |
| 71 stub := vpkg.NewPrincipalServiceStub(req, pImpl, bindings.GetAsyncWaiter ()) | 110 stub := vpkg.NewPrincipalServiceStub(req, pImpl, bindings.GetAsyncWaiter ()) |
| 72 pImpl.psd.addStubForCleanup(stub) | 111 pImpl.psd.addStubForCleanup(stub) |
| 73 go func() { | 112 go func() { |
| 74 for { | 113 for { |
| 75 if err := stub.ServeRequest(); err != nil { | 114 if err := stub.ServeRequest(); err != nil { |
| 76 connectionError, ok := err.(*bindings.Connection Error) | 115 connectionError, ok := err.(*bindings.Connection Error) |
| 77 if !ok || !connectionError.Closed() { | 116 if !ok || !connectionError.Closed() { |
| 78 log.Println(err) | 117 log.Println(err) |
| 79 } | 118 } |
| 80 break | 119 break |
| 81 } | 120 } |
| 82 } | 121 } |
| 83 }() | 122 }() |
| 84 } | 123 } |
| 85 | 124 |
| 86 type principal struct { | |
| 87 blessing *wireBlessings | |
| 88 private *ecdsa.PrivateKey | |
| 89 } | |
| 90 | |
| 91 type principalServiceDelegate struct { | 125 type principalServiceDelegate struct { |
| 92 » table map[vpkg.AppInstanceName]*principal | 126 » Ctx application.Context |
| 93 » Ctx application.Context | 127 » mu sync.Mutex |
| 94 » mu sync.Mutex | 128 » stubs []*bindings.Stub // GUARDED_BY(mu) |
| 95 » stubs []*bindings.Stub | 129 » 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
| |
| 96 } | 130 } |
| 97 | 131 |
| 98 func (psd *principalServiceDelegate) Initialize(context application.Context) { | 132 func (psd *principalServiceDelegate) Initialize(context application.Context) { |
| 99 » psd.table = make(map[vpkg.AppInstanceName]*principal) | 133 » psd.principals = make(map[vpkg.AppInstanceName]*principal) |
| 100 psd.Ctx = context | 134 psd.Ctx = context |
| 101 } | 135 } |
| 102 | 136 |
| 103 func (psd *principalServiceDelegate) AcceptConnection(connection *application.Co nnection) { | 137 func (psd *principalServiceDelegate) AcceptConnection(connection *application.Co nnection) { |
| 104 app := vpkg.AppInstanceName{ | 138 app := vpkg.AppInstanceName{ |
| 105 Url: connection.RequestorURL(), | 139 Url: connection.RequestorURL(), |
| 106 Qualifier: nil, | 140 Qualifier: nil, |
| 107 } | 141 } |
| 108 connection.ProvideServices(&vpkg.PrincipalService_ServiceFactory{&princi palServiceImpl{app, psd}}) | 142 connection.ProvideServices(&vpkg.PrincipalService_ServiceFactory{&princi palServiceImpl{app, psd}}) |
| 109 } | 143 } |
| 110 | 144 |
| 111 func (psd *principalServiceDelegate) addStubForCleanup(stub *bindings.Stub) { | 145 func (psd *principalServiceDelegate) addStubForCleanup(stub *bindings.Stub) { |
| 112 psd.mu.Lock() | 146 psd.mu.Lock() |
| 113 defer psd.mu.Unlock() | 147 defer psd.mu.Unlock() |
| 114 psd.stubs = append(psd.stubs, stub) | 148 psd.stubs = append(psd.stubs, stub) |
| 115 } | 149 } |
| 116 | 150 |
| 151 func (psd *principalServiceDelegate) principal(app vpkg.AppInstanceName) *princi pal { | |
| 152 psd.mu.Lock() | |
| 153 defer psd.mu.Unlock() | |
| 154 return psd.principals[app] | |
| 155 } | |
| 156 | |
| 157 func (psd *principalServiceDelegate) initPrincipal(app vpkg.AppInstanceName) (*p rincipal, error) { | |
| 158 psd.mu.Lock() | |
| 159 defer psd.mu.Unlock() | |
| 160 if p, ok := psd.principals[app]; ok { | |
| 161 return p, nil | |
| 162 } | |
| 163 p, err := newPrincipal() | |
| 164 if err != nil { | |
| 165 return nil, err | |
| 166 } | |
| 167 psd.principals[app] = p | |
| 168 return p, nil | |
| 169 } | |
| 170 | |
| 117 func (psd *principalServiceDelegate) getOAuth2Token() (string, error) { | 171 func (psd *principalServiceDelegate) getOAuth2Token() (string, error) { |
| 118 authReq, authPtr := auth.CreateMessagePipeForAuthenticationService() | 172 authReq, authPtr := auth.CreateMessagePipeForAuthenticationService() |
| 119 psd.Ctx.ConnectToApplication("mojo:authentication").ConnectToService(&au thReq) | 173 psd.Ctx.ConnectToApplication("mojo:authentication").ConnectToService(&au thReq) |
| 120 authProxy := auth.NewAuthenticationServiceProxy(authPtr, bindings.GetAsy ncWaiter()) | 174 authProxy := auth.NewAuthenticationServiceProxy(authPtr, bindings.GetAsy ncWaiter()) |
| 121 | 175 |
| 122 name, errString, _ := authProxy.SelectAccount(false /*return_last_select ed*/) | 176 name, errString, _ := authProxy.SelectAccount(false /*return_last_select ed*/) |
| 123 if name == nil { | 177 if name == nil { |
| 124 » » return "", fmt.Errorf("Failed to select an account for user:%s", errString) | 178 » » return "", fmt.Errorf("failed to select an account for user:%s", errString) |
| 125 } | 179 } |
| 126 | |
| 127 token, errString, _ := authProxy.GetOAuth2Token(*name, []string{"email"} ) | 180 token, errString, _ := authProxy.GetOAuth2Token(*name, []string{"email"} ) |
| 128 if token == nil { | 181 if token == nil { |
| 129 » » return "", fmt.Errorf("Failed to obtain OAuth2 token for selecte d account:%s", errString) | 182 » » return "", fmt.Errorf("failed to obtain OAuth2 token for selecte d account:%s", errString) |
| 130 } | 183 } |
| 131 return *token, nil | 184 return *token, nil |
| 132 } | 185 } |
| 133 | 186 |
| 134 func (psd *principalServiceDelegate) fetchWireBlessings(token string, pub public Key) (*wireBlessings, error) { | 187 func (psd *principalServiceDelegate) getBlessings(token string, pub publicKey) ( *wireBlessings, error) { |
| 135 networkReq, networkPtr := network.CreateMessagePipeForNetworkService() | 188 networkReq, networkPtr := network.CreateMessagePipeForNetworkService() |
| 136 psd.Ctx.ConnectToApplication("mojo:network_service").ConnectToService(&n etworkReq) | 189 psd.Ctx.ConnectToApplication("mojo:network_service").ConnectToService(&n etworkReq) |
| 137 networkProxy := network.NewNetworkServiceProxy(networkPtr, bindings.GetA syncWaiter()) | 190 networkProxy := network.NewNetworkServiceProxy(networkPtr, bindings.GetA syncWaiter()) |
| 138 | 191 |
| 139 urlLoaderReq, urlLoaderPtr := url_loader.CreateMessagePipeForUrlLoader() | 192 urlLoaderReq, urlLoaderPtr := url_loader.CreateMessagePipeForUrlLoader() |
| 140 if err := networkProxy.CreateUrlLoader(urlLoaderReq); err != nil { | 193 if err := networkProxy.CreateUrlLoader(urlLoaderReq); err != nil { |
| 141 » » return nil, fmt.Errorf("Failed to create url loader: %v", err) | 194 » » return nil, fmt.Errorf("failed to create url loader: %v", err) |
| 142 } | 195 } |
| 143 » urlLoaderProxy := url_loader.NewUrlLoaderProxy(urlLoaderPtr, bindings.Ge tAsyncWaiter()) | 196 » urlLoader := url_loader.NewUrlLoaderProxy(urlLoaderPtr, bindings.GetAsyn cWaiter()) |
| 144 | 197 |
| 145 req, err := blessingRequestURL(token, pub) | 198 req, err := blessingRequestURL(token, pub) |
| 146 if err != nil { | 199 if err != nil { |
| 147 return nil, err | 200 return nil, err |
| 148 } | 201 } |
| 149 | 202 |
| 150 » resp, err := urlLoaderProxy.Start(*req) | 203 » resp, err := urlLoader.Start(*req) |
| 151 if err != nil || resp.Error != nil { | 204 if err != nil || resp.Error != nil { |
| 152 » » return nil, fmt.Errorf("Blessings request to Vanadium Identity P rovider failed: %v(%v)", err, resp.Error) | 205 » » return nil, fmt.Errorf("blessings request to Vanadium Identity P rovider failed: %v(%v)", err, resp.Error) |
| 153 } | 206 } |
| 154 | 207 |
| 155 res, b := (*resp.Body).ReadData(system.MOJO_READ_DATA_FLAG_ALL_OR_NONE) | 208 res, b := (*resp.Body).ReadData(system.MOJO_READ_DATA_FLAG_ALL_OR_NONE) |
| 156 if res != system.MOJO_RESULT_OK { | 209 if res != system.MOJO_RESULT_OK { |
| 157 » » return nil, fmt.Errorf("Failed to read response (blessings) from Vanadium Identity Provider. Result: %v", res) | 210 » » return nil, fmt.Errorf("failed to read response (blessings) from Vanadium Identity Provider. Result: %v", res) |
| 158 } | 211 } |
| 159 | 212 |
| 160 var wb wireBlessings | 213 var wb wireBlessings |
| 161 if err := json.Unmarshal(b, &wb); err != nil { | 214 if err := json.Unmarshal(b, &wb); err != nil { |
| 162 » » return nil, fmt.Errorf("Failed to unmarshal response (blessings) from Vanadium Identity Provider: %v", err) | 215 » » return nil, fmt.Errorf("failed to unmarshal response (blessings) from Vanadium Identity Provider: %v", err) |
| 163 } | 216 } |
| 164 » // TODO(ataly, gauthamt): We should verify all signatures on the certifi cate chains in the | 217 |
| 165 » // wire blessings to ensure that it was not tampered with. | 218 » // TODO(ataly, gauthamt): We should verify all signatures on the certifi cate |
| 219 » // chains in the wire blessings to ensure that it was not tampered with. | |
| 166 return &wb, nil | 220 return &wb, nil |
| 167 } | 221 } |
| 168 | 222 |
| 169 func (psd *principalServiceDelegate) addPrincipal(app vpkg.AppInstanceName, p *p rincipal) { | |
| 170 psd.mu.Lock() | |
| 171 defer psd.mu.Unlock() | |
| 172 psd.table[app] = p | |
| 173 } | |
| 174 | |
| 175 func (psd *principalServiceDelegate) getBlessing(app vpkg.AppInstanceName) *vpkg .Blessing { | |
| 176 psd.mu.Lock() | |
| 177 defer psd.mu.Unlock() | |
| 178 if p, ok := psd.table[app]; ok { | |
| 179 return newBlessing(p.blessing) | |
| 180 } | |
| 181 return nil | |
| 182 } | |
| 183 | |
| 184 func (psd *principalServiceDelegate) deletePrincipal(app vpkg.AppInstanceName) { | |
| 185 psd.mu.Lock() | |
| 186 defer psd.mu.Unlock() | |
| 187 delete(psd.table, app) | |
| 188 } | |
| 189 | |
| 190 func (psd *principalServiceDelegate) Quit() { | 223 func (psd *principalServiceDelegate) Quit() { |
| 191 psd.mu.Lock() | 224 psd.mu.Lock() |
| 192 defer psd.mu.Unlock() | 225 defer psd.mu.Unlock() |
| 193 for _, stub := range psd.stubs { | 226 for _, stub := range psd.stubs { |
| 194 stub.Close() | 227 stub.Close() |
| 195 } | 228 } |
| 196 } | 229 } |
| 197 | 230 |
| 198 func blessingRequestURL(token string, pub publicKey) (*url_request.UrlRequest, e rror) { | 231 func blessingRequestURL(token string, pub publicKey) (*url_request.UrlRequest, e rror) { |
| 199 baseURL, err := url.Parse(blesserURL) | 232 baseURL, err := url.Parse(blesserURL) |
| (...skipping 16 matching lines...) Expand all Loading... | |
| 216 } | 249 } |
| 217 | 250 |
| 218 //export MojoMain | 251 //export MojoMain |
| 219 func MojoMain(handle C.MojoHandle) C.MojoResult { | 252 func MojoMain(handle C.MojoHandle) C.MojoResult { |
| 220 application.Run(&principalServiceDelegate{}, system.MojoHandle(handle)) | 253 application.Run(&principalServiceDelegate{}, system.MojoHandle(handle)) |
| 221 return C.MOJO_RESULT_OK | 254 return C.MOJO_RESULT_OK |
| 222 } | 255 } |
| 223 | 256 |
| 224 func main() { | 257 func main() { |
| 225 } | 258 } |
| OLD | NEW |