Wire batch authorize into server APIs
Add authz.NewBatchAuthorizeFunc — the batch counterpart to the existing AuthorizeFunc — together with WithBatchAttr, WithBatchSkipAssumptionCheck, and WithBatchDryRun options. It maps the new batch errors (mixed organization, empty batch, unsupported resource type) to GraphQL Invalid responses, and reuses the existing mappings for ErrAssumptionRequired / ErrInsufficientPermissions / ErrResourceNotFound. Plumb the new function into the Connect and Console resolvers and add Resolver.AuthorizeBatch to the MCP resolver with equivalent error mapping for tool callers. Signed-off-by: Bryan Frimin <bryan@probo.com>
This commit is contained in:
@@ -27,8 +27,10 @@ import (
|
||||
)
|
||||
|
||||
type (
|
||||
AuthorizeFuncOption func(*iam.AuthorizeParams)
|
||||
AuthorizeFunc func(context.Context, gid.GID, string, ...AuthorizeFuncOption) (*coredata.Scope, error)
|
||||
AuthorizeFuncOption func(*iam.AuthorizeParams)
|
||||
AuthorizeFunc func(context.Context, gid.GID, string, ...AuthorizeFuncOption) (*coredata.Scope, error)
|
||||
BatchAuthorizeFuncOption func(*iam.AuthorizeBatchParams)
|
||||
BatchAuthorizeFunc func(context.Context, string, []gid.GID, ...BatchAuthorizeFuncOption) (*coredata.Scope, error)
|
||||
)
|
||||
|
||||
func WithAttr(key, value string) AuthorizeFuncOption {
|
||||
@@ -51,6 +53,24 @@ func WithDryRun() AuthorizeFuncOption {
|
||||
}
|
||||
}
|
||||
|
||||
func WithBatchAttr(key, value string) BatchAuthorizeFuncOption {
|
||||
return func(params *iam.AuthorizeBatchParams) {
|
||||
params.ResourceAttributes[key] = value
|
||||
}
|
||||
}
|
||||
|
||||
func WithBatchSkipAssumptionCheck() BatchAuthorizeFuncOption {
|
||||
return func(params *iam.AuthorizeBatchParams) {
|
||||
params.SkipAssumptionCheck = true
|
||||
}
|
||||
}
|
||||
|
||||
func WithBatchDryRun() BatchAuthorizeFuncOption {
|
||||
return func(params *iam.AuthorizeBatchParams) {
|
||||
params.DryRun = true
|
||||
}
|
||||
}
|
||||
|
||||
func NewAuthorizeFunc(
|
||||
svc *iam.Service,
|
||||
logger *log.Logger,
|
||||
@@ -100,3 +120,65 @@ func NewAuthorizeFunc(
|
||||
return scope, nil
|
||||
}
|
||||
}
|
||||
|
||||
func NewBatchAuthorizeFunc(
|
||||
svc *iam.Service,
|
||||
logger *log.Logger,
|
||||
) BatchAuthorizeFunc {
|
||||
return func(
|
||||
ctx context.Context,
|
||||
action string,
|
||||
objectIDs []gid.GID,
|
||||
options ...BatchAuthorizeFuncOption,
|
||||
) (*coredata.Scope, error) {
|
||||
identity := authn.IdentityFromContext(ctx)
|
||||
session := authn.SessionFromContext(ctx)
|
||||
|
||||
params := iam.AuthorizeBatchParams{
|
||||
Principal: identity.ID,
|
||||
Action: action,
|
||||
Resources: objectIDs,
|
||||
ResourceAttributes: make(map[string]string),
|
||||
}
|
||||
if session != nil {
|
||||
params.Session = &session.ID
|
||||
}
|
||||
|
||||
for _, option := range options {
|
||||
option(¶ms)
|
||||
}
|
||||
|
||||
scope, err := svc.Authorizer.AuthorizeBatch(ctx, params)
|
||||
if err != nil {
|
||||
if _, ok := errors.AsType[*iam.ErrAssumptionRequired](err); ok {
|
||||
return nil, gqlutils.AssumptionRequired(ctx, err)
|
||||
}
|
||||
|
||||
if _, ok := errors.AsType[*iam.ErrInsufficientPermissions](err); ok {
|
||||
return nil, gqlutils.Forbidden(ctx, err)
|
||||
}
|
||||
|
||||
if _, ok := errors.AsType[*iam.ErrMixedOrganizationBatch](err); ok {
|
||||
return nil, gqlutils.Invalid(ctx, err)
|
||||
}
|
||||
|
||||
if _, ok := errors.AsType[*iam.ErrEmptyResourceBatch](err); ok {
|
||||
return nil, gqlutils.Invalid(ctx, err)
|
||||
}
|
||||
|
||||
if _, ok := errors.AsType[*iam.ErrBatchAuthorizationUnsupportedResourceType](err); ok {
|
||||
return nil, gqlutils.Invalid(ctx, err)
|
||||
}
|
||||
|
||||
if errors.Is(err, coredata.ErrResourceNotFound) {
|
||||
return nil, gqlutils.NotFoundf(ctx, "resource not found")
|
||||
}
|
||||
|
||||
logger.ErrorCtx(ctx, "cannot batch authorize", log.Error(err))
|
||||
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return scope, nil
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user