Multiple grant scope IDs (#4251)

Co-authored-by: Timothy Messier <tim.messier@gmail.com>
Co-authored-by: Todd <github@quaddi.com>
This commit is contained in:
authored and GitHub committed 2024-01-23 14:33:09 -05:00
1 parent 659df2797c
commit f5dd457b34
70 files changed
+5460 -1009

No files matched your search

@@ -6,6 +6,8 @@ package roles
import (
"context"
"fmt"
"sort"
"strings"
"github.com/hashicorp/boundary/globals"
"github.com/hashicorp/boundary/internal/daemon/controller/auth"
@@ -47,6 +49,9 @@ var (
action.AddGrants,
action.SetGrants,
action.RemoveGrants,
action.AddGrantScopes,
action.SetGrantScopes,
action.RemoveGrantScopes,
)
// CollectionActions contains the set of actions that can be performed on
@@ -144,7 +149,7 @@ func (s Service) ListRoles(ctx context.Context, req *pbs.ListRolesRequest) (*pbs
if !ok {
return false, nil
}
pbItem, err := toProto(ctx, item, nil, nil, outputOpts...)
pbItem, err := toProto(ctx, item, nil, nil, nil, outputOpts...)
if err != nil {
return false, err
}
@@ -209,7 +214,7 @@ func (s Service) ListRoles(ctx context.Context, req *pbs.ListRolesRequest) (*pbs
if !ok {
continue
}
item, err := toProto(ctx, item, nil, nil, outputOpts...)
item, err := toProto(ctx, item, nil, nil, nil, outputOpts...)
if err != nil {
return nil, errors.Wrap(ctx, err, op)
}
@@ -248,7 +253,7 @@ func (s Service) GetRole(ctx context.Context, req *pbs.GetRoleRequest) (*pbs.Get
if authResults.Error != nil {
return nil, authResults.Error
}
r, prs, rgs, err := s.getFromRepo(ctx, req.GetId())
r, prs, rgs, grantScopes, err := s.getFromRepo(ctx, req.GetId())
if err != nil {
return nil, err
}
@@ -267,7 +272,7 @@ func (s Service) GetRole(ctx context.Context, req *pbs.GetRoleRequest) (*pbs.Get
outputOpts = append(outputOpts, handlers.WithAuthorizedActions(authResults.FetchActionSetForId(ctx, r.GetPublicId(), IdActions).Strings()))
}
item, err := toProto(ctx, r, prs, rgs, outputOpts...)
item, err := toProto(ctx, r, prs, rgs, grantScopes, outputOpts...)
if err != nil {
return nil, err
}
@@ -286,7 +291,7 @@ func (s Service) CreateRole(ctx context.Context, req *pbs.CreateRoleRequest) (*p
if authResults.Error != nil {
return nil, authResults.Error
}
r, err := s.createInRepo(ctx, authResults.Scope.GetId(), req.GetItem())
r, prs, rgs, grantScopes, err := s.createInRepo(ctx, authResults.Scope.GetId(), req.GetItem())
if err != nil {
return nil, err
}
@@ -305,7 +310,7 @@ func (s Service) CreateRole(ctx context.Context, req *pbs.CreateRoleRequest) (*p
outputOpts = append(outputOpts, handlers.WithAuthorizedActions(authResults.FetchActionSetForId(ctx, r.GetPublicId(), IdActions).Strings()))
}
item, err := toProto(ctx, r, nil, nil, outputOpts...)
item, err := toProto(ctx, r, prs, rgs, grantScopes, outputOpts...)
if err != nil {
return nil, err
}
@@ -324,7 +329,7 @@ func (s Service) UpdateRole(ctx context.Context, req *pbs.UpdateRoleRequest) (*p
if authResults.Error != nil {
return nil, authResults.Error
}
r, prs, rgs, err := s.updateInRepo(ctx, authResults.Scope.GetId(), req.GetId(), req.GetUpdateMask().GetPaths(), req.GetItem())
r, prs, rgs, grantScopes, err := s.updateInRepo(ctx, authResults.Scope.GetId(), req.GetId(), req.GetUpdateMask().GetPaths(), req.GetItem())
if err != nil {
return nil, err
}
@@ -343,7 +348,7 @@ func (s Service) UpdateRole(ctx context.Context, req *pbs.UpdateRoleRequest) (*p
outputOpts = append(outputOpts, handlers.WithAuthorizedActions(authResults.FetchActionSetForId(ctx, r.GetPublicId(), IdActions).Strings()))
}
item, err := toProto(ctx, r, prs, rgs, outputOpts...)
item, err := toProto(ctx, r, prs, rgs, grantScopes, outputOpts...)
if err != nil {
return nil, err
}
@@ -378,7 +383,7 @@ func (s Service) AddRolePrincipals(ctx context.Context, req *pbs.AddRolePrincipa
if authResults.Error != nil {
return nil, authResults.Error
}
r, prs, rgs, err := s.addPrinciplesInRepo(ctx, req.GetId(), req.GetPrincipalIds(), req.GetVersion())
r, prs, rgs, grantScopes, err := s.addPrincipalsInRepo(ctx, req.GetId(), req.GetPrincipalIds(), req.GetVersion())
if err != nil {
return nil, err
}
@@ -397,7 +402,7 @@ func (s Service) AddRolePrincipals(ctx context.Context, req *pbs.AddRolePrincipa
outputOpts = append(outputOpts, handlers.WithAuthorizedActions(authResults.FetchActionSetForId(ctx, r.GetPublicId(), IdActions).Strings()))
}
item, err := toProto(ctx, r, prs, rgs, outputOpts...)
item, err := toProto(ctx, r, prs, rgs, grantScopes, outputOpts...)
if err != nil {
return nil, err
}
@@ -416,7 +421,7 @@ func (s Service) SetRolePrincipals(ctx context.Context, req *pbs.SetRolePrincipa
if authResults.Error != nil {
return nil, authResults.Error
}
r, prs, rgs, err := s.setPrinciplesInRepo(ctx, req.GetId(), req.GetPrincipalIds(), req.GetVersion())
r, prs, rgs, grantScopes, err := s.setPrincipalsInRepo(ctx, req.GetId(), req.GetPrincipalIds(), req.GetVersion())
if err != nil {
return nil, err
}
@@ -435,7 +440,7 @@ func (s Service) SetRolePrincipals(ctx context.Context, req *pbs.SetRolePrincipa
outputOpts = append(outputOpts, handlers.WithAuthorizedActions(authResults.FetchActionSetForId(ctx, r.GetPublicId(), IdActions).Strings()))
}
item, err := toProto(ctx, r, prs, rgs, outputOpts...)
item, err := toProto(ctx, r, prs, rgs, grantScopes, outputOpts...)
if err != nil {
return nil, err
}
@@ -454,7 +459,7 @@ func (s Service) RemoveRolePrincipals(ctx context.Context, req *pbs.RemoveRolePr
if authResults.Error != nil {
return nil, authResults.Error
}
r, prs, rgs, err := s.removePrinciplesInRepo(ctx, req.GetId(), req.GetPrincipalIds(), req.GetVersion())
r, prs, rgs, grantScopes, err := s.removePrincipalsInRepo(ctx, req.GetId(), req.GetPrincipalIds(), req.GetVersion())
if err != nil {
return nil, err
}
@@ -473,7 +478,7 @@ func (s Service) RemoveRolePrincipals(ctx context.Context, req *pbs.RemoveRolePr
outputOpts = append(outputOpts, handlers.WithAuthorizedActions(authResults.FetchActionSetForId(ctx, r.GetPublicId(), IdActions).Strings()))
}
item, err := toProto(ctx, r, prs, rgs, outputOpts...)
item, err := toProto(ctx, r, prs, rgs, grantScopes, outputOpts...)
if err != nil {
return nil, err
}
@@ -492,7 +497,7 @@ func (s Service) AddRoleGrants(ctx context.Context, req *pbs.AddRoleGrantsReques
if authResults.Error != nil {
return nil, authResults.Error
}
r, prs, rgs, err := s.addGrantsInRepo(ctx, req.GetId(), req.GetGrantStrings(), req.GetVersion())
r, prs, rgs, grantScopes, err := s.addGrantsInRepo(ctx, req.GetId(), req.GetGrantStrings(), req.GetVersion())
if err != nil {
return nil, err
}
@@ -511,7 +516,7 @@ func (s Service) AddRoleGrants(ctx context.Context, req *pbs.AddRoleGrantsReques
outputOpts = append(outputOpts, handlers.WithAuthorizedActions(authResults.FetchActionSetForId(ctx, r.GetPublicId(), IdActions).Strings()))
}
item, err := toProto(ctx, r, prs, rgs, outputOpts...)
item, err := toProto(ctx, r, prs, rgs, grantScopes, outputOpts...)
if err != nil {
return nil, err
}
@@ -530,7 +535,7 @@ func (s Service) SetRoleGrants(ctx context.Context, req *pbs.SetRoleGrantsReques
if authResults.Error != nil {
return nil, authResults.Error
}
r, prs, rgs, err := s.setGrantsInRepo(ctx, req.GetId(), req.GetGrantStrings(), req.GetVersion())
r, prs, rgs, grantScopes, err := s.setGrantsInRepo(ctx, req.GetId(), req.GetGrantStrings(), req.GetVersion())
if err != nil {
return nil, err
}
@@ -549,7 +554,7 @@ func (s Service) SetRoleGrants(ctx context.Context, req *pbs.SetRoleGrantsReques
outputOpts = append(outputOpts, handlers.WithAuthorizedActions(authResults.FetchActionSetForId(ctx, r.GetPublicId(), IdActions).Strings()))
}
item, err := toProto(ctx, r, prs, rgs, outputOpts...)
item, err := toProto(ctx, r, prs, rgs, grantScopes, outputOpts...)
if err != nil {
return nil, err
}
@@ -568,7 +573,7 @@ func (s Service) RemoveRoleGrants(ctx context.Context, req *pbs.RemoveRoleGrants
if authResults.Error != nil {
return nil, authResults.Error
}
r, prs, rgs, err := s.removeGrantsInRepo(ctx, req.GetId(), req.GetGrantStrings(), req.GetVersion())
r, prs, rgs, grantScopes, err := s.removeGrantsInRepo(ctx, req.GetId(), req.GetGrantStrings(), req.GetVersion())
if err != nil {
return nil, err
}
@@ -587,7 +592,7 @@ func (s Service) RemoveRoleGrants(ctx context.Context, req *pbs.RemoveRoleGrants
outputOpts = append(outputOpts, handlers.WithAuthorizedActions(authResults.FetchActionSetForId(ctx, r.GetPublicId(), IdActions).Strings()))
}
item, err := toProto(ctx, r, prs, rgs, outputOpts...)
item, err := toProto(ctx, r, prs, rgs, grantScopes, outputOpts...)
if err != nil {
return nil, err
}
@@ -595,25 +600,142 @@ func (s Service) RemoveRoleGrants(ctx context.Context, req *pbs.RemoveRoleGrants
return &pbs.RemoveRoleGrantsResponse{Item: item}, nil
}
func (s Service) getFromRepo(ctx context.Context, id string) (*iam.Role, []*iam.PrincipalRole, []*iam.RoleGrant, error) {
repo, err := s.repoFn()
// AddRoleGrantScopes implements the interface pbs.RoleServiceServer.
func (s Service) AddRoleGrantScopes(ctx context.Context, req *pbs.AddRoleGrantScopesRequest) (*pbs.AddRoleGrantScopesResponse, error) {
const op = "roles.(Service).AddRoleGrantScopes"
if err := validateRoleGrantScopesRequest(ctx, req); err != nil {
return nil, err
}
authResults := s.authResult(ctx, req.GetId(), action.AddGrantScopes)
if authResults.Error != nil {
return nil, authResults.Error
}
r, prs, rgs, grantScopes, err := s.addGrantScopesInRepo(ctx, req)
if err != nil {
return nil, nil, nil, err
return nil, err
}
out, pr, roleGrants, err := repo.LookupRole(ctx, id)
outputFields, ok := requests.OutputFields(ctx)
if !ok {
return nil, errors.New(ctx, errors.Internal, op, "no request context found")
}
outputOpts := make([]handlers.Option, 0, 3)
outputOpts = append(outputOpts, handlers.WithOutputFields(outputFields))
if outputFields.Has(globals.ScopeField) {
outputOpts = append(outputOpts, handlers.WithScope(authResults.Scope))
}
if outputFields.Has(globals.AuthorizedActionsField) {
outputOpts = append(outputOpts, handlers.WithAuthorizedActions(authResults.FetchActionSetForId(ctx, r.GetPublicId(), IdActions).Strings()))
}
item, err := toProto(ctx, r, prs, rgs, grantScopes, outputOpts...)
if err != nil {
if errors.IsNotFoundError(err) {
return nil, nil, nil, handlers.NotFoundErrorf("Role %q doesn't exist.", id)
}
return nil, nil, nil, err
return nil, err
}
if out == nil {
return nil, nil, nil, handlers.NotFoundErrorf("Role %q doesn't exist.", id)
}
return out, pr, roleGrants, nil
return &pbs.AddRoleGrantScopesResponse{Item: item}, nil
}
func (s Service) createInRepo(ctx context.Context, scopeId string, item *pb.Role) (*iam.Role, error) {
// SetRoleGrantScopes implements the interface pbs.RoleServiceServer.
func (s Service) SetRoleGrantScopes(ctx context.Context, req *pbs.SetRoleGrantScopesRequest) (*pbs.SetRoleGrantScopesResponse, error) {
const op = "roles.(Service).SetRoleGrantScopes"
if err := validateRoleGrantScopesRequest(ctx, req); err != nil {
return nil, err
}
authResults := s.authResult(ctx, req.GetId(), action.SetGrantScopes)
if authResults.Error != nil {
return nil, authResults.Error
}
r, prs, rgs, grantScopes, err := s.setGrantScopesInRepo(ctx, req)
if err != nil {
return nil, err
}
outputFields, ok := requests.OutputFields(ctx)
if !ok {
return nil, errors.New(ctx, errors.Internal, op, "no request context found")
}
outputOpts := make([]handlers.Option, 0, 3)
outputOpts = append(outputOpts, handlers.WithOutputFields(outputFields))
if outputFields.Has(globals.ScopeField) {
outputOpts = append(outputOpts, handlers.WithScope(authResults.Scope))
}
if outputFields.Has(globals.AuthorizedActionsField) {
outputOpts = append(outputOpts, handlers.WithAuthorizedActions(authResults.FetchActionSetForId(ctx, r.GetPublicId(), IdActions).Strings()))
}
item, err := toProto(ctx, r, prs, rgs, grantScopes, outputOpts...)
if err != nil {
return nil, err
}
return &pbs.SetRoleGrantScopesResponse{Item: item}, nil
}
// RemoveRoleGrantScopes implements the interface pbs.RoleServiceServer.
func (s Service) RemoveRoleGrantScopes(ctx context.Context, req *pbs.RemoveRoleGrantScopesRequest) (*pbs.RemoveRoleGrantScopesResponse, error) {
const op = "roles.(Service).RemoveRoleGrantScopes"
if err := validateRoleGrantScopesRequest(ctx, req); err != nil {
return nil, err
}
authResults := s.authResult(ctx, req.GetId(), action.RemoveGrants)
if authResults.Error != nil {
return nil, authResults.Error
}
r, prs, rgs, grantScopes, err := s.removeGrantScopesInRepo(ctx, req)
if err != nil {
return nil, err
}
outputFields, ok := requests.OutputFields(ctx)
if !ok {
return nil, errors.New(ctx, errors.Internal, op, "no request context found")
}
outputOpts := make([]handlers.Option, 0, 3)
outputOpts = append(outputOpts, handlers.WithOutputFields(outputFields))
if outputFields.Has(globals.ScopeField) {
outputOpts = append(outputOpts, handlers.WithScope(authResults.Scope))
}
if outputFields.Has(globals.AuthorizedActionsField) {
outputOpts = append(outputOpts, handlers.WithAuthorizedActions(authResults.FetchActionSetForId(ctx, r.GetPublicId(), IdActions).Strings()))
}
item, err := toProto(ctx, r, prs, rgs, grantScopes, outputOpts...)
if err != nil {
return nil, err
}
return &pbs.RemoveRoleGrantScopesResponse{Item: item}, nil
}
func (s Service) getFromRepo(ctx context.Context, id string) (*iam.Role, []*iam.PrincipalRole, []*iam.RoleGrant, []*iam.RoleGrantScope, error) {
repo, err := s.repoFn()
if err != nil {
return nil, nil, nil, nil, err
}
out, pr, roleGrants, roleGrantScopes, err := repo.LookupRole(ctx, id)
if err != nil {
if errors.IsNotFoundError(err) {
return nil, nil, nil, nil, handlers.NotFoundErrorf("Role %q doesn't exist.", id)
}
return nil, nil, nil, nil, err
}
if out == nil {
return nil, nil, nil, nil, handlers.NotFoundErrorf("Role %q doesn't exist.", id)
}
return out, pr, roleGrants, roleGrantScopes, nil
}
func (s Service) createInRepo(ctx context.Context, scopeId string, item *pb.Role) (*iam.Role, []*iam.PrincipalRole, []*iam.RoleGrant, []*iam.RoleGrantScope, error) {
const op = "roles.(Service).createInRepo"
var opts []iam.Option
if item.GetName() != nil {
@@ -627,23 +749,23 @@ func (s Service) createInRepo(ctx context.Context, scopeId string, item *pb.Role
}
u, err := iam.NewRole(ctx, scopeId, opts...)
if err != nil {
return nil, handlers.ApiErrorWithCodeAndMessage(codes.Internal, "Unable to build role for creation: %v.", err)
return nil, nil, nil, nil, handlers.ApiErrorWithCodeAndMessage(codes.Internal, "Unable to build role for creation: %v.", err)
}
repo, err := s.repoFn()
if err != nil {
return nil, err
return nil, nil, nil, nil, err
}
out, err := repo.CreateRole(ctx, u)
out, pr, roleGrants, roleGrantScopes, err := repo.CreateRole(ctx, u, opts...)
if err != nil {
return nil, errors.Wrap(ctx, err, op)
return nil, nil, nil, nil, errors.Wrap(ctx, err, op)
}
if out == nil {
return nil, handlers.ApiErrorWithCodeAndMessage(codes.Internal, "Unable to create role but no error returned from repository.")
return nil, nil, nil, nil, handlers.ApiErrorWithCodeAndMessage(codes.Internal, "Unable to create role but no error returned from repository.")
}
return out, nil
return out, pr, roleGrants, roleGrantScopes, nil
}
func (s Service) updateInRepo(ctx context.Context, scopeId, id string, mask []string, item *pb.Role) (*iam.Role, []*iam.PrincipalRole, []*iam.RoleGrant, error) {
func (s Service) updateInRepo(ctx context.Context, scopeId, id string, mask []string, item *pb.Role) (*iam.Role, []*iam.PrincipalRole, []*iam.RoleGrant, []*iam.RoleGrantScope, error) {
const op = "roles.(Service).updateInRepo"
var opts []iam.Option
if desc := item.GetDescription(); desc != nil {
@@ -652,32 +774,54 @@ func (s Service) updateInRepo(ctx context.Context, scopeId, id string, mask []st
if name := item.GetName(); name != nil {
opts = append(opts, iam.WithName(name.GetValue()))
}
if grantScopeId := item.GetGrantScopeId(); grantScopeId != nil {
opts = append(opts, iam.WithGrantScopeId(grantScopeId.GetValue()))
}
version := item.GetVersion()
u, err := iam.NewRole(ctx, scopeId, opts...)
if err != nil {
return nil, nil, nil, handlers.ApiErrorWithCodeAndMessage(codes.Internal, "Unable to build role for update: %v.", err)
return nil, nil, nil, nil, handlers.ApiErrorWithCodeAndMessage(codes.Internal, "Unable to build role for update: %v.", err)
}
u.PublicId = id
dbMask := maskManager.Translate(mask)
if len(dbMask) == 0 {
return nil, nil, nil, handlers.InvalidArgumentErrorf("No valid fields included in the update mask.", map[string]string{"update_mask": "No valid fields provided in the update mask."})
}
repo, err := s.repoFn()
if err != nil {
return nil, nil, nil, err
return nil, nil, nil, nil, err
}
out, pr, gr, rowsUpdated, err := repo.UpdateRole(ctx, u, version, dbMask)
// This has to be separate from Translate since the field only exists on the
// API side now.
var hasGrantScopeIdMask bool
if grantScopeId := item.GetGrantScopeId(); grantScopeId != nil {
// Have to manually check the masks, which could be concatenated strings or slices
for _, v := range mask {
if strutil.StrListContains(strings.Split(v, ","), "grant_scope_id") {
opts = append(opts, iam.WithGrantScopeId(grantScopeId.GetValue()))
hasGrantScopeIdMask = true
break
}
}
if hasGrantScopeIdMask {
if err := validateRoleGrantScopesHierarchy(ctx, repo, id, []string{item.GetGrantScopeId().GetValue()}); err != nil {
return nil, nil, nil, nil, err
}
}
}
dbMask := maskManager.Translate(mask)
if len(dbMask) == 0 && !hasGrantScopeIdMask {
return nil, nil, nil, nil, handlers.InvalidArgumentErrorf("No valid fields provided in the update mask.", map[string]string{"update_mask": "No valid fields provided in the update mask."})
}
out, pr, gr, grantScopes, rowsUpdated, err := repo.UpdateRole(ctx, u, version, dbMask, opts...)
if err != nil {
return nil, nil, nil, errors.Wrap(ctx, err, op)
return nil, nil, nil, nil, errors.Wrap(ctx, err, op)
}
if rowsUpdated == 0 {
return nil, nil, nil, handlers.NotFoundErrorf("Role %q doesn't exist or incorrect version provided.", id)
// This is slightly problematic but it's a very unlikely error case and when
// we remove the ability to update grant scope ID via here in 0.17 it will
// go away.
if rowsUpdated == 0 && !hasGrantScopeIdMask {
return nil, nil, nil, nil, handlers.NotFoundErrorf("Role %q doesn't exist or incorrect version provided.", id)
}
return out, pr, gr, nil
return out, pr, gr, grantScopes, nil
}
func (s Service) deleteFromRepo(ctx context.Context, id string) (bool, error) {
@@ -696,95 +840,95 @@ func (s Service) deleteFromRepo(ctx context.Context, id string) (bool, error) {
return rows > 0, nil
}
func (s Service) addPrinciplesInRepo(ctx context.Context, roleId string, principalIds []string, version uint32) (*iam.Role, []*iam.PrincipalRole, []*iam.RoleGrant, error) {
func (s Service) addPrincipalsInRepo(ctx context.Context, roleId string, principalIds []string, version uint32) (*iam.Role, []*iam.PrincipalRole, []*iam.RoleGrant, []*iam.RoleGrantScope, error) {
const op = "roles.(Service).addPrincpleInRepo"
repo, err := s.repoFn()
if err != nil {
return nil, nil, nil, err
return nil, nil, nil, nil, err
}
_, err = repo.AddPrincipalRoles(ctx, roleId, version, strutil.RemoveDuplicates(principalIds, false))
if err != nil {
// TODO: Figure out a way to surface more helpful error info beyond the Internal error.
return nil, nil, nil, handlers.ApiErrorWithCodeAndMessage(codes.Internal, "Unable to add principals to role: %v.", err)
return nil, nil, nil, nil, handlers.ApiErrorWithCodeAndMessage(codes.Internal, "Unable to add principals to role: %v.", err)
}
out, pr, roleGrants, err := repo.LookupRole(ctx, roleId)
out, pr, roleGrants, grantScopes, err := repo.LookupRole(ctx, roleId)
if err != nil {
return nil, nil, nil, errors.Wrap(ctx, err, op, errors.WithMsg("unable to look up role after adding principals"))
return nil, nil, nil, nil, errors.Wrap(ctx, err, op, errors.WithMsg("unable to look up role after adding principals"))
}
if out == nil {
return nil, nil, nil, handlers.ApiErrorWithCodeAndMessage(codes.Internal, "Unable to lookup role after adding principals to it.")
return nil, nil, nil, nil, handlers.ApiErrorWithCodeAndMessage(codes.Internal, "Unable to lookup role after adding principals to it.")
}
return out, pr, roleGrants, nil
return out, pr, roleGrants, grantScopes, nil
}
func (s Service) setPrinciplesInRepo(ctx context.Context, roleId string, principalIds []string, version uint32) (*iam.Role, []*iam.PrincipalRole, []*iam.RoleGrant, error) {
const op = "roles.(Service).setPrinciplesInRepo"
func (s Service) setPrincipalsInRepo(ctx context.Context, roleId string, principalIds []string, version uint32) (*iam.Role, []*iam.PrincipalRole, []*iam.RoleGrant, []*iam.RoleGrantScope, error) {
const op = "roles.(Service).setPrincipalsInRepo"
repo, err := s.repoFn()
if err != nil {
return nil, nil, nil, err
return nil, nil, nil, nil, err
}
_, _, err = repo.SetPrincipalRoles(ctx, roleId, version, strutil.RemoveDuplicates(principalIds, false))
if err != nil {
// TODO: Figure out a way to surface more helpful error info beyond the Internal error.
return nil, nil, nil, handlers.ApiErrorWithCodeAndMessage(codes.Internal, "Unable to set principals on role: %v.", err)
return nil, nil, nil, nil, handlers.ApiErrorWithCodeAndMessage(codes.Internal, "Unable to set principals on role: %v.", err)
}
out, pr, roleGrants, err := repo.LookupRole(ctx, roleId)
out, pr, roleGrants, grantScopes, err := repo.LookupRole(ctx, roleId)
if err != nil {
return nil, nil, nil, errors.Wrap(ctx, err, op, errors.WithMsg("unable to look up role after setting principals"))
return nil, nil, nil, nil, errors.Wrap(ctx, err, op, errors.WithMsg("unable to look up role after setting principals"))
}
if out == nil {
return nil, nil, nil, handlers.ApiErrorWithCodeAndMessage(codes.Internal, "Unable to lookup role after setting principals for it.")
return nil, nil, nil, nil, handlers.ApiErrorWithCodeAndMessage(codes.Internal, "Unable to lookup role after setting principals for it.")
}
return out, pr, roleGrants, nil
return out, pr, roleGrants, grantScopes, nil
}
func (s Service) removePrinciplesInRepo(ctx context.Context, roleId string, principalIds []string, version uint32) (*iam.Role, []*iam.PrincipalRole, []*iam.RoleGrant, error) {
const op = "roles.(Service).removePrinciplesInRepo"
func (s Service) removePrincipalsInRepo(ctx context.Context, roleId string, principalIds []string, version uint32) (*iam.Role, []*iam.PrincipalRole, []*iam.RoleGrant, []*iam.RoleGrantScope, error) {
const op = "roles.(Service).removePrincipalsInRepo"
repo, err := s.repoFn()
if err != nil {
return nil, nil, nil, err
return nil, nil, nil, nil, err
}
_, err = repo.DeletePrincipalRoles(ctx, roleId, version, strutil.RemoveDuplicates(principalIds, false))
if err != nil {
// TODO: Figure out a way to surface more helpful error info beyond the Internal error.
return nil, nil, nil, handlers.ApiErrorWithCodeAndMessage(codes.Internal, "Unable to remove principals from role: %v.", err)
return nil, nil, nil, nil, handlers.ApiErrorWithCodeAndMessage(codes.Internal, "Unable to remove principals from role: %v.", err)
}
out, pr, roleGrants, err := repo.LookupRole(ctx, roleId)
out, pr, roleGrants, grantScopes, err := repo.LookupRole(ctx, roleId)
if err != nil {
return nil, nil, nil, errors.Wrap(ctx, err, op, errors.WithMsg("unable to look up role after removing principals"))
return nil, nil, nil, nil, errors.Wrap(ctx, err, op, errors.WithMsg("unable to look up role after removing principals"))
}
if out == nil {
return nil, nil, nil, handlers.ApiErrorWithCodeAndMessage(codes.Internal, "Unable to lookup role after removing principals from it.")
return nil, nil, nil, nil, handlers.ApiErrorWithCodeAndMessage(codes.Internal, "Unable to lookup role after removing principals from it.")
}
return out, pr, roleGrants, nil
return out, pr, roleGrants, grantScopes, nil
}
func (s Service) addGrantsInRepo(ctx context.Context, roleId string, grants []string, version uint32) (*iam.Role, []*iam.PrincipalRole, []*iam.RoleGrant, error) {
func (s Service) addGrantsInRepo(ctx context.Context, roleId string, grants []string, version uint32) (*iam.Role, []*iam.PrincipalRole, []*iam.RoleGrant, []*iam.RoleGrantScope, error) {
const op = "service.(Service).addGrantsInRepo"
repo, err := s.repoFn()
if err != nil {
return nil, nil, nil, err
return nil, nil, nil, nil, err
}
_, err = repo.AddRoleGrants(ctx, roleId, version, strutil.RemoveDuplicates(grants, false))
if err != nil {
// TODO: Figure out a way to surface more helpful error info beyond the Internal error.
return nil, nil, nil, handlers.ApiErrorWithCodeAndMessage(codes.Internal, "Unable to add grants to role: %v.", err)
return nil, nil, nil, nil, handlers.ApiErrorWithCodeAndMessage(codes.Internal, "Unable to add grants to role: %v.", err)
}
out, pr, roleGrants, err := repo.LookupRole(ctx, roleId)
out, pr, roleGrants, grantScopes, err := repo.LookupRole(ctx, roleId)
if err != nil {
return nil, nil, nil, errors.Wrap(ctx, err, op, errors.WithMsg("unable to look up role after adding grants"))
return nil, nil, nil, nil, errors.Wrap(ctx, err, op, errors.WithMsg("unable to look up role after adding grants"))
}
if out == nil {
return nil, nil, nil, handlers.ApiErrorWithCodeAndMessage(codes.Internal, "Unable to lookup role after adding grants to it.")
return nil, nil, nil, nil, handlers.ApiErrorWithCodeAndMessage(codes.Internal, "Unable to lookup role after adding grants to it.")
}
return out, pr, roleGrants, nil
return out, pr, roleGrants, grantScopes, nil
}
func (s Service) setGrantsInRepo(ctx context.Context, roleId string, grants []string, version uint32) (*iam.Role, []*iam.PrincipalRole, []*iam.RoleGrant, error) {
func (s Service) setGrantsInRepo(ctx context.Context, roleId string, grants []string, version uint32) (*iam.Role, []*iam.PrincipalRole, []*iam.RoleGrant, []*iam.RoleGrantScope, error) {
const op = "roles.(Service).setGrantsInRepo"
repo, err := s.repoFn()
if err != nil {
return nil, nil, nil, err
return nil, nil, nil, nil, err
}
// If no grant was provided, we clear the grants.
if grants == nil {
@@ -793,37 +937,115 @@ func (s Service) setGrantsInRepo(ctx context.Context, roleId string, grants []st
_, _, err = repo.SetRoleGrants(ctx, roleId, version, strutil.RemoveDuplicates(grants, false))
if err != nil {
// TODO: Figure out a way to surface more helpful error info beyond the Internal error.
return nil, nil, nil, handlers.ApiErrorWithCodeAndMessage(codes.Internal, "Unable to set grants on role: %v.", err)
return nil, nil, nil, nil, handlers.ApiErrorWithCodeAndMessage(codes.Internal, "Unable to set grants on role: %v.", err)
}
out, pr, roleGrants, err := repo.LookupRole(ctx, roleId)
out, pr, roleGrants, grantScopes, err := repo.LookupRole(ctx, roleId)
if err != nil {
return nil, nil, nil, errors.Wrap(ctx, err, op, errors.WithMsg("unable to look up role after setting grants"))
return nil, nil, nil, nil, errors.Wrap(ctx, err, op, errors.WithMsg("unable to look up role after setting grants"))
}
if out == nil {
return nil, nil, nil, handlers.ApiErrorWithCodeAndMessage(codes.Internal, "Unable to lookup role after setting grants on it.")
return nil, nil, nil, nil, handlers.ApiErrorWithCodeAndMessage(codes.Internal, "Unable to lookup role after setting grants on it.")
}
return out, pr, roleGrants, nil
return out, pr, roleGrants, grantScopes, nil
}
func (s Service) removeGrantsInRepo(ctx context.Context, roleId string, grants []string, version uint32) (*iam.Role, []*iam.PrincipalRole, []*iam.RoleGrant, error) {
func (s Service) removeGrantsInRepo(ctx context.Context, roleId string, grants []string, version uint32) (*iam.Role, []*iam.PrincipalRole, []*iam.RoleGrant, []*iam.RoleGrantScope, error) {
const op = "roles.(Service).removeGrantsInRepo"
repo, err := s.repoFn()
if err != nil {
return nil, nil, nil, err
return nil, nil, nil, nil, err
}
_, err = repo.DeleteRoleGrants(ctx, roleId, version, strutil.RemoveDuplicates(grants, false))
if err != nil {
// TODO: Figure out a way to surface more helpful error info beyond the Internal error.
return nil, nil, nil, handlers.ApiErrorWithCodeAndMessage(codes.Internal, "Unable to remove grants from role: %v", err)
return nil, nil, nil, nil, handlers.ApiErrorWithCodeAndMessage(codes.Internal, "Unable to remove grants from role: %v", err)
}
out, pr, roleGrants, err := repo.LookupRole(ctx, roleId)
out, pr, roleGrants, grantScopes, err := repo.LookupRole(ctx, roleId)
if err != nil {
return nil, nil, nil, errors.Wrap(ctx, err, op, errors.WithMsg("uable to look up role after removing grant"))
return nil, nil, nil, nil, errors.Wrap(ctx, err, op, errors.WithMsg("uable to look up role after removing grant"))
}
if out == nil {
return nil, nil, nil, handlers.ApiErrorWithCodeAndMessage(codes.Internal, "Unable to lookup role after removing grants from it.")
return nil, nil, nil, nil, handlers.ApiErrorWithCodeAndMessage(codes.Internal, "Unable to lookup role after removing grants from it.")
}
return out, pr, roleGrants, nil
return out, pr, roleGrants, grantScopes, nil
}
func (s Service) addGrantScopesInRepo(ctx context.Context, req grantScopeRequest) (*iam.Role, []*iam.PrincipalRole, []*iam.RoleGrant, []*iam.RoleGrantScope, error) {
const op = "service.(Service).addGrantScopesInRepo"
repo, err := s.repoFn()
if err != nil {
return nil, nil, nil, nil, err
}
deduped := strutil.RemoveDuplicates(req.GetGrantScopeIds(), false)
if err := validateRoleGrantScopesHierarchy(ctx, repo, req.GetId(), deduped); err != nil {
return nil, nil, nil, nil, err
}
_, err = repo.AddRoleGrantScopes(ctx, req.GetId(), req.GetVersion(), deduped)
if err != nil {
// TODO: Figure out a way to surface more helpful error info beyond the Internal error.
return nil, nil, nil, nil, handlers.ApiErrorWithCodeAndMessage(codes.Internal, "Unable to add grant scopes to role: %v.", err)
}
out, pr, roleGrants, grantScopes, err := repo.LookupRole(ctx, req.GetId())
if err != nil {
return nil, nil, nil, nil, errors.Wrap(ctx, err, op, errors.WithMsg("unable to look up role after adding grant scopes"))
}
if out == nil {
return nil, nil, nil, nil, handlers.ApiErrorWithCodeAndMessage(codes.Internal, "Unable to lookup role after adding grant scopes to it.")
}
return out, pr, roleGrants, grantScopes, nil
}
func (s Service) setGrantScopesInRepo(ctx context.Context, req grantScopeRequest) (*iam.Role, []*iam.PrincipalRole, []*iam.RoleGrant, []*iam.RoleGrantScope, error) {
const op = "service.(Service).setGrantScopesInRepo"
repo, err := s.repoFn()
if err != nil {
return nil, nil, nil, nil, err
}
deduped := strutil.RemoveDuplicates(req.GetGrantScopeIds(), false)
if err := validateRoleGrantScopesHierarchy(ctx, repo, req.GetId(), deduped); err != nil {
return nil, nil, nil, nil, err
}
_, _, err = repo.SetRoleGrantScopes(ctx, req.GetId(), req.GetVersion(), deduped)
if err != nil {
// TODO: Figure out a way to surface more helpful error info beyond the Internal error.
return nil, nil, nil, nil, handlers.ApiErrorWithCodeAndMessage(codes.Internal, "Unable to set grant scopes on role: %v.", err)
}
out, pr, roleGrants, grantScopes, err := repo.LookupRole(ctx, req.GetId())
if err != nil {
return nil, nil, nil, nil, errors.Wrap(ctx, err, op, errors.WithMsg("unable to look up role after setting grant scopes"))
}
if out == nil {
return nil, nil, nil, nil, handlers.ApiErrorWithCodeAndMessage(codes.Internal, "Unable to lookup role after setting grant scopes to it.")
}
return out, pr, roleGrants, grantScopes, nil
}
func (s Service) removeGrantScopesInRepo(ctx context.Context, req grantScopeRequest) (*iam.Role, []*iam.PrincipalRole, []*iam.RoleGrant, []*iam.RoleGrantScope, error) {
const op = "service.(Service).setGrantScopesInRepo"
repo, err := s.repoFn()
if err != nil {
return nil, nil, nil, nil, err
}
_, err = repo.DeleteRoleGrantScopes(ctx, req.GetId(), req.GetVersion(), strutil.RemoveDuplicates(req.GetGrantScopeIds(), false))
if err != nil {
// TODO: Figure out a way to surface more helpful error info beyond the Internal error.
return nil, nil, nil, nil, handlers.ApiErrorWithCodeAndMessage(codes.Internal, "Unable to remove grant scopes from role: %v.", err)
}
out, pr, roleGrants, grantScopes, err := repo.LookupRole(ctx, req.GetId())
if err != nil {
return nil, nil, nil, nil, errors.Wrap(ctx, err, op, errors.WithMsg("unable to look up role after removing grant scopes"))
}
if out == nil {
return nil, nil, nil, nil, handlers.ApiErrorWithCodeAndMessage(codes.Internal, "Unable to lookup role after removing grant scopes to it.")
}
return out, pr, roleGrants, grantScopes, nil
}
func (s Service) authResult(ctx context.Context, id string, a action.Type) auth.VerifyResults {
@@ -849,7 +1071,7 @@ func (s Service) authResult(ctx context.Context, id string, a action.Type) auth.
return res
}
default:
r, _, _, err := repo.LookupRole(ctx, id)
r, _, _, _, err := repo.LookupRole(ctx, id)
if err != nil {
res.Error = err
return res
@@ -865,7 +1087,7 @@ func (s Service) authResult(ctx context.Context, id string, a action.Type) auth.
return auth.Verify(ctx, opts...)
}
func toProto(ctx context.Context, in *iam.Role, principals []*iam.PrincipalRole, grants []*iam.RoleGrant, opt ...handlers.Option) (*pb.Role, error) {
func toProto(ctx context.Context, in *iam.Role, principals []*iam.PrincipalRole, grants []*iam.RoleGrant, grantScopes []*iam.RoleGrantScope, opt ...handlers.Option) (*pb.Role, error) {
opts := handlers.GetOpts(opt...)
if opts.WithOutputFields == nil {
return nil, handlers.ApiErrorWithCodeAndMessage(codes.Internal, "output fields not found when building role proto")
@@ -900,14 +1122,20 @@ func toProto(ctx context.Context, in *iam.Role, principals []*iam.PrincipalRole,
if outputFields.Has(globals.AuthorizedActionsField) {
out.AuthorizedActions = opts.WithAuthorizedActions
}
if outputFields.Has(globals.GrantScopeIdField) && in.GetGrantScopeId() != "" {
out.GrantScopeId = &wrapperspb.StringValue{Value: in.GetGrantScopeId()}
}
if outputFields.Has(globals.PrincipalIdsField) {
for _, p := range principals {
out.PrincipalIds = append(out.PrincipalIds, p.GetPrincipalId())
}
}
if outputFields.Has(globals.GrantScopeIdsField) {
for _, gs := range grantScopes {
out.GrantScopeIds = append(out.GrantScopeIds, gs.GetScopeIdOrSpecial())
}
sort.Strings(out.GrantScopeIds)
}
if outputFields.Has(globals.GrantScopeIdField) && len(grantScopes) == 1 {
out.GrantScopeId = &wrapperspb.StringValue{Value: grantScopes[0].ScopeIdOrSpecial}
}
if outputFields.Has(globals.PrincipalsField) {
for _, p := range principals {
principal := &pb.Principal{
@@ -925,7 +1153,7 @@ func toProto(ctx context.Context, in *iam.Role, principals []*iam.PrincipalRole,
}
if outputFields.Has(globals.GrantsField) {
for _, g := range grants {
parsed, err := perms.Parse(ctx, in.GetGrantScopeId(), g.GetRawGrant())
parsed, err := perms.Parse(ctx, in.GetScopeId(), g.GetRawGrant())
if err != nil {
// This should never happen as we validate on the way in, but let's
// return what we can since we are still returning the raw grant
@@ -971,9 +1199,15 @@ func validateCreateRequest(req *pbs.CreateRoleRequest) error {
scope.Global.String() != item.GetScopeId() {
badFields["scope_id"] = "This field is missing or improperly formatted."
}
if item.GetGrantScopeId() != nil && handlers.ValidId(handlers.Id(item.GetScopeId()), scope.Project.Prefix()) {
if item.GetGrantScopeId().GetValue() != item.GetScopeId() {
badFields["grant_scope_id"] = "When the role is in a project scope this value must be that project's scope ID."
if item.GetGrantScopeId() != nil {
switch {
case handlers.ValidId(handlers.Id(item.GetScopeId()), scope.Project.Prefix()):
switch item.GetGrantScopeId().GetValue() {
case item.GetScopeId(),
globals.GrantScopeThis:
default:
badFields["grant_scope_id"] = "When the role is in a project scope this value must be that project's scope ID or \"this\"."
}
}
}
if item.GetPrincipals() != nil {
@@ -1001,9 +1235,15 @@ func validateUpdateRequest(req *pbs.UpdateRoleRequest) error {
if req.GetItem().GetGrantStrings() != nil {
badFields["grant_strings"] = "This is a read only field and cannot be specified in an update request."
}
if req.GetItem().GetGrantScopeId() != nil && handlers.ValidId(handlers.Id(req.GetItem().GetScopeId()), scope.Project.Prefix()) {
if req.GetItem().GetGrantScopeId().GetValue() != req.GetItem().GetScopeId() {
badFields["grant_scope_id"] = "When the role is in a project scope this value must be that project's scope ID"
if item := req.GetItem(); item != nil {
switch {
case handlers.ValidId(handlers.Id(item.GetScopeId()), scope.Project.Prefix()):
switch item.GetGrantScopeId().GetValue() {
case item.GetScopeId(),
globals.GrantScopeThis:
default:
badFields["grant_scope_id"] = "When the role is in a project scope this value must be that project's scope ID or \"this\"."
}
}
}
return badFields
@@ -1224,6 +1464,113 @@ func validateRemoveRoleGrantsRequest(ctx context.Context, req *pbs.RemoveRoleGra
return nil
}
// grantScopeRequest allows us to reuse a few request types in a common way for
// grant scope add/set/remove operations
type grantScopeRequest interface {
GetId() string
GetVersion() uint32
GetGrantScopeIds() []string
}
func validateRoleGrantScopesRequest(ctx context.Context, req grantScopeRequest) error {
badFields := map[string]string{}
if !handlers.ValidId(handlers.Id(req.GetId()), globals.RolePrefix) {
badFields["id"] = "Incorrectly formatted identifier."
}
if req.GetVersion() == 0 {
badFields["version"] = "Required field."
}
if len(req.GetGrantScopeIds()) == 0 {
// This is actually okay for Set because they could be setting to null,
// e.g. removing all grant scope ids
if _, ok := req.(*pbs.SetRoleGrantScopesRequest); !ok {
badFields["grant_scope_ids"] = "Must be non-empty."
}
}
for _, v := range req.GetGrantScopeIds() {
if len(v) == 0 {
badFields["grant_scope_ids"] = "Grant scope IDs must not be empty."
break
}
switch {
case v == scope.Global.String(),
v == globals.GrantScopeThis,
v == globals.GrantScopeChildren,
v == globals.GrantScopeDescendants:
case globals.ResourceInfoFromPrefix(v).Type == resource.Scope:
if !handlers.ValidId(handlers.Id(v), globals.ProjectPrefix) &&
!handlers.ValidId(handlers.Id(v), globals.OrgPrefix) {
badFields["grant_scope_ids"] = fmt.Sprintf("Incorrectly formatted identifier %q.", v)
break
}
default:
badFields["grant_scope_ids"] = fmt.Sprintf("Unknown value %q.", v)
break
}
}
if len(badFields) > 0 {
return handlers.InvalidArgumentErrorf("Errors in provided fields.", badFields)
}
return nil
}
// validateRoleGrantScopesHierarchy is the companion to the domain-side logic to
// validate scopes. It doesn't do all of the same checking but will allow for
// better error messages when possible. We perform this check after
// authentication to limit the possibility of an anonymous user causing DB load
// due to this lookup, which is not a cheap one.
func validateRoleGrantScopesHierarchy(ctx context.Context, repo *iam.Repository, roleId string, grantScopes []string) error {
const op = "service.(Service).validateRoleGrantScopesHierarchy"
// We want to ensure that the values being passed in make sense to whatever
// extent we can right now, so we can provide nice errors back instead of DB
// errors.
role, _, _, _, err := repo.LookupRole(ctx, roleId)
if err != nil {
return errors.Wrap(ctx, err, op)
}
switch {
case role.ScopeId == scope.Global.String():
// Nothing, any grant scope is allowed for global
case strings.HasPrefix(role.ScopeId, scope.Project.Prefix()):
// In this case only "this" or the same project scope is allowed
for _, grantScope := range grantScopes {
switch grantScope {
case globals.GrantScopeThis, role.ScopeId:
default:
return handlers.InvalidArgumentErrorf(
"Invalid grant scope.",
map[string]string{
"grant_scope_id": `Project scopes can only have their own scope ID or "this" as a grant scope ID.`,
})
}
}
case strings.HasPrefix(role.ScopeId, scope.Org.Prefix()):
// Orgs can have "this", its own scope, a project scope, or "children"
for _, grantScope := range grantScopes {
switch {
case grantScope == role.ScopeId,
grantScope == globals.GrantScopeThis,
grantScope == globals.GrantScopeChildren,
strings.HasPrefix(grantScope, scope.Project.Prefix()):
default:
return handlers.InvalidArgumentErrorf(
"Invalid grant scope.",
map[string]string{
"grant_scope_id": fmt.Sprintf("Grant scope ID %q is not valid to set on an organization role.", grantScope),
})
}
}
default:
// Should never happen
return handlers.InvalidArgumentErrorf(
"Improperly formatted identifier.",
map[string]string{
"grant_scope_id": `Unknown scope prefix type.`,
})
}
return nil
}
func newOutputOpts(ctx context.Context, item *iam.Role, scopeInfoMap map[string]*scopes.ScopeInfo, authResults auth.VerifyResults) ([]handlers.Option, bool) {
res := perms.Resource{
Type: resource.Role,
File diff suppressed because it is too large. Load diff
@@ -63,7 +63,7 @@ func Test_newRateLimiterConfig(t *testing.T) {
ratelimit.DefaultLimiterMaxQuotas(),
false,
&rateLimiterConfig{
maxSize: 316158,
maxSize: 322161,
configs: nil,
disabled: false,
limits: defaultLimits,
@@ -2031,6 +2031,32 @@
"unlimited": false
}
],
"add-grant-scopes": [
{
"action": "add-grant-scopes",
"limit": 30000,
"per": "ip-address",
"period": "30s",
"resource": "role",
"unlimited": false
},
{
"action": "add-grant-scopes",
"limit": 3000,
"per": "auth-token",
"period": "30s",
"resource": "role",
"unlimited": false
},
{
"action": "add-grant-scopes",
"limit": 30000,
"per": "total",
"period": "30s",
"resource": "role",
"unlimited": false
}
],
"add-principals": [
{
"action": "add-principals",
@@ -2213,6 +2239,32 @@
"unlimited": false
}
],
"remove-grant-scopes": [
{
"action": "remove-grant-scopes",
"limit": 30000,
"per": "total",
"period": "30s",
"resource": "role",
"unlimited": false
},
{
"action": "remove-grant-scopes",
"limit": 30000,
"per": "ip-address",
"period": "30s",
"resource": "role",
"unlimited": false
},
{
"action": "remove-grant-scopes",
"limit": 3000,
"per": "auth-token",
"period": "30s",
"resource": "role",
"unlimited": false
}
],
"remove-principals": [
{
"action": "remove-principals",
@@ -2265,6 +2317,32 @@
"unlimited": false
}
],
"set-grant-scopes": [
{
"action": "set-grant-scopes",
"limit": 30000,
"per": "ip-address",
"period": "30s",
"resource": "role",
"unlimited": false
},
{
"action": "set-grant-scopes",
"limit": 3000,
"per": "auth-token",
"period": "30s",
"resource": "role",
"unlimited": false
},
{
"action": "set-grant-scopes",
"limit": 30000,
"per": "total",
"period": "30s",
"resource": "role",
"unlimited": false
}
],
"set-principals": [
{
"action": "set-principals",
@@ -3997,7 +4075,7 @@
]
}
},
"max_size": 316158,
"max_size": 322161,
"msg": "controller api rate limiter"
},
"op": "controller.(rateLimiterConfig).writeSysEvent",
@@ -2031,6 +2031,32 @@
"unlimited": false
}
],
"add-grant-scopes": [
{
"action": "add-grant-scopes",
"limit": 30000,
"per": "ip-address",
"period": "30s",
"resource": "role",
"unlimited": false
},
{
"action": "add-grant-scopes",
"limit": 3000,
"per": "auth-token",
"period": "30s",
"resource": "role",
"unlimited": false
},
{
"action": "add-grant-scopes",
"limit": 30000,
"per": "total",
"period": "30s",
"resource": "role",
"unlimited": false
}
],
"add-principals": [
{
"action": "add-principals",
@@ -2213,6 +2239,32 @@
"unlimited": false
}
],
"remove-grant-scopes": [
{
"action": "remove-grant-scopes",
"limit": 30000,
"per": "total",
"period": "30s",
"resource": "role",
"unlimited": false
},
{
"action": "remove-grant-scopes",
"limit": 30000,
"per": "ip-address",
"period": "30s",
"resource": "role",
"unlimited": false
},
{
"action": "remove-grant-scopes",
"limit": 3000,
"per": "auth-token",
"period": "30s",
"resource": "role",
"unlimited": false
}
],
"remove-principals": [
{
"action": "remove-principals",
@@ -2265,6 +2317,32 @@
"unlimited": false
}
],
"set-grant-scopes": [
{
"action": "set-grant-scopes",
"limit": 30000,
"per": "ip-address",
"period": "30s",
"resource": "role",
"unlimited": false
},
{
"action": "set-grant-scopes",
"limit": 3000,
"per": "auth-token",
"period": "30s",
"resource": "role",
"unlimited": false
},
{
"action": "set-grant-scopes",
"limit": 30000,
"per": "total",
"period": "30s",
"resource": "role",
"unlimited": false
}
],
"set-principals": [
{
"action": "set-principals",
@@ -2031,6 +2031,32 @@
"unlimited": false
}
],
"add-grant-scopes": [
{
"action": "add-grant-scopes",
"limit": 100,
"per": "ip-address",
"period": "1m0s",
"resource": "role",
"unlimited": false
},
{
"action": "add-grant-scopes",
"limit": 100,
"per": "auth-token",
"period": "1m0s",
"resource": "role",
"unlimited": false
},
{
"action": "add-grant-scopes",
"limit": 100,
"per": "total",
"period": "1m0s",
"resource": "role",
"unlimited": false
}
],
"add-principals": [
{
"action": "add-principals",
@@ -2213,6 +2239,32 @@
"unlimited": false
}
],
"remove-grant-scopes": [
{
"action": "remove-grant-scopes",
"limit": 100,
"per": "total",
"period": "1m0s",
"resource": "role",
"unlimited": false
},
{
"action": "remove-grant-scopes",
"limit": 100,
"per": "ip-address",
"period": "1m0s",
"resource": "role",
"unlimited": false
},
{
"action": "remove-grant-scopes",
"limit": 100,
"per": "auth-token",
"period": "1m0s",
"resource": "role",
"unlimited": false
}
],
"remove-principals": [
{
"action": "remove-principals",
@@ -2265,6 +2317,32 @@
"unlimited": false
}
],
"set-grant-scopes": [
{
"action": "set-grant-scopes",
"limit": 100,
"per": "ip-address",
"period": "1m0s",
"resource": "role",
"unlimited": false
},
{
"action": "set-grant-scopes",
"limit": 100,
"per": "auth-token",
"period": "1m0s",
"resource": "role",
"unlimited": false
},
{
"action": "set-grant-scopes",
"limit": 100,
"per": "total",
"period": "1m0s",
"resource": "role",
"unlimited": false
}
],
"set-principals": [
{
"action": "set-principals",
@@ -3997,7 +4075,7 @@
]
}
},
"max_size": 316158,
"max_size": 322161,
"msg": "controller api rate limiter"
},
"op": "controller.(rateLimiterConfig).writeSysEvent",
+22 -8
View File
@@ -370,8 +370,8 @@ type TestControllerOpts struct {
// DefaultPassword is the password used when creating the default accounts.
DefaultPassword string
// DisableInitialLoginRoleCreation can be set true to disable creating the
// global scope login role automatically.
// DisableInitialLoginRoleCreation can be set true to disable creating the global
// scope default role automatically.
DisableInitialLoginRoleCreation bool
// DisableAuthMethodCreation can be set true to disable creating an auth
@@ -424,6 +424,11 @@ type TestControllerOpts struct {
// eventer.
EnableEventing bool
// EventerConfig allows specifying a custom event config. You must not run
// the test in parallel (no calls to t.Parallel) since the this option
// relies on modifying the system wide default eventer.
EventerConfig *event.EventerConfig
// DisableAuthorizationFailures will still cause authz checks to be
// performed but they won't cause 403 Forbidden. Useful for API-level
// testing to avoid a lot of faff.
@@ -661,12 +666,15 @@ func TestControllerConfig(t testing.TB, ctx context.Context, tc *TestController,
opts.Config.Controller.Scheduler.JobRunIntervalDuration = opts.SchedulerRunJobInterval
opts.Config.Controller.ApiRateLimiterMaxQuotas = ratelimit.DefaultLimiterMaxQuotas()
if opts.EnableEventing {
opts.Config.Eventing = &event.EventerConfig{
AuditEnabled: true,
ObservationsEnabled: true,
SysEventsEnabled: true,
ErrorEventsDisabled: true,
if opts.EnableEventing || opts.EventerConfig != nil {
opts.Config.Eventing = opts.EventerConfig
if opts.Config.Eventing == nil {
opts.Config.Eventing = &event.EventerConfig{
AuditEnabled: true,
ObservationsEnabled: true,
SysEventsEnabled: true,
ErrorEventsDisabled: true,
}
}
}
serverName, err := os.Hostname()
@@ -757,6 +765,9 @@ func TestControllerConfig(t testing.TB, ctx context.Context, tc *TestController,
if _, err := tc.b.CreateInitialLoginRole(ctx); err != nil {
t.Fatal(err)
}
if _, err := tc.b.CreateInitialAuthenticatedUserRole(ctx); err != nil {
t.Fatal(err)
}
if !opts.DisableAuthMethodCreation {
if _, _, err := tc.b.CreateInitialPasswordAuthMethod(ctx); err != nil {
t.Fatal(err)
@@ -791,6 +802,9 @@ func TestControllerConfig(t testing.TB, ctx context.Context, tc *TestController,
}
} else if !opts.DisableDatabaseCreation {
var createOpts []base.Option
if opts.DisableInitialLoginRoleCreation {
createOpts = append(createOpts, base.WithSkipDefaultRoleCreation())
}
if opts.DisableAuthMethodCreation {
createOpts = append(createOpts, base.WithSkipAuthMethodCreation())
}