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

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

Powered by Google App Engine
This is Rietveld 408576698