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

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

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

Powered by Google App Engine
This is Rietveld 408576698