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  }