blob: 6f31f5b81fc7a8be49abe4b0dcc3da5285e25136 [file] [log] [blame]
Gautham Thambidorai658bb422015-08-19 12:40:00 -07001// 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
5package main
6
7import (
Gautham Thambidoraie4b35ef2015-08-21 13:43:02 -07008 "crypto/ecdsa"
Ankur0378d792015-08-31 11:30:09 -07009 "encoding/base64"
10 "encoding/json"
Gautham Thambidorai658bb422015-08-19 12:40:00 -070011 "fmt"
12 "log"
Ankur0378d792015-08-31 11:30:09 -070013 "net/url"
Gautham Thambidorai658bb422015-08-19 12:40:00 -070014 "sync"
15
16 "mojo/public/go/application"
17 "mojo/public/go/bindings"
18 "mojo/public/go/system"
Ankur0378d792015-08-31 11:30:09 -070019 "mojo/public/interfaces/network/url_request"
Viet-Trung Luu08e339a2015-10-10 01:03:09 -070020 auth "mojo/services/authentication/interfaces/authentication"
Ankur0378d792015-08-31 11:30:09 -070021 network "mojo/services/network/public/interfaces/network_service"
22 "mojo/services/network/public/interfaces/url_loader"
Viet-Trung Luu15a59a82015-10-10 01:11:00 -070023 vpkg "mojo/services/vanadium/security/interfaces/principal"
Gautham Thambidorai658bb422015-08-19 12:40:00 -070024)
25
26//#include "mojo/public/c/system/types.h"
27import "C"
28
Ankur0378d792015-08-31 11:30:09 -070029const blesserURL = "https://dev.v.io/auth/google/bless"
30
Gautham Thambidoraie4b35ef2015-08-21 13:43:02 -070031type principalServiceImpl struct {
32 app vpkg.AppInstanceName
33 psd *principalServiceDelegate
Gautham Thambidorai658bb422015-08-19 12:40:00 -070034}
35
Ankur0378d792015-08-31 11:30:09 -070036func (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 Thambidoraie4b35ef2015-08-21 13:43:02 -070040 }
Gautham Thambidoraie4b35ef2015-08-21 13:43:02 -070041
Ankur0378d792015-08-31 11:30:09 -070042 token, err := pImpl.psd.getOAuth2Token()
43 if err != nil {
44 return nil, err
Gautham Thambidorai658bb422015-08-19 12:40:00 -070045 }
Ankur0378d792015-08-31 11:30:09 -070046
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 Thambidorai658bb422015-08-19 12:40:00 -070059}
60
Gautham Thambidoraie4b35ef2015-08-21 13:43:02 -070061func (pImpl *principalServiceImpl) Logout() (err error) {
62 pImpl.psd.deletePrincipal(pImpl.app)
Gautham Thambidorai658bb422015-08-19 12:40:00 -070063 return
64}
65
Gautham Thambidoraie4b35ef2015-08-21 13:43:02 -070066func (pImpl *principalServiceImpl) GetUserBlessing(app vpkg.AppInstanceName) (*vpkg.Blessing, error) {
67 return pImpl.psd.getBlessing(app), nil
Gautham Thambidorai658bb422015-08-19 12:40:00 -070068}
69
Gautham Thambidoraie4b35ef2015-08-21 13:43:02 -070070func (pImpl *principalServiceImpl) Create(req vpkg.PrincipalService_Request) {
71 stub := vpkg.NewPrincipalServiceStub(req, pImpl, bindings.GetAsyncWaiter())
Gautham Thambidorai658bb422015-08-19 12:40:00 -070072 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 Thambidoraie4b35ef2015-08-21 13:43:02 -070086type principal struct {
Ankur0378d792015-08-31 11:30:09 -070087 blessing *wireBlessings
Gautham Thambidoraie4b35ef2015-08-21 13:43:02 -070088 private *ecdsa.PrivateKey
89}
90
91type principalServiceDelegate struct {
92 table map[vpkg.AppInstanceName]*principal
Gautham Thambidorai658bb422015-08-19 12:40:00 -070093 Ctx application.Context
94 mu sync.Mutex
95 stubs []*bindings.Stub
96}
97
Gautham Thambidoraie4b35ef2015-08-21 13:43:02 -070098func (psd *principalServiceDelegate) Initialize(context application.Context) {
99 psd.table = make(map[vpkg.AppInstanceName]*principal)
Gautham Thambidorai658bb422015-08-19 12:40:00 -0700100 psd.Ctx = context
101}
102
Gautham Thambidoraie4b35ef2015-08-21 13:43:02 -0700103func (psd *principalServiceDelegate) AcceptConnection(connection *application.Connection) {
104 app := vpkg.AppInstanceName{
Gautham Thambidorai658bb422015-08-19 12:40:00 -0700105 Url: connection.RequestorURL(),
106 Qualifier: nil,
107 }
Gautham Thambidoraie4b35ef2015-08-21 13:43:02 -0700108 connection.ProvideServices(&vpkg.PrincipalService_ServiceFactory{&principalServiceImpl{app, psd}})
Gautham Thambidorai658bb422015-08-19 12:40:00 -0700109}
110
Gautham Thambidoraie4b35ef2015-08-21 13:43:02 -0700111func (psd *principalServiceDelegate) addStubForCleanup(stub *bindings.Stub) {
Gautham Thambidorai658bb422015-08-19 12:40:00 -0700112 psd.mu.Lock()
113 defer psd.mu.Unlock()
114 psd.stubs = append(psd.stubs, stub)
115}
116
Ankur0378d792015-08-31 11:30:09 -0700117func (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
134func (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 Thambidoraie4b35ef2015-08-21 13:43:02 -0700169func (psd *principalServiceDelegate) addPrincipal(app vpkg.AppInstanceName, p *principal) {
Gautham Thambidorai658bb422015-08-19 12:40:00 -0700170 psd.mu.Lock()
171 defer psd.mu.Unlock()
Gautham Thambidoraie4b35ef2015-08-21 13:43:02 -0700172 psd.table[app] = p
Gautham Thambidorai658bb422015-08-19 12:40:00 -0700173}
174
Gautham Thambidoraie4b35ef2015-08-21 13:43:02 -0700175func (psd *principalServiceDelegate) getBlessing(app vpkg.AppInstanceName) *vpkg.Blessing {
Gautham Thambidorai658bb422015-08-19 12:40:00 -0700176 psd.mu.Lock()
177 defer psd.mu.Unlock()
Gautham Thambidoraie4b35ef2015-08-21 13:43:02 -0700178 if p, ok := psd.table[app]; ok {
Ankur0378d792015-08-31 11:30:09 -0700179 return newBlessing(p.blessing)
Gautham Thambidoraie4b35ef2015-08-21 13:43:02 -0700180 }
181 return nil
Gautham Thambidorai658bb422015-08-19 12:40:00 -0700182}
183
Gautham Thambidoraie4b35ef2015-08-21 13:43:02 -0700184func (psd *principalServiceDelegate) deletePrincipal(app vpkg.AppInstanceName) {
Gautham Thambidorai658bb422015-08-19 12:40:00 -0700185 psd.mu.Lock()
186 defer psd.mu.Unlock()
Gautham Thambidoraie4b35ef2015-08-21 13:43:02 -0700187 delete(psd.table, app)
Gautham Thambidorai658bb422015-08-19 12:40:00 -0700188}
189
Gautham Thambidoraie4b35ef2015-08-21 13:43:02 -0700190func (psd *principalServiceDelegate) Quit() {
Gautham Thambidorai658bb422015-08-19 12:40:00 -0700191 psd.mu.Lock()
192 defer psd.mu.Unlock()
193 for _, stub := range psd.stubs {
194 stub.Close()
195 }
196}
197
Ankur0378d792015-08-31 11:30:09 -0700198func 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 Thambidorai658bb422015-08-19 12:40:00 -0700218//export MojoMain
219func MojoMain(handle C.MojoHandle) C.MojoResult {
Gautham Thambidoraie4b35ef2015-08-21 13:43:02 -0700220 application.Run(&principalServiceDelegate{}, system.MojoHandle(handle))
Gautham Thambidorai658bb422015-08-19 12:40:00 -0700221 return C.MOJO_RESULT_OK
222}
223
224func main() {
225}