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:
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,
|
||||
|
||||
+79
-1
@@ -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",
|
||||
|
||||
+78
@@ -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",
|
||||
|
||||
+79
-1
@@ -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",
|
||||
|
||||
@@ -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())
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user