go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/auth_service/impl/model/snapshot_test.go (about) 1 // Copyright 2021 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 15 package model 16 17 import ( 18 "context" 19 "fmt" 20 "testing" 21 22 "google.golang.org/protobuf/proto" 23 24 "go.chromium.org/luci/gae/impl/memory" 25 "go.chromium.org/luci/gae/service/datastore" 26 "go.chromium.org/luci/server/auth/service/protocol" 27 28 "go.chromium.org/luci/auth_service/internal/permissions" 29 30 . "github.com/smartystreets/goconvey/convey" 31 . "go.chromium.org/luci/common/testing/assertions" 32 ) 33 34 func TestTakeSnapshot(t *testing.T) { 35 t.Parallel() 36 37 const testAuthDBRev = 12345 38 39 Convey("Testing TakeSnapshot", t, func() { 40 ctx := memory.Use(context.Background()) 41 42 _, err := TakeSnapshot(ctx) 43 So(err, ShouldEqual, datastore.ErrNoSuchEntity) 44 45 realmsGlobals := testAuthRealmsGlobals(ctx) 46 perms := makeTestPermissions("luci.dev.p1", "luci.dev.p2") 47 realmsGlobals.PermissionsList = &permissions.PermissionsList{ 48 Permissions: perms, 49 } 50 projectRealms1 := testAuthProjectRealms(ctx, "project-1") 51 projectRealms1.Realms, err = proto.Marshal(&protocol.Realms{ 52 Permissions: makeTestPermissions("luci.dev.p2"), 53 Conditions: makeTestConditions("a", "c"), 54 Realms: []*protocol.Realm{ 55 { 56 Name: "project-1:@root", 57 Bindings: []*protocol.Binding{ 58 { 59 Permissions: []uint32{0}, 60 Conditions: []uint32{0, 1}, 61 Principals: []string{"group:group-1"}, 62 }, 63 }, 64 }, 65 }, 66 }) 67 So(err, ShouldBeNil) 68 projectRealms2 := testAuthProjectRealms(ctx, "project-2") 69 projectRealms2.Realms, err = proto.Marshal(&protocol.Realms{ 70 Permissions: makeTestPermissions("luci.dev.p1"), 71 Conditions: makeTestConditions("b"), 72 Realms: []*protocol.Realm{ 73 { 74 Name: "project-2:@root", 75 Bindings: []*protocol.Binding{ 76 { 77 Permissions: []uint32{0}, 78 Conditions: []uint32{0}, 79 Principals: []string{"group:group-2"}, 80 }, 81 }, 82 }, 83 }, 84 }) 85 So(err, ShouldBeNil) 86 So(datastore.Put(ctx, 87 testAuthReplicationState(ctx, testAuthDBRev), 88 testAuthGlobalConfig(ctx), 89 testAuthGroup(ctx, "group-2"), 90 testAuthGroup(ctx, "group-1"), 91 testIPAllowlist(ctx, "ip-allowlist-2", nil), 92 testIPAllowlist(ctx, "ip-allowlist-1", nil), 93 realmsGlobals, 94 projectRealms2, 95 projectRealms1, 96 ), ShouldBeNil) 97 98 snap, err := TakeSnapshot(ctx) 99 So(err, ShouldBeNil) 100 101 So(snap, ShouldResembleProto, &Snapshot{ 102 ReplicationState: testAuthReplicationState(ctx, 12345), 103 GlobalConfig: testAuthGlobalConfig(ctx), 104 Groups: []*AuthGroup{ 105 testAuthGroup(ctx, "group-1"), 106 testAuthGroup(ctx, "group-2"), 107 }, 108 IPAllowlists: []*AuthIPAllowlist{ 109 testIPAllowlist(ctx, "ip-allowlist-1", nil), 110 testIPAllowlist(ctx, "ip-allowlist-2", nil), 111 }, 112 RealmsGlobals: realmsGlobals, 113 ProjectRealms: []*AuthProjectRealms{ 114 projectRealms1, 115 projectRealms2, 116 }, 117 }) 118 119 Convey("ToAuthDBProto", func() { 120 groupProto := func(name string) *protocol.AuthGroup { 121 return &protocol.AuthGroup{ 122 Name: name, 123 Members: []string{ 124 fmt.Sprintf("user:%s-m1@example.com", name), 125 fmt.Sprintf("user:%s-m2@example.com", name), 126 }, 127 Globs: []string{"user:*@example.com"}, 128 Nested: []string{"nested-" + name}, 129 Description: fmt.Sprintf("This is a test auth group %q.", name), 130 CreatedTs: testCreatedTS.UnixNano() / 1000, 131 CreatedBy: "user:test-creator@example.com", 132 ModifiedTs: testModifiedTS.UnixNano() / 1000, 133 ModifiedBy: "user:test-modifier@example.com", 134 Owners: "owners-" + name, 135 } 136 } 137 138 allowlistProto := func(name string) *protocol.AuthIPWhitelist { 139 return &protocol.AuthIPWhitelist{ 140 Name: name, 141 Subnets: []string{ 142 "127.0.0.1/10", 143 "127.0.0.1/20", 144 }, 145 Description: fmt.Sprintf("This is a test AuthIPAllowlist %q.", name), 146 CreatedTs: testCreatedTS.UnixNano() / 1000, 147 CreatedBy: "user:test-creator@example.com", 148 ModifiedTs: testModifiedTS.UnixNano() / 1000, 149 ModifiedBy: "user:test-modifier@example.com", 150 } 151 } 152 153 expectedMergedRealmsProto := &protocol.Realms{ 154 ApiVersion: RealmsAPIVersion, 155 Permissions: makeTestPermissions("luci.dev.p1", "luci.dev.p2"), 156 Conditions: makeTestConditions("a", "c", "b"), 157 Realms: []*protocol.Realm{ 158 { 159 Name: "project-1:@root", 160 Bindings: []*protocol.Binding{ 161 { 162 Permissions: []uint32{1}, 163 Conditions: []uint32{0, 1}, 164 Principals: []string{"group:group-1"}, 165 }, 166 }, 167 }, 168 { 169 Name: "project-2:@root", 170 Bindings: []*protocol.Binding{ 171 { 172 Permissions: []uint32{0}, 173 Conditions: []uint32{2}, 174 Principals: []string{"group:group-2"}, 175 }, 176 }, 177 }, 178 }, 179 } 180 181 authDBProto, err := snap.ToAuthDBProto(false) 182 So(err, ShouldBeNil) 183 So(authDBProto, ShouldResembleProto, &protocol.AuthDB{ 184 OauthClientId: "test-client-id", 185 OauthClientSecret: "test-client-secret", 186 OauthAdditionalClientIds: []string{ 187 "additional-client-id-0", 188 "additional-client-id-1", 189 }, 190 TokenServerUrl: "https://token-server.example.com", 191 SecurityConfig: testSecurityConfigBlob(), 192 Groups: []*protocol.AuthGroup{ 193 groupProto("group-1"), 194 groupProto("group-2"), 195 }, 196 IpWhitelists: []*protocol.AuthIPWhitelist{ 197 allowlistProto("ip-allowlist-1"), 198 allowlistProto("ip-allowlist-2"), 199 }, 200 Realms: expectedMergedRealmsProto, 201 }) 202 203 Convey("empty string fields are set to `empty`", func() { 204 sparseGlobalConfig := &AuthGlobalConfig{ 205 Kind: "AuthGlobalConfig", 206 ID: "root", 207 AuthVersionedEntityMixin: testAuthVersionedEntityMixin(), 208 } 209 sparseAuthGroup1 := testAuthGroup(ctx, "group-1") 210 sparseAuthGroup1.Description = "" 211 sparseSnapshot := &Snapshot{ 212 ReplicationState: testAuthReplicationState(ctx, 12345), 213 GlobalConfig: sparseGlobalConfig, 214 Groups: []*AuthGroup{ 215 sparseAuthGroup1, 216 testAuthGroup(ctx, "group-2"), 217 }, 218 } 219 220 expectedGroup1 := groupProto("group-1") 221 expectedGroup1.Description = "empty" 222 authDBProto, err := sparseSnapshot.ToAuthDBProto(false) 223 So(err, ShouldBeNil) 224 So(authDBProto, ShouldResembleProto, &protocol.AuthDB{ 225 OauthClientId: "empty", 226 OauthClientSecret: "empty", 227 TokenServerUrl: "empty", 228 Groups: []*protocol.AuthGroup{ 229 expectedGroup1, 230 groupProto("group-2"), 231 }, 232 Realms: &protocol.Realms{ 233 ApiVersion: RealmsAPIVersion, 234 }, 235 }) 236 }) 237 }) 238 239 Convey("ToAuthDB", func() { 240 db, err := snap.ToAuthDB(false) 241 So(err, ShouldBeNil) 242 So(db.Rev, ShouldEqual, testAuthDBRev) 243 }) 244 }) 245 }