blob: a51246ff46331b026b9a07035badc182b701a41a [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"
15 "v.io/x/ref/services/identity/internal/util"
Suharsh Sivakumarfb5cbb72014-08-27 13:14:22 -070016
Todd Wang54feabe2015-04-15 23:38:26 -070017 "v.io/v23/context"
Matt Rosencrantz94502cf2015-03-18 09:43:44 -070018 "v.io/v23/rpc"
Jiri Simsa6ac95222015-02-23 16:11:49 -080019 "v.io/v23/security"
Asim Shankar61071792014-07-22 13:03:18 -070020)
21
Ankur123a5c72015-01-12 16:03:43 -080022type oauthBlesser struct {
23 oauthProvider oauth.OAuthProvider
Suharsh Sivakumarfb5cbb72014-08-27 13:14:22 -070024 authcodeClient struct{ ID, Secret string }
Ankur123a5c72015-01-12 16:03:43 -080025 accessTokenClients []oauth.AccessTokenClient
Suharsh Sivakumarfb5cbb72014-08-27 13:14:22 -070026 duration time.Duration
Asim Shankarc195b6d2015-02-03 11:26:55 -080027 emailClassifier *util.EmailClassifier
Suharsh Sivakumarfb5cbb72014-08-27 13:14:22 -070028 dischargerLocation string
Suharsh Sivakumar8e898db2014-12-17 14:07:21 -080029 revocationManager revocation.RevocationManager
Asim Shankar7a721752014-08-02 14:27:23 -070030}
31
Ankur123a5c72015-01-12 16:03:43 -080032// OAuthBlesserParams represents all the parameters provided to NewOAuthBlesserServer
33type OAuthBlesserParams struct {
34 // The OAuth provider that must have issued the access tokens accepted by ths service.
35 OAuthProvider oauth.OAuthProvider
Srdjan Petrovic89779ad2014-11-03 15:40:36 -080036 // The OAuth client IDs and names for the clients of the BlessUsingAccessToken RPCs.
Ankur123a5c72015-01-12 16:03:43 -080037 AccessTokenClients []oauth.AccessTokenClient
Asim Shankarc195b6d2015-02-03 11:26:55 -080038 // Determines prefixes used for blessing extensions based on email address.
39 EmailClassifier *util.EmailClassifier
Suharsh Sivakumarfb5cbb72014-08-27 13:14:22 -070040 // The object name of the discharger service. If this is empty then revocation caveats will not be granted.
41 DischargerLocation string
42 // The revocation manager that generates caveats and manages revocation.
Suharsh Sivakumar8e898db2014-12-17 14:07:21 -080043 RevocationManager revocation.RevocationManager
Asim Shankarb18a44f2014-10-21 20:25:07 -070044 // The duration for which blessings will be valid. (Used iff RevocationManager is nil).
45 BlessingDuration time.Duration
Asim Shankar61071792014-07-22 13:03:18 -070046}
47
Ankur123a5c72015-01-12 16:03:43 -080048// NewOAuthBlesserServer provides an identity.OAuthBlesserService that uses OAuth2
49// access tokens to obtain the username of a client and provide blessings with that
50// name.
Asim Shankar61071792014-07-22 13:03:18 -070051//
Ankur123a5c72015-01-12 16:03:43 -080052// Blessings generated by this service carry a third-party revocation caveat if a
53// RevocationManager is specified by the params or they carry an ExpiryCaveat that
Asim Shankarc195b6d2015-02-03 11:26:55 -080054// expires after the duration specified by the params.
Ankur123a5c72015-01-12 16:03:43 -080055func NewOAuthBlesserServer(p OAuthBlesserParams) identity.OAuthBlesserServerStub {
56 return identity.OAuthBlesserServer(&oauthBlesser{
57 oauthProvider: p.OAuthProvider,
Suharsh Sivakumarfb5cbb72014-08-27 13:14:22 -070058 duration: p.BlessingDuration,
Asim Shankarc195b6d2015-02-03 11:26:55 -080059 emailClassifier: p.EmailClassifier,
Suharsh Sivakumarfb5cbb72014-08-27 13:14:22 -070060 dischargerLocation: p.DischargerLocation,
61 revocationManager: p.RevocationManager,
Suharsh Sivakumard308c7e2014-10-03 12:46:50 -070062 accessTokenClients: p.AccessTokenClients,
63 })
Asim Shankar7a721752014-08-02 14:27:23 -070064}
65
Todd Wang54feabe2015-04-15 23:38:26 -070066func (b *oauthBlesser) BlessUsingAccessToken(ctx *context.T, _ rpc.ServerCall, accessToken string) (security.Blessings, string, error) {
Asim Shankarb07ec692015-02-27 23:40:44 -080067 var noblessings security.Blessings
Ankur123a5c72015-01-12 16:03:43 -080068 email, clientName, err := b.oauthProvider.GetEmailAndClientName(accessToken, b.accessTokenClients)
Asim Shankar7a721752014-08-02 14:27:23 -070069 if err != nil {
Ankur123a5c72015-01-12 16:03:43 -080070 return noblessings, "", err
Asim Shankar7a721752014-08-02 14:27:23 -070071 }
Todd Wang54feabe2015-04-15 23:38:26 -070072 return b.bless(security.GetCall(ctx), email, clientName)
Asim Shankar7a721752014-08-02 14:27:23 -070073}
74
Matt Rosencrantz311378b2015-03-25 15:26:12 -070075func (b *oauthBlesser) bless(call security.Call, email, clientName string) (security.Blessings, string, error) {
Asim Shankarb07ec692015-02-27 23:40:44 -080076 var noblessings security.Blessings
Matt Rosencrantz9dce9b22015-03-02 10:48:37 -080077 self := call.LocalPrincipal()
Asim Shankarb3a82ba2014-10-29 11:41:27 -070078 if self == nil {
79 return noblessings, "", fmt.Errorf("server error: no authentication happened")
80 }
Ankur3c33d422014-10-09 11:53:25 -070081 var caveat security.Caveat
82 var err error
83 if b.revocationManager != nil {
Suharsh Sivakumar38a1a7b2014-11-17 15:14:38 -080084 caveat, err = b.revocationManager.NewCaveat(self.PublicKey(), b.dischargerLocation)
Ankur3c33d422014-10-09 11:53:25 -070085 } else {
86 caveat, err = security.ExpiryCaveat(time.Now().Add(b.duration))
87 }
88 if err != nil {
Asim Shankarb18a44f2014-10-21 20:25:07 -070089 return noblessings, "", err
Ankur3c33d422014-10-09 11:53:25 -070090 }
Asim Shankarc195b6d2015-02-03 11:26:55 -080091 extension := strings.Join([]string{
92 b.emailClassifier.Classify(email),
93 email,
94 // Append clientName (e.g., "android", "chrome") to the email and then bless under that.
95 // Since blessings issued by this process do not have many caveats on them and typically
96 // have a large expiry duration, we include the clientName in the extension so that
97 // servers can explicitly distinguish these clients while specifying authorization policies
Benjamin Prosnitzb60efb92015-03-11 17:47:43 -070098 // (say, via AccessLists).
Asim Shankarc195b6d2015-02-03 11:26:55 -080099 clientName,
100 }, security.ChainSeparator)
Matt Rosencrantz9dce9b22015-03-02 10:48:37 -0800101 blessing, err := self.Bless(call.RemoteBlessings().PublicKey(), call.LocalBlessings(), extension, caveat)
Ankur3c33d422014-10-09 11:53:25 -0700102 if err != nil {
Asim Shankarb18a44f2014-10-21 20:25:07 -0700103 return noblessings, "", err
Ankur3c33d422014-10-09 11:53:25 -0700104 }
Asim Shankarb07ec692015-02-27 23:40:44 -0800105 return blessing, extension, nil
Ankur3c33d422014-10-09 11:53:25 -0700106}