| OLD | NEW |
| (Empty) | |
| 1 // Copyright 2017 The LUCI Authors. |
| 2 // |
| 3 // Licensed under the Apache License, Version 2.0 (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 |
| 6 // |
| 7 // http://www.apache.org/licenses/LICENSE-2.0 |
| 8 // |
| 9 // Unless required by applicable law or agreed to in writing, software |
| 10 // distributed under the License is distributed on an "AS IS" BASIS, |
| 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 12 // See the License for the specific language governing permissions and |
| 13 // limitations under the License. |
| 14 package acl |
| 15 |
| 16 import ( |
| 17 "fmt" |
| 18 "testing" |
| 19 |
| 20 "github.com/luci/luci-go/appengine/gaetesting" |
| 21 "github.com/luci/luci-go/scheduler/appengine/messages" |
| 22 "github.com/luci/luci-go/server/auth" |
| 23 "github.com/luci/luci-go/server/auth/authtest" |
| 24 . "github.com/smartystreets/goconvey/convey" |
| 25 ) |
| 26 |
| 27 func TestAclsValidation(t *testing.T) { |
| 28 t.Parallel() |
| 29 |
| 30 validGrant := &messages.Acl{Role: messages.Acl_READER, GrantedTo: "group
:all"} |
| 31 validGrants := []*messages.Acl{validGrant} |
| 32 |
| 33 Convey("grant validation", t, func() { |
| 34 So(validateGrants(validGrants), ShouldBeNil) |
| 35 |
| 36 call := func(acls ...*messages.Acl) error { |
| 37 return validateGrants(acls) |
| 38 } |
| 39 So(call(&messages.Acl{Role: messages.Acl_OWNER, GrantedTo: "e@ex
ample.com"}), ShouldBeNil) |
| 40 |
| 41 So(call(&messages.Acl{Role: 3}).Error(), ShouldResemble, "invali
d role \"3\"") |
| 42 So(call(&messages.Acl{Role: messages.Acl_OWNER, GrantedTo: ""}).
Error(), |
| 43 ShouldResemble, "missing granted_to for role OWNER") |
| 44 So(call(&messages.Acl{Role: messages.Acl_OWNER, GrantedTo: "grou
p:"}).Error(), |
| 45 ShouldResemble, "invalid granted_to \"group:\" for role
OWNER: needs a group name") |
| 46 So(call(&messages.Acl{Role: messages.Acl_OWNER, GrantedTo: "not-
email"}).Error(), |
| 47 ShouldStartWith, "invalid granted_to \"not-email\" for r
ole OWNER: ") |
| 48 So(call(&messages.Acl{Role: messages.Acl_OWNER, GrantedTo: "bot:
"}).Error(), |
| 49 ShouldStartWith, "invalid granted_to \"bot:\" for role O
WNER: ") |
| 50 }) |
| 51 |
| 52 validAclSet := &messages.AclSet{Name: "public", Acls: validGrants} |
| 53 |
| 54 Convey("Validate AclSets", t, func() { |
| 55 as, err := ValidateAclSets([]*messages.AclSet{validAclSet}) |
| 56 So(err, ShouldBeNil) |
| 57 So(len(as), ShouldEqual, 1) |
| 58 So(as["public"], ShouldResemble, validGrants) |
| 59 |
| 60 shouldError := func(sets ...*messages.AclSet) { |
| 61 _, err := ValidateAclSets(sets) |
| 62 So(err, ShouldNotBeNil) |
| 63 } |
| 64 |
| 65 shouldError(&messages.AclSet{Name: "one"}) |
| 66 shouldError(&messages.AclSet{Name: "?bad i'd", Acls: validGrants
}) |
| 67 shouldError(validAclSet, validAclSet) |
| 68 }) |
| 69 |
| 70 Convey("Task Acls", t, func() { |
| 71 Convey("Without AclSets", func() { |
| 72 jobAcls, err := ValidateTaskAcls(nil, []string{}, validG
rants) |
| 73 So(err, ShouldBeNil) |
| 74 So(jobAcls.Owners, ShouldResemble, []string{}) |
| 75 So(jobAcls.Readers, ShouldResemble, []string{"group:all"
}) |
| 76 }) |
| 77 |
| 78 Convey("Without AclSets but with bad ACLs", func() { |
| 79 _, err := ValidateTaskAcls(nil, []string{}, []*messages.
Acl{ |
| 80 {Role: messages.Acl_OWNER, GrantedTo: ""}}) |
| 81 So(err, ShouldNotBeNil) |
| 82 }) |
| 83 |
| 84 Convey("Many ACLs", func() { |
| 85 taskGrants := make([]*messages.Acl, maxGrantsPerJob) |
| 86 for i := 0; i < maxGrantsPerJob; i++ { |
| 87 taskGrants[i] = &messages.Acl{Role: messages.Acl
_OWNER, GrantedTo: fmt.Sprintf("group:%d", i)} |
| 88 } |
| 89 Convey("Hitting max is OK", func() { |
| 90 r, err := ValidateTaskAcls(nil, []string{}, task
Grants) |
| 91 So(err, ShouldBeNil) |
| 92 So(len(r.Owners), ShouldEqual, maxGrantsPerJob) |
| 93 }) |
| 94 Convey("1 too many", func() { |
| 95 aclSets := map[string][]*messages.Acl{ |
| 96 "public": {{Role: messages.Acl_READER, G
rantedTo: "group:all"}}, |
| 97 } |
| 98 _, err := ValidateTaskAcls(aclSets, []string{"pu
blic"}, taskGrants) |
| 99 So(err.Error(), ShouldResemble, "Job or Trigger
can have at most 32 acls, but 33 given") |
| 100 }) |
| 101 }) |
| 102 |
| 103 protoAclSets := []*messages.AclSet{ |
| 104 {Name: "public", Acls: []*messages.Acl{ |
| 105 {Role: messages.Acl_READER, GrantedTo: "group:al
l"}, |
| 106 {Role: messages.Acl_OWNER, GrantedTo: "group:own
ers"}, |
| 107 }}, |
| 108 {Name: "power-owners", Acls: []*messages.Acl{ |
| 109 {Role: messages.Acl_OWNER, GrantedTo: "group:pow
er"}, |
| 110 }}, |
| 111 {Name: "private", Acls: []*messages.Acl{ |
| 112 {Role: messages.Acl_READER, GrantedTo: "group:in
ternal"}, |
| 113 }}, |
| 114 } |
| 115 aclSets, err := ValidateAclSets(protoAclSets) |
| 116 So(err, ShouldBeNil) |
| 117 So(len(aclSets), ShouldEqual, 3) |
| 118 |
| 119 Convey("Bad acl_set reference in a task definition", func() { |
| 120 _, err := ValidateTaskAcls(aclSets, []string{"typo"}, va
lidGrants) |
| 121 So(err.Error(), ShouldResemble, "referencing AclSet 'typ
o' which doesn't exist") |
| 122 }) |
| 123 |
| 124 Convey("Merging", func() { |
| 125 jobAcls, err := ValidateTaskAcls( |
| 126 aclSets, []string{"public", "power-owners"}, |
| 127 []*messages.Acl{ |
| 128 {Role: messages.Acl_OWNER, GrantedTo: "m
e@example.com"}, |
| 129 {Role: messages.Acl_READER, GrantedTo: "
you@example.com"}, |
| 130 }) |
| 131 So(err, ShouldBeNil) |
| 132 So(jobAcls.Owners, ShouldResemble, []string{"group:owner
s", "group:power", "me@example.com"}) |
| 133 So(jobAcls.Readers, ShouldResemble, []string{"group:all"
, "you@example.com"}) |
| 134 |
| 135 jobAcls, err = ValidateTaskAcls( |
| 136 aclSets, []string{"private"}, |
| 137 []*messages.Acl{ |
| 138 {Role: messages.Acl_OWNER, GrantedTo: "m
e@example.com"}, |
| 139 }) |
| 140 So(err, ShouldBeNil) |
| 141 So(jobAcls.Owners, ShouldResemble, []string{"me@example.
com"}) |
| 142 So(jobAcls.Readers, ShouldResemble, []string{"group:inte
rnal"}) |
| 143 }) |
| 144 }) |
| 145 } |
| 146 |
| 147 func TestAclsChecks(t *testing.T) { |
| 148 t.Parallel() |
| 149 ctx := gaetesting.TestingContext() |
| 150 |
| 151 basicGroups := GrantsByRole{Owners: []string{"group:owners"}, Readers: [
]string{"group:readers"}} |
| 152 |
| 153 Convey("Admins are owners and readers", t, func() { |
| 154 ctx = auth.WithState(ctx, &authtest.FakeState{ |
| 155 Identity: "user:admin@example.com", |
| 156 IdentityGroups: []string{"administrators"}, |
| 157 }) |
| 158 yup, err := basicGroups.IsOwner(ctx) |
| 159 So(err, ShouldBeNil) |
| 160 So(yup, ShouldBeTrue) |
| 161 yup, err = basicGroups.IsReader(ctx) |
| 162 So(err, ShouldBeNil) |
| 163 So(yup, ShouldBeTrue) |
| 164 }) |
| 165 Convey("Owners", t, func() { |
| 166 ctx = auth.WithState(ctx, &authtest.FakeState{ |
| 167 Identity: "user:owner@example.com", |
| 168 IdentityGroups: []string{"owners"}, |
| 169 }) |
| 170 yup, err := basicGroups.IsReader(ctx) |
| 171 So(err, ShouldBeNil) |
| 172 So(yup, ShouldBeTrue) |
| 173 yup, err = basicGroups.IsReader(ctx) |
| 174 So(err, ShouldBeNil) |
| 175 So(yup, ShouldBeTrue) |
| 176 }) |
| 177 Convey("Readers", t, func() { |
| 178 ctx = auth.WithState(ctx, &authtest.FakeState{ |
| 179 Identity: "user:reader@example.com", |
| 180 IdentityGroups: []string{"readers"}, |
| 181 }) |
| 182 nope, err := basicGroups.IsOwner(ctx) |
| 183 So(err, ShouldBeNil) |
| 184 So(nope, ShouldBeFalse) |
| 185 yup, err := basicGroups.IsReader(ctx) |
| 186 So(err, ShouldBeNil) |
| 187 So(yup, ShouldBeTrue) |
| 188 }) |
| 189 Convey("By email", t, func() { |
| 190 ctx = auth.WithState(ctx, &authtest.FakeState{ |
| 191 Identity: "user:reader@example.com", |
| 192 IdentityGroups: []string{"all"}, |
| 193 }) |
| 194 g := GrantsByRole{ |
| 195 Owners: []string{"group:owners"}, |
| 196 Readers: []string{"group:some", "reader@example.com"}, |
| 197 } |
| 198 nope, err := g.IsOwner(ctx) |
| 199 So(err, ShouldBeNil) |
| 200 So(nope, ShouldBeFalse) |
| 201 yup, err := g.IsReader(ctx) |
| 202 So(err, ShouldBeNil) |
| 203 So(yup, ShouldBeTrue) |
| 204 }) |
| 205 } |
| 206 |
| 207 func TestAclsEqual(t *testing.T) { |
| 208 t.Parallel() |
| 209 Convey("GrantsByRole.Equal", t, func() { |
| 210 x1 := GrantsByRole{Readers: []string{"a"}, Owners: []string{"b",
"c"}} |
| 211 x2 := GrantsByRole{Readers: []string{"a"}, Owners: []string{"b",
"c"}} |
| 212 So(x1.Equal(&x2), ShouldBeTrue) |
| 213 y := GrantsByRole{Readers: []string{"e", "g"}, Owners: []string{
"b", "d"}} |
| 214 z := GrantsByRole{Readers: []string{"e", "g"}, Owners: []string{
"b", "c", "d"}} |
| 215 So(x1.Equal(&y), ShouldBeFalse) |
| 216 So(y.Equal(&z), ShouldBeFalse) |
| 217 }) |
| 218 } |
| OLD | NEW |