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

Side by Side Diff: server/auth/delegation/minter.go

Issue 2236163002: auth: Low-level API for minting delegation tokens. (Closed) Base URL: https://chromium.googlesource.com/external/github.com/luci/luci-go@store-int-in-cache
Patch Set: Created 4 years, 4 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
« server/auth/delegation/doc.go ('K') | « server/auth/delegation/doc.go ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright 2016 The LUCI Authors. All rights reserved.
2 // Use of this source code is governed under the Apache License, Version 2.0
3 // that can be found in the LICENSE file.
4
5 package delegation
6
7 import (
8 "encoding/gob"
9 "fmt"
10 "time"
11
12 "golang.org/x/net/context"
13
14 "github.com/luci/luci-go/common/clock"
15 "github.com/luci/luci-go/server/auth/identity"
16 "github.com/luci/luci-go/server/auth/internal"
17 )
18
19 // TokenRequest describes parameters of a new delegation token.
20 type TokenRequest struct {
21 // AuthServiceURL is root URL (e.g. https://<host>) of the service to us e for
iannucci 2016/08/11 22:52:35 I think I almost asked this elsewhere, but deleted
Vadim Sh. 2016/08/11 23:25:37 Usually using https://<host> is less strings manip
22 // minting the delegation token.
23 //
24 // The token will be signed by the service's private key. Only services that
25 // trust this auth service would be able to accept the new token.
26 //
27 // Required.
28 AuthServiceURL string
29
30 // Audience is to whom caller's identity is delegated.
iannucci 2016/08/11 22:52:35 IIUC, the Audience set (all identities in this sli
Vadim Sh. 2016/08/11 23:25:37 Correct.
31 //
32 // Only clients that can prove they are intended audience (e.g. by prese nting
33 // valid access token) would be able to use the delegation token.
34 //
35 // Optional. If both Audience and AudienceGroups are empty, the token is
36 // usable by any bearer.
iannucci 2016/08/11 22:52:35 that's a bit awkward; if you somehow strip both of
Vadim Sh. 2016/08/11 23:25:37 Done.
37 Audience []identity.Identity
38
39 // AudienceGroups can be used to specify a group (or a bunch of groups) as
40 // a target audience of the token.
41 //
42 // It works in addition to Audience.
43 //
44 // Optional. If both Audience and AudienceGroups are empty, the token is
45 // usable by any bearer.
46 AudienceGroups []string
47
48 // Services is a list of 'service:...' identities with services that acc ept
49 // the token.
50 //
51 // This can be used to limit the scope of the token.
52 //
53 // Optional. If empty, the token is accepted by any LUCI service.
54 Services []identity.Identity
iannucci 2016/08/11 22:52:35 Yeah I'm not super happy with go's zero-value for
Vadim Sh. 2016/08/11 23:25:37 Done.
55
56 // Impersonate defines on whose behalf the token is being created.
57 //
58 // By default the token delegates an identity of whoever requested it. T his
59 // identity is extracted from credentials that accompany token minting r equest
60 // (e.g. OAuth access token).
iannucci 2016/08/11 22:52:35 could we ever run into a situation where this extr
Vadim Sh. 2016/08/11 23:25:37 No, auth_service enforces that user is not using d
61 //
62 // By using 'Impersonate' a caller can make a token that delegates someo ne
63 // else's identity, effectively producing an impersonation token.
64 //
65 // Only limited set of callers can do this. The set of who can be impers onated
66 // is also limited. The rules are enforced by the auth service.
67 Impersonate identity.Identity
68
69 // ValidityDuration defines for how long the token would be valid.
70 //
71 // Maximum theoretical TTL is limited by the lifetime of the signing key of
72 // the auth service (~= 24 hours). Minimum acceptable value is 30 sec.
73 //
74 // Required.
75 ValidityDuration time.Duration
76
77 // Intent is a reason why the token is created.
78 //
79 // Used only for logging purposes on the auth service, will be indexed. Should
80 // be a short identifier-like string.
iannucci 2016/08/11 22:52:35 Will it be publicly visible, or could you put priv
Vadim Sh. 2016/08/11 23:25:37 It is not encoded in the token body. It ends up in
81 //
82 // Optional.
83 Intent string
84 }
85
86 // Token is actual delegation token with its expiration time and ID.
87 type Token struct {
88 Token string // base64-encoded URL-safe blob with the token
89 Expiry time.Time // UTC time when it expires (also encoded in Token)
90 SubtokenID string // identifier of the token (also encoded in Token)
91 }
92
93 // CreateToken makes a request to the auth service to generate the token.
94 //
95 // If uses current service's credentials to authenticate the request.
96 //
97 // If req.Impersonate is not used, the identity encoded in the authentication
98 // credentials will be delegated by the token, otherwise the service will check
99 // that caller is allowed to do the impersonation and will return a token that
100 // delegates the identity specified by req.Impersonate.
101 func CreateToken(c context.Context, req TokenRequest) (*Token, error) {
102 // See https://github.com/luci/luci-py/blob/master/appengine/auth_servic e/delegation.py.
103 var params struct {
104 Audience []string `json:"audience,omitempty"`
105 Services []string `json:"services,omitempty"`
106 ValidityDuration int `json:"validity_duration"`
107 Impersonate string `json:"impersonate,omitempty"`
108 Intent string `json:"intent,omitempty"`
109 }
110
111 // Audience.
112 params.Audience = make([]string, 0, len(req.Audience)+len(req.AudienceGr oups))
113 for _, aud := range req.Audience {
114 if err := aud.Validate(); err != nil {
115 return nil, err
116 }
117 params.Audience = append(params.Audience, string(aud))
118 }
119 for _, group := range req.AudienceGroups {
120 params.Audience = append(params.Audience, "group:"+group)
121 }
122 if len(params.Audience) == 0 {
123 params.Audience = []string{"*"} // means "Any bearer"
124 }
125
126 // Services.
127 params.Services = make([]string, 0, len(req.Services))
128 for _, srv := range req.Services {
129 if err := srv.Validate(); err != nil {
130 return nil, err
131 }
132 params.Services = append(params.Services, string(srv))
133 }
134 if len(params.Services) == 0 {
135 params.Services = []string{"*"} // means "Any service"
136 }
137
138 // Validity duration.
139 params.ValidityDuration = int(req.ValidityDuration / time.Second)
140 if params.ValidityDuration < 30 {
141 return nil, fmt.Errorf("ValidityDuration must be >= 30 sec, got %s", req.ValidityDuration)
142 }
143 if params.ValidityDuration > 24*3600 {
144 return nil, fmt.Errorf("ValidityDuration must be <= 24h, got %s" , req.ValidityDuration)
145 }
146
147 // The rest of the fields.
148 if req.Impersonate != "" {
149 if err := req.Impersonate.Validate(); err != nil {
150 return nil, err
151 }
152 params.Impersonate = string(req.Impersonate)
153 }
154 params.Intent = req.Intent
155
156 var response struct {
157 DelegationToken string `json:"delegation_token,omitempty"`
158 ValidityDuration int `json:"validity_duration,omitempty"`
159 SubtokenID string `json:"subtoken_id,omitempty"`
160 Text string `json:"text,omitempty"` // for error res ponses
161 }
162
163 httpReq := internal.Request{
164 Method: "POST",
165 URL: req.AuthServiceURL + "/auth_service/api/v1/delegation/to ken/create",
166 Scopes: []string{"https://www.googleapis.com/auth/userinfo.email "},
167 Body: &params,
168 Out: &response,
169 }
170 if err := httpReq.Do(c); err != nil {
171 if response.Text != "" {
172 err = fmt.Errorf("%s - %s", err, response.Text)
173 }
174 return nil, err
175 }
176
177 return &Token{
178 Token: response.DelegationToken,
179 Expiry: clock.Now(c).Add(time.Duration(response.ValidityDura tion) * time.Second).UTC(),
180 SubtokenID: response.SubtokenID,
181 }, nil
182 }
183
184 func init() {
185 // For token cache.
186 gob.Register(Token{})
187 }
OLDNEW
« server/auth/delegation/doc.go ('K') | « server/auth/delegation/doc.go ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698