go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/auth_service/impl/authdb_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 impl
    16  
    17  import (
    18  	"context"
    19  	"testing"
    20  
    21  	"google.golang.org/protobuf/proto"
    22  
    23  	"go.chromium.org/luci/gae/impl/memory"
    24  	"go.chromium.org/luci/gae/service/datastore"
    25  	"go.chromium.org/luci/server/auth/authdb"
    26  	"go.chromium.org/luci/server/auth/realms"
    27  	"go.chromium.org/luci/server/auth/service/protocol"
    28  
    29  	"go.chromium.org/luci/auth_service/impl/model"
    30  	"go.chromium.org/luci/auth_service/internal/permissions"
    31  
    32  	. "github.com/smartystreets/goconvey/convey"
    33  )
    34  
    35  var (
    36  	testPerm1 = realms.RegisterPermission("testing.tests.perm1")
    37  	testPerm2 = realms.RegisterPermission("testing.tests.perm2")
    38  )
    39  
    40  func makeTestPermissions(names ...string) []*protocol.Permission {
    41  	perms := make([]*protocol.Permission, len(names))
    42  	for i, name := range names {
    43  		perms[i] = &protocol.Permission{Name: name}
    44  	}
    45  	return perms
    46  }
    47  
    48  func TestAuthDBProvider(t *testing.T) {
    49  	t.Setenv(model.DryRunCronRealmsEnvVar, "false")
    50  
    51  	Convey("AuthDBProvider works", t, func() {
    52  		ctx := memory.Use(context.Background())
    53  		authDB := &AuthDBProvider{}
    54  
    55  		putRev := func(rev int64, members []string) {
    56  			err := datastore.RunInTransaction(ctx, func(ctx context.Context) error {
    57  				globals := &model.AuthGlobalConfig{}
    58  				state := &model.AuthReplicationState{
    59  					AuthDBRev: rev,
    60  					Parent:    model.RootKey(ctx),
    61  				}
    62  				group := &model.AuthGroup{
    63  					ID:      "test-group",
    64  					Parent:  model.RootKey(ctx),
    65  					Members: members,
    66  				}
    67  				realmsGlobals := &model.AuthRealmsGlobals{
    68  					Kind:   "AuthRealmsGlobals",
    69  					ID:     "globals",
    70  					Parent: model.RootKey(ctx),
    71  					PermissionsList: &permissions.PermissionsList{
    72  						Permissions: makeTestPermissions(testPerm1.String(), testPerm2.String()),
    73  					},
    74  				}
    75  				// Grant all members of test-group testPerm2 permission
    76  				// in project "test-project" root realm.
    77  				marshalled, marshalErr := proto.Marshal(&protocol.Realms{
    78  					Permissions: makeTestPermissions(testPerm2.String()),
    79  					Realms: []*protocol.Realm{
    80  						{
    81  							Name: "test-project:@root",
    82  							Bindings: []*protocol.Binding{
    83  								{
    84  									Permissions: []uint32{0},
    85  									Principals:  []string{"group:test-group"},
    86  								},
    87  							},
    88  						},
    89  					},
    90  				})
    91  				So(marshalErr, ShouldBeNil)
    92  				projectRealms := &model.AuthProjectRealms{
    93  					Kind:   "AuthProjectRealms",
    94  					ID:     "test-project",
    95  					Parent: model.RootKey(ctx),
    96  					Realms: marshalled,
    97  				}
    98  				return datastore.Put(ctx, globals, state, group, realmsGlobals, projectRealms)
    99  			}, nil)
   100  			So(err, ShouldBeNil)
   101  		}
   102  
   103  		// Initial revision.
   104  		putRev(1000, []string{"user:a@example.com"})
   105  
   106  		// Got it.
   107  		db1, err := authDB.GetAuthDB(ctx)
   108  		So(err, ShouldBeNil)
   109  		So(authdb.Revision(db1), ShouldEqual, 1000)
   110  
   111  		// Works.
   112  		yes, err := db1.IsMember(ctx, "user:a@example.com", []string{"test-group"})
   113  		So(err, ShouldBeNil)
   114  		So(yes, ShouldBeTrue)
   115  
   116  		// Check permission which hasn't been granted.
   117  		allowed, err := db1.HasPermission(ctx, "user:a@example.com", testPerm1, "test-project:@root", nil)
   118  		So(err, ShouldBeNil)
   119  		So(allowed, ShouldBeFalse)
   120  		// Check permission which has been granted.
   121  		allowed, err = db1.HasPermission(ctx, "user:a@example.com", testPerm2, "test-project:@root", nil)
   122  		So(err, ShouldBeNil)
   123  		So(allowed, ShouldBeTrue)
   124  		// Check realms fall back to @root.
   125  		allowed, err = db1.HasPermission(ctx, "user:a@example.com", testPerm2, "test-project:unknown", nil)
   126  		So(err, ShouldBeNil)
   127  		So(allowed, ShouldBeTrue)
   128  
   129  		// Calling again returns the exact same object.
   130  		db2, err := authDB.GetAuthDB(ctx)
   131  		So(err, ShouldBeNil)
   132  		So(db2, ShouldEqual, db1)
   133  
   134  		// Updated.
   135  		putRev(1001, nil)
   136  
   137  		// Got the new one.
   138  		db3, err := authDB.GetAuthDB(ctx)
   139  		So(err, ShouldBeNil)
   140  		So(authdb.Revision(db3), ShouldEqual, 1001)
   141  
   142  		// The group there is updated too.
   143  		yes, err = db3.IsMember(ctx, "user:a@example.com", []string{"test-group"})
   144  		So(err, ShouldBeNil)
   145  		So(yes, ShouldBeFalse)
   146  
   147  		// Check permission which hasn't been granted, as the member is
   148  		// no longer in the group.
   149  		allowed, err = db3.HasPermission(ctx, "user:a@example.com", testPerm2, "test-project:@root", nil)
   150  		So(err, ShouldBeNil)
   151  		So(allowed, ShouldBeFalse)
   152  	})
   153  }