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

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, 2 months 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
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"
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
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 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698