| OLD | NEW |
| (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 access |
| 6 |
| 7 import ( |
| 8 "fmt" |
| 9 "testing" |
| 10 |
| 11 configPB "github.com/luci/luci-go/common/proto/config" |
| 12 "github.com/luci/luci-go/luci_config/server/cfgclient" |
| 13 "github.com/luci/luci-go/luci_config/server/cfgclient/backend" |
| 14 "github.com/luci/luci-go/server/auth" |
| 15 "github.com/luci/luci-go/server/auth/authtest" |
| 16 "github.com/luci/luci-go/server/auth/identity" |
| 17 |
| 18 "github.com/golang/protobuf/proto" |
| 19 "golang.org/x/net/context" |
| 20 |
| 21 . "github.com/luci/luci-go/common/testing/assertions" |
| 22 . "github.com/smartystreets/goconvey/convey" |
| 23 ) |
| 24 |
| 25 type testingBackend struct { |
| 26 backend.B |
| 27 |
| 28 item *backend.Item |
| 29 } |
| 30 |
| 31 func (tb *testingBackend) Get(c context.Context, configSet, path string, p backe
nd.Params) (*backend.Item, error) { |
| 32 if tb.item == nil { |
| 33 return nil, cfgclient.ErrNoConfig |
| 34 } |
| 35 clone := *tb.item |
| 36 return &clone, nil |
| 37 } |
| 38 |
| 39 func tpb(msg proto.Message) string { return proto.MarshalTextString(msg) } |
| 40 |
| 41 func accessCfg(access ...string) string { |
| 42 return tpb(&configPB.ProjectCfg{ |
| 43 Access: access, |
| 44 }) |
| 45 } |
| 46 |
| 47 func TestCheckAccess(t *testing.T) { |
| 48 t.Parallel() |
| 49 |
| 50 Convey(`A testing environment`, t, func() { |
| 51 c := context.Background() |
| 52 |
| 53 authState := authtest.FakeState{ |
| 54 Identity: identity.AnonymousIdentity, |
| 55 IdentityGroups: []string{"all"}, |
| 56 } |
| 57 c = auth.WithState(c, &authState) |
| 58 |
| 59 tb := testingBackend{} |
| 60 setAccess := func(access ...string) { |
| 61 if len(access) == 0 { |
| 62 tb.item = nil |
| 63 return |
| 64 } |
| 65 tb.item = &backend.Item{ |
| 66 Content: tpb(&configPB.ProjectCfg{Access: access
}), |
| 67 } |
| 68 } |
| 69 |
| 70 c = backend.WithBackend(c, &tb) |
| 71 |
| 72 Convey(`Will grant AsService access to any config`, func() { |
| 73 So(Check(c, backend.AsService, "foo/bar"), ShouldBeNil) |
| 74 So(Check(c, backend.AsService, "services/foo"), ShouldBe
Nil) |
| 75 So(Check(c, backend.AsService, "projects/nonexistent"),
ShouldBeNil) |
| 76 So(Check(c, backend.AsService, "projects/public"), Shoul
dBeNil) |
| 77 }) |
| 78 |
| 79 for _, tc := range []struct { |
| 80 A backend.Authority |
| 81 Name string |
| 82 }{ |
| 83 {backend.AsUser, "AsUser"}, |
| 84 {backend.AsAnonymous, "AsAnonymous"}, |
| 85 } { |
| 86 Convey(fmt.Sprintf(`Will deny %q access to any config`,
tc.Name), func() { |
| 87 So(Check(c, tc.A, "foo/bar"), ShouldEqual, ErrNo
Access) |
| 88 So(Check(c, tc.A, "services/foo"), ShouldEqual,
ErrNoAccess) |
| 89 So(Check(c, tc.A, "projects/nonexistent"), Shoul
dErrLike, "failed to load \"project.cfg\"") |
| 90 }) |
| 91 |
| 92 Convey(fmt.Sprintf(`Will grant %q access to an all-inclu
sive project`, tc.Name), func() { |
| 93 setAccess("group:all") |
| 94 So(Check(c, tc.A, "projects/public"), ShouldBeNi
l) |
| 95 }) |
| 96 } |
| 97 |
| 98 mustMakeIdentity := func(v string) identity.Identity { |
| 99 id, err := identity.MakeIdentity(v) |
| 100 if err != nil { |
| 101 panic(err) |
| 102 } |
| 103 return id |
| 104 } |
| 105 for _, tc := range []struct { |
| 106 name string |
| 107 explicit bool |
| 108 apply func() |
| 109 }{ |
| 110 {"a special user", false, |
| 111 func() { authState.Identity = mustMakeIdentity("
user:cat@example.com") }}, |
| 112 {"a special user (e-mail)", false, |
| 113 func() { authState.Identity = mustMakeIdentity("
user:email@example.com") }}, |
| 114 {"a member of a special group", true, |
| 115 func() { authState.IdentityGroups = append(authS
tate.IdentityGroups, "special") }}, |
| 116 } { |
| 117 Convey(fmt.Sprintf(`When user is %s`, tc.name), func() { |
| 118 tc.apply() |
| 119 |
| 120 setAccess() |
| 121 So(Check(c, backend.AsService, "foo/bar"), Shoul
dBeNil) |
| 122 So(Check(c, backend.AsUser, "foo/bar"), ShouldEq
ual, ErrNoAccess) |
| 123 So(Check(c, backend.AsAnonymous, "foo/bar"), Sho
uldEqual, ErrNoAccess) |
| 124 |
| 125 So(Check(c, backend.AsService, "services/foo"),
ShouldBeNil) |
| 126 So(Check(c, backend.AsUser, "services/foo"), Sho
uldEqual, ErrNoAccess) |
| 127 So(Check(c, backend.AsAnonymous, "services/foo")
, ShouldEqual, ErrNoAccess) |
| 128 |
| 129 So(Check(c, backend.AsService, "projects/nonexis
tent"), ShouldBeNil) |
| 130 So(Check(c, backend.AsUser, "projects/nonexisten
t"), ShouldErrLike, "failed to load \"project.cfg\"") |
| 131 So(Check(c, backend.AsAnonymous, "projects/nonex
istent"), ShouldErrLike, "failed to load \"project.cfg\"") |
| 132 |
| 133 setAccess("group:all") |
| 134 So(Check(c, backend.AsService, "projects/public"
), ShouldBeNil) |
| 135 So(Check(c, backend.AsUser, "projects/public"),
ShouldBeNil) |
| 136 So(Check(c, backend.AsAnonymous, "projects/publi
c"), ShouldBeNil) |
| 137 |
| 138 setAccess("group:special", "user:cat@example.com
", "email@example.com") |
| 139 So(Check(c, backend.AsUser, "projects/exclusive"
), ShouldBeNil) |
| 140 if tc.explicit { |
| 141 So(Check(c, backend.AsAnonymous, "projec
ts/exclusive"), ShouldBeNil) |
| 142 } else { |
| 143 So(Check(c, backend.AsAnonymous, "projec
ts/exclusive"), ShouldEqual, ErrNoAccess) |
| 144 } |
| 145 }) |
| 146 } |
| 147 }) |
| 148 } |
| OLD | NEW |