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

Side by Side Diff: tokenserver/appengine/impl/serviceaccounts/config.go

Issue 2993763002: tokenserver: Extract rules check into a separate function. (Closed)
Patch Set: more nits Created 3 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
OLDNEW
1 // Copyright 2017 The LUCI Authors. 1 // Copyright 2017 The LUCI Authors.
2 // 2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); 3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License. 4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at 5 // You may obtain a copy of the License at
6 // 6 //
7 // http://www.apache.org/licenses/LICENSE-2.0 7 // http://www.apache.org/licenses/LICENSE-2.0
8 // 8 //
9 // Unless required by applicable law or agreed to in writing, software 9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, 10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and 12 // See the License for the specific language governing permissions and
13 // limitations under the License. 13 // limitations under the License.
14 14
15 package serviceaccounts 15 package serviceaccounts
16 16
17 import ( 17 import (
18 "fmt" 18 "fmt"
19 19
20 "google.golang.org/grpc"
21 "google.golang.org/grpc/codes"
22
20 "golang.org/x/net/context" 23 "golang.org/x/net/context"
21 24
22 "github.com/luci/luci-go/common/config/validation" 25 "github.com/luci/luci-go/common/config/validation"
23 "github.com/luci/luci-go/common/data/stringset" 26 "github.com/luci/luci-go/common/data/stringset"
27 "github.com/luci/luci-go/common/logging"
28 "github.com/luci/luci-go/server/auth/identity"
24 29
25 "github.com/luci/luci-go/tokenserver/api/admin/v1" 30 "github.com/luci/luci-go/tokenserver/api/admin/v1"
26 "github.com/luci/luci-go/tokenserver/appengine/impl/utils/identityset" 31 "github.com/luci/luci-go/tokenserver/appengine/impl/utils/identityset"
27 "github.com/luci/luci-go/tokenserver/appengine/impl/utils/policy" 32 "github.com/luci/luci-go/tokenserver/appengine/impl/utils/policy"
28 ) 33 )
29 34
30 // serviceAccountsCfg is name of the config file with the policy. 35 // serviceAccountsCfg is name of the config file with the policy.
31 // 36 //
32 // Also used as a name for the imported configs in the datastore, so change it 37 // Also used as a name for the imported configs in the datastore, so change it
33 // very carefully. 38 // very carefully.
(...skipping 19 matching lines...) Expand all
53 // 58 //
54 // It should be treated like read-only object. It is shared by many concurrent 59 // It should be treated like read-only object. It is shared by many concurrent
55 // requests. 60 // requests.
56 type Rule struct { 61 type Rule struct {
57 Rule *admin.ServiceAccountRule // original proto with the rule 62 Rule *admin.ServiceAccountRule // original proto with the rule
58 AllowedScopes stringset.Set // parsed 'allowed_scope' 63 AllowedScopes stringset.Set // parsed 'allowed_scope'
59 EndUsers *identityset.Set // parsed 'end_user' 64 EndUsers *identityset.Set // parsed 'end_user'
60 Proxies *identityset.Set // parsed 'proxy' 65 Proxies *identityset.Set // parsed 'proxy'
61 } 66 }
62 67
68 // RulesQuery describes circumstances of using some service account.
69 //
70 // Passed to 'Check'.
71 type RulesQuery struct {
72 ServiceAccount string // email of an account being used
73 Proxy identity.Identity // who's calling the Token Server
74 EndUser identity.Identity // who initiates the usage of an accoun t
75 }
76
63 // RulesCache is a stateful object with parsed service_accounts.cfg rules. 77 // RulesCache is a stateful object with parsed service_accounts.cfg rules.
64 // 78 //
65 // It uses policy.Policy internally to manage datastore-cached copy of imported 79 // It uses policy.Policy internally to manage datastore-cached copy of imported
66 // service accounts configs. 80 // service accounts configs.
67 // 81 //
68 // Use NewRulesCache() to create a new instance. Each instance owns its own 82 // Use NewRulesCache() to create a new instance. Each instance owns its own
69 // in-memory cache, but uses same shared datastore cache. 83 // in-memory cache, but uses same shared datastore cache.
70 // 84 //
71 // There's also a process global instance of RulesCache (GlobalRulesCache var) 85 // There's also a process global instance of RulesCache (GlobalRulesCache var)
72 // which is used by the main process. Unit tests don't use it though to avoid 86 // which is used by the main process. Unit tests don't use it though to avoid
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after
154 return r.revision 168 return r.revision
155 } 169 }
156 170
157 // Rule returns a rule governing the access to the given service account. 171 // Rule returns a rule governing the access to the given service account.
158 // 172 //
159 // Returns nil if such service account is not specified in the config. 173 // Returns nil if such service account is not specified in the config.
160 func (r *Rules) Rule(serviceAccount string) *Rule { 174 func (r *Rules) Rule(serviceAccount string) *Rule {
161 return r.rules[serviceAccount] 175 return r.rules[serviceAccount]
162 } 176 }
163 177
178 // Check checks that rules allow the requested usage.
179 //
180 // Returns the corresponding rule on success, or gRPC error on failure.
181 // The returned rule can be consulted further to check additional restrictions,
182 // such as allowed OAuth scopes or validity duration.
183 //
184 // It is supposed to be called as part of some RPC handler. It logs errors
185 // internally, so no need to log them outside.
186 func (r *Rules) Check(c context.Context, query *RulesQuery) (*Rule, error) {
187 // Grab the rule for this account. Don't leak information about presence or
188 // absence of the account to the caller, they may not be authorized to s ee the
189 // account at all.
190 rule := r.rules[query.ServiceAccount]
191 if rule == nil {
192 logging.Errorf(c, "No rule for service account %q in the config rev %s", query.ServiceAccount, r.revision)
193 return nil, grpc.Errorf(codes.PermissionDenied, "unknown service account or not enough permissions to use it")
194 }
195 logging.Infof(c, "Found the matching rule %q in the config rev %s", rule .Rule.Name, r.revision)
196
197 // If the 'Proxy' is in 'Proxies' list, we assume it's known to us and w e
198 // trust it enough to start returning more detailed error messages.
199 switch known, err := rule.Proxies.IsMember(c, query.Proxy); {
200 case err != nil:
201 logging.WithError(err).Errorf(c, "Failed to check membership of caller %q", query.Proxy)
202 return nil, grpc.Errorf(codes.Internal, "membership check failed ")
203 case !known:
204 logging.Errorf(c, "Caller %q is not authorized to use account %q ", query.Proxy, query.ServiceAccount)
205 return nil, grpc.Errorf(codes.PermissionDenied, "unknown service account or not enough permissions to use it")
206 }
207
208 switch known, err := rule.EndUsers.IsMember(c, query.EndUser); {
209 case err != nil:
210 logging.WithError(err).Errorf(c, "Failed to check membership of end user %q", query.EndUser)
211 return nil, grpc.Errorf(codes.Internal, "membership check failed ")
212 case !known:
213 logging.Errorf(c, "End user %q is not authorized to use account %q", query.EndUser, query.ServiceAccount)
214 return nil, grpc.Errorf(
215 codes.PermissionDenied, "per rule %q the user %q is not authorized to use the service account %q",
216 rule.Rule.Name, query.EndUser, query.ServiceAccount)
217 }
218
219 return rule, nil
220 }
221
164 // makeRule converts ServiceAccountRule into queriable Rule. 222 // makeRule converts ServiceAccountRule into queriable Rule.
165 // 223 //
166 // Mutates 'ruleProto' in-place filling in defaults. 224 // Mutates 'ruleProto' in-place filling in defaults.
167 func makeRule(ruleProto *admin.ServiceAccountRule) (*Rule, error) { 225 func makeRule(ruleProto *admin.ServiceAccountRule) (*Rule, error) {
168 v := validation.Context{} 226 v := validation.Context{}
169 validateRule(ruleProto.Name, ruleProto, &v) 227 validateRule(ruleProto.Name, ruleProto, &v)
170 if err := v.Finalize(); err != nil { 228 if err := v.Finalize(); err != nil {
171 return nil, err 229 return nil, err
172 } 230 }
173 231
(...skipping 16 matching lines...) Expand all
190 ruleProto.MaxGrantValidityDuration = defaultMaxGrantValidityDura tion 248 ruleProto.MaxGrantValidityDuration = defaultMaxGrantValidityDura tion
191 } 249 }
192 250
193 return &Rule{ 251 return &Rule{
194 Rule: ruleProto, 252 Rule: ruleProto,
195 AllowedScopes: allowedScopes, 253 AllowedScopes: allowedScopes,
196 EndUsers: endUsers, 254 EndUsers: endUsers,
197 Proxies: proxies, 255 Proxies: proxies,
198 }, nil 256 }, nil
199 } 257 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698