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 }