Gautham Thambidorai | 658bb42 | 2015-08-19 12:40:00 -0700 | [diff] [blame] | 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 |
| 3 | // found in the LICENSE file. |
| 4 | |
| 5 | package main |
| 6 | |
| 7 | import ( |
Gautham Thambidorai | e4b35ef | 2015-08-21 13:43:02 -0700 | [diff] [blame] | 8 | "crypto/ecdsa" |
Ankur | 0378d79 | 2015-08-31 11:30:09 -0700 | [diff] [blame] | 9 | "encoding/base64" |
| 10 | "encoding/json" |
Gautham Thambidorai | 658bb42 | 2015-08-19 12:40:00 -0700 | [diff] [blame] | 11 | "fmt" |
| 12 | "log" |
Ankur | 0378d79 | 2015-08-31 11:30:09 -0700 | [diff] [blame] | 13 | "net/url" |
Gautham Thambidorai | 658bb42 | 2015-08-19 12:40:00 -0700 | [diff] [blame] | 14 | "sync" |
| 15 | |
| 16 | "mojo/public/go/application" |
| 17 | "mojo/public/go/bindings" |
| 18 | "mojo/public/go/system" |
Ankur | 0378d79 | 2015-08-31 11:30:09 -0700 | [diff] [blame] | 19 | "mojo/public/interfaces/network/url_request" |
Viet-Trung Luu | 08e339a | 2015-10-10 01:03:09 -0700 | [diff] [blame] | 20 | auth "mojo/services/authentication/interfaces/authentication" |
Ankur | 0378d79 | 2015-08-31 11:30:09 -0700 | [diff] [blame] | 21 | network "mojo/services/network/public/interfaces/network_service" |
| 22 | "mojo/services/network/public/interfaces/url_loader" |
Viet-Trung Luu | 15a59a8 | 2015-10-10 01:11:00 -0700 | [diff] [blame^] | 23 | vpkg "mojo/services/vanadium/security/interfaces/principal" |
Gautham Thambidorai | 658bb42 | 2015-08-19 12:40:00 -0700 | [diff] [blame] | 24 | ) |
| 25 | |
| 26 | //#include "mojo/public/c/system/types.h" |
| 27 | import "C" |
| 28 | |
Ankur | 0378d79 | 2015-08-31 11:30:09 -0700 | [diff] [blame] | 29 | const blesserURL = "https://dev.v.io/auth/google/bless" |
| 30 | |
Gautham Thambidorai | e4b35ef | 2015-08-21 13:43:02 -0700 | [diff] [blame] | 31 | type principalServiceImpl struct { |
| 32 | app vpkg.AppInstanceName |
| 33 | psd *principalServiceDelegate |
Gautham Thambidorai | 658bb42 | 2015-08-19 12:40:00 -0700 | [diff] [blame] | 34 | } |
| 35 | |
Ankur | 0378d79 | 2015-08-31 11:30:09 -0700 | [diff] [blame] | 36 | func (pImpl *principalServiceImpl) Login() (*vpkg.Blessing, error) { |
| 37 | if b := pImpl.psd.getBlessing(pImpl.app); b != nil { |
| 38 | // The app has already logged in. |
| 39 | return b, nil |
Gautham Thambidorai | e4b35ef | 2015-08-21 13:43:02 -0700 | [diff] [blame] | 40 | } |
Gautham Thambidorai | e4b35ef | 2015-08-21 13:43:02 -0700 | [diff] [blame] | 41 | |
Ankur | 0378d79 | 2015-08-31 11:30:09 -0700 | [diff] [blame] | 42 | token, err := pImpl.psd.getOAuth2Token() |
| 43 | if err != nil { |
| 44 | return nil, err |
Gautham Thambidorai | 658bb42 | 2015-08-19 12:40:00 -0700 | [diff] [blame] | 45 | } |
Ankur | 0378d79 | 2015-08-31 11:30:09 -0700 | [diff] [blame] | 46 | |
| 47 | pub, priv, err := newPrincipalKey() |
| 48 | if err != nil { |
| 49 | return nil, err |
| 50 | } |
| 51 | |
| 52 | wb, err := pImpl.psd.fetchWireBlessings(token, pub) |
| 53 | if err != nil { |
| 54 | return nil, err |
| 55 | } |
| 56 | |
| 57 | pImpl.psd.addPrincipal(pImpl.app, &principal{wb, priv}) |
| 58 | return newBlessing(wb), nil |
Gautham Thambidorai | 658bb42 | 2015-08-19 12:40:00 -0700 | [diff] [blame] | 59 | } |
| 60 | |
Gautham Thambidorai | e4b35ef | 2015-08-21 13:43:02 -0700 | [diff] [blame] | 61 | func (pImpl *principalServiceImpl) Logout() (err error) { |
| 62 | pImpl.psd.deletePrincipal(pImpl.app) |
Gautham Thambidorai | 658bb42 | 2015-08-19 12:40:00 -0700 | [diff] [blame] | 63 | return |
| 64 | } |
| 65 | |
Gautham Thambidorai | e4b35ef | 2015-08-21 13:43:02 -0700 | [diff] [blame] | 66 | func (pImpl *principalServiceImpl) GetUserBlessing(app vpkg.AppInstanceName) (*vpkg.Blessing, error) { |
| 67 | return pImpl.psd.getBlessing(app), nil |
Gautham Thambidorai | 658bb42 | 2015-08-19 12:40:00 -0700 | [diff] [blame] | 68 | } |
| 69 | |
Gautham Thambidorai | e4b35ef | 2015-08-21 13:43:02 -0700 | [diff] [blame] | 70 | func (pImpl *principalServiceImpl) Create(req vpkg.PrincipalService_Request) { |
| 71 | stub := vpkg.NewPrincipalServiceStub(req, pImpl, bindings.GetAsyncWaiter()) |
Gautham Thambidorai | 658bb42 | 2015-08-19 12:40:00 -0700 | [diff] [blame] | 72 | pImpl.psd.addStubForCleanup(stub) |
| 73 | go func() { |
| 74 | for { |
| 75 | if err := stub.ServeRequest(); err != nil { |
| 76 | connectionError, ok := err.(*bindings.ConnectionError) |
| 77 | if !ok || !connectionError.Closed() { |
| 78 | log.Println(err) |
| 79 | } |
| 80 | break |
| 81 | } |
| 82 | } |
| 83 | }() |
| 84 | } |
| 85 | |
Gautham Thambidorai | e4b35ef | 2015-08-21 13:43:02 -0700 | [diff] [blame] | 86 | type principal struct { |
Ankur | 0378d79 | 2015-08-31 11:30:09 -0700 | [diff] [blame] | 87 | blessing *wireBlessings |
Gautham Thambidorai | e4b35ef | 2015-08-21 13:43:02 -0700 | [diff] [blame] | 88 | private *ecdsa.PrivateKey |
| 89 | } |
| 90 | |
| 91 | type principalServiceDelegate struct { |
| 92 | table map[vpkg.AppInstanceName]*principal |
Gautham Thambidorai | 658bb42 | 2015-08-19 12:40:00 -0700 | [diff] [blame] | 93 | Ctx application.Context |
| 94 | mu sync.Mutex |
| 95 | stubs []*bindings.Stub |
| 96 | } |
| 97 | |
Gautham Thambidorai | e4b35ef | 2015-08-21 13:43:02 -0700 | [diff] [blame] | 98 | func (psd *principalServiceDelegate) Initialize(context application.Context) { |
| 99 | psd.table = make(map[vpkg.AppInstanceName]*principal) |
Gautham Thambidorai | 658bb42 | 2015-08-19 12:40:00 -0700 | [diff] [blame] | 100 | psd.Ctx = context |
| 101 | } |
| 102 | |
Gautham Thambidorai | e4b35ef | 2015-08-21 13:43:02 -0700 | [diff] [blame] | 103 | func (psd *principalServiceDelegate) AcceptConnection(connection *application.Connection) { |
| 104 | app := vpkg.AppInstanceName{ |
Gautham Thambidorai | 658bb42 | 2015-08-19 12:40:00 -0700 | [diff] [blame] | 105 | Url: connection.RequestorURL(), |
| 106 | Qualifier: nil, |
| 107 | } |
Gautham Thambidorai | e4b35ef | 2015-08-21 13:43:02 -0700 | [diff] [blame] | 108 | connection.ProvideServices(&vpkg.PrincipalService_ServiceFactory{&principalServiceImpl{app, psd}}) |
Gautham Thambidorai | 658bb42 | 2015-08-19 12:40:00 -0700 | [diff] [blame] | 109 | } |
| 110 | |
Gautham Thambidorai | e4b35ef | 2015-08-21 13:43:02 -0700 | [diff] [blame] | 111 | func (psd *principalServiceDelegate) addStubForCleanup(stub *bindings.Stub) { |
Gautham Thambidorai | 658bb42 | 2015-08-19 12:40:00 -0700 | [diff] [blame] | 112 | psd.mu.Lock() |
| 113 | defer psd.mu.Unlock() |
| 114 | psd.stubs = append(psd.stubs, stub) |
| 115 | } |
| 116 | |
Ankur | 0378d79 | 2015-08-31 11:30:09 -0700 | [diff] [blame] | 117 | func (psd *principalServiceDelegate) getOAuth2Token() (string, error) { |
| 118 | authReq, authPtr := auth.CreateMessagePipeForAuthenticationService() |
| 119 | psd.Ctx.ConnectToApplication("mojo:authentication").ConnectToService(&authReq) |
| 120 | authProxy := auth.NewAuthenticationServiceProxy(authPtr, bindings.GetAsyncWaiter()) |
| 121 | |
| 122 | name, errString, _ := authProxy.SelectAccount(false /*return_last_selected*/) |
| 123 | if name == nil { |
| 124 | return "", fmt.Errorf("Failed to select an account for user:%s", errString) |
| 125 | } |
| 126 | |
| 127 | token, errString, _ := authProxy.GetOAuth2Token(*name, []string{"email"}) |
| 128 | if token == nil { |
| 129 | return "", fmt.Errorf("Failed to obtain OAuth2 token for selected account:%s", errString) |
| 130 | } |
| 131 | return *token, nil |
| 132 | } |
| 133 | |
| 134 | func (psd *principalServiceDelegate) fetchWireBlessings(token string, pub publicKey) (*wireBlessings, error) { |
| 135 | networkReq, networkPtr := network.CreateMessagePipeForNetworkService() |
| 136 | psd.Ctx.ConnectToApplication("mojo:network_service").ConnectToService(&networkReq) |
| 137 | networkProxy := network.NewNetworkServiceProxy(networkPtr, bindings.GetAsyncWaiter()) |
| 138 | |
| 139 | urlLoaderReq, urlLoaderPtr := url_loader.CreateMessagePipeForUrlLoader() |
| 140 | if err := networkProxy.CreateUrlLoader(urlLoaderReq); err != nil { |
| 141 | return nil, fmt.Errorf("Failed to create url loader: %v", err) |
| 142 | } |
| 143 | urlLoaderProxy := url_loader.NewUrlLoaderProxy(urlLoaderPtr, bindings.GetAsyncWaiter()) |
| 144 | |
| 145 | req, err := blessingRequestURL(token, pub) |
| 146 | if err != nil { |
| 147 | return nil, err |
| 148 | } |
| 149 | |
| 150 | resp, err := urlLoaderProxy.Start(*req) |
| 151 | if err != nil || resp.Error != nil { |
| 152 | return nil, fmt.Errorf("Blessings request to Vanadium Identity Provider failed: %v(%v)", err, resp.Error) |
| 153 | } |
| 154 | |
| 155 | res, b := (*resp.Body).ReadData(system.MOJO_READ_DATA_FLAG_ALL_OR_NONE) |
| 156 | if res != system.MOJO_RESULT_OK { |
| 157 | return nil, fmt.Errorf("Failed to read response (blessings) from Vanadium Identity Provider. Result: %v", res) |
| 158 | } |
| 159 | |
| 160 | var wb wireBlessings |
| 161 | if err := json.Unmarshal(b, &wb); err != nil { |
| 162 | return nil, fmt.Errorf("Failed to unmarshal response (blessings) from Vanadium Identity Provider: %v", err) |
| 163 | } |
| 164 | // TODO(ataly, gauthamt): We should verify all signatures on the certificate chains in the |
| 165 | // wire blessings to ensure that it was not tampered with. |
| 166 | return &wb, nil |
| 167 | } |
| 168 | |
Gautham Thambidorai | e4b35ef | 2015-08-21 13:43:02 -0700 | [diff] [blame] | 169 | func (psd *principalServiceDelegate) addPrincipal(app vpkg.AppInstanceName, p *principal) { |
Gautham Thambidorai | 658bb42 | 2015-08-19 12:40:00 -0700 | [diff] [blame] | 170 | psd.mu.Lock() |
| 171 | defer psd.mu.Unlock() |
Gautham Thambidorai | e4b35ef | 2015-08-21 13:43:02 -0700 | [diff] [blame] | 172 | psd.table[app] = p |
Gautham Thambidorai | 658bb42 | 2015-08-19 12:40:00 -0700 | [diff] [blame] | 173 | } |
| 174 | |
Gautham Thambidorai | e4b35ef | 2015-08-21 13:43:02 -0700 | [diff] [blame] | 175 | func (psd *principalServiceDelegate) getBlessing(app vpkg.AppInstanceName) *vpkg.Blessing { |
Gautham Thambidorai | 658bb42 | 2015-08-19 12:40:00 -0700 | [diff] [blame] | 176 | psd.mu.Lock() |
| 177 | defer psd.mu.Unlock() |
Gautham Thambidorai | e4b35ef | 2015-08-21 13:43:02 -0700 | [diff] [blame] | 178 | if p, ok := psd.table[app]; ok { |
Ankur | 0378d79 | 2015-08-31 11:30:09 -0700 | [diff] [blame] | 179 | return newBlessing(p.blessing) |
Gautham Thambidorai | e4b35ef | 2015-08-21 13:43:02 -0700 | [diff] [blame] | 180 | } |
| 181 | return nil |
Gautham Thambidorai | 658bb42 | 2015-08-19 12:40:00 -0700 | [diff] [blame] | 182 | } |
| 183 | |
Gautham Thambidorai | e4b35ef | 2015-08-21 13:43:02 -0700 | [diff] [blame] | 184 | func (psd *principalServiceDelegate) deletePrincipal(app vpkg.AppInstanceName) { |
Gautham Thambidorai | 658bb42 | 2015-08-19 12:40:00 -0700 | [diff] [blame] | 185 | psd.mu.Lock() |
| 186 | defer psd.mu.Unlock() |
Gautham Thambidorai | e4b35ef | 2015-08-21 13:43:02 -0700 | [diff] [blame] | 187 | delete(psd.table, app) |
Gautham Thambidorai | 658bb42 | 2015-08-19 12:40:00 -0700 | [diff] [blame] | 188 | } |
| 189 | |
Gautham Thambidorai | e4b35ef | 2015-08-21 13:43:02 -0700 | [diff] [blame] | 190 | func (psd *principalServiceDelegate) Quit() { |
Gautham Thambidorai | 658bb42 | 2015-08-19 12:40:00 -0700 | [diff] [blame] | 191 | psd.mu.Lock() |
| 192 | defer psd.mu.Unlock() |
| 193 | for _, stub := range psd.stubs { |
| 194 | stub.Close() |
| 195 | } |
| 196 | } |
| 197 | |
Ankur | 0378d79 | 2015-08-31 11:30:09 -0700 | [diff] [blame] | 198 | func blessingRequestURL(token string, pub publicKey) (*url_request.UrlRequest, error) { |
| 199 | baseURL, err := url.Parse(blesserURL) |
| 200 | if err != nil { |
| 201 | return nil, err |
| 202 | } |
| 203 | |
| 204 | pubBytes, err := pub.MarshalBinary() |
| 205 | if err != nil { |
| 206 | return nil, err |
| 207 | } |
| 208 | |
| 209 | params := url.Values{} |
| 210 | params.Add("public_key", base64.URLEncoding.EncodeToString(pubBytes)) |
| 211 | params.Add("token", token) |
| 212 | params.Add("output_format", "json") |
| 213 | |
| 214 | baseURL.RawQuery = params.Encode() |
| 215 | return &url_request.UrlRequest{Url: baseURL.String(), Method: "GET"}, nil |
| 216 | } |
| 217 | |
Gautham Thambidorai | 658bb42 | 2015-08-19 12:40:00 -0700 | [diff] [blame] | 218 | //export MojoMain |
| 219 | func MojoMain(handle C.MojoHandle) C.MojoResult { |
Gautham Thambidorai | e4b35ef | 2015-08-21 13:43:02 -0700 | [diff] [blame] | 220 | application.Run(&principalServiceDelegate{}, system.MojoHandle(handle)) |
Gautham Thambidorai | 658bb42 | 2015-08-19 12:40:00 -0700 | [diff] [blame] | 221 | return C.MOJO_RESULT_OK |
| 222 | } |
| 223 | |
| 224 | func main() { |
| 225 | } |