github.com/polarismesh/polaris@v1.17.8/store/boltdb/strategy.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 boltdb 19 20 import ( 21 "errors" 22 "fmt" 23 "sort" 24 "strings" 25 "time" 26 27 apisecurity "github.com/polarismesh/specification/source/go/api/v1/security" 28 bolt "go.etcd.io/bbolt" 29 "go.uber.org/zap" 30 31 "github.com/polarismesh/polaris/common/model" 32 "github.com/polarismesh/polaris/common/utils" 33 "github.com/polarismesh/polaris/store" 34 ) 35 36 const ( 37 tblStrategy string = "strategy" 38 39 StrategyFieldID string = "ID" 40 StrategyFieldName string = "Name" 41 StrategyFieldAction string = "Action" 42 StrategyFieldComment string = "Comment" 43 StrategyFieldUsersPrincipal string = "Users" 44 StrategyFieldGroupsPrincipal string = "Groups" 45 StrategyFieldDefault string = "Default" 46 StrategyFieldOwner string = "Owner" 47 StrategyFieldNsResources string = "NsResources" 48 StrategyFieldSvcResources string = "SvcResources" 49 StrategyFieldCfgResources string = "CfgResources" 50 StrategyFieldValid string = "Valid" 51 StrategyFieldRevision string = "Revision" 52 StrategyFieldCreateTime string = "CreateTime" 53 StrategyFieldModifyTime string = "ModifyTime" 54 ) 55 56 var ( 57 ErrorMultiDefaultStrategy error = errors.New("multiple strategy found") 58 ErrorStrategyNotFound error = errors.New("strategy not fonud") 59 ) 60 61 type strategyForStore struct { 62 ID string 63 Name string 64 Action string 65 Comment string 66 Users map[string]string 67 Groups map[string]string 68 Default bool 69 Owner string 70 NsResources map[string]string 71 SvcResources map[string]string 72 CfgResources map[string]string 73 Valid bool 74 Revision string 75 CreateTime time.Time 76 ModifyTime time.Time 77 } 78 79 // StrategyStore 80 type strategyStore struct { 81 handler BoltHandler 82 } 83 84 // AddStrategy add a new strategy 85 func (ss *strategyStore) AddStrategy(strategy *model.StrategyDetail) error { 86 if strategy.ID == "" || strategy.Name == "" || strategy.Owner == "" { 87 return store.NewStatusError(store.EmptyParamsErr, fmt.Sprintf( 88 "add auth_strategy missing some params, id is %s, name is %s, owner is %s", 89 strategy.ID, strategy.Name, strategy.Owner)) 90 } 91 92 initStrategy(strategy) 93 94 proxy, err := ss.handler.StartTx() 95 if err != nil { 96 return err 97 } 98 tx := proxy.GetDelegateTx().(*bolt.Tx) 99 100 defer func() { 101 _ = tx.Rollback() 102 }() 103 104 return ss.addStrategy(tx, strategy) 105 } 106 107 func (ss *strategyStore) addStrategy(tx *bolt.Tx, strategy *model.StrategyDetail) error { 108 if err := ss.cleanInvalidStrategy(tx, strategy.Name, strategy.Owner); err != nil { 109 log.Error("[Store][Strategy] clean invalid auth_strategy", zap.Error(err), 110 zap.String("name", strategy.Name), zap.Any("owner", strategy.Owner)) 111 return err 112 } 113 114 if err := saveValue(tx, tblStrategy, strategy.ID, convertForStrategyStore(strategy)); err != nil { 115 log.Error("[Store][Strategy] save auth_strategy", zap.Error(err), 116 zap.String("name", strategy.Name), zap.String("owner", strategy.Owner)) 117 return err 118 } 119 120 if err := tx.Commit(); err != nil { 121 log.Error("[Store][Strategy] clean invalid auth_strategy tx commit", zap.Error(err), 122 zap.String("name", strategy.Name), zap.String("owner", strategy.Owner)) 123 return err 124 } 125 126 return nil 127 } 128 129 // UpdateStrategy update a strategy 130 func (ss *strategyStore) UpdateStrategy(strategy *model.ModifyStrategyDetail) error { 131 if strategy.ID == "" { 132 return store.NewStatusError(store.EmptyParamsErr, fmt.Sprintf( 133 "update auth_strategy missing some params, id is %s", strategy.ID)) 134 } 135 136 proxy, err := ss.handler.StartTx() 137 if err != nil { 138 return err 139 } 140 tx := proxy.GetDelegateTx().(*bolt.Tx) 141 142 defer func() { 143 _ = tx.Rollback() 144 }() 145 146 ret, err := loadStrategyById(tx, strategy.ID) 147 if err != nil { 148 return err 149 } 150 if ret == nil { 151 return ErrorStrategyNotFound 152 } 153 154 return ss.updateStrategy(tx, strategy, ret) 155 } 156 157 // updateStrategy 158 func (ss *strategyStore) updateStrategy(tx *bolt.Tx, modify *model.ModifyStrategyDetail, 159 saveVal *strategyForStore) error { 160 161 saveVal.Action = modify.Action 162 saveVal.Comment = modify.Comment 163 saveVal.Revision = utils.NewUUID() 164 165 computePrincipals(false, modify.AddPrincipals, saveVal) 166 computePrincipals(true, modify.RemovePrincipals, saveVal) 167 168 computeResources(false, modify.AddResources, saveVal) 169 computeResources(true, modify.RemoveResources, saveVal) 170 171 saveVal.ModifyTime = time.Now() 172 173 if err := saveValue(tx, tblStrategy, saveVal.ID, saveVal); err != nil { 174 log.Error("[Store][Strategy] update auth_strategy", zap.Error(err), 175 zap.String("id", saveVal.ID)) 176 return err 177 } 178 179 if err := tx.Commit(); err != nil { 180 log.Error("[Store][Strategy] update auth_strategy tx commit", zap.Error(err), 181 zap.String("id", saveVal.ID)) 182 return err 183 } 184 185 return nil 186 } 187 188 func computePrincipals(remove bool, principals []model.Principal, saveVal *strategyForStore) { 189 for i := range principals { 190 principal := principals[i] 191 if principal.PrincipalRole == model.PrincipalUser { 192 if remove { 193 delete(saveVal.Users, principal.PrincipalID) 194 } else { 195 saveVal.Users[principal.PrincipalID] = "" 196 } 197 } else { 198 if remove { 199 delete(saveVal.Groups, principal.PrincipalID) 200 } else { 201 saveVal.Groups[principal.PrincipalID] = "" 202 } 203 } 204 } 205 } 206 207 func computeResources(remove bool, resources []model.StrategyResource, saveVal *strategyForStore) { 208 for i := range resources { 209 resource := resources[i] 210 if resource.ResType == int32(apisecurity.ResourceType_Namespaces) { 211 if remove { 212 delete(saveVal.NsResources, resource.ResID) 213 } else { 214 saveVal.NsResources[resource.ResID] = "" 215 } 216 continue 217 } 218 if resource.ResType == int32(apisecurity.ResourceType_Services) { 219 if remove { 220 delete(saveVal.SvcResources, resource.ResID) 221 } else { 222 saveVal.SvcResources[resource.ResID] = "" 223 } 224 continue 225 } 226 if resource.ResType == int32(apisecurity.ResourceType_ConfigGroups) { 227 if remove { 228 delete(saveVal.CfgResources, resource.ResID) 229 } else { 230 saveVal.CfgResources[resource.ResID] = "" 231 } 232 continue 233 } 234 } 235 } 236 237 // DeleteStrategy delete a strategy 238 func (ss *strategyStore) DeleteStrategy(id string) error { 239 if id == "" { 240 return store.NewStatusError(store.EmptyParamsErr, fmt.Sprintf( 241 "delete auth_strategy missing some params, id is %s", id)) 242 } 243 244 properties := make(map[string]interface{}) 245 properties[StrategyFieldValid] = false 246 properties[StrategyFieldModifyTime] = time.Now() 247 248 if err := ss.handler.UpdateValue(tblStrategy, id, properties); err != nil { 249 log.Error("[Store][Strategy] delete auth_strategy", zap.Error(err), zap.String("id", id)) 250 return err 251 } 252 253 return nil 254 } 255 256 // RemoveStrategyResources 删除策略的资源数据信息 257 func (ss *strategyStore) RemoveStrategyResources(resources []model.StrategyResource) error { 258 return ss.operateStrategyResources(true, resources) 259 } 260 261 // LooseAddStrategyResources 松要求的添加鉴权策略的资源,允许忽略主键冲突的问题 262 func (ss *strategyStore) LooseAddStrategyResources(resources []model.StrategyResource) error { 263 return ss.operateStrategyResources(false, resources) 264 } 265 266 func (ss *strategyStore) operateStrategyResources(remove bool, resources []model.StrategyResource) error { 267 proxy, err := ss.handler.StartTx() 268 if err != nil { 269 return err 270 } 271 tx := proxy.GetDelegateTx().(*bolt.Tx) 272 273 defer func() { 274 _ = tx.Rollback() 275 }() 276 277 resMap := buildResMap(resources) 278 for id, ress := range resMap { 279 rule, err := loadStrategyById(tx, id) 280 if err != nil { 281 return err 282 } 283 if rule == nil { 284 return ErrorStrategyNotFound 285 } 286 287 computeResources(remove, ress, rule) 288 rule.ModifyTime = time.Now() 289 if err := saveValue(tx, tblStrategy, rule.ID, rule); err != nil { 290 log.Error("[Store][Strategy] operate strategy resource", zap.Error(err), 291 zap.Bool("remove", remove), zap.String("id", id)) 292 return err 293 } 294 } 295 296 if err := tx.Commit(); err != nil { 297 log.Error("[Store][Strategy] update auth_strategy resource tx commit", 298 zap.Error(err), zap.Bool("remove", remove)) 299 return err 300 } 301 302 return nil 303 } 304 305 func loadStrategyById(tx *bolt.Tx, id string) (*strategyForStore, error) { 306 values := make(map[string]interface{}) 307 308 if err := loadValues(tx, tblStrategy, []string{id}, &strategyForStore{}, values); err != nil { 309 log.Error("[Store][Strategy] get auth_strategy by id", zap.Error(err), 310 zap.String("id", id)) 311 return nil, err 312 } 313 314 if len(values) == 0 { 315 return nil, nil 316 } 317 if len(values) > 1 { 318 return nil, ErrorMultiDefaultStrategy 319 } 320 321 var ret *strategyForStore 322 for _, v := range values { 323 ret = v.(*strategyForStore) 324 break 325 } 326 327 if !ret.Valid { 328 return nil, nil 329 } 330 331 return ret, nil 332 } 333 334 func buildResMap(resources []model.StrategyResource) map[string][]model.StrategyResource { 335 ret := make(map[string][]model.StrategyResource) 336 337 for i := range resources { 338 resource := resources[i] 339 if _, exist := ret[resource.StrategyID]; !exist { 340 ret[resource.StrategyID] = make([]model.StrategyResource, 0, 4) 341 } 342 343 val := ret[resource.StrategyID] 344 val = append(val, resource) 345 346 ret[resource.StrategyID] = val 347 } 348 349 return ret 350 } 351 352 // GetStrategyDetail 获取策略详情 353 func (ss *strategyStore) GetStrategyDetail(id string) (*model.StrategyDetail, error) { 354 proxy, err := ss.handler.StartTx() 355 if err != nil { 356 return nil, err 357 } 358 tx := proxy.GetDelegateTx().(*bolt.Tx) 359 defer func() { 360 _ = tx.Rollback() 361 }() 362 363 return ss.getStrategyDetail(tx, id) 364 } 365 366 // GetStrategyDetail 367 func (ss *strategyStore) getStrategyDetail(tx *bolt.Tx, id string) (*model.StrategyDetail, error) { 368 ret, err := loadStrategyById(tx, id) 369 if err != nil { 370 return nil, err 371 } 372 if ret == nil { 373 return nil, nil 374 } 375 376 return convertForStrategyDetail(ret), nil 377 } 378 379 // GetStrategyResources 获取策略的资源 380 func (ss *strategyStore) GetStrategyResources(principalId string, 381 principalRole model.PrincipalType) ([]model.StrategyResource, error) { 382 383 fields := []string{StrategyFieldValid, StrategyFieldDefault, StrategyFieldUsersPrincipal} 384 385 if principalRole == model.PrincipalGroup { 386 fields = []string{StrategyFieldValid, StrategyFieldDefault, StrategyFieldGroupsPrincipal} 387 } 388 389 values, err := ss.handler.LoadValuesByFilter(tblStrategy, fields, &strategyForStore{}, 390 func(m map[string]interface{}) bool { 391 valid, ok := m[StrategyFieldValid].(bool) 392 if ok && !valid { 393 return false 394 } 395 396 var principals map[string]string 397 398 if principalRole == model.PrincipalUser { 399 principals, _ = m[StrategyFieldUsersPrincipal].(map[string]string) 400 } else { 401 principals, _ = m[StrategyFieldGroupsPrincipal].(map[string]string) 402 } 403 404 _, exist := principals[principalId] 405 406 return exist 407 }) 408 409 if err != nil { 410 return nil, err 411 } 412 413 ret := make([]model.StrategyResource, 0, 4) 414 415 for _, item := range values { 416 rule := item.(*strategyForStore) 417 ret = append(ret, collectStrategyResources(rule)...) 418 } 419 420 return ret, nil 421 } 422 423 func collectStrategyResources(rule *strategyForStore) []model.StrategyResource { 424 ret := make([]model.StrategyResource, 0, len(rule.NsResources)+len(rule.SvcResources)+len(rule.CfgResources)) 425 426 for id := range rule.NsResources { 427 ret = append(ret, model.StrategyResource{ 428 StrategyID: rule.ID, 429 ResType: int32(apisecurity.ResourceType_Namespaces), 430 ResID: id, 431 }) 432 } 433 434 for id := range rule.SvcResources { 435 ret = append(ret, model.StrategyResource{ 436 StrategyID: rule.ID, 437 ResType: int32(apisecurity.ResourceType_Services), 438 ResID: id, 439 }) 440 } 441 442 for id := range rule.CfgResources { 443 ret = append(ret, model.StrategyResource{ 444 StrategyID: rule.ID, 445 ResType: int32(apisecurity.ResourceType_ConfigGroups), 446 ResID: id, 447 }) 448 } 449 450 return ret 451 } 452 453 // GetDefaultStrategyDetailByPrincipal 获取默认策略详情 454 func (ss *strategyStore) GetDefaultStrategyDetailByPrincipal(principalId string, 455 principalType model.PrincipalType) (*model.StrategyDetail, error) { 456 457 fields := []string{StrategyFieldValid, StrategyFieldDefault, StrategyFieldUsersPrincipal} 458 459 if principalType == model.PrincipalGroup { 460 fields = []string{StrategyFieldValid, StrategyFieldDefault, StrategyFieldGroupsPrincipal} 461 } 462 463 values, err := ss.handler.LoadValuesByFilter(tblStrategy, fields, &strategyForStore{}, 464 func(m map[string]interface{}) bool { 465 valid, ok := m[StrategyFieldValid].(bool) 466 if ok && !valid { 467 return false 468 } 469 470 isDefault, _ := m[StrategyFieldDefault].(bool) 471 if !isDefault { 472 return false 473 } 474 475 var principals map[string]string 476 477 if principalType == model.PrincipalUser { 478 principals, _ = m[StrategyFieldUsersPrincipal].(map[string]string) 479 } else { 480 principals, _ = m[StrategyFieldGroupsPrincipal].(map[string]string) 481 } 482 483 _, exist := principals[principalId] 484 485 return exist 486 }) 487 488 if err != nil { 489 log.Error("[Store][Strategy] get default auth_strategy by principal", zap.Error(err), 490 zap.String("principal-id", principalId), zap.String("principal", principalType.String())) 491 return nil, err 492 } 493 if len(values) == 0 { 494 return nil, ErrorStrategyNotFound 495 } 496 if len(values) > 1 { 497 return nil, ErrorMultiDefaultStrategy 498 } 499 500 var ret *strategyForStore 501 for _, v := range values { 502 ret = v.(*strategyForStore) 503 break 504 } 505 506 return convertForStrategyDetail(ret), nil 507 } 508 509 // GetStrategies 查询鉴权策略列表 510 func (ss *strategyStore) GetStrategies(filters map[string]string, offset uint32, limit uint32) (uint32, 511 []*model.StrategyDetail, error) { 512 513 showDetail := filters["show_detail"] 514 delete(filters, "show_detail") 515 516 return ss.listStrategies(filters, offset, limit, showDetail == "true") 517 } 518 519 func (ss *strategyStore) listStrategies(filters map[string]string, offset uint32, limit uint32, 520 showDetail bool) (uint32, []*model.StrategyDetail, error) { 521 522 fields := []string{StrategyFieldValid, StrategyFieldName, StrategyFieldUsersPrincipal, 523 StrategyFieldGroupsPrincipal, StrategyFieldNsResources, StrategyFieldSvcResources, 524 StrategyFieldCfgResources, StrategyFieldOwner, StrategyFieldDefault} 525 526 values, err := ss.handler.LoadValuesByFilter(tblStrategy, fields, &strategyForStore{}, 527 func(m map[string]interface{}) bool { 528 valid, ok := m[StrategyFieldValid].(bool) 529 if ok && !valid { 530 return false 531 } 532 533 saveName, _ := m[StrategyFieldName].(string) 534 saveDefault, _ := m[StrategyFieldDefault].(bool) 535 saveOwner, _ := m[StrategyFieldOwner].(string) 536 537 if name, ok := filters["name"]; ok { 538 if utils.IsPrefixWildName(name) { 539 name = name[:len(name)-1] 540 } 541 if !strings.Contains(saveName, name) { 542 return false 543 } 544 } 545 546 if owner, ok := filters["owner"]; ok { 547 if strings.Compare(saveOwner, owner) != 0 { 548 if principalId, ok := filters["principal_id"]; ok { 549 principalType := filters["principal_type"] 550 if !comparePrincipalExist(principalType, principalId, m) { 551 return false 552 } 553 } 554 } 555 } 556 557 if isDefault, ok := filters["default"]; ok { 558 compareParam2BoolNotEqual := func(param string, b bool) bool { 559 if param == "0" && !b { 560 return true 561 } 562 if param == "1" && b { 563 return true 564 } 565 return false 566 } 567 if !compareParam2BoolNotEqual(isDefault, saveDefault) { 568 return false 569 } 570 } 571 572 if resType, ok := filters["res_type"]; ok { 573 resId := filters["res_id"] 574 if !compareResExist(resType, resId, m) { 575 return false 576 } 577 } 578 579 if principalId, ok := filters["principal_id"]; ok { 580 principalType := filters["principal_type"] 581 if !comparePrincipalExist(principalType, principalId, m) { 582 return false 583 } 584 } 585 586 return true 587 }) 588 589 if err != nil { 590 log.Error("[Store][Strategy] get auth_strategy for list", zap.Error(err)) 591 return 0, nil, err 592 } 593 594 return uint32(len(values)), doStrategyPage(values, offset, limit, showDetail), nil 595 } 596 597 func doStrategyPage(ret map[string]interface{}, offset, limit uint32, showDetail bool) []*model.StrategyDetail { 598 rules := make([]*model.StrategyDetail, 0, len(ret)) 599 600 beginIndex := offset 601 endIndex := beginIndex + limit 602 totalCount := uint32(len(ret)) 603 604 if totalCount == 0 { 605 return rules 606 } 607 if beginIndex >= endIndex { 608 return rules 609 } 610 if beginIndex >= totalCount { 611 return rules 612 } 613 if endIndex > totalCount { 614 endIndex = totalCount 615 } 616 617 emptyPrincipals := make([]model.Principal, 0) 618 emptyResources := make([]model.StrategyResource, 0) 619 620 for k := range ret { 621 rule := convertForStrategyDetail(ret[k].(*strategyForStore)) 622 if !showDetail { 623 rule.Principals = emptyPrincipals 624 rule.Resources = emptyResources 625 } 626 rules = append(rules, rule) 627 } 628 629 sort.Slice(rules, func(i, j int) bool { 630 return rules[i].ModifyTime.After(rules[j].ModifyTime) 631 }) 632 633 return rules[beginIndex:endIndex] 634 } 635 636 func compareResExist(resType, resId string, m map[string]interface{}) bool { 637 saveNsRes, _ := m[StrategyFieldNsResources].(map[string]string) 638 saveSvcRes, _ := m[StrategyFieldSvcResources].(map[string]string) 639 saveCfgRes, _ := m[StrategyFieldCfgResources].(map[string]string) 640 641 if strings.Compare(resType, "0") == 0 { 642 _, exist := saveNsRes[resId] 643 return exist 644 } 645 646 if strings.Compare(resType, "1") == 0 { 647 _, exist := saveSvcRes[resId] 648 return exist 649 } 650 651 if strings.Compare(resType, "2") == 0 { 652 _, exist := saveCfgRes[resId] 653 return exist 654 } 655 656 return true 657 } 658 659 func comparePrincipalExist(principalType, principalId string, m map[string]interface{}) bool { 660 saveUsers, _ := m[StrategyFieldUsersPrincipal].(map[string]string) 661 saveGroups, _ := m[StrategyFieldGroupsPrincipal].(map[string]string) 662 663 if strings.Compare(principalType, "1") == 0 { 664 _, exist := saveUsers[principalId] 665 return exist 666 } 667 668 if strings.Compare(principalType, "2") == 0 { 669 _, exist := saveGroups[principalId] 670 return exist 671 } 672 673 return true 674 } 675 676 // GetStrategyDetailsForCache get strategy details for cache 677 func (ss *strategyStore) GetStrategyDetailsForCache(mtime time.Time, 678 firstUpdate bool) ([]*model.StrategyDetail, error) { 679 680 ret, err := ss.handler.LoadValuesByFilter(tblStrategy, []string{StrategyFieldModifyTime}, &strategyForStore{}, 681 func(m map[string]interface{}) bool { 682 mt := m[StrategyFieldModifyTime].(time.Time) 683 isAfter := mt.After(mtime) 684 return isAfter 685 }) 686 if err != nil { 687 log.Error("[Store][Strategy] get auth_strategy for cache", zap.Error(err)) 688 return nil, err 689 } 690 691 strategies := make([]*model.StrategyDetail, 0, len(ret)) 692 693 for k := range ret { 694 val := ret[k] 695 strategies = append(strategies, convertForStrategyDetail(val.(*strategyForStore))) 696 } 697 698 return strategies, nil 699 } 700 701 // cleanInvalidStrategy clean up authentication strategy by name 702 func (ss *strategyStore) cleanInvalidStrategy(tx *bolt.Tx, name, owner string) error { 703 704 fields := []string{StrategyFieldName, StrategyFieldOwner, StrategyFieldValid} 705 values := make(map[string]interface{}) 706 707 err := loadValuesByFilter(tx, tblStrategy, fields, &strategyForStore{}, 708 func(m map[string]interface{}) bool { 709 valid, ok := m[StrategyFieldValid].(bool) 710 // 如果数据是 valid 的,则不能被清理 711 if ok && valid { 712 return false 713 } 714 715 saveName := m[StrategyFieldName] 716 saveOwner := m[StrategyFieldOwner] 717 718 return saveName == name && saveOwner == owner 719 }, values) 720 721 if err != nil { 722 log.Error("[Store][Strategy] clean invalid auth_strategy", zap.Error(err), 723 zap.String("name", name), zap.Any("owner", owner)) 724 return err 725 } 726 727 if len(values) == 0 { 728 return nil 729 } 730 731 keys := make([]string, 0, len(values)) 732 for k := range values { 733 keys = append(keys, k) 734 } 735 736 return deleteValues(tx, tblStrategy, keys) 737 } 738 739 func createDefaultStrategy(tx *bolt.Tx, role model.PrincipalType, principalId, name, owner string) error { 740 strategy := &model.StrategyDetail{ 741 ID: utils.NewUUID(), 742 Name: model.BuildDefaultStrategyName(role, name), 743 Action: apisecurity.AuthAction_READ_WRITE.String(), 744 Default: true, 745 Owner: owner, 746 Revision: utils.NewUUID(), 747 Resources: []model.StrategyResource{}, 748 Valid: true, 749 Principals: []model.Principal{ 750 { 751 PrincipalID: principalId, 752 PrincipalRole: role, 753 }, 754 }, 755 Comment: "Default Strategy", 756 } 757 758 return saveValue(tx, tblStrategy, strategy.ID, convertForStrategyStore(strategy)) 759 } 760 761 func cleanLinkStrategy(tx *bolt.Tx, role model.PrincipalType, principalId, owner string) error { 762 763 fields := []string{StrategyFieldDefault, StrategyFieldUsersPrincipal, StrategyFieldGroupsPrincipal} 764 values := make(map[string]interface{}) 765 766 err := loadValuesByFilter(tx, tblStrategy, fields, &strategyForStore{}, 767 func(m map[string]interface{}) bool { 768 isDefault := m[StrategyFieldDefault].(bool) 769 if !isDefault { 770 return false 771 } 772 773 var principals map[string]string 774 if role == model.PrincipalUser { 775 principals = m[StrategyFieldUsersPrincipal].(map[string]string) 776 } else { 777 principals = m[StrategyFieldGroupsPrincipal].(map[string]string) 778 } 779 780 if len(principals) != 1 { 781 return false 782 } 783 _, exist := principals[principalId] 784 return exist 785 }, values) 786 787 if err != nil { 788 log.Error("[Store][Strategy] load link auth_strategy", zap.Error(err), 789 zap.String("principal-id", principalId), zap.Any("principal-type", role)) 790 return err 791 } 792 793 if len(values) == 0 { 794 return nil 795 } 796 if len(values) > 1 { 797 return ErrorMultiDefaultStrategy 798 } 799 800 for k := range values { 801 802 properties := make(map[string]interface{}) 803 properties[StrategyFieldValid] = false 804 properties[StrategyFieldModifyTime] = time.Now() 805 806 if err := updateValue(tx, tblStrategy, k, properties); err != nil { 807 log.Error("[Store][Strategy] clean link auth_strategy", zap.Error(err), 808 zap.String("principal-id", principalId), zap.Any("principal-type", role)) 809 return err 810 } 811 } 812 813 return nil 814 } 815 816 func convertForStrategyStore(strategy *model.StrategyDetail) *strategyForStore { 817 818 var ( 819 users = make(map[string]string, 4) 820 groups = make(map[string]string, 4) 821 principals = strategy.Principals 822 ) 823 824 for i := range principals { 825 principal := principals[i] 826 if principal.PrincipalRole == model.PrincipalUser { 827 users[principal.PrincipalID] = "" 828 } else { 829 groups[principal.PrincipalID] = "" 830 } 831 } 832 833 ns := make(map[string]string, 4) 834 svc := make(map[string]string, 4) 835 cfg := make(map[string]string, 4) 836 837 resources := strategy.Resources 838 839 for i := range resources { 840 res := resources[i] 841 switch res.ResType { 842 case int32(apisecurity.ResourceType_Namespaces): 843 ns[res.ResID] = "" 844 case int32(apisecurity.ResourceType_Services): 845 svc[res.ResID] = "" 846 case int32(apisecurity.ResourceType_ConfigGroups): 847 cfg[res.ResID] = "" 848 } 849 } 850 851 return &strategyForStore{ 852 ID: strategy.ID, 853 Name: strategy.Name, 854 Action: strategy.Action, 855 Comment: strategy.Comment, 856 Users: users, 857 Groups: groups, 858 Default: strategy.Default, 859 Owner: strategy.Owner, 860 NsResources: ns, 861 SvcResources: svc, 862 CfgResources: cfg, 863 Valid: strategy.Valid, 864 Revision: strategy.Revision, 865 CreateTime: strategy.CreateTime, 866 ModifyTime: strategy.ModifyTime, 867 } 868 } 869 870 func convertForStrategyDetail(strategy *strategyForStore) *model.StrategyDetail { 871 872 principals := make([]model.Principal, 0, len(strategy.Users)+len(strategy.Groups)) 873 resources := make([]model.StrategyResource, 0, len(strategy.NsResources)+ 874 len(strategy.SvcResources)+len(strategy.CfgResources)) 875 876 for id := range strategy.Users { 877 principals = append(principals, model.Principal{ 878 StrategyID: strategy.ID, 879 PrincipalID: id, 880 PrincipalRole: model.PrincipalUser, 881 }) 882 } 883 for id := range strategy.Groups { 884 principals = append(principals, model.Principal{ 885 StrategyID: strategy.ID, 886 PrincipalID: id, 887 PrincipalRole: model.PrincipalGroup, 888 }) 889 } 890 891 fillRes := func(idMap map[string]string, resType apisecurity.ResourceType) []model.StrategyResource { 892 res := make([]model.StrategyResource, 0, len(idMap)) 893 894 for id := range idMap { 895 res = append(res, model.StrategyResource{ 896 StrategyID: strategy.ID, 897 ResType: int32(resType), 898 ResID: id, 899 }) 900 } 901 902 return res 903 } 904 905 resources = append(resources, fillRes(strategy.NsResources, apisecurity.ResourceType_Namespaces)...) 906 resources = append(resources, fillRes(strategy.SvcResources, apisecurity.ResourceType_Services)...) 907 resources = append(resources, fillRes(strategy.CfgResources, apisecurity.ResourceType_ConfigGroups)...) 908 909 return &model.StrategyDetail{ 910 ID: strategy.ID, 911 Name: strategy.Name, 912 Action: strategy.Action, 913 Comment: strategy.Comment, 914 Principals: principals, 915 Resources: resources, 916 Default: strategy.Default, 917 Owner: strategy.Owner, 918 Valid: strategy.Valid, 919 Revision: strategy.Revision, 920 CreateTime: strategy.CreateTime, 921 ModifyTime: strategy.ModifyTime, 922 } 923 } 924 925 func initStrategy(rule *model.StrategyDetail) { 926 if rule != nil { 927 rule.Valid = true 928 929 tn := time.Now() 930 rule.CreateTime = tn 931 rule.ModifyTime = tn 932 933 for i := range rule.Resources { 934 rule.Resources[i].StrategyID = rule.ID 935 } 936 } 937 }