Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(184)

Side by Side Diff: services/vanadium/security/principal_service.go

Issue 1418013004: Principal Service: Add support for multiple user accounts (Closed) Base URL: https://github.com/domokit/mojo.git@master
Patch Set: Created 5 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « services/vanadium/security/principal.go ('k') | services/vanadium/security/public_key.go » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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"
10 "errors"
11 "fmt" 11 "fmt"
12 "log" 12 "log"
13 "net/url" 13 "net/url"
14 "sync" 14 "sync"
15 15
16 "mojo/public/go/application" 16 "mojo/public/go/application"
17 "mojo/public/go/bindings" 17 "mojo/public/go/bindings"
18 "mojo/public/go/system" 18 "mojo/public/go/system"
19 "mojo/public/interfaces/network/url_request" 19 "mojo/public/interfaces/network/url_request"
20 auth "mojo/services/authentication/interfaces/authentication" 20 auth "mojo/services/authentication/interfaces/authentication"
21 network "mojo/services/network/interfaces/network_service" 21 network "mojo/services/network/interfaces/network_service"
22 "mojo/services/network/interfaces/url_loader" 22 "mojo/services/network/interfaces/url_loader"
23 vpkg "mojo/services/vanadium/security/interfaces/principal" 23 vpkg "mojo/services/vanadium/security/interfaces/principal"
24 ) 24 )
25 25
26 //#include "mojo/public/c/system/types.h" 26 //#include "mojo/public/c/system/types.h"
27 import "C" 27 import "C"
28 28
29 const blesserURL = "https://dev.v.io/auth/google/bless" 29 const blesserURL = "https://dev.v.io/auth/google/bless"
30 30
31 type principalServiceImpl struct { 31 type principalServiceImpl struct {
32 app vpkg.AppInstanceName 32 app vpkg.AppInstanceName
33 psd *principalServiceDelegate 33 psd *principalServiceDelegate
34 } 34 }
35 35
36 func (pImpl *principalServiceImpl) Login() (*vpkg.Blessing, error) { 36 func (pImpl *principalServiceImpl) Login() (*vpkg.User, error) {
37 » if b := pImpl.psd.getBlessing(pImpl.app); b != nil { 37 » p, err := pImpl.psd.initPrincipal(pImpl.app)
38 » » // The app has already logged in. 38 » if err != nil {
39 » » return b, nil 39 » » return nil, err
40 } 40 }
41 41
42 token, err := pImpl.psd.getOAuth2Token() 42 token, err := pImpl.psd.getOAuth2Token()
43 if err != nil { 43 if err != nil {
44 return nil, err 44 return nil, err
45 } 45 }
46 46
47 » pub, priv, err := newPrincipalKey() 47 » wb, err := pImpl.psd.getBlessings(token, p.publicKey())
48 if err != nil { 48 if err != nil {
49 return nil, err 49 return nil, err
50 } 50 }
51 51
52 » wb, err := pImpl.psd.fetchWireBlessings(token, pub) 52 » email, err := emailFromBlessings(wb)
53 if err != nil { 53 if err != nil {
54 return nil, err 54 return nil, err
55 } 55 }
56 56
57 » pImpl.psd.addPrincipal(pImpl.app, &principal{wb, priv}) 57 » user := vpkg.User{Email: email, Blessing: newBlessing(wb)}
58 » return newBlessing(wb), nil 58 » p.addUser(user)
59 » return &user, nil
60 }
61
62 func (pImpl *principalServiceImpl) GetLoggedInUsers() ([]vpkg.User, error) {
63 » if p := pImpl.psd.principal(pImpl.app); p != nil {
64 » » users := p.users()
65 » » return users, nil
66 » }
67 » return nil, fmt.Errorf("no principal available for app %v", pImpl.app)
68 }
69
70 func (pImpl *principalServiceImpl) SetUser(user vpkg.User) (*string, error) {
71 » if p := pImpl.psd.principal(pImpl.app); p != nil {
72 » » return p.setCurrentUser(user), nil
73 » }
74 » str := fmt.Sprintf("no principal available for app %v; please invoke Log in()", pImpl.app)
75 » return &str, errors.New(str)
59 } 76 }
60 77
61 func (pImpl *principalServiceImpl) Logout() (err error) { 78 func (pImpl *principalServiceImpl) Logout() (err error) {
62 » pImpl.psd.deletePrincipal(pImpl.app) 79 » if p := pImpl.psd.principal(pImpl.app); p != nil {
63 » return 80 » » p.clearCurrentUser()
81 » }
82 » return nil
64 } 83 }
65 84
66 func (pImpl *principalServiceImpl) GetUserBlessing(app vpkg.AppInstanceName) (*v pkg.Blessing, error) { 85 func (pImpl *principalServiceImpl) GetUser(app *vpkg.AppInstanceName) (*vpkg.Use r, error) {
67 » return pImpl.psd.getBlessing(app), nil 86 » if app == nil {
87 » » app = &pImpl.app
88 » }
89 » p := pImpl.psd.principal(*app)
90 » if p == nil {
91 » » return nil, fmt.Errorf("no principal available for app %v", pImp l.app)
92 » }
93 » return p.curr, nil
68 } 94 }
69 95
70 func (pImpl *principalServiceImpl) Create(req vpkg.PrincipalService_Request) { 96 func (pImpl *principalServiceImpl) Create(req vpkg.PrincipalService_Request) {
71 stub := vpkg.NewPrincipalServiceStub(req, pImpl, bindings.GetAsyncWaiter ()) 97 stub := vpkg.NewPrincipalServiceStub(req, pImpl, bindings.GetAsyncWaiter ())
72 pImpl.psd.addStubForCleanup(stub) 98 pImpl.psd.addStubForCleanup(stub)
73 go func() { 99 go func() {
74 for { 100 for {
75 if err := stub.ServeRequest(); err != nil { 101 if err := stub.ServeRequest(); err != nil {
76 connectionError, ok := err.(*bindings.Connection Error) 102 connectionError, ok := err.(*bindings.Connection Error)
77 if !ok || !connectionError.Closed() { 103 if !ok || !connectionError.Closed() {
78 log.Println(err) 104 log.Println(err)
79 } 105 }
80 break 106 break
81 } 107 }
82 } 108 }
83 }() 109 }()
84 } 110 }
85 111
86 type principal struct {
87 blessing *wireBlessings
88 private *ecdsa.PrivateKey
89 }
90
91 type principalServiceDelegate struct { 112 type principalServiceDelegate struct {
92 » table map[vpkg.AppInstanceName]*principal 113 » Ctx application.Context
93 » Ctx application.Context 114 » mu sync.Mutex
94 » mu sync.Mutex 115 » stubs []*bindings.Stub // GUARDED_BY(mu)
95 » stubs []*bindings.Stub 116 » appPrincipals map[vpkg.AppInstanceName]*principal // GUARDED_BY(mu)
96 } 117 }
97 118
98 func (psd *principalServiceDelegate) Initialize(context application.Context) { 119 func (psd *principalServiceDelegate) Initialize(context application.Context) {
99 » psd.table = make(map[vpkg.AppInstanceName]*principal) 120 » psd.appPrincipals = make(map[vpkg.AppInstanceName]*principal)
100 psd.Ctx = context 121 psd.Ctx = context
101 } 122 }
102 123
103 func (psd *principalServiceDelegate) AcceptConnection(connection *application.Co nnection) { 124 func (psd *principalServiceDelegate) AcceptConnection(connection *application.Co nnection) {
104 app := vpkg.AppInstanceName{ 125 app := vpkg.AppInstanceName{
105 Url: connection.RequestorURL(), 126 Url: connection.RequestorURL(),
106 Qualifier: nil, 127 Qualifier: nil,
107 } 128 }
108 connection.ProvideServices(&vpkg.PrincipalService_ServiceFactory{&princi palServiceImpl{app, psd}}) 129 connection.ProvideServices(&vpkg.PrincipalService_ServiceFactory{&princi palServiceImpl{app, psd}})
109 } 130 }
110 131
111 func (psd *principalServiceDelegate) addStubForCleanup(stub *bindings.Stub) { 132 func (psd *principalServiceDelegate) addStubForCleanup(stub *bindings.Stub) {
112 psd.mu.Lock() 133 psd.mu.Lock()
113 defer psd.mu.Unlock() 134 defer psd.mu.Unlock()
114 psd.stubs = append(psd.stubs, stub) 135 psd.stubs = append(psd.stubs, stub)
115 } 136 }
116 137
138 func (psd *principalServiceDelegate) principal(app vpkg.AppInstanceName) *princi pal {
139 psd.mu.Lock()
140 defer psd.mu.Unlock()
141 return psd.appPrincipals[app]
142 }
143
144 func (psd *principalServiceDelegate) initPrincipal(app vpkg.AppInstanceName) (*p rincipal, error) {
145 psd.mu.Lock()
146 defer psd.mu.Unlock()
147 if p, ok := psd.appPrincipals[app]; ok {
148 return p, nil
149 }
150 p, err := newPrincipal()
151 if err != nil {
152 return nil, err
153 }
154 psd.appPrincipals[app] = p
155 return p, nil
156 }
157
117 func (psd *principalServiceDelegate) getOAuth2Token() (string, error) { 158 func (psd *principalServiceDelegate) getOAuth2Token() (string, error) {
118 authReq, authPtr := auth.CreateMessagePipeForAuthenticationService() 159 authReq, authPtr := auth.CreateMessagePipeForAuthenticationService()
119 psd.Ctx.ConnectToApplication("mojo:authentication").ConnectToService(&au thReq) 160 psd.Ctx.ConnectToApplication("mojo:authentication").ConnectToService(&au thReq)
120 authProxy := auth.NewAuthenticationServiceProxy(authPtr, bindings.GetAsy ncWaiter()) 161 authProxy := auth.NewAuthenticationServiceProxy(authPtr, bindings.GetAsy ncWaiter())
121 162
122 name, errString, _ := authProxy.SelectAccount(false /*return_last_select ed*/) 163 name, errString, _ := authProxy.SelectAccount(false /*return_last_select ed*/)
123 if name == nil { 164 if name == nil {
124 » » return "", fmt.Errorf("Failed to select an account for user:%s", errString) 165 » » return "", fmt.Errorf("failed to select an account for user:%s", errString)
125 } 166 }
126
127 token, errString, _ := authProxy.GetOAuth2Token(*name, []string{"email"} ) 167 token, errString, _ := authProxy.GetOAuth2Token(*name, []string{"email"} )
128 if token == nil { 168 if token == nil {
129 » » return "", fmt.Errorf("Failed to obtain OAuth2 token for selecte d account:%s", errString) 169 » » return "", fmt.Errorf("failed to obtain OAuth2 token for selecte d account:%s", errString)
130 } 170 }
131 return *token, nil 171 return *token, nil
132 } 172 }
133 173
134 func (psd *principalServiceDelegate) fetchWireBlessings(token string, pub public Key) (*wireBlessings, error) { 174 func (psd *principalServiceDelegate) getBlessings(token string, pub publicKey) ( *wireBlessings, error) {
135 networkReq, networkPtr := network.CreateMessagePipeForNetworkService() 175 networkReq, networkPtr := network.CreateMessagePipeForNetworkService()
136 psd.Ctx.ConnectToApplication("mojo:network_service").ConnectToService(&n etworkReq) 176 psd.Ctx.ConnectToApplication("mojo:network_service").ConnectToService(&n etworkReq)
137 networkProxy := network.NewNetworkServiceProxy(networkPtr, bindings.GetA syncWaiter()) 177 networkProxy := network.NewNetworkServiceProxy(networkPtr, bindings.GetA syncWaiter())
138 178
139 urlLoaderReq, urlLoaderPtr := url_loader.CreateMessagePipeForUrlLoader() 179 urlLoaderReq, urlLoaderPtr := url_loader.CreateMessagePipeForUrlLoader()
140 if err := networkProxy.CreateUrlLoader(urlLoaderReq); err != nil { 180 if err := networkProxy.CreateUrlLoader(urlLoaderReq); err != nil {
141 » » return nil, fmt.Errorf("Failed to create url loader: %v", err) 181 » » return nil, fmt.Errorf("failed to create url loader: %v", err)
142 } 182 }
143 » urlLoaderProxy := url_loader.NewUrlLoaderProxy(urlLoaderPtr, bindings.Ge tAsyncWaiter()) 183 » urlLoader := url_loader.NewUrlLoaderProxy(urlLoaderPtr, bindings.GetAsyn cWaiter())
144 184
145 req, err := blessingRequestURL(token, pub) 185 req, err := blessingRequestURL(token, pub)
146 if err != nil { 186 if err != nil {
147 return nil, err 187 return nil, err
148 } 188 }
149 189
150 » resp, err := urlLoaderProxy.Start(*req) 190 » resp, err := urlLoader.Start(*req)
151 if err != nil || resp.Error != nil { 191 if err != nil || resp.Error != nil {
152 » » return nil, fmt.Errorf("Blessings request to Vanadium Identity P rovider failed: %v(%v)", err, resp.Error) 192 » » return nil, fmt.Errorf("blessings request to Vanadium Identity P rovider failed: %v(%v)", err, resp.Error)
153 } 193 }
154 194
155 res, b := (*resp.Body).ReadData(system.MOJO_READ_DATA_FLAG_ALL_OR_NONE) 195 res, b := (*resp.Body).ReadData(system.MOJO_READ_DATA_FLAG_ALL_OR_NONE)
156 if res != system.MOJO_RESULT_OK { 196 if res != system.MOJO_RESULT_OK {
157 » » return nil, fmt.Errorf("Failed to read response (blessings) from Vanadium Identity Provider. Result: %v", res) 197 » » return nil, fmt.Errorf("failed to read response (blessings) from Vanadium Identity Provider. Result: %v", res)
158 } 198 }
159 199
160 var wb wireBlessings 200 var wb wireBlessings
161 if err := json.Unmarshal(b, &wb); err != nil { 201 if err := json.Unmarshal(b, &wb); err != nil {
162 » » return nil, fmt.Errorf("Failed to unmarshal response (blessings) from Vanadium Identity Provider: %v", err) 202 » » return nil, fmt.Errorf("failed to unmarshal response (blessings) from Vanadium Identity Provider: %v", err)
163 } 203 }
164 » // TODO(ataly, gauthamt): We should verify all signatures on the certifi cate chains in the 204
165 » // wire blessings to ensure that it was not tampered with. 205 » // TODO(ataly, gauthamt): We should verify all signatures on the certifi cate
206 » // chains in the wire blessings to ensure that it was not tampered with.
166 return &wb, nil 207 return &wb, nil
167 } 208 }
168 209
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() { 210 func (psd *principalServiceDelegate) Quit() {
191 psd.mu.Lock() 211 psd.mu.Lock()
192 defer psd.mu.Unlock() 212 defer psd.mu.Unlock()
193 for _, stub := range psd.stubs { 213 for _, stub := range psd.stubs {
194 stub.Close() 214 stub.Close()
195 } 215 }
196 } 216 }
197 217
198 func blessingRequestURL(token string, pub publicKey) (*url_request.UrlRequest, e rror) { 218 func blessingRequestURL(token string, pub publicKey) (*url_request.UrlRequest, e rror) {
199 baseURL, err := url.Parse(blesserURL) 219 baseURL, err := url.Parse(blesserURL)
(...skipping 16 matching lines...) Expand all
216 } 236 }
217 237
218 //export MojoMain 238 //export MojoMain
219 func MojoMain(handle C.MojoHandle) C.MojoResult { 239 func MojoMain(handle C.MojoHandle) C.MojoResult {
220 application.Run(&principalServiceDelegate{}, system.MojoHandle(handle)) 240 application.Run(&principalServiceDelegate{}, system.MojoHandle(handle))
221 return C.MOJO_RESULT_OK 241 return C.MOJO_RESULT_OK
222 } 242 }
223 243
224 func main() { 244 func main() {
225 } 245 }
OLDNEW
« no previous file with comments | « services/vanadium/security/principal.go ('k') | services/vanadium/security/public_key.go » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698