github.com/polarismesh/polaris@v1.17.8/service/server_authability.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 service
    19  
    20  import (
    21  	"context"
    22  	"errors"
    23  
    24  	apifault "github.com/polarismesh/specification/source/go/api/v1/fault_tolerance"
    25  	apimodel "github.com/polarismesh/specification/source/go/api/v1/model"
    26  	apisecurity "github.com/polarismesh/specification/source/go/api/v1/security"
    27  	apiservice "github.com/polarismesh/specification/source/go/api/v1/service_manage"
    28  	apitraffic "github.com/polarismesh/specification/source/go/api/v1/traffic_manage"
    29  	"go.uber.org/zap"
    30  
    31  	"github.com/polarismesh/polaris/auth"
    32  	"github.com/polarismesh/polaris/cache"
    33  	"github.com/polarismesh/polaris/common/model"
    34  	"github.com/polarismesh/polaris/common/utils"
    35  )
    36  
    37  // serverAuthAbility 带有鉴权能力的 discoverServer
    38  //
    39  //	该层会对请求参数做一些调整,根据具体的请求发起人,设置为数据对应的 owner,不可为为别人进行创建资源
    40  type serverAuthAbility struct {
    41  	targetServer *Server
    42  	userMgn      auth.UserServer
    43  	strategyMgn  auth.StrategyServer
    44  }
    45  
    46  func newServerAuthAbility(targetServer *Server,
    47  	userMgn auth.UserServer, strategyMgn auth.StrategyServer) DiscoverServer {
    48  	proxy := &serverAuthAbility{
    49  		targetServer: targetServer,
    50  		userMgn:      userMgn,
    51  		strategyMgn:  strategyMgn,
    52  	}
    53  
    54  	targetServer.SetResourceHooks(proxy)
    55  
    56  	return proxy
    57  }
    58  
    59  // Cache Get cache management
    60  func (svr *serverAuthAbility) Cache() *cache.CacheManager {
    61  	return svr.targetServer.Cache()
    62  }
    63  
    64  // GetServiceInstanceRevision 获取服务实例的版本号
    65  func (svr *serverAuthAbility) GetServiceInstanceRevision(serviceID string,
    66  	instances []*model.Instance) (string, error) {
    67  	return svr.targetServer.GetServiceInstanceRevision(serviceID, instances)
    68  }
    69  
    70  // collectServiceAuthContext 对于服务的处理,收集所有的与鉴权的相关信息
    71  //
    72  //	@receiver svr serverAuthAbility
    73  //	@param ctx 请求上下文 ctx
    74  //	@param req 实际请求对象
    75  //	@param resourceOp 该接口的数据操作类型
    76  //	@return *model.AcquireContext 返回鉴权上下文
    77  func (svr *serverAuthAbility) collectServiceAuthContext(ctx context.Context, req []*apiservice.Service,
    78  	resourceOp model.ResourceOperation, methodName string) *model.AcquireContext {
    79  	return model.NewAcquireContext(
    80  		model.WithRequestContext(ctx),
    81  		model.WithOperation(resourceOp),
    82  		model.WithModule(model.DiscoverModule),
    83  		model.WithMethod(methodName),
    84  		model.WithAccessResources(svr.queryServiceResource(req)),
    85  	)
    86  }
    87  
    88  // collectServiceAliasAuthContext 对于服务别名的处理,收集所有的与鉴权的相关信息
    89  //
    90  //	@receiver svr serverAuthAbility
    91  //	@param ctx 请求上下文 ctx
    92  //	@param req 实际请求对象
    93  //	@param resourceOp 该接口的数据操作类型
    94  //	@return *model.AcquireContext 返回鉴权上下文
    95  func (svr *serverAuthAbility) collectServiceAliasAuthContext(ctx context.Context, req []*apiservice.ServiceAlias,
    96  	resourceOp model.ResourceOperation, methodName string) *model.AcquireContext {
    97  	return model.NewAcquireContext(
    98  		model.WithRequestContext(ctx),
    99  		model.WithOperation(resourceOp),
   100  		model.WithModule(model.DiscoverModule),
   101  		model.WithMethod(methodName),
   102  		model.WithAccessResources(svr.queryServiceAliasResource(req)),
   103  	)
   104  }
   105  
   106  // collectInstanceAuthContext 对于服务实例的处理,收集所有的与鉴权的相关信息
   107  //
   108  //	@receiver svr serverAuthAbility
   109  //	@param ctx 请求上下文 ctx
   110  //	@param req 实际请求对象
   111  //	@param resourceOp 该接口的数据操作类型
   112  //	@return *model.AcquireContext 返回鉴权上下文
   113  func (svr *serverAuthAbility) collectInstanceAuthContext(ctx context.Context, req []*apiservice.Instance,
   114  	resourceOp model.ResourceOperation, methodName string) *model.AcquireContext {
   115  	return model.NewAcquireContext(
   116  		model.WithRequestContext(ctx),
   117  		model.WithOperation(resourceOp),
   118  		model.WithModule(model.DiscoverModule),
   119  		model.WithMethod(methodName),
   120  		model.WithAccessResources(svr.queryInstanceResource(req)),
   121  	)
   122  }
   123  
   124  // collectClientInstanceAuthContext 对于服务实例的处理,收集所有的与鉴权的相关信息
   125  func (svr *serverAuthAbility) collectClientInstanceAuthContext(ctx context.Context, req []*apiservice.Instance,
   126  	resourceOp model.ResourceOperation, methodName string) *model.AcquireContext {
   127  	return model.NewAcquireContext(
   128  		model.WithRequestContext(ctx),
   129  		model.WithOperation(resourceOp),
   130  		model.WithModule(model.DiscoverModule),
   131  		model.WithMethod(methodName),
   132  		model.WithFromClient(),
   133  		model.WithAccessResources(svr.queryInstanceResource(req)),
   134  	)
   135  }
   136  
   137  // collectCircuitBreakerAuthContext 对于服务熔断的处理,收集所有的与鉴权的相关信息
   138  //
   139  //	@receiver svr serverAuthAbility
   140  //	@param ctx 请求上下文 ctx
   141  //	@param req 实际请求对象
   142  //	@param resourceOp 该接口的数据操作类型
   143  //	@return *model.AcquireContext 返回鉴权上下文
   144  func (svr *serverAuthAbility) collectCircuitBreakerAuthContext(ctx context.Context, req []*apifault.CircuitBreaker,
   145  	resourceOp model.ResourceOperation, methodName string) *model.AcquireContext {
   146  	return model.NewAcquireContext(
   147  		model.WithRequestContext(ctx),
   148  		model.WithOperation(resourceOp),
   149  		model.WithModule(model.DiscoverModule),
   150  		model.WithMethod(methodName),
   151  		model.WithAccessResources(svr.queryCircuitBreakerResource(req)),
   152  	)
   153  }
   154  
   155  // collectCircuitBreakerReleaseAuthContext
   156  //
   157  //	@receiver svr
   158  //	@param ctx
   159  //	@param req
   160  //	@param resourceOp
   161  //	@return *model.AcquireContext
   162  func (svr *serverAuthAbility) collectCircuitBreakerReleaseAuthContext(ctx context.Context,
   163  	req []*apiservice.ConfigRelease, resourceOp model.ResourceOperation, methodName string) *model.AcquireContext {
   164  	return model.NewAcquireContext(
   165  		model.WithRequestContext(ctx),
   166  		model.WithOperation(resourceOp),
   167  		model.WithModule(model.DiscoverModule),
   168  		model.WithMethod(methodName),
   169  		model.WithAccessResources(svr.queryCircuitBreakerReleaseResource(req)),
   170  	)
   171  }
   172  
   173  // collectRouteRuleAuthContext 对于服务路由规则的处理,收集所有的与鉴权的相关信息
   174  //
   175  //	@receiver svr serverAuthAbility
   176  //	@param ctx 请求上下文 ctx
   177  //	@param req 实际请求对象
   178  //	@param resourceOp 该接口的数据操作类型
   179  //	@return *model.AcquireContext 返回鉴权上下文
   180  func (svr *serverAuthAbility) collectRouteRuleAuthContext(ctx context.Context, req []*apitraffic.Routing,
   181  	resourceOp model.ResourceOperation, methodName string) *model.AcquireContext {
   182  	return model.NewAcquireContext(
   183  		model.WithRequestContext(ctx),
   184  		model.WithOperation(resourceOp),
   185  		model.WithModule(model.DiscoverModule),
   186  		model.WithMethod(methodName),
   187  		model.WithAccessResources(svr.queryRouteRuleResource(req)),
   188  	)
   189  }
   190  
   191  // collectRateLimitAuthContext 对于服务限流规则的处理,收集所有的与鉴权的相关信息
   192  //
   193  //	@receiver svr serverAuthAbility
   194  //	@param ctx 请求上下文 ctx
   195  //	@param req 实际请求对象
   196  //	@param resourceOp 该接口的数据操作类型
   197  //	@return *model.AcquireContext 返回鉴权上下文
   198  func (svr *serverAuthAbility) collectRateLimitAuthContext(ctx context.Context, req []*apitraffic.Rule,
   199  	resourceOp model.ResourceOperation, methodName string) *model.AcquireContext {
   200  	return model.NewAcquireContext(
   201  		model.WithRequestContext(ctx),
   202  		model.WithOperation(resourceOp),
   203  		model.WithModule(model.DiscoverModule),
   204  		model.WithMethod(methodName),
   205  		model.WithAccessResources(svr.queryRateLimitConfigResource(req)),
   206  	)
   207  }
   208  
   209  // collectRouteRuleV2AuthContext 收集路由v2规则
   210  func (svr *serverAuthAbility) collectRouteRuleV2AuthContext(ctx context.Context, req []*apitraffic.RouteRule,
   211  	resourceOp model.ResourceOperation, methodName string) *model.AcquireContext {
   212  	return model.NewAcquireContext(
   213  		model.WithRequestContext(ctx),
   214  		model.WithOperation(resourceOp),
   215  		model.WithModule(model.DiscoverModule),
   216  		model.WithMethod(methodName),
   217  		model.WithAccessResources(map[apisecurity.ResourceType][]model.ResourceEntry{}),
   218  	)
   219  }
   220  
   221  // collectRouteRuleV2AuthContext 收集熔断v2规则
   222  func (svr *serverAuthAbility) collectCircuitBreakerRuleV2AuthContext(ctx context.Context,
   223  	req []*apifault.CircuitBreakerRule,
   224  	resourceOp model.ResourceOperation, methodName string) *model.AcquireContext {
   225  	return model.NewAcquireContext(
   226  		model.WithRequestContext(ctx),
   227  		model.WithOperation(resourceOp),
   228  		model.WithModule(model.DiscoverModule),
   229  		model.WithMethod(methodName),
   230  		model.WithAccessResources(map[apisecurity.ResourceType][]model.ResourceEntry{}),
   231  	)
   232  }
   233  
   234  // collectRouteRuleV2AuthContext 收集主动探测规则
   235  func (svr *serverAuthAbility) collectFaultDetectAuthContext(ctx context.Context,
   236  	req []*apifault.FaultDetectRule,
   237  	resourceOp model.ResourceOperation, methodName string) *model.AcquireContext {
   238  	return model.NewAcquireContext(
   239  		model.WithRequestContext(ctx),
   240  		model.WithOperation(resourceOp),
   241  		model.WithModule(model.DiscoverModule),
   242  		model.WithMethod(methodName),
   243  		model.WithAccessResources(map[apisecurity.ResourceType][]model.ResourceEntry{}),
   244  	)
   245  }
   246  
   247  // queryServiceResource  根据所给的 service 信息,收集对应的 ResourceEntry 列表
   248  func (svr *serverAuthAbility) queryServiceResource(
   249  	req []*apiservice.Service) map[apisecurity.ResourceType][]model.ResourceEntry {
   250  	if len(req) == 0 {
   251  		return make(map[apisecurity.ResourceType][]model.ResourceEntry)
   252  	}
   253  
   254  	names := utils.NewSet[string]()
   255  	svcSet := utils.NewMap[string, *model.Service]()
   256  
   257  	for index := range req {
   258  		svcName := req[index].GetName().GetValue()
   259  		svcNamespace := req[index].GetNamespace().GetValue()
   260  		names.Add(svcNamespace)
   261  		svc := svr.Cache().Service().GetServiceByName(svcName, svcNamespace)
   262  		if svc != nil {
   263  			svcSet.Store(svc.ID, svc)
   264  		}
   265  	}
   266  
   267  	ret := svr.convertToDiscoverResourceEntryMaps(names, svcSet)
   268  	if authLog.DebugEnabled() {
   269  		authLog.Debug("[Auth][Server] collect service access res", zap.Any("res", ret))
   270  	}
   271  	return ret
   272  }
   273  
   274  // queryServiceAliasResource  根据所给的 servicealias 信息,收集对应的 ResourceEntry 列表
   275  func (svr *serverAuthAbility) queryServiceAliasResource(
   276  	req []*apiservice.ServiceAlias) map[apisecurity.ResourceType][]model.ResourceEntry {
   277  	if len(req) == 0 {
   278  		return make(map[apisecurity.ResourceType][]model.ResourceEntry)
   279  	}
   280  
   281  	names := utils.NewSet[string]()
   282  	svcSet := utils.NewMap[string, *model.Service]()
   283  
   284  	for index := range req {
   285  		aliasSvcName := req[index].GetAlias().GetValue()
   286  		aliasSvcNamespace := req[index].GetAliasNamespace().GetValue()
   287  		svcNamespace := req[index].GetNamespace().GetValue()
   288  		names.Add(svcNamespace)
   289  		alias := svr.Cache().Service().GetServiceByName(aliasSvcName, aliasSvcNamespace)
   290  		if alias != nil {
   291  			svc := svr.Cache().Service().GetServiceByID(alias.Reference)
   292  			if svc != nil {
   293  				svcSet.Store(svc.ID, svc)
   294  			}
   295  		}
   296  	}
   297  
   298  	ret := svr.convertToDiscoverResourceEntryMaps(names, svcSet)
   299  	if authLog.DebugEnabled() {
   300  		authLog.Debug("[Auth][Server] collect service alias access res", zap.Any("res", ret))
   301  	}
   302  	return ret
   303  }
   304  
   305  // queryInstanceResource 根据所给的 instances 信息,收集对应的 ResourceEntry 列表
   306  // 由于实例是注册到服务下的,因此只需要判断,是否有对应服务的权限即可
   307  func (svr *serverAuthAbility) queryInstanceResource(
   308  	req []*apiservice.Instance) map[apisecurity.ResourceType][]model.ResourceEntry {
   309  	if len(req) == 0 {
   310  		return make(map[apisecurity.ResourceType][]model.ResourceEntry)
   311  	}
   312  
   313  	names := utils.NewSet[string]()
   314  	svcSet := utils.NewMap[string, *model.Service]()
   315  
   316  	for index := range req {
   317  		svcName := req[index].GetService().GetValue()
   318  		svcNamespace := req[index].GetNamespace().GetValue()
   319  		item := req[index]
   320  		if svcNamespace != "" && svcName != "" {
   321  			svc := svr.Cache().Service().GetServiceByName(svcName, svcNamespace)
   322  			if svc != nil {
   323  				svcSet.Store(svc.ID, svc)
   324  			} else {
   325  				names.Add(svcNamespace)
   326  			}
   327  		} else {
   328  			ins := svr.Cache().Instance().GetInstance(item.GetId().GetValue())
   329  			if ins != nil {
   330  				svc := svr.Cache().Service().GetServiceByID(ins.ServiceID)
   331  				if svc != nil {
   332  					svcSet.Store(svc.ID, svc)
   333  				} else {
   334  					names.Add(svcNamespace)
   335  				}
   336  			}
   337  		}
   338  	}
   339  
   340  	ret := svr.convertToDiscoverResourceEntryMaps(names, svcSet)
   341  	if authLog.DebugEnabled() {
   342  		authLog.Debug("[Auth][Server] collect instance access res", zap.Any("res", ret))
   343  	}
   344  	return ret
   345  }
   346  
   347  // queryCircuitBreakerResource 根据所给的 CircuitBreaker 信息,收集对应的 ResourceEntry 列表
   348  func (svr *serverAuthAbility) queryCircuitBreakerResource(
   349  	req []*apifault.CircuitBreaker) map[apisecurity.ResourceType][]model.ResourceEntry {
   350  	if len(req) == 0 {
   351  		return make(map[apisecurity.ResourceType][]model.ResourceEntry)
   352  	}
   353  
   354  	names := utils.NewSet[string]()
   355  	svcSet := utils.NewMap[string, *model.Service]()
   356  
   357  	for index := range req {
   358  		svcName := req[index].GetService().GetValue()
   359  		svcNamespace := req[index].GetNamespace().GetValue()
   360  		svc := svr.Cache().Service().GetServiceByName(svcName, svcNamespace)
   361  		if svc != nil {
   362  			svcSet.Store(svc.ID, svc)
   363  		}
   364  	}
   365  	ret := svr.convertToDiscoverResourceEntryMaps(names, svcSet)
   366  	if authLog.DebugEnabled() {
   367  		authLog.Debug("[Auth][Server] collect circuit-breaker access res", zap.Any("res", ret))
   368  	}
   369  	return ret
   370  }
   371  
   372  // queryCircuitBreakerReleaseResource 根据所给的 CircuitBreakerRelease 信息,收集对应的 ResourceEntry 列表
   373  func (svr *serverAuthAbility) queryCircuitBreakerReleaseResource(
   374  	req []*apiservice.ConfigRelease) map[apisecurity.ResourceType][]model.ResourceEntry {
   375  	if len(req) == 0 {
   376  		return make(map[apisecurity.ResourceType][]model.ResourceEntry)
   377  	}
   378  
   379  	names := utils.NewSet[string]()
   380  	svcSet := utils.NewMap[string, *model.Service]()
   381  
   382  	for index := range req {
   383  		svcName := req[index].GetService().GetName().GetValue()
   384  		svcNamespace := req[index].GetService().GetNamespace().GetValue()
   385  		svc := svr.Cache().Service().GetServiceByName(svcName, svcNamespace)
   386  		if svc != nil {
   387  			svcSet.Store(svc.ID, svc)
   388  		}
   389  	}
   390  
   391  	ret := svr.convertToDiscoverResourceEntryMaps(names, svcSet)
   392  	if authLog.DebugEnabled() {
   393  		authLog.Debug("[Auth][Server] collect circuit-breaker-release access res", zap.Any("res", ret))
   394  	}
   395  	return ret
   396  }
   397  
   398  // queryRouteRuleResource 根据所给的 RouteRule 信息,收集对应的 ResourceEntry 列表
   399  func (svr *serverAuthAbility) queryRouteRuleResource(
   400  	req []*apitraffic.Routing) map[apisecurity.ResourceType][]model.ResourceEntry {
   401  	if len(req) == 0 {
   402  		return make(map[apisecurity.ResourceType][]model.ResourceEntry)
   403  	}
   404  
   405  	names := utils.NewSet[string]()
   406  	svcSet := utils.NewMap[string, *model.Service]()
   407  
   408  	for index := range req {
   409  		svcName := req[index].GetService().GetValue()
   410  		svcNamespace := req[index].GetNamespace().GetValue()
   411  		svc := svr.Cache().Service().GetServiceByName(svcName, svcNamespace)
   412  		if svc != nil {
   413  			svcSet.Store(svc.ID, svc)
   414  		}
   415  	}
   416  
   417  	ret := svr.convertToDiscoverResourceEntryMaps(names, svcSet)
   418  	if authLog.DebugEnabled() {
   419  		authLog.Debug("[Auth][Server] collect route-rule access res", zap.Any("res", ret))
   420  	}
   421  	return ret
   422  }
   423  
   424  // queryRateLimitConfigResource 根据所给的 RateLimit 信息,收集对应的 ResourceEntry 列表
   425  func (svr *serverAuthAbility) queryRateLimitConfigResource(
   426  	req []*apitraffic.Rule) map[apisecurity.ResourceType][]model.ResourceEntry {
   427  	if len(req) == 0 {
   428  		return make(map[apisecurity.ResourceType][]model.ResourceEntry)
   429  	}
   430  
   431  	names := utils.NewSet[string]()
   432  	svcSet := utils.NewMap[string, *model.Service]()
   433  
   434  	for index := range req {
   435  		svcName := req[index].GetService().GetValue()
   436  		svcNamespace := req[index].GetNamespace().GetValue()
   437  		svc := svr.Cache().Service().GetServiceByName(svcName, svcNamespace)
   438  		if svc != nil {
   439  			svcSet.Store(svc.ID, svc)
   440  		}
   441  	}
   442  
   443  	ret := svr.convertToDiscoverResourceEntryMaps(names, svcSet)
   444  	if authLog.DebugEnabled() {
   445  		authLog.Debug("[Auth][Server] collect rate-limit access res", zap.Any("res", ret))
   446  	}
   447  	return ret
   448  }
   449  
   450  // convertToDiscoverResourceEntryMaps 通用方法,进行转换为期望的、服务相关的 ResourceEntry
   451  func (svr *serverAuthAbility) convertToDiscoverResourceEntryMaps(nsSet *utils.Set[string],
   452  	svcSet *utils.Map[string, *model.Service]) map[apisecurity.ResourceType][]model.ResourceEntry {
   453  	var (
   454  		param = nsSet.ToSlice()
   455  		nsArr = svr.Cache().Namespace().GetNamespacesByName(param)
   456  		nsRet = make([]model.ResourceEntry, 0, len(nsArr))
   457  	)
   458  	for index := range nsArr {
   459  		ns := nsArr[index]
   460  		nsRet = append(nsRet, model.ResourceEntry{
   461  			ID:    ns.Name,
   462  			Owner: ns.Owner,
   463  		})
   464  	}
   465  
   466  	svcRet := make([]model.ResourceEntry, 0, svcSet.Len())
   467  	svcSet.Range(func(key string, svc *model.Service) {
   468  		svcRet = append(svcRet, model.ResourceEntry{
   469  			ID:    svc.ID,
   470  			Owner: svc.Owner,
   471  		})
   472  	})
   473  
   474  	return map[apisecurity.ResourceType][]model.ResourceEntry{
   475  		apisecurity.ResourceType_Namespaces: nsRet,
   476  		apisecurity.ResourceType_Services:   svcRet,
   477  	}
   478  }
   479  
   480  func convertToErrCode(err error) apimodel.Code {
   481  	if errors.Is(err, model.ErrorTokenNotExist) {
   482  		return apimodel.Code_TokenNotExisted
   483  	}
   484  	if errors.Is(err, model.ErrorTokenDisabled) {
   485  		return apimodel.Code_TokenDisabled
   486  	}
   487  	return apimodel.Code_NotAllowedAccess
   488  }