| 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}).Error(), |
| 45 ShouldResemble, "missing granted_to for role OWNER") |
| 46 // TODO(tandrii): validate contents of granted_to. |
| 47 }) |
| 48 |
| 49 validAclSet := &messages.AclSet{Name: "public", Acls: validGrants} |
| 50 |
| 51 Convey("Validate AclSets", t, func() { |
| 52 as, err := ValidateAclSets([]*messages.AclSet{validAclSet}) |
| 53 So(err, ShouldBeNil) |
| 54 So(len(as), ShouldEqual, 1) |
| 55 So(as["public"], ShouldResemble, validGrants) |
| 56 |
| 57 shouldError := func(sets ...*messages.AclSet) { |
| 58 _, err := ValidateAclSets(sets) |
| 59 So(err, ShouldNotBeNil) |
| 60 } |
| 61 |
| 62 shouldError(&messages.AclSet{Name: "one"}) |
| 63 shouldError(&messages.AclSet{Name: "?bad i'd", Acls: validGrants
}) |
| 64 shouldError(validAclSet, validAclSet) |
| 65 }) |
| 66 |
| 67 Convey("Task Acls", t, func() { |
| 68 Convey("Without AclSets", func() { |
| 69 jobAcls, err := ValidateTaskAcls(nil, []string{}, validG
rants) |
| 70 So(err, ShouldBeNil) |
| 71 So(jobAcls.Owners, ShouldResemble, []string{}) |
| 72 So(jobAcls.Readers, ShouldResemble, []string{"group:all"
}) |
| 73 }) |
| 74 |
| 75 Convey("Without AclSets but with bad ACLs", func() { |
| 76 _, err := ValidateTaskAcls(nil, []string{}, []*messages.
Acl{ |
| 77 {Role: messages.Acl_OWNER, GrantedTo: ""}}) |
| 78 So(err, ShouldNotBeNil) |
| 79 }) |
| 80 |
| 81 Convey("Many ACLs", func() { |
| 82 taskGrants := make([]*messages.Acl, maxGrantsPerJob) |
| 83 for i := 0; i < maxGrantsPerJob; i++ { |
| 84 taskGrants[i] = &messages.Acl{Role: messages.Acl
_OWNER, GrantedTo: fmt.Sprintf("%d", i)} |
| 85 } |
| 86 Convey("Hitting max is OK", func() { |
| 87 r, err := ValidateTaskAcls(nil, []string{}, task
Grants) |
| 88 So(err, ShouldBeNil) |
| 89 So(len(r.Owners), ShouldEqual, maxGrantsPerJob) |
| 90 }) |
| 91 Convey("1 too many", func() { |
| 92 aclSets := map[string][]*messages.Acl{ |
| 93 "public": {{Role: messages.Acl_READER, G
rantedTo: "group:all"}}, |
| 94 } |
| 95 _, err := ValidateTaskAcls(aclSets, []string{"pu
blic"}, taskGrants) |
| 96 So(err.Error(), ShouldResemble, "Job or Trigger
can have at most 32 acls, but 33 given") |
| 97 }) |
| 98 }) |
| 99 |
| 100 protoAclSets := []*messages.AclSet{ |
| 101 {Name: "public", Acls: []*messages.Acl{ |
| 102 {Role: messages.Acl_READER, GrantedTo: "group:al
l"}, |
| 103 {Role: messages.Acl_OWNER, GrantedTo: "group:own
ers"}, |
| 104 }}, |
| 105 {Name: "power-owners", Acls: []*messages.Acl{ |
| 106 {Role: messages.Acl_OWNER, GrantedTo: "group:pow
er"}, |
| 107 }}, |
| 108 {Name: "private", Acls: []*messages.Acl{ |
| 109 {Role: messages.Acl_READER, GrantedTo: "group:in
ternal"}, |
| 110 }}, |
| 111 } |
| 112 aclSets, err := ValidateAclSets(protoAclSets) |
| 113 So(err, ShouldBeNil) |
| 114 So(len(aclSets), ShouldEqual, 3) |
| 115 |
| 116 Convey("Bad acl_set reference in a task definition", func() { |
| 117 _, err := ValidateTaskAcls(aclSets, []string{"typo"}, va
lidGrants) |
| 118 So(err.Error(), ShouldResemble, "referencing AclSet 'typ
o' which doesn't exist") |
| 119 }) |
| 120 |
| 121 Convey("Merging", func() { |
| 122 jobAcls, err := ValidateTaskAcls( |
| 123 aclSets, []string{"public", "power-owners"}, |
| 124 []*messages.Acl{ |
| 125 {Role: messages.Acl_OWNER, GrantedTo: "m
e@example.com"}, |
| 126 {Role: messages.Acl_READER, GrantedTo: "
you@example.com"}, |
| 127 }) |
| 128 So(err, ShouldBeNil) |
| 129 So(jobAcls.Owners, ShouldResemble, []string{"group:owner
s", "group:power", "me@example.com"}) |
| 130 So(jobAcls.Readers, ShouldResemble, []string{"group:all"
, "you@example.com"}) |
| 131 |
| 132 jobAcls, err = ValidateTaskAcls( |
| 133 aclSets, []string{"private"}, |
| 134 []*messages.Acl{ |
| 135 {Role: messages.Acl_OWNER, GrantedTo: "m
e@example.com"}, |
| 136 }) |
| 137 So(err, ShouldBeNil) |
| 138 So(jobAcls.Owners, ShouldResemble, []string{"me@example.
com"}) |
| 139 So(jobAcls.Readers, ShouldResemble, []string{"group:inte
rnal"}) |
| 140 }) |
| 141 }) |
| 142 } |
| 143 |
| 144 func TestAclsChecks(t *testing.T) { |
| 145 t.Parallel() |
| 146 ctx := gaetesting.TestingContext() |
| 147 |
| 148 basicGroups := GrantsByRole{Owners: []string{"group:owners"}, Readers: [
]string{"group:readers"}} |
| 149 |
| 150 Convey("Admins are owners and readers", t, func() { |
| 151 ctx = auth.WithState(ctx, &authtest.FakeState{ |
| 152 Identity: "user:admin@example.com", |
| 153 IdentityGroups: []string{"administrators"}, |
| 154 }) |
| 155 yup, err := basicGroups.IsOwner(ctx) |
| 156 So(err, ShouldBeNil) |
| 157 So(yup, ShouldBeTrue) |
| 158 yup, err = basicGroups.IsReader(ctx) |
| 159 So(err, ShouldBeNil) |
| 160 So(yup, ShouldBeTrue) |
| 161 }) |
| 162 Convey("Owners", t, func() { |
| 163 ctx = auth.WithState(ctx, &authtest.FakeState{ |
| 164 Identity: "user:owner@example.com", |
| 165 IdentityGroups: []string{"owners"}, |
| 166 }) |
| 167 yup, err := basicGroups.IsReader(ctx) |
| 168 So(err, ShouldBeNil) |
| 169 So(yup, ShouldBeTrue) |
| 170 yup, err = basicGroups.IsReader(ctx) |
| 171 So(err, ShouldBeNil) |
| 172 So(yup, ShouldBeTrue) |
| 173 }) |
| 174 Convey("Readers", t, func() { |
| 175 ctx = auth.WithState(ctx, &authtest.FakeState{ |
| 176 Identity: "user:reader@example.com", |
| 177 IdentityGroups: []string{"readers"}, |
| 178 }) |
| 179 nope, err := basicGroups.IsOwner(ctx) |
| 180 So(err, ShouldBeNil) |
| 181 So(nope, ShouldBeFalse) |
| 182 yup, err := basicGroups.IsReader(ctx) |
| 183 So(err, ShouldBeNil) |
| 184 So(yup, ShouldBeTrue) |
| 185 }) |
| 186 Convey("By email", t, func() { |
| 187 ctx = auth.WithState(ctx, &authtest.FakeState{ |
| 188 Identity: "user:reader@example.com", |
| 189 IdentityGroups: []string{"all"}, |
| 190 }) |
| 191 g := GrantsByRole{ |
| 192 Owners: []string{"group:owners"}, |
| 193 Readers: []string{"group:some", "reader@example.com"}, |
| 194 } |
| 195 nope, err := g.IsOwner(ctx) |
| 196 So(err, ShouldBeNil) |
| 197 So(nope, ShouldBeFalse) |
| 198 yup, err := g.IsReader(ctx) |
| 199 So(err, ShouldBeNil) |
| 200 So(yup, ShouldBeTrue) |
| 201 }) |
| 202 } |
| 203 |
| 204 func TestAclsEqual(t *testing.T) { |
| 205 t.Parallel() |
| 206 Convey("GrantsByRole.Equal", t, func() { |
| 207 x1 := GrantsByRole{Readers: []string{"a"}, Owners: []string{"b",
"c"}} |
| 208 x2 := GrantsByRole{Readers: []string{"a"}, Owners: []string{"b",
"c"}} |
| 209 y := GrantsByRole{Readers: []string{"e", "g"}, Owners: []string{
"b", "d"}} |
| 210 So(x1.Equal(&y), ShouldBeFalse) |
| 211 So(x1.Equal(&x2), ShouldBeTrue) |
| 212 }) |
| 213 } |
| OLD | NEW |