github.com/polarismesh/polaris@v1.17.8/auth/defaultauth/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 defaultauth
    19  
    20  import (
    21  	"context"
    22  	"fmt"
    23  	"strconv"
    24  	"strings"
    25  	"time"
    26  
    27  	"github.com/gogo/protobuf/jsonpb"
    28  	"github.com/golang/protobuf/ptypes/wrappers"
    29  	apimodel "github.com/polarismesh/specification/source/go/api/v1/model"
    30  	apisecurity "github.com/polarismesh/specification/source/go/api/v1/security"
    31  	apiservice "github.com/polarismesh/specification/source/go/api/v1/service_manage"
    32  	"go.uber.org/zap"
    33  
    34  	api "github.com/polarismesh/polaris/common/api/v1"
    35  	"github.com/polarismesh/polaris/common/model"
    36  	authcommon "github.com/polarismesh/polaris/common/model/auth"
    37  	commonstore "github.com/polarismesh/polaris/common/store"
    38  	commontime "github.com/polarismesh/polaris/common/time"
    39  	"github.com/polarismesh/polaris/common/utils"
    40  )
    41  
    42  type (
    43  	// StrategyDetail2Api strategy detail to *apisecurity.AuthStrategy func
    44  	StrategyDetail2Api func(user *model.StrategyDetail) *apisecurity.AuthStrategy
    45  )
    46  
    47  var (
    48  	// StrategyFilterAttributes strategy filter attributes
    49  	StrategyFilterAttributes = map[string]bool{
    50  		"id":             true,
    51  		"name":           true,
    52  		"owner":          true,
    53  		"offset":         true,
    54  		"limit":          true,
    55  		"principal_id":   true,
    56  		"principal_type": true,
    57  		"res_id":         true,
    58  		"res_type":       true,
    59  		"default":        true,
    60  		"show_detail":    true,
    61  	}
    62  )
    63  
    64  // CreateStrategy 创建鉴权策略
    65  func (svr *Server) CreateStrategy(ctx context.Context, req *apisecurity.AuthStrategy) *apiservice.Response {
    66  	requestID := utils.ParseRequestID(ctx)
    67  	ownerId := utils.ParseOwnerID(ctx)
    68  	req.Owner = utils.NewStringValue(ownerId)
    69  
    70  	if checkErrResp := svr.checkCreateStrategy(req); checkErrResp != nil {
    71  		return checkErrResp
    72  	}
    73  
    74  	req.Resources = svr.normalizeResource(req.Resources)
    75  
    76  	data := svr.createAuthStrategyModel(req)
    77  	if err := svr.storage.AddStrategy(data); err != nil {
    78  		log.Error("[Auth][Strategy] create strategy into store", utils.ZapRequestID(requestID),
    79  			zap.Error(err))
    80  		return api.NewAuthResponse(commonstore.StoreCode2APICode(err))
    81  	}
    82  
    83  	log.Info("[Auth][Strategy] create strategy", utils.ZapRequestID(requestID),
    84  		zap.String("name", req.Name.GetValue()))
    85  	svr.RecordHistory(authStrategyRecordEntry(ctx, req, data, model.OCreate))
    86  
    87  	return api.NewAuthStrategyResponse(apimodel.Code_ExecuteSuccess, req)
    88  }
    89  
    90  // UpdateStrategies 批量修改鉴权
    91  func (svr *Server) UpdateStrategies(
    92  	ctx context.Context, reqs []*apisecurity.ModifyAuthStrategy) *apiservice.BatchWriteResponse {
    93  	resp := api.NewAuthBatchWriteResponse(apimodel.Code_ExecuteSuccess)
    94  
    95  	for index := range reqs {
    96  		ret := svr.UpdateStrategy(ctx, reqs[index])
    97  		api.Collect(resp, ret)
    98  	}
    99  
   100  	return resp
   101  }
   102  
   103  // UpdateStrategy 实现鉴权策略的变更
   104  // Case 1. 修改的是默认鉴权策略的话,只能修改资源,不能添加、删除用户 or 用户组
   105  // Case 2. 鉴权策略只能被自己的 owner 对应的用户修改
   106  // Case 3. 主账户的默认策略不得修改
   107  func (svr *Server) UpdateStrategy(ctx context.Context, req *apisecurity.ModifyAuthStrategy) *apiservice.Response {
   108  	requestID := utils.ParseRequestID(ctx)
   109  
   110  	strategy, err := svr.storage.GetStrategyDetail(req.GetId().GetValue())
   111  	if err != nil {
   112  		log.Error("[Auth][Strategy] get strategy from store", utils.ZapRequestID(requestID),
   113  			zap.Error(err))
   114  		return api.NewModifyAuthStrategyResponse(commonstore.StoreCode2APICode(err), req)
   115  	}
   116  	if strategy == nil {
   117  		return api.NewModifyAuthStrategyResponse(apimodel.Code_NotFoundAuthStrategyRule, req)
   118  	}
   119  
   120  	if checkErrResp := svr.checkUpdateStrategy(ctx, req, strategy); checkErrResp != nil {
   121  		return checkErrResp
   122  	}
   123  
   124  	req.AddResources = svr.normalizeResource(req.AddResources)
   125  	data, needUpdate := svr.updateAuthStrategyAttribute(ctx, req, strategy)
   126  	if !needUpdate {
   127  		return api.NewModifyAuthStrategyResponse(apimodel.Code_NoNeedUpdate, req)
   128  	}
   129  
   130  	if err := svr.storage.UpdateStrategy(data); err != nil {
   131  		log.Error("[Auth][Strategy] update strategy into store",
   132  			utils.ZapRequestID(requestID), zap.Error(err))
   133  		return api.NewAuthResponseWithMsg(commonstore.StoreCode2APICode(err), err.Error())
   134  	}
   135  
   136  	log.Info("[Auth][Strategy] update strategy into store", utils.ZapRequestID(requestID),
   137  		zap.String("name", strategy.Name))
   138  	svr.RecordHistory(authModifyStrategyRecordEntry(ctx, req, data, model.OUpdate))
   139  
   140  	return api.NewModifyAuthStrategyResponse(apimodel.Code_ExecuteSuccess, req)
   141  }
   142  
   143  // DeleteStrategies 批量删除鉴权策略
   144  func (svr *Server) DeleteStrategies(
   145  	ctx context.Context, reqs []*apisecurity.AuthStrategy) *apiservice.BatchWriteResponse {
   146  	resp := api.NewAuthBatchWriteResponse(apimodel.Code_ExecuteSuccess)
   147  	for index := range reqs {
   148  		ret := svr.DeleteStrategy(ctx, reqs[index])
   149  		api.Collect(resp, ret)
   150  	}
   151  
   152  	return resp
   153  }
   154  
   155  // DeleteStrategy 删除鉴权策略
   156  // Case 1. 只有该策略的 owner 账户可以删除策略
   157  // Case 2. 默认策略不能被删除,默认策略只能随着账户的删除而被清理
   158  func (svr *Server) DeleteStrategy(ctx context.Context, req *apisecurity.AuthStrategy) *apiservice.Response {
   159  	requestID := utils.ParseRequestID(ctx)
   160  
   161  	strategy, err := svr.storage.GetStrategyDetail(req.GetId().GetValue())
   162  	if err != nil {
   163  		log.Error("[Auth][Strategy] get strategy from store", utils.ZapRequestID(requestID),
   164  			zap.Error(err))
   165  		return api.NewAuthStrategyResponse(commonstore.StoreCode2APICode(err), req)
   166  	}
   167  
   168  	if strategy == nil {
   169  		return api.NewAuthStrategyResponse(apimodel.Code_ExecuteSuccess, req)
   170  	}
   171  
   172  	if strategy.Default {
   173  		log.Error("[Auth][Strategy] delete default strategy is denied", utils.ZapRequestID(requestID))
   174  		return api.NewAuthStrategyResponseWithMsg(apimodel.Code_BadRequest, "default strategy can't delete", req)
   175  	}
   176  
   177  	if strategy.Owner != utils.ParseUserID(ctx) {
   178  		return api.NewAuthStrategyResponse(apimodel.Code_NotAllowedAccess, req)
   179  	}
   180  
   181  	if err := svr.storage.DeleteStrategy(req.GetId().GetValue()); err != nil {
   182  		log.Error("[Auth][Strategy] delete strategy from store",
   183  			utils.ZapRequestID(requestID), zap.Error(err))
   184  		return api.NewAuthResponse(commonstore.StoreCode2APICode(err))
   185  	}
   186  
   187  	log.Info("[Auth][Strategy] delete strategy from store", utils.ZapRequestID(requestID),
   188  		zap.String("name", req.Name.GetValue()))
   189  	svr.RecordHistory(authStrategyRecordEntry(ctx, req, strategy, model.ODelete))
   190  
   191  	return api.NewAuthStrategyResponse(apimodel.Code_ExecuteSuccess, req)
   192  }
   193  
   194  // GetStrategies 查询鉴权策略列表
   195  // Case 1. 如果是以资源视角来查询鉴权策略,那么就会忽略自动根据账户类型进行数据查看的限制
   196  //
   197  //	eg. 比如当前子账户A想要查看资源R的相关的策略,那么不在会自动注入 principal_id 以及 principal_type 的查询条件
   198  //
   199  // Case 2. 如果是以用户视角来查询鉴权策略,如果没有带上 principal_id,那么就会根据账户类型自动注入 principal_id 以
   200  //
   201  //	及 principal_type 的查询条件,从而限制该账户的数据查看
   202  //	eg.
   203  //		a. 如果当前是超级管理账户,则按照传入的 query 进行查询即可
   204  //		b. 如果当前是主账户,则自动注入 owner 字段,即只能查看策略的 owner 是自己的策略
   205  //		c. 如果当前是子账户,则自动注入 principal_id 以及 principal_type 字段,即稚嫩查询与自己有关的策略
   206  func (svr *Server) GetStrategies(ctx context.Context, query map[string]string) *apiservice.BatchQueryResponse {
   207  	requestID := utils.ParseRequestID(ctx)
   208  	platformID := utils.ParsePlatformID(ctx)
   209  
   210  	log.Debug("[Auth][Strategy] origin get strategies query params", utils.ZapRequestID(requestID),
   211  		utils.ZapPlatformID(platformID), zap.Any("query", query))
   212  
   213  	showDetail := query["show_detail"]
   214  
   215  	searchFilters := make(map[string]string, len(query))
   216  	for key, value := range query {
   217  		if _, ok := StrategyFilterAttributes[key]; !ok {
   218  			log.Errorf("[Auth][Strategy] get strategies attribute(%s) it not allowed", key)
   219  			return api.NewAuthBatchQueryResponseWithMsg(apimodel.Code_InvalidParameter, key+" is not allowed")
   220  		}
   221  		searchFilters[key] = value
   222  	}
   223  
   224  	searchFilters = parseStrategySearchArgs(ctx, searchFilters)
   225  	offset, limit, err := utils.ParseOffsetAndLimit(searchFilters)
   226  
   227  	if err != nil {
   228  		return api.NewAuthBatchQueryResponse(apimodel.Code_InvalidParameter)
   229  	}
   230  
   231  	total, strategies, err := svr.storage.GetStrategies(searchFilters, offset, limit)
   232  	if err != nil {
   233  		log.Error("[Auth][Strategy] get strategies from store", zap.Any("query", searchFilters),
   234  			zap.Error(err))
   235  		return api.NewAuthBatchQueryResponse(commonstore.StoreCode2APICode(err))
   236  	}
   237  
   238  	resp := api.NewAuthBatchQueryResponse(apimodel.Code_ExecuteSuccess)
   239  	resp.Amount = utils.NewUInt32Value(total)
   240  	resp.Size = utils.NewUInt32Value(uint32(len(strategies)))
   241  
   242  	if strings.Compare(showDetail, "true") == 0 {
   243  		log.Info("[Auth][Strategy] fill strategy detail", utils.ZapRequestID(requestID))
   244  		resp.AuthStrategies = enhancedAuthStrategy2Api(strategies, svr.authStrategyFull2Api)
   245  	} else {
   246  		resp.AuthStrategies = enhancedAuthStrategy2Api(strategies, svr.authStrategy2Api)
   247  	}
   248  
   249  	return resp
   250  }
   251  
   252  var resTypeFilter = map[string]string{
   253  	"namespace":    "0",
   254  	"service":      "1",
   255  	"config_group": "2",
   256  }
   257  
   258  var principalTypeFilter = map[string]string{
   259  	"user":   "1",
   260  	"group":  "2",
   261  	"groups": "2",
   262  }
   263  
   264  // parseStrategySearchArgs 处理鉴权策略的搜索参数
   265  func parseStrategySearchArgs(ctx context.Context, searchFilters map[string]string) map[string]string {
   266  	if val, ok := searchFilters["res_type"]; ok {
   267  		if v, exist := resTypeFilter[val]; exist {
   268  			searchFilters["res_type"] = v
   269  		} else {
   270  			searchFilters["res_type"] = "0"
   271  		}
   272  	}
   273  
   274  	if val, ok := searchFilters["principal_type"]; ok {
   275  		if v, exist := principalTypeFilter[val]; exist {
   276  			searchFilters["principal_type"] = v
   277  		} else {
   278  			searchFilters["principal_type"] = "1"
   279  		}
   280  	}
   281  
   282  	if authcommon.ParseUserRole(ctx) != model.AdminUserRole {
   283  		// 如果当前账户不是 admin 角色,既不是走资源视角查看,也不是指定principal查看,那么只能查询当前操作用户被关联到的鉴权策略,
   284  		if _, ok := searchFilters["res_id"]; !ok {
   285  			// 设置 owner 参数,只能查看对应 owner 下的策略
   286  			searchFilters["owner"] = utils.ParseOwnerID(ctx)
   287  			if _, ok := searchFilters["principal_id"]; !ok {
   288  				// 如果当前不是 owner 角色,那么只能查询与自己有关的策略
   289  				if !utils.ParseIsOwner(ctx) {
   290  					searchFilters["principal_id"] = utils.ParseUserID(ctx)
   291  					searchFilters["principal_type"] = strconv.Itoa(int(model.PrincipalUser))
   292  				}
   293  			}
   294  		}
   295  	}
   296  
   297  	return searchFilters
   298  }
   299  
   300  // GetStrategy 根据策略ID获取详细的鉴权策略
   301  // Case 1 如果当前操作者是该策略 principal 中的一员,则可以查看
   302  // Case 2 如果当前操作者是该策略的 owner,则可以查看
   303  // Case 3 如果当前操作者是admin角色,直接查看
   304  func (svr *Server) GetStrategy(ctx context.Context, req *apisecurity.AuthStrategy) *apiservice.Response {
   305  	requestID := utils.ParseRequestID(ctx)
   306  	userId := utils.ParseUserID(ctx)
   307  	isOwner := utils.ParseIsOwner(ctx)
   308  
   309  	if req.GetId().GetValue() == "" {
   310  		return api.NewAuthResponse(apimodel.Code_EmptyQueryParameter)
   311  	}
   312  
   313  	ret, err := svr.storage.GetStrategyDetail(req.GetId().GetValue())
   314  	if err != nil {
   315  		log.Error("[Auth][Strategy] get strategt from store",
   316  			utils.ZapRequestID(requestID), zap.Error(err))
   317  		return api.NewAuthResponse(commonstore.StoreCode2APICode(err))
   318  	}
   319  	if ret == nil {
   320  		return api.NewAuthStrategyResponse(apimodel.Code_NotFoundAuthStrategyRule, req)
   321  	}
   322  
   323  	var canView bool
   324  	if isOwner {
   325  		// 是否是本鉴权策略的 owner 账户, 或者是否是超级管理员, 是的话则快速跳过下面的检查
   326  		canView = (ret.Owner == userId) || authcommon.ParseUserRole(ctx) == model.AdminUserRole
   327  	}
   328  
   329  	// 判断是否在该策略所属的成员列表中,如果自己在某个用户组,而该用户组又在这个策略的成员中,则也是可以查看的
   330  	if !canView {
   331  		for index := range ret.Principals {
   332  			principal := ret.Principals[index]
   333  			if principal.PrincipalRole == model.PrincipalUser && principal.PrincipalID == userId {
   334  				canView = true
   335  				break
   336  			}
   337  			if principal.PrincipalRole == model.PrincipalGroup {
   338  				if svr.cacheMgn.User().IsUserInGroup(userId, principal.PrincipalID) {
   339  					canView = true
   340  					break
   341  				}
   342  			}
   343  		}
   344  	}
   345  
   346  	if !canView {
   347  		log.Error("[Auth][Strategy] get strategy detail denied",
   348  			utils.ZapRequestID(requestID),
   349  			zap.String("user", userId),
   350  			zap.String("strategy", req.Id.Value),
   351  			zap.Bool("is-owner", isOwner),
   352  		)
   353  		return api.NewAuthStrategyResponse(apimodel.Code_NotAllowedAccess, req)
   354  	}
   355  
   356  	return api.NewAuthStrategyResponse(apimodel.Code_ExecuteSuccess, svr.authStrategyFull2Api(ret))
   357  }
   358  
   359  // GetPrincipalResources 获取某个principal可以获取到的所有资源ID数据信息
   360  func (svr *Server) GetPrincipalResources(ctx context.Context, query map[string]string) *apiservice.Response {
   361  	requestID := utils.ParseRequestID(ctx)
   362  	if len(query) == 0 {
   363  		return api.NewAuthResponse(apimodel.Code_EmptyRequest)
   364  	}
   365  
   366  	principalId := query["principal_id"]
   367  	if principalId == "" {
   368  		return api.NewAuthResponse(apimodel.Code_EmptyQueryParameter)
   369  	}
   370  
   371  	var principalType string
   372  	if v, exist := principalTypeFilter[query["principal_type"]]; exist {
   373  		principalType = v
   374  	} else {
   375  		principalType = "1"
   376  	}
   377  
   378  	principalRole, _ := strconv.ParseInt(principalType, 10, 64)
   379  	if err := model.CheckPrincipalType(int(principalRole)); err != nil {
   380  		return api.NewAuthResponse(apimodel.Code_InvalidPrincipalType)
   381  	}
   382  
   383  	var (
   384  		resources = make([]model.StrategyResource, 0, 20)
   385  		err       error
   386  	)
   387  
   388  	// 找这个用户所关联的用户组
   389  	if model.PrincipalType(principalRole) == model.PrincipalUser {
   390  		groupIds := svr.cacheMgn.User().GetUserLinkGroupIds(principalId)
   391  		for i := range groupIds {
   392  			res, err := svr.storage.GetStrategyResources(groupIds[i], model.PrincipalGroup)
   393  			if err != nil {
   394  				log.Error("[Auth][Strategy] get principal link resource", utils.ZapRequestID(requestID),
   395  					zap.String("principal-id", principalId), zap.Any("principal-role", principalRole), zap.Error(err))
   396  				return api.NewAuthResponse(commonstore.StoreCode2APICode(err))
   397  			}
   398  			resources = append(resources, res...)
   399  		}
   400  	}
   401  
   402  	pResources, err := svr.storage.GetStrategyResources(principalId, model.PrincipalType(principalRole))
   403  	if err != nil {
   404  		log.Error("[Auth][Strategy] get principal link resource", utils.ZapRequestID(requestID),
   405  			zap.String("principal-id", principalId), zap.Any("principal-role", principalRole), zap.Error(err))
   406  		return api.NewAuthResponse(commonstore.StoreCode2APICode(err))
   407  	}
   408  
   409  	resources = append(resources, pResources...)
   410  	tmp := &apisecurity.AuthStrategy{
   411  		Resources: &apisecurity.StrategyResources{
   412  			Namespaces:   make([]*apisecurity.StrategyResourceEntry, 0),
   413  			Services:     make([]*apisecurity.StrategyResourceEntry, 0),
   414  			ConfigGroups: make([]*apisecurity.StrategyResourceEntry, 0),
   415  		},
   416  	}
   417  
   418  	svr.fillResourceInfo(tmp, &model.StrategyDetail{
   419  		Resources: resourceDeduplication(resources),
   420  	})
   421  
   422  	return api.NewStrategyResourcesResponse(apimodel.Code_ExecuteSuccess, tmp.Resources)
   423  }
   424  
   425  // enhancedAuthStrategy2Api
   426  func enhancedAuthStrategy2Api(s []*model.StrategyDetail, fn StrategyDetail2Api) []*apisecurity.AuthStrategy {
   427  	out := make([]*apisecurity.AuthStrategy, 0, len(s))
   428  	for k := range s {
   429  		out = append(out, fn(s[k]))
   430  	}
   431  	return out
   432  }
   433  
   434  // authStrategy2Api
   435  func (svr *Server) authStrategy2Api(s *model.StrategyDetail) *apisecurity.AuthStrategy {
   436  	if s == nil {
   437  		return nil
   438  	}
   439  
   440  	// note: 不包括token,token比较特殊
   441  	out := &apisecurity.AuthStrategy{
   442  		Id:              utils.NewStringValue(s.ID),
   443  		Name:            utils.NewStringValue(s.Name),
   444  		Owner:           utils.NewStringValue(s.Owner),
   445  		Comment:         utils.NewStringValue(s.Comment),
   446  		Ctime:           utils.NewStringValue(commontime.Time2String(s.CreateTime)),
   447  		Mtime:           utils.NewStringValue(commontime.Time2String(s.ModifyTime)),
   448  		Action:          apisecurity.AuthAction(apisecurity.AuthAction_value[s.Action]),
   449  		DefaultStrategy: utils.NewBoolValue(s.Default),
   450  	}
   451  
   452  	return out
   453  }
   454  
   455  // authStrategyFull2Api
   456  func (svr *Server) authStrategyFull2Api(data *model.StrategyDetail) *apisecurity.AuthStrategy {
   457  	if data == nil {
   458  		return nil
   459  	}
   460  
   461  	users := make([]*wrappers.StringValue, 0, len(data.Principals))
   462  	groups := make([]*wrappers.StringValue, 0, len(data.Principals))
   463  	for index := range data.Principals {
   464  		principal := data.Principals[index]
   465  		if principal.PrincipalRole == model.PrincipalUser {
   466  			users = append(users, utils.NewStringValue(principal.PrincipalID))
   467  		} else {
   468  			groups = append(groups, utils.NewStringValue(principal.PrincipalID))
   469  		}
   470  	}
   471  
   472  	// note: 不包括token,token比较特殊
   473  	out := &apisecurity.AuthStrategy{
   474  		Id:              utils.NewStringValue(data.ID),
   475  		Name:            utils.NewStringValue(data.Name),
   476  		Owner:           utils.NewStringValue(data.Owner),
   477  		Comment:         utils.NewStringValue(data.Comment),
   478  		Ctime:           utils.NewStringValue(commontime.Time2String(data.CreateTime)),
   479  		Mtime:           utils.NewStringValue(commontime.Time2String(data.ModifyTime)),
   480  		Action:          apisecurity.AuthAction(apisecurity.AuthAction_value[data.Action]),
   481  		DefaultStrategy: utils.NewBoolValue(data.Default),
   482  	}
   483  
   484  	svr.fillPrincipalInfo(out, data)
   485  	svr.fillResourceInfo(out, data)
   486  	return out
   487  }
   488  
   489  // createAuthStrategyModel 创建鉴权策略的存储模型
   490  func (svr *Server) createAuthStrategyModel(strategy *apisecurity.AuthStrategy) *model.StrategyDetail {
   491  	ret := &model.StrategyDetail{
   492  		ID:         utils.NewUUID(),
   493  		Name:       strategy.Name.GetValue(),
   494  		Action:     apisecurity.AuthAction_READ_WRITE.String(),
   495  		Comment:    strategy.Comment.GetValue(),
   496  		Default:    false,
   497  		Owner:      strategy.Owner.GetValue(),
   498  		Valid:      true,
   499  		Revision:   utils.NewUUID(),
   500  		CreateTime: time.Now(),
   501  		ModifyTime: time.Now(),
   502  	}
   503  
   504  	// 收集涉及的资源信息
   505  	resEntry := make([]model.StrategyResource, 0, 20)
   506  	resEntry = append(resEntry, svr.collectResEntry(ret.ID, apisecurity.ResourceType_Namespaces,
   507  		strategy.GetResources().GetNamespaces(), false)...)
   508  	resEntry = append(resEntry, svr.collectResEntry(ret.ID, apisecurity.ResourceType_Services,
   509  		strategy.GetResources().GetServices(), false)...)
   510  	resEntry = append(resEntry, svr.collectResEntry(ret.ID, apisecurity.ResourceType_ConfigGroups,
   511  		strategy.GetResources().GetConfigGroups(), false)...)
   512  
   513  	// 收集涉及的 principal 信息
   514  	principals := make([]model.Principal, 0, 20)
   515  	principals = append(principals, collectPrincipalEntry(ret.ID, model.PrincipalUser,
   516  		strategy.GetPrincipals().GetUsers())...)
   517  	principals = append(principals, collectPrincipalEntry(ret.ID, model.PrincipalGroup,
   518  		strategy.GetPrincipals().GetGroups())...)
   519  
   520  	ret.Resources = resEntry
   521  	ret.Principals = principals
   522  
   523  	return ret
   524  }
   525  
   526  // updateAuthStrategyAttribute 更新计算鉴权策略的属性
   527  func (svr *Server) updateAuthStrategyAttribute(ctx context.Context, strategy *apisecurity.ModifyAuthStrategy,
   528  	saved *model.StrategyDetail) (*model.ModifyStrategyDetail, bool) {
   529  	var needUpdate bool
   530  	ret := &model.ModifyStrategyDetail{
   531  		ID:         strategy.Id.GetValue(),
   532  		Name:       saved.Name,
   533  		Action:     saved.Action,
   534  		Comment:    saved.Comment,
   535  		ModifyTime: time.Now(),
   536  	}
   537  
   538  	// 只有 owner 可以修改的属性
   539  	if utils.ParseIsOwner(ctx) {
   540  		if strategy.GetComment() != nil && strategy.GetComment().GetValue() != saved.Comment {
   541  			needUpdate = true
   542  			ret.Comment = strategy.GetComment().GetValue()
   543  		}
   544  
   545  		if strategy.GetName().GetValue() != "" && strategy.GetName().GetValue() != saved.Name {
   546  			needUpdate = true
   547  			ret.Name = strategy.GetName().GetValue()
   548  		}
   549  	}
   550  
   551  	if svr.computeResourceChange(ret, strategy) {
   552  		needUpdate = true
   553  	}
   554  	if computePrincipalChange(ret, strategy) {
   555  		needUpdate = true
   556  	}
   557  
   558  	return ret, needUpdate
   559  }
   560  
   561  // computeResourceChange 计算资源的变化情况,判断是否涉及变更
   562  func (svr *Server) computeResourceChange(
   563  	modify *model.ModifyStrategyDetail, strategy *apisecurity.ModifyAuthStrategy) bool {
   564  	var needUpdate bool
   565  	addResEntry := make([]model.StrategyResource, 0)
   566  	addResEntry = append(addResEntry, svr.collectResEntry(modify.ID, apisecurity.ResourceType_Namespaces,
   567  		strategy.GetAddResources().GetNamespaces(), false)...)
   568  	addResEntry = append(addResEntry, svr.collectResEntry(modify.ID, apisecurity.ResourceType_Services,
   569  		strategy.GetAddResources().GetServices(), false)...)
   570  	addResEntry = append(addResEntry, svr.collectResEntry(modify.ID, apisecurity.ResourceType_ConfigGroups,
   571  		strategy.GetAddResources().GetConfigGroups(), false)...)
   572  
   573  	if len(addResEntry) != 0 {
   574  		needUpdate = true
   575  		modify.AddResources = addResEntry
   576  	}
   577  
   578  	removeResEntry := make([]model.StrategyResource, 0)
   579  	removeResEntry = append(removeResEntry, svr.collectResEntry(modify.ID, apisecurity.ResourceType_Namespaces,
   580  		strategy.GetRemoveResources().GetNamespaces(), true)...)
   581  	removeResEntry = append(removeResEntry, svr.collectResEntry(modify.ID, apisecurity.ResourceType_Services,
   582  		strategy.GetRemoveResources().GetServices(), true)...)
   583  	removeResEntry = append(removeResEntry, svr.collectResEntry(modify.ID, apisecurity.ResourceType_ConfigGroups,
   584  		strategy.GetRemoveResources().GetConfigGroups(), true)...)
   585  
   586  	if len(removeResEntry) != 0 {
   587  		needUpdate = true
   588  		modify.RemoveResources = removeResEntry
   589  	}
   590  
   591  	return needUpdate
   592  }
   593  
   594  // computePrincipalChange 计算 principal 的变化情况,判断是否涉及变更
   595  func computePrincipalChange(modify *model.ModifyStrategyDetail, strategy *apisecurity.ModifyAuthStrategy) bool {
   596  	var needUpdate bool
   597  	addPrincipals := make([]model.Principal, 0)
   598  	addPrincipals = append(addPrincipals, collectPrincipalEntry(modify.ID, model.PrincipalUser,
   599  		strategy.GetAddPrincipals().GetUsers())...)
   600  	addPrincipals = append(addPrincipals, collectPrincipalEntry(modify.ID, model.PrincipalGroup,
   601  		strategy.GetAddPrincipals().GetGroups())...)
   602  
   603  	if len(addPrincipals) != 0 {
   604  		needUpdate = true
   605  		modify.AddPrincipals = addPrincipals
   606  	}
   607  
   608  	removePrincipals := make([]model.Principal, 0)
   609  	removePrincipals = append(removePrincipals, collectPrincipalEntry(modify.ID, model.PrincipalUser,
   610  		strategy.GetRemovePrincipals().GetUsers())...)
   611  	removePrincipals = append(removePrincipals, collectPrincipalEntry(modify.ID, model.PrincipalGroup,
   612  		strategy.GetRemovePrincipals().GetGroups())...)
   613  
   614  	if len(removePrincipals) != 0 {
   615  		needUpdate = true
   616  		modify.RemovePrincipals = removePrincipals
   617  	}
   618  
   619  	return needUpdate
   620  }
   621  
   622  // collectResEntry 将资源ID转换为对应的 []model.StrategyResource 数组
   623  func (svr *Server) collectResEntry(ruleId string, resType apisecurity.ResourceType,
   624  	res []*apisecurity.StrategyResourceEntry, delete bool) []model.StrategyResource {
   625  	resEntries := make([]model.StrategyResource, 0, len(res)+1)
   626  	if len(res) == 0 {
   627  		return resEntries
   628  	}
   629  
   630  	for index := range res {
   631  		// 如果是添加的动作,那么需要进行归一化处理
   632  		if !delete {
   633  			// 归一化处理
   634  			if res[index].GetId().GetValue() == "*" || res[index].GetName().GetValue() == "*" {
   635  				return []model.StrategyResource{
   636  					{
   637  						StrategyID: ruleId,
   638  						ResType:    int32(resType),
   639  						ResID:      "*",
   640  					},
   641  				}
   642  			}
   643  		}
   644  
   645  		entry := model.StrategyResource{
   646  			StrategyID: ruleId,
   647  			ResType:    int32(resType),
   648  			ResID:      res[index].GetId().GetValue(),
   649  		}
   650  
   651  		resEntries = append(resEntries, entry)
   652  	}
   653  
   654  	return resEntries
   655  }
   656  
   657  // collectPrincipalEntry 将 Principal 转换为对应的 []model.Principal 数组
   658  func collectPrincipalEntry(ruleID string, uType model.PrincipalType, res []*apisecurity.Principal) []model.Principal {
   659  	principals := make([]model.Principal, 0, len(res)+1)
   660  	if len(res) == 0 {
   661  		return principals
   662  	}
   663  
   664  	for index := range res {
   665  		principals = append(principals, model.Principal{
   666  			StrategyID:    ruleID,
   667  			PrincipalID:   res[index].GetId().GetValue(),
   668  			PrincipalRole: uType,
   669  		})
   670  	}
   671  
   672  	return principals
   673  }
   674  
   675  // checkCreateStrategy 检查创建鉴权策略的请求
   676  func (svr *Server) checkCreateStrategy(req *apisecurity.AuthStrategy) *apiservice.Response {
   677  	// 检查名称信息
   678  	if err := checkName(req.GetName()); err != nil {
   679  		return api.NewAuthStrategyResponse(apimodel.Code_InvalidUserName, req)
   680  	}
   681  
   682  	// 检查 owner 信息
   683  	if err := checkOwner(req.GetOwner()); err != nil {
   684  		return api.NewAuthStrategyResponse(apimodel.Code_InvalidAuthStrategyOwners, req)
   685  	}
   686  
   687  	// 检查用户是否存在
   688  	if err := svr.checkUserExist(convertPrincipalsToUsers(req.GetPrincipals())); err != nil {
   689  		return api.NewAuthStrategyResponse(apimodel.Code_NotFoundUser, req)
   690  	}
   691  
   692  	// 检查用户组是否存在
   693  	if err := svr.checkGroupExist(convertPrincipalsToGroups(req.GetPrincipals())); err != nil {
   694  		return api.NewAuthStrategyResponse(apimodel.Code_NotFoundUserGroup, req)
   695  	}
   696  
   697  	// 检查资源是否存在
   698  	if errResp := svr.checkResourceExist(req.GetResources()); errResp != nil {
   699  		return errResp
   700  	}
   701  
   702  	return nil
   703  }
   704  
   705  // checkUpdateStrategy 检查更新鉴权策略的请求
   706  // Case 1. 修改的是默认鉴权策略的话,只能修改资源,不能添加用户 or 用户组
   707  // Case 2. 鉴权策略只能被自己的 owner 对应的用户修改
   708  func (svr *Server) checkUpdateStrategy(ctx context.Context, req *apisecurity.ModifyAuthStrategy,
   709  	saved *model.StrategyDetail) *apiservice.Response {
   710  	userId := utils.ParseUserID(ctx)
   711  	if authcommon.ParseUserRole(ctx) != model.AdminUserRole {
   712  		if !utils.ParseIsOwner(ctx) || userId != saved.Owner {
   713  			log.Error("[Auth][Strategy] modify strategy denied, current user not owner",
   714  				utils.ZapRequestID(utils.ParseRequestID(ctx)),
   715  				zap.String("user", userId),
   716  				zap.String("owner", saved.Owner),
   717  				zap.String("strategy", saved.ID))
   718  			return api.NewModifyAuthStrategyResponse(apimodel.Code_NotAllowedAccess, req)
   719  		}
   720  	}
   721  
   722  	if saved.Default {
   723  		if len(req.AddPrincipals.Users) != 0 ||
   724  			len(req.AddPrincipals.Groups) != 0 ||
   725  			len(req.RemovePrincipals.Groups) != 0 ||
   726  			len(req.RemovePrincipals.Users) != 0 {
   727  			return api.NewModifyAuthStrategyResponse(apimodel.Code_NotAllowModifyDefaultStrategyPrincipal, req)
   728  		}
   729  
   730  		// 主账户的默认策略禁止编辑
   731  		if len(saved.Principals) == 1 && saved.Principals[0].PrincipalRole == model.PrincipalUser {
   732  			if saved.Principals[0].PrincipalID == utils.ParseOwnerID(ctx) {
   733  				return api.NewAuthResponse(apimodel.Code_NotAllowModifyOwnerDefaultStrategy)
   734  			}
   735  		}
   736  	}
   737  
   738  	// 检查用户是否存在
   739  	if err := svr.checkUserExist(convertPrincipalsToUsers(req.GetAddPrincipals())); err != nil {
   740  		return api.NewModifyAuthStrategyResponse(apimodel.Code_NotFoundUser, req)
   741  	}
   742  
   743  	// 检查用户组是否存
   744  	if err := svr.checkGroupExist(convertPrincipalsToGroups(req.GetAddPrincipals())); err != nil {
   745  		return api.NewModifyAuthStrategyResponse(apimodel.Code_NotFoundUserGroup, req)
   746  	}
   747  
   748  	// 检查资源是否存在
   749  	if errResp := svr.checkResourceExist(req.GetAddResources()); errResp != nil {
   750  		return errResp
   751  	}
   752  
   753  	return nil
   754  }
   755  
   756  // authStrategyRecordEntry 转换为鉴权策略的记录结构体
   757  func authStrategyRecordEntry(ctx context.Context, req *apisecurity.AuthStrategy, md *model.StrategyDetail,
   758  	operationType model.OperationType) *model.RecordEntry {
   759  
   760  	marshaler := jsonpb.Marshaler{}
   761  	detail, _ := marshaler.MarshalToString(req)
   762  
   763  	entry := &model.RecordEntry{
   764  		ResourceType:  model.RAuthStrategy,
   765  		ResourceName:  fmt.Sprintf("%s(%s)", md.Name, md.ID),
   766  		OperationType: operationType,
   767  		Operator:      utils.ParseOperator(ctx),
   768  		Detail:        detail,
   769  		HappenTime:    time.Now(),
   770  	}
   771  
   772  	return entry
   773  }
   774  
   775  // authModifyStrategyRecordEntry
   776  func authModifyStrategyRecordEntry(
   777  	ctx context.Context, req *apisecurity.ModifyAuthStrategy, md *model.ModifyStrategyDetail,
   778  	operationType model.OperationType) *model.RecordEntry {
   779  
   780  	marshaler := jsonpb.Marshaler{}
   781  	detail, _ := marshaler.MarshalToString(req)
   782  
   783  	entry := &model.RecordEntry{
   784  		ResourceType:  model.RAuthStrategy,
   785  		ResourceName:  fmt.Sprintf("%s(%s)", md.Name, md.ID),
   786  		OperationType: operationType,
   787  		Operator:      utils.ParseOperator(ctx),
   788  		Detail:        detail,
   789  		HappenTime:    time.Now(),
   790  	}
   791  
   792  	return entry
   793  }
   794  
   795  func convertPrincipalsToUsers(principals *apisecurity.Principals) []*apisecurity.User {
   796  	if principals == nil {
   797  		return make([]*apisecurity.User, 0)
   798  	}
   799  
   800  	users := make([]*apisecurity.User, 0, len(principals.Users))
   801  	for k := range principals.GetUsers() {
   802  		user := principals.GetUsers()[k]
   803  		users = append(users, &apisecurity.User{
   804  			Id: user.Id,
   805  		})
   806  	}
   807  
   808  	return users
   809  }
   810  
   811  func convertPrincipalsToGroups(principals *apisecurity.Principals) []*apisecurity.UserGroup {
   812  	if principals == nil {
   813  		return make([]*apisecurity.UserGroup, 0)
   814  	}
   815  
   816  	groups := make([]*apisecurity.UserGroup, 0, len(principals.Groups))
   817  	for k := range principals.GetGroups() {
   818  		group := principals.GetGroups()[k]
   819  		groups = append(groups, &apisecurity.UserGroup{
   820  			Id: group.Id,
   821  		})
   822  	}
   823  
   824  	return groups
   825  }
   826  
   827  // checkUserExist 检查用户是否存在
   828  func (svr *Server) checkUserExist(users []*apisecurity.User) error {
   829  	if len(users) == 0 {
   830  		return nil
   831  	}
   832  
   833  	userCache := svr.cacheMgn.User()
   834  
   835  	for index := range users {
   836  		if val := userCache.GetUserByID(users[index].GetId().GetValue()); val == nil {
   837  			return model.ErrorNoUser
   838  		}
   839  	}
   840  
   841  	return nil
   842  }
   843  
   844  // checkUserGroupExist 检查用户组是否存在
   845  func (svr *Server) checkGroupExist(groups []*apisecurity.UserGroup) error {
   846  	if len(groups) == 0 {
   847  		return nil
   848  	}
   849  	userCache := svr.cacheMgn.User()
   850  
   851  	for index := range groups {
   852  		if val := userCache.GetGroup(groups[index].GetId().GetValue()); val == nil {
   853  			return model.ErrorNoUserGroup
   854  		}
   855  	}
   856  
   857  	return nil
   858  }
   859  
   860  // checkResourceExist 检查资源是否存在
   861  func (svr *Server) checkResourceExist(resources *apisecurity.StrategyResources) *apiservice.Response {
   862  	namespaces := resources.GetNamespaces()
   863  
   864  	nsCache := svr.cacheMgn.Namespace()
   865  	for index := range namespaces {
   866  		val := namespaces[index]
   867  		if val.GetId().GetValue() == "*" {
   868  			break
   869  		}
   870  		ns := nsCache.GetNamespace(val.GetId().GetValue())
   871  		if ns == nil {
   872  			return api.NewAuthResponse(apimodel.Code_NotFoundNamespace)
   873  		}
   874  	}
   875  
   876  	services := resources.GetServices()
   877  	svcCache := svr.cacheMgn.Service()
   878  	for index := range services {
   879  		val := services[index]
   880  		if val.GetId().GetValue() == "*" {
   881  			break
   882  		}
   883  		svc := svcCache.GetServiceByID(val.GetId().GetValue())
   884  		if svc == nil {
   885  			return api.NewAuthResponse(apimodel.Code_NotFoundService)
   886  		}
   887  	}
   888  
   889  	return nil
   890  }
   891  
   892  // normalizeResource 对于资源进行归一化处理
   893  //
   894  //	如果出现 * 的话,则该资源访问策略就是 *
   895  func (svr *Server) normalizeResource(resources *apisecurity.StrategyResources) *apisecurity.StrategyResources {
   896  	namespaces := resources.GetNamespaces()
   897  	for index := range namespaces {
   898  		val := namespaces[index]
   899  		if val.GetId().GetValue() == "*" {
   900  			resources.Namespaces = []*apisecurity.StrategyResourceEntry{{
   901  				Id: utils.NewStringValue("*"),
   902  			}}
   903  			break
   904  		}
   905  	}
   906  
   907  	services := resources.GetServices()
   908  	for index := range services {
   909  		val := services[index]
   910  		if val.GetId().GetValue() == "*" {
   911  			resources.Services = []*apisecurity.StrategyResourceEntry{{
   912  				Id: utils.NewStringValue("*"),
   913  			}}
   914  			break
   915  		}
   916  	}
   917  
   918  	return resources
   919  }
   920  
   921  // fillPrincipalInfo 填充 principal 摘要信息
   922  func (svr *Server) fillPrincipalInfo(resp *apisecurity.AuthStrategy, data *model.StrategyDetail) {
   923  	users := make([]*apisecurity.Principal, 0, len(data.Principals))
   924  	groups := make([]*apisecurity.Principal, 0, len(data.Principals))
   925  	for index := range data.Principals {
   926  		principal := data.Principals[index]
   927  		if principal.PrincipalRole == model.PrincipalUser {
   928  			user := svr.cacheMgn.User().GetUserByID(principal.PrincipalID)
   929  			if user == nil {
   930  				continue
   931  			}
   932  			users = append(users, &apisecurity.Principal{
   933  				Id:   utils.NewStringValue(user.ID),
   934  				Name: utils.NewStringValue(user.Name),
   935  			})
   936  		} else {
   937  			group := svr.cacheMgn.User().GetGroup(principal.PrincipalID)
   938  			if group == nil {
   939  				continue
   940  			}
   941  			groups = append(groups, &apisecurity.Principal{
   942  				Id:   utils.NewStringValue(group.ID),
   943  				Name: utils.NewStringValue(group.Name),
   944  			})
   945  		}
   946  	}
   947  
   948  	resp.Principals = &apisecurity.Principals{
   949  		Users:  users,
   950  		Groups: groups,
   951  	}
   952  }
   953  
   954  // fillResourceInfo 填充资源摘要信息
   955  func (svr *Server) fillResourceInfo(resp *apisecurity.AuthStrategy, data *model.StrategyDetail) {
   956  	namespaces := make([]*apisecurity.StrategyResourceEntry, 0, len(data.Resources))
   957  	services := make([]*apisecurity.StrategyResourceEntry, 0, len(data.Resources))
   958  	configGroups := make([]*apisecurity.StrategyResourceEntry, 0, len(data.Resources))
   959  
   960  	var (
   961  		autoAllNs          bool
   962  		autoAllSvc         bool
   963  		autoAllConfigGroup bool
   964  	)
   965  
   966  	for index := range data.Resources {
   967  		res := data.Resources[index]
   968  		switch res.ResType {
   969  		case int32(apisecurity.ResourceType_Namespaces):
   970  			if res.ResID == "*" {
   971  				autoAllNs = true
   972  				namespaces = []*apisecurity.StrategyResourceEntry{
   973  					{
   974  						Id:        utils.NewStringValue("*"),
   975  						Namespace: utils.NewStringValue("*"),
   976  						Name:      utils.NewStringValue("*"),
   977  					},
   978  				}
   979  				continue
   980  			}
   981  
   982  			if !autoAllNs {
   983  				ns := svr.cacheMgn.Namespace().GetNamespace(res.ResID)
   984  				if ns == nil {
   985  					log.Warn("[Auth][Strategy] not found namespace in fill-info",
   986  						zap.String("id", data.ID), zap.String("namespace", res.ResID))
   987  					continue
   988  				}
   989  				namespaces = append(namespaces, &apisecurity.StrategyResourceEntry{
   990  					Id:        utils.NewStringValue(ns.Name),
   991  					Namespace: utils.NewStringValue(ns.Name),
   992  					Name:      utils.NewStringValue(ns.Name),
   993  				})
   994  			}
   995  		case int32(apisecurity.ResourceType_Services):
   996  			if res.ResID == "*" {
   997  				autoAllSvc = true
   998  				services = []*apisecurity.StrategyResourceEntry{
   999  					{
  1000  						Id:        utils.NewStringValue("*"),
  1001  						Namespace: utils.NewStringValue("*"),
  1002  						Name:      utils.NewStringValue("*"),
  1003  					},
  1004  				}
  1005  				continue
  1006  			}
  1007  
  1008  			if !autoAllSvc {
  1009  				svc := svr.cacheMgn.Service().GetServiceByID(res.ResID)
  1010  				if svc == nil {
  1011  					log.Warn("[Auth][Strategy] not found service in fill-info",
  1012  						zap.String("id", data.ID), zap.String("service", res.ResID))
  1013  					continue
  1014  				}
  1015  				services = append(services, &apisecurity.StrategyResourceEntry{
  1016  					Id:        utils.NewStringValue(svc.ID),
  1017  					Namespace: utils.NewStringValue(svc.Namespace),
  1018  					Name:      utils.NewStringValue(svc.Name),
  1019  				})
  1020  			}
  1021  		case int32(apisecurity.ResourceType_ConfigGroups):
  1022  			if res.ResID == "*" {
  1023  				autoAllConfigGroup = true
  1024  				configGroups = []*apisecurity.StrategyResourceEntry{
  1025  					{
  1026  						Id:        utils.NewStringValue("*"),
  1027  						Namespace: utils.NewStringValue("*"),
  1028  						Name:      utils.NewStringValue("*"),
  1029  					},
  1030  				}
  1031  				continue
  1032  			}
  1033  			if !autoAllConfigGroup {
  1034  				groupId, err := strconv.ParseUint(res.ResID, 10, 64)
  1035  				if err != nil {
  1036  					log.Warn("[Auth][Strategy] invalid resource id",
  1037  						zap.String("id", data.ID), zap.String("config_file_group", res.ResID))
  1038  					continue
  1039  				}
  1040  				group := svr.cacheMgn.ConfigGroup().GetGroupByID(groupId)
  1041  				if group == nil {
  1042  					log.Warn("[Auth][Strategy] not found config_file_group in fill-info",
  1043  						zap.String("id", data.ID), zap.String("config_file_group", res.ResID))
  1044  					continue
  1045  				}
  1046  				configGroups = append(configGroups, &apisecurity.StrategyResourceEntry{
  1047  					Id:        utils.NewStringValue(res.ResID),
  1048  					Namespace: utils.NewStringValue(group.Namespace),
  1049  					Name:      utils.NewStringValue(group.Name),
  1050  				})
  1051  			}
  1052  		}
  1053  	}
  1054  
  1055  	resp.Resources = &apisecurity.StrategyResources{
  1056  		Namespaces:   namespaces,
  1057  		Services:     services,
  1058  		ConfigGroups: configGroups,
  1059  	}
  1060  }
  1061  
  1062  type resourceFilter struct {
  1063  	ns   map[string]struct{}
  1064  	svc  map[string]struct{}
  1065  	conf map[string]struct{}
  1066  }
  1067  
  1068  // filter different types of Strategy resources
  1069  func resourceDeduplication(resources []model.StrategyResource) []model.StrategyResource {
  1070  	rLen := len(resources)
  1071  	ret := make([]model.StrategyResource, 0, rLen)
  1072  	rf := resourceFilter{
  1073  		ns:   make(map[string]struct{}, rLen),
  1074  		svc:  make(map[string]struct{}, rLen),
  1075  		conf: make(map[string]struct{}, rLen),
  1076  	}
  1077  
  1078  	est := struct{}{}
  1079  	for i := range resources {
  1080  		res := resources[i]
  1081  		if res.ResType == int32(apisecurity.ResourceType_Namespaces) {
  1082  			if _, exist := rf.ns[res.ResID]; !exist {
  1083  				rf.ns[res.ResID] = est
  1084  				ret = append(ret, res)
  1085  			}
  1086  			continue
  1087  		}
  1088  
  1089  		if res.ResType == int32(apisecurity.ResourceType_Services) {
  1090  			if _, exist := rf.svc[res.ResID]; !exist {
  1091  				rf.svc[res.ResID] = est
  1092  				ret = append(ret, res)
  1093  			}
  1094  
  1095  			continue
  1096  		}
  1097  
  1098  		// other type conf
  1099  		if _, exist := rf.conf[res.ResID]; !exist {
  1100  			rf.conf[res.ResID] = est
  1101  			ret = append(ret, res)
  1102  		}
  1103  	}
  1104  
  1105  	return ret
  1106  }