go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/server/auth/authtest/db_test.go (about)

     1  // Copyright 2015 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 authtest
    16  
    17  import (
    18  	"context"
    19  	"errors"
    20  	"net"
    21  	"sort"
    22  	"testing"
    23  
    24  	"go.chromium.org/luci/auth/identity"
    25  
    26  	"go.chromium.org/luci/server/auth/realms"
    27  	"go.chromium.org/luci/server/auth/service/protocol"
    28  
    29  	. "github.com/smartystreets/goconvey/convey"
    30  	. "go.chromium.org/luci/common/testing/assertions"
    31  )
    32  
    33  var (
    34  	testPerm1 = realms.RegisterPermission("testing.tests.perm1")
    35  	testPerm2 = realms.RegisterPermission("testing.tests.perm2")
    36  	testPerm3 = realms.RegisterPermission("testing.tests.perm3")
    37  )
    38  
    39  func init() {
    40  	testPerm1.AddFlags(realms.UsedInQueryRealms)
    41  }
    42  
    43  func TestFakeDB(t *testing.T) {
    44  	t.Parallel()
    45  
    46  	ctx := context.Background()
    47  
    48  	dataRoot := &protocol.RealmData{EnforceInService: []string{"A"}}
    49  	dataSome := &protocol.RealmData{EnforceInService: []string{"B"}}
    50  
    51  	Convey("With FakeDB", t, func() {
    52  		db := NewFakeDB(
    53  			MockMembership("user:abc@def.com", "group-a"),
    54  			MockMembership("user:abc@def.com", "group-b"),
    55  
    56  			MockGroup("group-c", []identity.Identity{"user:abc@def.com"}),
    57  			MockGroup("group-d", nil),
    58  
    59  			MockPermission("user:abc@def.com", "proj:realm", testPerm1),
    60  			MockPermission("user:abc@def.com", "another:realm", testPerm1),
    61  			MockPermission("user:abc@def.com", "proj:realm", testPerm2),
    62  
    63  			MockPermission("user:abc@def.com", "proj:cond", testPerm1,
    64  				RestrictAttribute("attr1", "val1", "val2")),
    65  			MockPermission("user:abc@def.com", "proj:cond", testPerm2,
    66  				RestrictAttribute("attr1", "val1", "val2"),
    67  				RestrictAttribute("attr2", "val3")),
    68  
    69  			MockRealmData("proj:@root", dataRoot),
    70  			MockRealmData("proj:some", dataSome),
    71  
    72  			MockIPAllowlist("127.0.0.42", "allowlist"),
    73  		)
    74  
    75  		Convey("Membership checks work", func() {
    76  			out, err := db.CheckMembership(ctx, "user:abc@def.com", []string{"group-a", "group-b", "group-c", "group-d"})
    77  			So(err, ShouldBeNil)
    78  			So(out, ShouldResemble, []string{"group-a", "group-b", "group-c"})
    79  
    80  			resp, err := db.IsMember(ctx, "user:abc@def.com", nil)
    81  			So(err, ShouldBeNil)
    82  			So(resp, ShouldBeFalse)
    83  
    84  			resp, err = db.IsMember(ctx, "user:abc@def.com", []string{"group-b"})
    85  			So(err, ShouldBeNil)
    86  			So(resp, ShouldBeTrue)
    87  
    88  			resp, err = db.IsMember(ctx, "user:abc@def.com", []string{"group-c"})
    89  			So(err, ShouldBeNil)
    90  			So(resp, ShouldBeTrue)
    91  
    92  			resp, err = db.IsMember(ctx, "user:abc@def.com", []string{"group-d"})
    93  			So(err, ShouldBeNil)
    94  			So(resp, ShouldBeFalse)
    95  
    96  			resp, err = db.IsMember(ctx, "user:abc@def.com", []string{"another", "group-b"})
    97  			So(err, ShouldBeNil)
    98  			So(resp, ShouldBeTrue)
    99  
   100  			resp, err = db.IsMember(ctx, "user:another@def.com", []string{"group-b"})
   101  			So(err, ShouldBeNil)
   102  			So(resp, ShouldBeFalse)
   103  
   104  			resp, err = db.IsMember(ctx, "user:another@def.com", []string{"another", "group-b"})
   105  			So(err, ShouldBeNil)
   106  			So(resp, ShouldBeFalse)
   107  
   108  			resp, err = db.IsMember(ctx, "user:abc@def.com", []string{"another"})
   109  			So(err, ShouldBeNil)
   110  			So(resp, ShouldBeFalse)
   111  		})
   112  
   113  		Convey("Permission checks work", func() {
   114  			resp, err := db.HasPermission(ctx, "user:abc@def.com", testPerm1, "proj:realm", nil)
   115  			So(err, ShouldBeNil)
   116  			So(resp, ShouldBeTrue)
   117  
   118  			resp, err = db.HasPermission(ctx, "user:abc@def.com", testPerm2, "proj:realm", nil)
   119  			So(err, ShouldBeNil)
   120  			So(resp, ShouldBeTrue)
   121  
   122  			resp, err = db.HasPermission(ctx, "user:abc@def.com", testPerm3, "proj:realm", nil)
   123  			So(err, ShouldBeNil)
   124  			So(resp, ShouldBeFalse)
   125  
   126  			resp, err = db.HasPermission(ctx, "user:abc@def.com", testPerm1, "proj:unknown", nil)
   127  			So(err, ShouldBeNil)
   128  			So(resp, ShouldBeFalse)
   129  		})
   130  
   131  		Convey("Conditional permission checks work", func() {
   132  			resp, err := db.HasPermission(ctx, "user:abc@def.com", testPerm1, "proj:cond", nil)
   133  			So(err, ShouldBeNil)
   134  			So(resp, ShouldBeFalse)
   135  
   136  			resp, err = db.HasPermission(ctx, "user:abc@def.com", testPerm1, "proj:cond", realms.Attrs{
   137  				"attr1": "val1",
   138  			})
   139  			So(err, ShouldBeNil)
   140  			So(resp, ShouldBeTrue)
   141  
   142  			resp, err = db.HasPermission(ctx, "user:abc@def.com", testPerm1, "proj:cond", realms.Attrs{
   143  				"attr1": "val2",
   144  			})
   145  			So(err, ShouldBeNil)
   146  			So(resp, ShouldBeTrue)
   147  
   148  			resp, err = db.HasPermission(ctx, "user:abc@def.com", testPerm1, "proj:cond", realms.Attrs{
   149  				"attr1": "val3",
   150  			})
   151  			So(err, ShouldBeNil)
   152  			So(resp, ShouldBeFalse)
   153  
   154  			resp, err = db.HasPermission(ctx, "user:abc@def.com", testPerm1, "proj:cond", realms.Attrs{
   155  				"unknown": "val1",
   156  			})
   157  			So(err, ShouldBeNil)
   158  			So(resp, ShouldBeFalse)
   159  
   160  			resp, err = db.HasPermission(ctx, "user:abc@def.com", testPerm2, "proj:cond", realms.Attrs{
   161  				"attr1": "val1",
   162  			})
   163  			So(err, ShouldBeNil)
   164  			So(resp, ShouldBeFalse)
   165  
   166  			resp, err = db.HasPermission(ctx, "user:abc@def.com", testPerm2, "proj:cond", realms.Attrs{
   167  				"attr1": "val1",
   168  				"attr2": "val3",
   169  			})
   170  			So(err, ShouldBeNil)
   171  			So(resp, ShouldBeTrue)
   172  		})
   173  
   174  		Convey("QueryRealms works", func() {
   175  			res, err := db.QueryRealms(ctx, "user:abc@def.com", testPerm1, "", nil)
   176  			So(err, ShouldBeNil)
   177  			sort.Strings(res)
   178  			So(res, ShouldResemble, []string{"another:realm", "proj:realm"})
   179  
   180  			res, err = db.QueryRealms(ctx, "user:abc@def.com", testPerm1, "proj", nil)
   181  			So(err, ShouldBeNil)
   182  			So(res, ShouldResemble, []string{"proj:realm"})
   183  
   184  			res, err = db.QueryRealms(ctx, "user:zzz@def.com", testPerm1, "", nil)
   185  			So(err, ShouldBeNil)
   186  			So(res, ShouldBeEmpty)
   187  
   188  			// Conditional bindings.
   189  			res, err = db.QueryRealms(ctx, "user:abc@def.com", testPerm1, "", realms.Attrs{
   190  				"attr1": "val1",
   191  			})
   192  			So(err, ShouldBeNil)
   193  			sort.Strings(res)
   194  			So(res, ShouldResemble, []string{"another:realm", "proj:cond", "proj:realm"})
   195  
   196  			// Unflagged permission.
   197  			_, err = db.QueryRealms(ctx, "user:abc@def.com", testPerm2, "", nil)
   198  			So(err, ShouldErrLike, "permission testing.tests.perm2 cannot be used in QueryRealms")
   199  		})
   200  
   201  		Convey("FilterKnownGroups works", func() {
   202  			known, err := db.FilterKnownGroups(ctx, []string{"missing", "group-b", "group-a", "group-c", "group-d", "group-a", "missing"})
   203  			So(err, ShouldBeNil)
   204  			So(known, ShouldResemble, []string{
   205  				"group-b", "group-a", "group-c", "group-d", "group-a",
   206  			})
   207  		})
   208  
   209  		Convey("GetRealmData works", func() {
   210  			data, err := db.GetRealmData(ctx, "proj:some")
   211  			So(err, ShouldBeNil)
   212  			So(data, ShouldEqual, dataSome)
   213  
   214  			// No automatic fallback to root happens, mock it yourself.
   215  			data, err = db.GetRealmData(ctx, "proj:zzz")
   216  			So(err, ShouldBeNil)
   217  			So(data, ShouldBeNil)
   218  		})
   219  
   220  		Convey("IP allowlist checks work", func() {
   221  			resp, err := db.IsAllowedIP(ctx, net.ParseIP("127.0.0.42"), "allowlist")
   222  			So(err, ShouldBeNil)
   223  			So(resp, ShouldBeTrue)
   224  
   225  			resp, err = db.IsAllowedIP(ctx, net.ParseIP("127.0.0.42"), "another")
   226  			So(err, ShouldBeNil)
   227  			So(resp, ShouldBeFalse)
   228  
   229  			resp, err = db.IsAllowedIP(ctx, net.ParseIP("192.0.0.1"), "allowlist")
   230  			So(err, ShouldBeNil)
   231  			So(resp, ShouldBeFalse)
   232  		})
   233  
   234  		Convey("Error works", func() {
   235  			mockedErr := errors.New("boom")
   236  			db.AddMocks(MockError(mockedErr))
   237  
   238  			_, err := db.IsMember(ctx, "user:abc@def.com", []string{"group-a"})
   239  			So(err, ShouldEqual, mockedErr)
   240  
   241  			_, err = db.HasPermission(ctx, "user:abc@def.com", testPerm1, "proj:realm", nil)
   242  			So(err, ShouldEqual, mockedErr)
   243  
   244  			_, err = db.IsAllowedIP(ctx, net.ParseIP("127.0.0.42"), "allowlist")
   245  			So(err, ShouldEqual, mockedErr)
   246  
   247  			_, err = db.FilterKnownGroups(ctx, []string{"a", "b"})
   248  			So(err, ShouldEqual, mockedErr)
   249  		})
   250  	})
   251  }