github.com/polarismesh/polaris@v1.17.8/cache/auth/strategy_test.go (about)

     1  /**
     2   * Tencent is pleased to support the open source community by making Polaris available.
     3   *
     4   * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
     5   *
     6   * Licensed under the BSD 3-Clause License (the "License");
     7   * you may not use this file except in compliance with the License.
     8   * You may obtain a copy of the License at
     9   *
    10   * https://opensource.org/licenses/BSD-3-Clause
    11   *
    12   * Unless required by applicable law or agreed to in writing, software distributed
    13   * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
    14   * CONDITIONS OF ANY KIND, either express or implied. See the License for the
    15   * specific language governing permissions and limitations under the License.
    16   */
    17  
    18  package auth
    19  
    20  import (
    21  	"fmt"
    22  	"testing"
    23  
    24  	"github.com/golang/mock/gomock"
    25  	apisecurity "github.com/polarismesh/specification/source/go/api/v1/security"
    26  	"github.com/stretchr/testify/assert"
    27  
    28  	types "github.com/polarismesh/polaris/cache/api"
    29  	cachemock "github.com/polarismesh/polaris/cache/mock"
    30  	"github.com/polarismesh/polaris/common/model"
    31  	"github.com/polarismesh/polaris/common/utils"
    32  	"github.com/polarismesh/polaris/store/mock"
    33  )
    34  
    35  func Test_strategyCache_IsResourceEditable_1(t *testing.T) {
    36  	t.Run("资源没有关联任何策略", func(t *testing.T) {
    37  		ctrl := gomock.NewController(t)
    38  		mockCacheMgr := cachemock.NewMockCacheManager(ctrl)
    39  		mockStore := mock.NewMockStore(ctrl)
    40  
    41  		t.Cleanup(func() {
    42  			ctrl.Finish()
    43  		})
    44  
    45  		userCache := NewUserCache(mockStore, mockCacheMgr)
    46  		strategyCache := NewStrategyCache(mockStore, mockCacheMgr).(*strategyCache)
    47  
    48  		mockCacheMgr.EXPECT().GetCacher(types.CacheUser).Return(userCache).AnyTimes()
    49  
    50  		userCache.Initialize(map[string]interface{}{})
    51  		strategyCache.Initialize(map[string]interface{}{})
    52  
    53  		strategyCache.setStrategys(buildStrategies(10))
    54  
    55  		ret := strategyCache.IsResourceEditable(model.Principal{
    56  			PrincipalID:   "user-1",
    57  			PrincipalRole: model.PrincipalUser,
    58  		}, apisecurity.ResourceType_Namespaces, "namespace-1")
    59  
    60  		assert.True(t, ret, "must be true")
    61  	})
    62  
    63  	t.Run("操作的目标资源关联了策略-自己在principal-user列表中", func(t *testing.T) {
    64  		ctrl := gomock.NewController(t)
    65  		mockCacheMgr := cachemock.NewMockCacheManager(ctrl)
    66  		mockStore := mock.NewMockStore(ctrl)
    67  
    68  		t.Cleanup(func() {
    69  			ctrl.Finish()
    70  		})
    71  
    72  		userCache := NewUserCache(mockStore, mockCacheMgr)
    73  		strategyCache := NewStrategyCache(mockStore, mockCacheMgr).(*strategyCache)
    74  
    75  		mockCacheMgr.EXPECT().GetCacher(types.CacheUser).Return(userCache).AnyTimes()
    76  
    77  		userCache.Initialize(map[string]interface{}{})
    78  		strategyCache.Initialize(map[string]interface{}{})
    79  
    80  		strategyCache.setStrategys([]*model.StrategyDetail{
    81  			{
    82  				ID:   fmt.Sprintf("rule-%d", 1),
    83  				Name: fmt.Sprintf("rule-%d", 1),
    84  				Principals: []model.Principal{
    85  					{
    86  						PrincipalID:   "user-1",
    87  						PrincipalRole: model.PrincipalUser,
    88  					},
    89  				},
    90  				Valid: true,
    91  				Resources: []model.StrategyResource{
    92  					{
    93  						StrategyID: fmt.Sprintf("rule-%d", 1),
    94  						ResType:    0,
    95  						ResID:      "*",
    96  					},
    97  				},
    98  			},
    99  		})
   100  
   101  		ret := strategyCache.IsResourceEditable(model.Principal{
   102  			PrincipalID:   "user-1",
   103  			PrincipalRole: model.PrincipalUser,
   104  		}, apisecurity.ResourceType_Namespaces, "namespace-1")
   105  
   106  		assert.True(t, ret, "must be true")
   107  	})
   108  
   109  	t.Run("操作的目标资源关联了策略-自己不在principal-user列表中", func(t *testing.T) {
   110  		ctrl := gomock.NewController(t)
   111  		mockCacheMgr := cachemock.NewMockCacheManager(ctrl)
   112  		mockStore := mock.NewMockStore(ctrl)
   113  
   114  		t.Cleanup(func() {
   115  			ctrl.Finish()
   116  		})
   117  
   118  		userCache := NewUserCache(mockStore, mockCacheMgr)
   119  		strategyCache := NewStrategyCache(mockStore, mockCacheMgr).(*strategyCache)
   120  
   121  		mockCacheMgr.EXPECT().GetCacher(types.CacheUser).Return(userCache).AnyTimes()
   122  
   123  		userCache.Initialize(map[string]interface{}{})
   124  		strategyCache.Initialize(map[string]interface{}{})
   125  
   126  		strategyCache.setStrategys(buildStrategies(10))
   127  
   128  		ret := strategyCache.IsResourceEditable(model.Principal{
   129  			PrincipalID:   "user-20",
   130  			PrincipalRole: model.PrincipalUser,
   131  		}, apisecurity.ResourceType_Namespaces, "namespace-1")
   132  
   133  		assert.False(t, ret, "must be false")
   134  	})
   135  
   136  	t.Run("操作的目标资源关联了策略-自己属于principal-group中组成员", func(t *testing.T) {
   137  		ctrl := gomock.NewController(t)
   138  		mockCacheMgr := cachemock.NewMockCacheManager(ctrl)
   139  		mockStore := mock.NewMockStore(ctrl)
   140  
   141  		t.Cleanup(func() {
   142  			ctrl.Finish()
   143  		})
   144  
   145  		userCache := NewUserCache(mockStore, mockCacheMgr).(*userCache)
   146  		strategyCache := NewStrategyCache(mockStore, mockCacheMgr).(*strategyCache)
   147  
   148  		mockCacheMgr.EXPECT().GetCacher(types.CacheUser).Return(userCache).AnyTimes()
   149  
   150  		userCache.Initialize(map[string]interface{}{})
   151  		strategyCache.Initialize(map[string]interface{}{})
   152  
   153  		userCache.groups.Store("group-1", &model.UserGroupDetail{
   154  			UserGroup: &model.UserGroup{
   155  				ID: "group-1",
   156  			},
   157  			UserIds: map[string]struct{}{
   158  				"user-1": {},
   159  			},
   160  		})
   161  
   162  		userCache.user2Groups.Store("user-1", utils.NewSyncSet[string]())
   163  		links, _ := userCache.user2Groups.Load("user-1")
   164  		links.Add("group-1")
   165  
   166  		strategyCache.setStrategys(buildStrategies(10))
   167  
   168  		ret := strategyCache.IsResourceEditable(model.Principal{
   169  			PrincipalID:   "user-1",
   170  			PrincipalRole: model.PrincipalUser,
   171  		}, apisecurity.ResourceType_Namespaces, "namespace-1")
   172  
   173  		assert.True(t, ret, "must be true")
   174  	})
   175  
   176  	t.Run("操作关联策略的资源-策略在操作成功-策略移除操作失败", func(t *testing.T) {
   177  		ctrl := gomock.NewController(t)
   178  		mockCacheMgr := cachemock.NewMockCacheManager(ctrl)
   179  		mockStore := mock.NewMockStore(ctrl)
   180  
   181  		t.Cleanup(func() {
   182  			ctrl.Finish()
   183  		})
   184  
   185  		userCache := NewUserCache(mockStore, mockCacheMgr).(*userCache)
   186  		strategyCache := NewStrategyCache(mockStore, mockCacheMgr).(*strategyCache)
   187  
   188  		mockCacheMgr.EXPECT().GetCacher(types.CacheUser).Return(userCache).AnyTimes()
   189  
   190  		userCache.Initialize(map[string]interface{}{})
   191  		strategyCache.Initialize(map[string]interface{}{})
   192  
   193  		userCache.groups.Store("group-1", &model.UserGroupDetail{
   194  			UserGroup: &model.UserGroup{
   195  				ID: "group-1",
   196  			},
   197  			UserIds: map[string]struct{}{
   198  				"user-1": {},
   199  			},
   200  		})
   201  
   202  		userCache.user2Groups.Store("user-1", utils.NewSyncSet[string]())
   203  		links, _ := userCache.user2Groups.Load("user-1")
   204  		links.Add("group-1")
   205  		strategyCache.strategys.Store("rule-1", &model.StrategyDetailCache{
   206  			StrategyDetail: &model.StrategyDetail{
   207  				ID:         "rule-1",
   208  				Name:       "rule-1",
   209  				Principals: []model.Principal{},
   210  				Resources:  []model.StrategyResource{},
   211  			},
   212  			GroupPrincipal: map[string]model.Principal{
   213  				"group-1": {
   214  					PrincipalID: "group-1",
   215  				},
   216  			},
   217  		})
   218  		strategyCache.strategys.Store("rule-2", &model.StrategyDetailCache{
   219  			StrategyDetail: &model.StrategyDetail{
   220  				ID:         "rule-2",
   221  				Name:       "rule-2",
   222  				Principals: []model.Principal{},
   223  				Resources:  []model.StrategyResource{},
   224  			},
   225  			GroupPrincipal: map[string]model.Principal{
   226  				"group-2": {
   227  					PrincipalID: "group-2",
   228  				},
   229  			},
   230  		})
   231  
   232  		strategyCache.writeSet(strategyCache.namespace2Strategy, "namespace-1", "rule-1", false)
   233  		strategyCache.writeSet(strategyCache.namespace2Strategy, "namespace-1", "rule-2", false)
   234  
   235  		ret := strategyCache.IsResourceEditable(model.Principal{
   236  			PrincipalID:   "user-1",
   237  			PrincipalRole: model.PrincipalUser,
   238  		}, apisecurity.ResourceType_Namespaces, "namespace-1")
   239  
   240  		assert.True(t, ret, "must be true")
   241  
   242  		strategyCache.handlerResourceStrategy([]*model.StrategyDetail{
   243  			{
   244  				ID:         "rule-1",
   245  				Name:       "rule-1",
   246  				Valid:      false,
   247  				Principals: []model.Principal{},
   248  				Resources: []model.StrategyResource{
   249  					{
   250  						StrategyID: "rule-1",
   251  						ResType:    0,
   252  						ResID:      "namespace-1",
   253  					},
   254  				},
   255  			},
   256  		})
   257  
   258  		ret = strategyCache.IsResourceEditable(model.Principal{
   259  			PrincipalID:   "user-1",
   260  			PrincipalRole: model.PrincipalUser,
   261  		}, apisecurity.ResourceType_Namespaces, "namespace-1")
   262  
   263  		assert.False(t, ret, "must be false")
   264  	})
   265  
   266  	t.Run("", func(t *testing.T) {
   267  		ctrl := gomock.NewController(t)
   268  		mockCacheMgr := cachemock.NewMockCacheManager(ctrl)
   269  		mockStore := mock.NewMockStore(ctrl)
   270  
   271  		t.Cleanup(func() {
   272  			ctrl.Finish()
   273  		})
   274  
   275  		userCache := NewUserCache(mockStore, mockCacheMgr).(*userCache)
   276  		strategyCache := NewStrategyCache(mockStore, mockCacheMgr).(*strategyCache)
   277  
   278  		mockCacheMgr.EXPECT().GetCacher(types.CacheUser).Return(userCache).AnyTimes()
   279  
   280  		userCache.Initialize(map[string]interface{}{})
   281  		strategyCache.Initialize(map[string]interface{}{})
   282  
   283  		userCache.groups.Store("group-1", &model.UserGroupDetail{
   284  			UserGroup: &model.UserGroup{
   285  				ID: "group-1",
   286  			},
   287  			UserIds: map[string]struct{}{
   288  				"user-1": {},
   289  			},
   290  		})
   291  
   292  		strategyDetail := &model.StrategyDetail{
   293  			ID:   "rule-1",
   294  			Name: "rule-1",
   295  			Principals: []model.Principal{
   296  				{
   297  					PrincipalID:   "user-1",
   298  					PrincipalRole: model.PrincipalUser,
   299  				},
   300  				{
   301  					PrincipalID:   "group-1",
   302  					PrincipalRole: model.PrincipalGroup,
   303  				},
   304  			},
   305  			Valid: true,
   306  			Resources: []model.StrategyResource{
   307  				{
   308  					StrategyID: "rule-1",
   309  					ResType:    0,
   310  					ResID:      "*",
   311  				},
   312  			},
   313  		}
   314  
   315  		strategyDetail2 := &model.StrategyDetail{
   316  			ID:   "rule-2",
   317  			Name: "rule-2",
   318  			Principals: []model.Principal{
   319  				{
   320  					PrincipalID:   "user-2",
   321  					PrincipalRole: model.PrincipalUser,
   322  				},
   323  				{
   324  					PrincipalID:   "group-2",
   325  					PrincipalRole: model.PrincipalGroup,
   326  				},
   327  			},
   328  			Valid: true,
   329  			Resources: []model.StrategyResource{
   330  				{
   331  					StrategyID: "rule-2",
   332  					ResType:    0,
   333  					ResID:      "namespace-1",
   334  				},
   335  			},
   336  		}
   337  
   338  		strategyCache.strategys.Store("rule-1", &model.StrategyDetailCache{
   339  			StrategyDetail: strategyDetail,
   340  			UserPrincipal: map[string]model.Principal{
   341  				"user-1": {
   342  					PrincipalID: "user-1",
   343  				},
   344  			},
   345  			GroupPrincipal: map[string]model.Principal{
   346  				"group-1": {
   347  					PrincipalID: "group-1",
   348  				},
   349  			},
   350  		})
   351  		strategyCache.strategys.Store("rule-2", &model.StrategyDetailCache{
   352  			StrategyDetail: strategyDetail2,
   353  			UserPrincipal: map[string]model.Principal{
   354  				"user-2": {
   355  					PrincipalID: "user-2",
   356  				},
   357  			},
   358  			GroupPrincipal: map[string]model.Principal{
   359  				"group-2": {
   360  					PrincipalID: "group-2",
   361  				},
   362  			},
   363  		})
   364  
   365  		strategyCache.handlerPrincipalStrategy([]*model.StrategyDetail{strategyDetail2})
   366  		strategyCache.handlerResourceStrategy([]*model.StrategyDetail{strategyDetail2})
   367  		strategyCache.handlerPrincipalStrategy([]*model.StrategyDetail{strategyDetail})
   368  		strategyCache.handlerResourceStrategy([]*model.StrategyDetail{strategyDetail})
   369  		ret := strategyCache.IsResourceEditable(model.Principal{
   370  			PrincipalID:   "user-1",
   371  			PrincipalRole: model.PrincipalUser,
   372  		}, apisecurity.ResourceType_Namespaces, "namespace-1")
   373  
   374  		assert.True(t, ret, "must be true")
   375  
   376  		strategyDetail.Valid = false
   377  
   378  		strategyCache.handlerPrincipalStrategy([]*model.StrategyDetail{strategyDetail})
   379  		strategyCache.handlerResourceStrategy([]*model.StrategyDetail{strategyDetail})
   380  		strategyCache.strategys.Delete(strategyDetail.ID)
   381  		ret = strategyCache.IsResourceEditable(model.Principal{
   382  			PrincipalID:   "user-1",
   383  			PrincipalRole: model.PrincipalUser,
   384  		}, apisecurity.ResourceType_Namespaces, "namespace-1")
   385  
   386  		assert.False(t, ret, "must be false")
   387  	})
   388  }
   389  
   390  func buildStrategies(num int) []*model.StrategyDetail {
   391  
   392  	ret := make([]*model.StrategyDetail, 0, num)
   393  
   394  	for i := 0; i < num; i++ {
   395  		principals := make([]model.Principal, 0, num)
   396  		for j := 0; j < num; j++ {
   397  			principals = append(principals, model.Principal{
   398  				PrincipalID:   fmt.Sprintf("user-%d", i+1),
   399  				PrincipalRole: model.PrincipalUser,
   400  			}, model.Principal{
   401  				PrincipalID:   fmt.Sprintf("group-%d", i+1),
   402  				PrincipalRole: model.PrincipalGroup,
   403  			})
   404  		}
   405  
   406  		ret = append(ret, &model.StrategyDetail{
   407  			ID:         fmt.Sprintf("rule-%d", i+1),
   408  			Name:       fmt.Sprintf("rule-%d", i+1),
   409  			Principals: principals,
   410  			Valid:      true,
   411  			Resources: []model.StrategyResource{
   412  				{
   413  					StrategyID: fmt.Sprintf("rule-%d", i+1),
   414  					ResType:    0,
   415  					ResID:      fmt.Sprintf("namespace-%d", i+1),
   416  				},
   417  				{
   418  					StrategyID: fmt.Sprintf("rule-%d", i+1),
   419  					ResType:    1,
   420  					ResID:      fmt.Sprintf("service-%d", i+1),
   421  				},
   422  			},
   423  		})
   424  	}
   425  
   426  	return ret
   427  }
   428  
   429  func testBuildPrincipalMap(principals []model.Principal, role model.PrincipalType) map[string]model.Principal {
   430  	ret := make(map[string]model.Principal, 0)
   431  	for i := range principals {
   432  		principal := principals[i]
   433  		if principal.PrincipalRole == role {
   434  			ret[principal.PrincipalID] = principal
   435  		}
   436  	}
   437  
   438  	return ret
   439  }