blob: 40138e61fe4cc9bdfd9ca800fa3f041c5f28d6e4 [file] [log] [blame]
Jiri Simsad7616c92015-03-24 23:44:30 -07001// Copyright 2015 The Vanadium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
Asim Shankar61071792014-07-22 13:03:18 -07005package blesser
6
7import (
Asim Shankar71061572014-07-22 16:59:18 -07008 "fmt"
Asim Shankar3bbd1e32015-01-09 11:52:54 -08009 "strings"
Asim Shankar61071792014-07-22 13:03:18 -070010 "time"
11
Jiri Simsaffceefa2015-02-28 11:03:34 -080012 "v.io/x/ref/services/identity"
Suharsh Sivakumarc0048112015-03-19 11:48:28 -070013 "v.io/x/ref/services/identity/internal/oauth"
14 "v.io/x/ref/services/identity/internal/revocation"
Suharsh Sivakumarfb5cbb72014-08-27 13:14:22 -070015
Todd Wang54feabe2015-04-15 23:38:26 -070016 "v.io/v23/context"
Matt Rosencrantz94502cf2015-03-18 09:43:44 -070017 "v.io/v23/rpc"
Jiri Simsa6ac95222015-02-23 16:11:49 -080018 "v.io/v23/security"
Asim Shankar61071792014-07-22 13:03:18 -070019)
20
Ankur123a5c72015-01-12 16:03:43 -080021type oauthBlesser struct {
22 oauthProvider oauth.OAuthProvider
Suharsh Sivakumarfb5cbb72014-08-27 13:14:22 -070023 authcodeClient struct{ ID, Secret string }
Ankur123a5c72015-01-12 16:03:43 -080024 accessTokenClients []oauth.AccessTokenClient
Suharsh Sivakumarfb5cbb72014-08-27 13:14:22 -070025 duration time.Duration
Suharsh Sivakumarfb5cbb72014-08-27 13:14:22 -070026 dischargerLocation string
Suharsh Sivakumar8e898db2014-12-17 14:07:21 -080027 revocationManager revocation.RevocationManager
Asim Shankar7a721752014-08-02 14:27:23 -070028}
29
Ankur123a5c72015-01-12 16:03:43 -080030// OAuthBlesserParams represents all the parameters provided to NewOAuthBlesserServer
31type OAuthBlesserParams struct {
32 // The OAuth provider that must have issued the access tokens accepted by ths service.
33 OAuthProvider oauth.OAuthProvider
Srdjan Petrovic89779ad2014-11-03 15:40:36 -080034 // The OAuth client IDs and names for the clients of the BlessUsingAccessToken RPCs.
Ankur123a5c72015-01-12 16:03:43 -080035 AccessTokenClients []oauth.AccessTokenClient
Suharsh Sivakumarfb5cbb72014-08-27 13:14:22 -070036 // The object name of the discharger service. If this is empty then revocation caveats will not be granted.
37 DischargerLocation string
38 // The revocation manager that generates caveats and manages revocation.
Suharsh Sivakumar8e898db2014-12-17 14:07:21 -080039 RevocationManager revocation.RevocationManager
Asim Shankarb18a44f2014-10-21 20:25:07 -070040 // The duration for which blessings will be valid. (Used iff RevocationManager is nil).
41 BlessingDuration time.Duration
Asim Shankar61071792014-07-22 13:03:18 -070042}
43
Ankur123a5c72015-01-12 16:03:43 -080044// NewOAuthBlesserServer provides an identity.OAuthBlesserService that uses OAuth2
45// access tokens to obtain the username of a client and provide blessings with that
46// name.
Asim Shankar61071792014-07-22 13:03:18 -070047//
Ankur123a5c72015-01-12 16:03:43 -080048// Blessings generated by this service carry a third-party revocation caveat if a
49// RevocationManager is specified by the params or they carry an ExpiryCaveat that
Asim Shankarc195b6d2015-02-03 11:26:55 -080050// expires after the duration specified by the params.
Ankur123a5c72015-01-12 16:03:43 -080051func NewOAuthBlesserServer(p OAuthBlesserParams) identity.OAuthBlesserServerStub {
52 return identity.OAuthBlesserServer(&oauthBlesser{
53 oauthProvider: p.OAuthProvider,
Suharsh Sivakumarfb5cbb72014-08-27 13:14:22 -070054 duration: p.BlessingDuration,
Suharsh Sivakumarfb5cbb72014-08-27 13:14:22 -070055 dischargerLocation: p.DischargerLocation,
56 revocationManager: p.RevocationManager,
Suharsh Sivakumard308c7e2014-10-03 12:46:50 -070057 accessTokenClients: p.AccessTokenClients,
58 })
Asim Shankar7a721752014-08-02 14:27:23 -070059}
60
Todd Wang4264e4b2015-04-16 22:43:40 -070061func (b *oauthBlesser) BlessUsingAccessToken(ctx *context.T, call rpc.ServerCall, accessToken string) (security.Blessings, string, error) {
Asim Shankarb07ec692015-02-27 23:40:44 -080062 var noblessings security.Blessings
Ankur123a5c72015-01-12 16:03:43 -080063 email, clientName, err := b.oauthProvider.GetEmailAndClientName(accessToken, b.accessTokenClients)
Asim Shankar7a721752014-08-02 14:27:23 -070064 if err != nil {
Ankur123a5c72015-01-12 16:03:43 -080065 return noblessings, "", err
Asim Shankar7a721752014-08-02 14:27:23 -070066 }
Suharsh Sivakumar6069de72015-08-06 17:25:33 -070067 return b.bless(ctx, call.Security(), email, clientName, nil)
Asim Shankar7a721752014-08-02 14:27:23 -070068}
69
Suharsh Sivakumar6069de72015-08-06 17:25:33 -070070func (b *oauthBlesser) BlessUsingAccessTokenWithCaveats(ctx *context.T, call rpc.ServerCall, accessToken string, caveats []security.Caveat) (security.Blessings, string, error) {
71 var noblessings security.Blessings
72 email, clientName, err := b.oauthProvider.GetEmailAndClientName(accessToken, b.accessTokenClients)
73 if err != nil {
74 return noblessings, "", err
75 }
76 return b.bless(ctx, call.Security(), email, clientName, caveats)
77}
78
79func (b *oauthBlesser) bless(ctx *context.T, call security.Call, email, clientName string, caveats []security.Caveat) (security.Blessings, string, error) {
Asim Shankarb07ec692015-02-27 23:40:44 -080080 var noblessings security.Blessings
Matt Rosencrantz9dce9b22015-03-02 10:48:37 -080081 self := call.LocalPrincipal()
Asim Shankarb3a82ba2014-10-29 11:41:27 -070082 if self == nil {
83 return noblessings, "", fmt.Errorf("server error: no authentication happened")
84 }
Suharsh Sivakumar6069de72015-08-06 17:25:33 -070085 // TODO(suharshs, ataly): Should we ensure that we have at least a revocation or expiry caveat?
86 if len(caveats) == 0 {
87 var caveat security.Caveat
88 var err error
89 if b.revocationManager != nil {
90 caveat, err = b.revocationManager.NewCaveat(self.PublicKey(), b.dischargerLocation)
91 } else {
92 caveat, err = security.NewExpiryCaveat(time.Now().Add(b.duration))
93 }
94 if err != nil {
95 return noblessings, "", err
96 }
97 caveats = append(caveats, caveat)
Ankur3c33d422014-10-09 11:53:25 -070098 }
Asim Shankar3cea5822015-05-11 20:06:43 -070099 // Append clientName (e.g., "android", "chrome") to the email and then bless under that.
100 // Since blessings issued by this process do not have many caveats on them and typically
101 // have a large expiry duration, we include the clientName in the extension so that
102 // servers can explicitly distinguish these clients while specifying authorization policies
103 // (say, via AccessLists).
Asim Shankar8e547062015-05-15 01:00:33 -0700104 extension := strings.Join([]string{email, clientName}, security.ChainSeparator)
Suharsh Sivakumar6069de72015-08-06 17:25:33 -0700105 blessing, err := self.Bless(call.RemoteBlessings().PublicKey(), call.LocalBlessings(), extension, caveats[0], caveats[1:]...)
Ankur3c33d422014-10-09 11:53:25 -0700106 if err != nil {
Asim Shankarb18a44f2014-10-21 20:25:07 -0700107 return noblessings, "", err
Ankur3c33d422014-10-09 11:53:25 -0700108 }
Asim Shankarb07ec692015-02-27 23:40:44 -0800109 return blessing, extension, nil
Ankur3c33d422014-10-09 11:53:25 -0700110}