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  }