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

Side by Side Diff: tokenserver/appengine/delegation/validation.go

Issue 2413683004: token-server: Delegation config import, validation and evaluation. (Closed)
Patch Set: also check validity_duration Created 4 years, 1 month 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
(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 "fmt"
9 "strings"
10
11 "github.com/luci/luci-go/common/data/stringset"
12 "github.com/luci/luci-go/common/errors"
13 "github.com/luci/luci-go/server/auth/identity"
14
15 "github.com/luci/luci-go/tokenserver/api/admin/v1"
16 )
17
18 // ValidateConfig checks delegation config for correctness.
19 //
20 // Tries to find all errors.
21 func ValidateConfig(cfg *admin.DelegationPermissions) errors.MultiError {
22 var errs errors.MultiError
23 names := stringset.New(0)
24
25 for i, rule := range cfg.Rules {
26 prefix := fmt.Sprintf("rule #%d (%q)", i+1, rule.Name)
27 if rule.Name != "" {
28 if names.Has(rule.Name) {
29 errs = append(errs, fmt.Errorf("%s: the rule wit h such name is already defined", prefix))
30 }
31 names.Add(rule.Name)
32 }
33 for _, singleErr := range ValidateRule(rule) {
34 errs = append(errs, fmt.Errorf("%s: %s", prefix, singleE rr))
35 }
36 }
37
38 return errs
39 }
40
41 // ValidateRule checks single DelegationRule proto.
42 //
43 // See config.proto, DelegationRule for the description of allowed values.
44 func ValidateRule(r *admin.DelegationRule) errors.MultiError {
45 var out errors.MultiError
46
47 emitErr := func(msg string, args ...interface{}) {
48 out = append(out, fmt.Errorf(msg, args...))
49 }
50
51 emitMultiErr := func(prefix string, merr errors.MultiError) {
52 for _, err := range merr {
53 emitErr("%s - %s", prefix, err)
54 }
55 }
56
57 if r.Name == "" {
58 emitErr("'name' is required")
59 }
60
61 if len(r.Requestor) == 0 {
62 emitErr("'requestor' is required")
63 } else {
64 v := identitySetValidator{
65 AllowGroups: true,
66 }
67 emitMultiErr("bad 'requestor'", v.Validate(r.Requestor))
68 }
69
70 if len(r.AllowedToImpersonate) == 0 {
71 emitErr("'allowed_to_impersonate' is required")
72 } else {
73 v := identitySetValidator{
74 AllowReservedWords: []string{Requestor}, // '*' is not a llowed here though
75 AllowGroups: true,
76 }
77 emitMultiErr("bad 'allowed_to_impersonate'", v.Validate(r.Allowe dToImpersonate))
78 }
79
80 if len(r.AllowedAudience) == 0 {
81 emitErr("'allowed_audience' is required")
82 } else {
83 v := identitySetValidator{
84 AllowReservedWords: []string{Requestor, "*"},
85 AllowGroups: true,
86 }
87 emitMultiErr("bad 'allowed_audience'", v.Validate(r.AllowedAudie nce))
88 }
89
90 if len(r.TargetService) == 0 {
91 emitErr("'target_service' is required")
92 } else {
93 v := identitySetValidator{
94 AllowReservedWords: []string{"*"},
95 AllowIDKinds: []identity.Kind{identity.Service},
96 }
97 emitMultiErr("bad 'target_service'", v.Validate(r.TargetService) )
98 }
99
100 if r.MaxValidityDuration == 0 {
101 emitErr("'max_validity_duration' is required")
102 }
103 if r.MaxValidityDuration < 0 {
104 emitErr("'max_validity_duration' must be positive")
105 }
106 if r.MaxValidityDuration > 24*3600 {
107 emitErr("'max_validity_duration' must be smaller than 86401")
108 }
109
110 return out
111 }
112
113 type identitySetValidator struct {
114 AllowReservedWords []string // to allow "*" and "REQUESTOR"
115 AllowGroups bool // true to allow "group:" entries
116 AllowIDKinds []identity.Kind // permitted identity kinds, or nil i f all
117 }
118
119 func (v *identitySetValidator) Validate(items []string) errors.MultiError {
120 var out errors.MultiError
121
122 emitErr := func(msg string, args ...interface{}) {
123 out = append(out, fmt.Errorf(msg, args...))
124 }
125
126 loop:
127 for _, s := range items {
128 // A reserved word?
129 for _, r := range v.AllowReservedWords {
130 if s == r {
131 continue loop
132 }
133 }
134
135 // A group reference?
136 if strings.HasPrefix(s, "group:") {
137 if !v.AllowGroups {
138 emitErr("group entries are not allowed - %q", s)
139 } else {
140 if s == "group:" {
141 emitErr("bad group entry %q", s)
142 }
143 }
144 continue
145 }
146
147 // An identity then.
148 id, err := identity.MakeIdentity(s)
149 if err != nil {
150 emitErr("%s", err)
151 continue
152 }
153
154 if v.AllowIDKinds != nil {
155 allowed := false
156 for _, k := range v.AllowIDKinds {
157 if id.Kind() == k {
158 allowed = true
159 break
160 }
161 }
162 if !allowed {
163 emitErr("identity of kind %q is not allowed here - %q", id.Kind(), s)
164 }
165 }
166 }
167
168 return out
169 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698