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
@@ -114,11 +114,19 @@ func (b *Server) CreateDevDatabase(ctx context.Context, opt ...Option) error {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := b.CreateInitialLoginRole(ctx); err != nil {
|
||||
if c != nil {
|
||||
err = errors.Join(err, c())
|
||||
if !opts.withSkipDefaultRoleCreation {
|
||||
if _, err := b.CreateInitialLoginRole(ctx); err != nil {
|
||||
if c != nil {
|
||||
err = errors.Join(err, c())
|
||||
}
|
||||
return err
|
||||
}
|
||||
if _, err := b.CreateInitialAuthenticatedUserRole(ctx, WithAuthUserTargetAuthorizeSessionGrant(true)); err != nil {
|
||||
if c != nil {
|
||||
err = errors.Join(err, c())
|
||||
}
|
||||
return err
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
if opts.withSkipAuthMethodCreation {
|
||||
@@ -151,7 +159,10 @@ func (b *Server) CreateDevDatabase(ctx context.Context, opt ...Option) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
if _, _, err := b.CreateInitialScopes(ctx); err != nil {
|
||||
if _, _, err := b.CreateInitialScopes(ctx, WithIamOptions(
|
||||
iam.WithSkipAdminRoleCreation(true),
|
||||
iam.WithSkipDefaultRoleCreation(true),
|
||||
)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
||||
@@ -45,26 +45,84 @@ func (b *Server) CreateInitialLoginRole(ctx context.Context) (*iam.Role, error)
|
||||
|
||||
pr, err := iam.NewRole(ctx,
|
||||
scope.Global.String(),
|
||||
iam.WithName("Login and Default Grants"),
|
||||
iam.WithDescription(`Role created for login capability, account self-management, and other default grants for users of the global scope at its creation time`),
|
||||
iam.WithName("Login Grants"),
|
||||
iam.WithDescription(`Role created for login capability for unauthenticated users`),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error creating in memory role for generated grants: %w", err)
|
||||
}
|
||||
role, err := iamRepo.CreateRole(ctx, pr)
|
||||
role, _, _, _, err := iamRepo.CreateRole(ctx, pr)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error creating role for default generated grants: %w", err)
|
||||
}
|
||||
if _, err := iamRepo.AddRoleGrants(ctx, role.PublicId, role.Version, []string{
|
||||
"ids=*;type=scope;actions=list,no-op",
|
||||
"ids=*;type=auth-method;actions=authenticate,list",
|
||||
"ids={{.Account.Id}};actions=read,change-password",
|
||||
"ids=*;type=auth-token;actions=list,read:self,delete:self",
|
||||
"ids=*;type=auth-method;actions=list,authenticate",
|
||||
"ids=*;type=auth-token;actions=read:self,delete:self",
|
||||
}); err != nil {
|
||||
return nil, fmt.Errorf("error creating grant for default generated grants: %w", err)
|
||||
return nil, fmt.Errorf("error creating grant for initial login grants: %w", err)
|
||||
}
|
||||
if _, err := iamRepo.AddPrincipalRoles(ctx, role.PublicId, role.Version+1, []string{globals.AnonymousUserId}, nil); err != nil {
|
||||
return nil, fmt.Errorf("error adding principal to role for default generated grants: %w", err)
|
||||
if _, err := iamRepo.AddPrincipalRoles(ctx, role.PublicId, role.Version+1, []string{globals.AnonymousUserId}); err != nil {
|
||||
return nil, fmt.Errorf("error adding principal to role for initial login grants: %w", err)
|
||||
}
|
||||
if _, _, err := iamRepo.SetRoleGrantScopes(ctx, role.PublicId, role.Version+2, []string{"this", "descendants"}); err != nil {
|
||||
return nil, fmt.Errorf("error adding scope grants to role for initial login grants: %w", err)
|
||||
}
|
||||
|
||||
return role, nil
|
||||
}
|
||||
|
||||
func (b *Server) CreateInitialAuthenticatedUserRole(ctx context.Context, opt ...Option) (*iam.Role, error) {
|
||||
rw := db.New(b.Database)
|
||||
|
||||
kmsCache, err := kms.New(ctx, rw, rw)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error creating kms cache: %w", err)
|
||||
}
|
||||
if err := kmsCache.AddExternalWrappers(
|
||||
b.Context,
|
||||
kms.WithRootWrapper(b.RootKms),
|
||||
); err != nil {
|
||||
return nil, fmt.Errorf("error adding config keys to kms: %w", err)
|
||||
}
|
||||
|
||||
iamRepo, err := iam.NewRepository(ctx, rw, rw, kmsCache, iam.WithRandomReader(b.SecureRandomReader))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to create repo for initial login role: %w", err)
|
||||
}
|
||||
|
||||
pr, err := iam.NewRole(ctx,
|
||||
scope.Global.String(),
|
||||
iam.WithName("Authenticated User Grants"),
|
||||
iam.WithDescription(`Role created for account self-management, and other initial authenticated user grants`),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error creating in memory role for generated grants: %w", err)
|
||||
}
|
||||
role, _, _, _, err := iamRepo.CreateRole(ctx, pr)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error creating role for default generated grants: %w", err)
|
||||
}
|
||||
grants := []string{
|
||||
"ids=*;type=scope;actions=read",
|
||||
"ids=*;type=auth-token;actions=list",
|
||||
"ids={{.Account.Id}};actions=read,change-password",
|
||||
"ids=*;type=session;actions=list,read:self,cancel:self",
|
||||
}
|
||||
opts := GetOpts(opt...)
|
||||
if opts.withAuthUserTargetAuthorizeSessionGrant {
|
||||
grants = append(grants, "ids=*;type=target;actions=list,read,authorize-session")
|
||||
} else {
|
||||
grants = append(grants, "ids=*;type=target;actions=list,read")
|
||||
}
|
||||
if _, err := iamRepo.AddRoleGrants(ctx, role.PublicId, role.Version, grants); err != nil {
|
||||
return nil, fmt.Errorf("error creating grant for initial authenticated user grants: %w", err)
|
||||
}
|
||||
if _, err := iamRepo.AddPrincipalRoles(ctx, role.PublicId, role.Version+1, []string{globals.AnyAuthenticatedUserId}); err != nil {
|
||||
return nil, fmt.Errorf("error adding principal to role for initial authenticated user grants: %w", err)
|
||||
}
|
||||
if _, _, err := iamRepo.SetRoleGrantScopes(ctx, role.PublicId, role.Version+2, []string{"this", "descendants"}); err != nil {
|
||||
return nil, fmt.Errorf("error adding scope grants to role for initial authenticated user grants: %w", err)
|
||||
}
|
||||
|
||||
return role, nil
|
||||
@@ -201,21 +259,24 @@ func (b *Server) CreateInitialPasswordAuthMethod(ctx context.Context) (*password
|
||||
pr, err := iam.NewRole(ctx,
|
||||
scope.Global.String(),
|
||||
iam.WithName("Administration"),
|
||||
iam.WithDescription(fmt.Sprintf(`Provides admin grants within the "%s" scope to the initial user`, scope.Global.String())),
|
||||
iam.WithDescription("Provides admin grants within all scopes to the initial admin user"),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error creating in memory role for generated grants: %w", err)
|
||||
}
|
||||
defPermsRole, err := iamRepo.CreateRole(ctx, pr)
|
||||
adminRole, _, _, _, err := iamRepo.CreateRole(ctx, pr)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error creating role for default generated grants: %w", err)
|
||||
}
|
||||
if _, err := iamRepo.AddRoleGrants(ctx, defPermsRole.PublicId, defPermsRole.Version, []string{"ids=*;type=*;actions=*"}); err != nil {
|
||||
if _, err := iamRepo.AddRoleGrants(ctx, adminRole.PublicId, adminRole.Version, []string{"ids=*;type=*;actions=*"}); err != nil {
|
||||
return nil, fmt.Errorf("error creating grant for default generated grants: %w", err)
|
||||
}
|
||||
if _, err := iamRepo.AddPrincipalRoles(ctx, defPermsRole.PublicId, defPermsRole.Version+1, []string{u.GetPublicId()}, nil); err != nil {
|
||||
if _, err := iamRepo.AddPrincipalRoles(ctx, adminRole.PublicId, adminRole.Version+1, []string{u.GetPublicId()}, nil); err != nil {
|
||||
return nil, fmt.Errorf("error adding principal to role for default generated grants: %w", err)
|
||||
}
|
||||
if _, _, err := iamRepo.SetRoleGrantScopes(ctx, adminRole.PublicId, adminRole.Version+2, []string{"this", "descendants"}); err != nil {
|
||||
return nil, fmt.Errorf("error adding scope grants to role for default generated grants: %w", err)
|
||||
}
|
||||
return u, nil
|
||||
}
|
||||
|
||||
@@ -256,7 +317,7 @@ func (b *Server) CreateInitialPasswordAuthMethod(ctx context.Context) (*password
|
||||
return am, u, nil
|
||||
}
|
||||
|
||||
func (b *Server) CreateInitialScopes(ctx context.Context) (*iam.Scope, *iam.Scope, error) {
|
||||
func (b *Server) CreateInitialScopes(ctx context.Context, opt ...Option) (*iam.Scope, *iam.Scope, error) {
|
||||
rw := db.New(b.Database)
|
||||
|
||||
kmsCache, err := kms.New(ctx, rw, rw)
|
||||
@@ -270,6 +331,8 @@ func (b *Server) CreateInitialScopes(ctx context.Context) (*iam.Scope, *iam.Scop
|
||||
return nil, nil, fmt.Errorf("error adding config keys to kms: %w", err)
|
||||
}
|
||||
|
||||
opts := GetOpts(opt...)
|
||||
|
||||
iamRepo, err := iam.NewRepository(ctx, rw, rw, kmsCache)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("error creating scopes repository: %w", err)
|
||||
@@ -282,17 +345,20 @@ func (b *Server) CreateInitialScopes(ctx context.Context) (*iam.Scope, *iam.Scop
|
||||
return nil, nil, fmt.Errorf("error generating initial org id: %w", err)
|
||||
}
|
||||
}
|
||||
opts := []iam.Option{
|
||||
iamOpts := []iam.Option{
|
||||
iam.WithName("Generated org scope"),
|
||||
iam.WithDescription("Provides an initial org scope in Boundary"),
|
||||
iam.WithRandomReader(b.SecureRandomReader),
|
||||
iam.WithPublicId(b.DevOrgId),
|
||||
}
|
||||
orgScope, err := iam.NewOrg(ctx, opts...)
|
||||
if len(opts.withIamOptions) > 0 {
|
||||
iamOpts = append(iamOpts, opts.withIamOptions...)
|
||||
}
|
||||
orgScope, err := iam.NewOrg(ctx, iamOpts...)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("error creating new in memory org scope: %w", err)
|
||||
}
|
||||
orgScope, err = iamRepo.CreateScope(ctx, orgScope, b.DevUserId, opts...)
|
||||
orgScope, err = iamRepo.CreateScope(ctx, orgScope, b.DevUserId, iamOpts...)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("error saving org scope to the db: %w", err)
|
||||
}
|
||||
@@ -305,17 +371,20 @@ func (b *Server) CreateInitialScopes(ctx context.Context) (*iam.Scope, *iam.Scop
|
||||
return nil, nil, fmt.Errorf("error generating initial project id: %w", err)
|
||||
}
|
||||
}
|
||||
opts = []iam.Option{
|
||||
iamOpts = []iam.Option{
|
||||
iam.WithName("Generated project scope"),
|
||||
iam.WithDescription("Provides an initial project scope in Boundary"),
|
||||
iam.WithRandomReader(b.SecureRandomReader),
|
||||
iam.WithPublicId(b.DevProjectId),
|
||||
}
|
||||
projScope, err := iam.NewProject(ctx, b.DevOrgId, opts...)
|
||||
if len(opts.withIamOptions) > 0 {
|
||||
iamOpts = append(iamOpts, opts.withIamOptions...)
|
||||
}
|
||||
projScope, err := iam.NewProject(ctx, b.DevOrgId, iamOpts...)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("error creating new in memory project scope: %w", err)
|
||||
}
|
||||
projScope, err = iamRepo.CreateScope(ctx, projScope, b.DevUserId, opts...)
|
||||
projScope, err = iamRepo.CreateScope(ctx, projScope, b.DevUserId, iamOpts...)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("error saving project scope to the db: %w", err)
|
||||
}
|
||||
@@ -472,17 +541,6 @@ func (b *Server) CreateInitialTargetWithAddress(ctx context.Context) (target.Tar
|
||||
b.InfoKeys = append(b.InfoKeys, "generated target with address id")
|
||||
b.Info["generated target with address id"] = b.DevTargetId
|
||||
|
||||
if b.DevUnprivilegedUserId != "" {
|
||||
iamRepo, err := iam.NewRepository(ctx, rw, rw, kmsCache, iam.WithRandomReader(b.SecureRandomReader))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create iam repository: %w", err)
|
||||
}
|
||||
err = unprivilegedDevUserRoleSetup(ctx, iamRepo, b.DevUnprivilegedUserId, b.DevProjectId, b.DevTargetId)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to set up unprivileged dev user: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
return tt, nil
|
||||
}
|
||||
|
||||
@@ -540,17 +598,6 @@ func (b *Server) CreateInitialTargetWithHostSources(ctx context.Context) (target
|
||||
b.InfoKeys = append(b.InfoKeys, "generated target with host source id")
|
||||
b.Info["generated target with host source id"] = b.DevSecondaryTargetId
|
||||
|
||||
if b.DevUnprivilegedUserId != "" {
|
||||
iamRepo, err := iam.NewRepository(ctx, rw, rw, kmsCache, iam.WithRandomReader(b.SecureRandomReader))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create iam repository: %w", err)
|
||||
}
|
||||
err = unprivilegedDevUserRoleSetup(ctx, iamRepo, b.DevUnprivilegedUserId, b.DevProjectId, b.DevSecondaryTargetId)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to set up unprivileged dev user: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
return tt, nil
|
||||
}
|
||||
|
||||
@@ -626,83 +673,3 @@ func (b *Server) RegisterPlugin(ctx context.Context, name string, hostClient plg
|
||||
|
||||
return plg, nil
|
||||
}
|
||||
|
||||
// unprivilegedDevUserRoleSetup adds dev user to the role that grants
|
||||
// list/read:self/cancel:self on sessions and read:self/delete:self/list on
|
||||
// tokens. It also creates a role with an `authorize-session` grant for the
|
||||
// provided targetId.
|
||||
func unprivilegedDevUserRoleSetup(ctx context.Context, repo *iam.Repository, userId, projectId, targetId string) error {
|
||||
noopFilter := func(ctx context.Context, item *iam.Role) (bool, error) {
|
||||
return true, nil
|
||||
}
|
||||
roles, err := iam.ListRoles(ctx, []byte("dummy grant"), globals.DefaultMaxPageSize, noopFilter, repo, []string{projectId})
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to list existing roles for project id %q: %w", projectId, err)
|
||||
}
|
||||
|
||||
// Look for default grants role to set unprivileged user as a principal.
|
||||
defaultRoleIdx := -1
|
||||
for i, r := range roles.Items {
|
||||
// Hacky, I know, but saves a DB trip to look up other
|
||||
// characteristics like "if any principals are currently attached".
|
||||
// No matter what we pick here it's a bit heuristical.
|
||||
if r.Name == "Default Grants" {
|
||||
defaultRoleIdx = i
|
||||
break
|
||||
}
|
||||
}
|
||||
if defaultRoleIdx == -1 {
|
||||
return fmt.Errorf("couldn't find default grants role for project id %q", projectId)
|
||||
}
|
||||
defaultRole := roles.Items[defaultRoleIdx]
|
||||
|
||||
// This function may be called more than once for the same boundary
|
||||
// deployment (eg: if we're creating more than one target), so we need to
|
||||
// check if the unprivileged user is not already a principal for the default
|
||||
// role in this project, as attempting to add an existing principal is an
|
||||
// error.
|
||||
principals, err := repo.ListPrincipalRoles(ctx, defaultRole.GetPublicId())
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to list principals for default project role: %w", err)
|
||||
}
|
||||
found := false
|
||||
for _, p := range principals {
|
||||
if p.PrincipalId == userId {
|
||||
found = true
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
_, err = repo.AddPrincipalRoles(ctx, defaultRole.GetPublicId(), defaultRole.GetVersion(), []string{userId})
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to add %q as principal for role id %q", userId, defaultRole.GetPublicId())
|
||||
}
|
||||
defaultRole.Version++ // The above call increments the role version in the database, so we must also track that with our state.
|
||||
}
|
||||
|
||||
// Create a new role for the "authorize-session" grant and add the
|
||||
// unprivileged user as a principal.
|
||||
asRole, err := iam.NewRole(ctx,
|
||||
projectId,
|
||||
iam.WithName(fmt.Sprintf("Session authorization for %s", targetId)),
|
||||
iam.WithDescription(fmt.Sprintf("Provides grants within the dev project scope to allow the initial unprivileged user to authorize sessions against %s", targetId)),
|
||||
)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create role object: %w", err)
|
||||
}
|
||||
|
||||
asRole, err = repo.CreateRole(ctx, asRole)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create role for unprivileged user: %w", err)
|
||||
}
|
||||
if _, err := repo.AddPrincipalRoles(ctx, asRole.GetPublicId(), asRole.GetVersion(), []string{userId}, nil); err != nil {
|
||||
return fmt.Errorf("failed to add unprivileged user as principal to new role: %w", err)
|
||||
}
|
||||
asRole.Version++
|
||||
|
||||
_, err = repo.AddRoleGrants(ctx, asRole.GetPublicId(), asRole.GetVersion(), []string{fmt.Sprintf("ids=%s;actions=authorize-session", targetId)})
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to add authorize-session grant for unprivileged user: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
+51
-22
@@ -5,6 +5,7 @@ package base
|
||||
|
||||
import (
|
||||
"github.com/hashicorp/boundary/internal/event"
|
||||
"github.com/hashicorp/boundary/internal/iam"
|
||||
"github.com/hashicorp/boundary/sdk/pbs/plugin"
|
||||
wrapping "github.com/hashicorp/go-kms-wrapping/v2"
|
||||
)
|
||||
@@ -25,28 +26,31 @@ type Option func(*Options)
|
||||
|
||||
// Options - how Options are represented.
|
||||
type Options struct {
|
||||
withNoTokenScope bool
|
||||
withNoTokenValue bool
|
||||
withSkipDatabaseDestruction bool
|
||||
withSkipAuthMethodCreation bool
|
||||
withSkipOidcAuthMethodCreation bool
|
||||
withSkipLdapAuthMethodCreation bool
|
||||
withSkipScopesCreation bool
|
||||
withSkipHostResourcesCreation bool
|
||||
withSkipTargetCreation bool
|
||||
withContainerImage string
|
||||
withDialect string
|
||||
withDatabaseTemplate string
|
||||
withEventerConfig *event.EventerConfig
|
||||
withEventFlags *EventFlags
|
||||
withEventWrapper wrapping.Wrapper
|
||||
withAttributeFieldPrefix string
|
||||
withStatusCode int
|
||||
withHostPlugin func() (string, plugin.HostPluginServiceClient)
|
||||
withEventGating bool
|
||||
withImplicitId string
|
||||
WithSkipScopeIdFlag bool
|
||||
WithInterceptedToken *string
|
||||
withNoTokenScope bool
|
||||
withNoTokenValue bool
|
||||
withSkipDefaultRoleCreation bool
|
||||
withSkipDatabaseDestruction bool
|
||||
withSkipAuthMethodCreation bool
|
||||
withSkipOidcAuthMethodCreation bool
|
||||
withSkipLdapAuthMethodCreation bool
|
||||
withSkipScopesCreation bool
|
||||
withSkipHostResourcesCreation bool
|
||||
withSkipTargetCreation bool
|
||||
withContainerImage string
|
||||
withDialect string
|
||||
withDatabaseTemplate string
|
||||
withEventerConfig *event.EventerConfig
|
||||
withEventFlags *EventFlags
|
||||
withEventWrapper wrapping.Wrapper
|
||||
withAttributeFieldPrefix string
|
||||
withStatusCode int
|
||||
withHostPlugin func() (string, plugin.HostPluginServiceClient)
|
||||
withEventGating bool
|
||||
withImplicitId string
|
||||
WithSkipScopeIdFlag bool
|
||||
WithInterceptedToken *string
|
||||
withAuthUserTargetAuthorizeSessionGrant bool
|
||||
withIamOptions []iam.Option
|
||||
}
|
||||
|
||||
func getDefaultOptions() Options {
|
||||
@@ -81,6 +85,14 @@ func WithNoTokenValue() Option {
|
||||
}
|
||||
}
|
||||
|
||||
// WithSkipDefaultRoleCreation tells the command not to instantiate the default
|
||||
// global role
|
||||
func WithSkipDefaultRoleCreation() Option {
|
||||
return func(o *Options) {
|
||||
o.withSkipDefaultRoleCreation = true
|
||||
}
|
||||
}
|
||||
|
||||
// WithSkipAuthMethodCreation tells the command not to instantiate any auth
|
||||
// method on first run.
|
||||
func WithSkipAuthMethodCreation() Option {
|
||||
@@ -227,3 +239,20 @@ func WithInterceptedToken(s *string) Option {
|
||||
o.WithInterceptedToken = s
|
||||
}
|
||||
}
|
||||
|
||||
// WithAuthUserTargetAuthorizeSessionGrant indicates that we should add an
|
||||
// authorize-session grant to the global authenticated user role. This is the
|
||||
// default for dev mode.
|
||||
func WithAuthUserTargetAuthorizeSessionGrant(with bool) Option {
|
||||
return func(o *Options) {
|
||||
o.withAuthUserTargetAuthorizeSessionGrant = with
|
||||
}
|
||||
}
|
||||
|
||||
// WithIamOptions provides options to pass through to the IAM package when
|
||||
// creating initial resources
|
||||
func WithIamOptions(with ...iam.Option) Option {
|
||||
return func(o *Options) {
|
||||
o.withIamOptions = with
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/boundary/internal/event"
|
||||
"github.com/hashicorp/boundary/internal/iam"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
@@ -71,6 +72,13 @@ func Test_GetOpts(t *testing.T) {
|
||||
testOpts.withNoTokenValue = true
|
||||
assert.Equal(opts, testOpts)
|
||||
})
|
||||
t.Run("WithSkipDefaultRoleCreation", func(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
opts := GetOpts(WithSkipDefaultRoleCreation())
|
||||
testOpts := getDefaultOptions()
|
||||
testOpts.withSkipDefaultRoleCreation = true
|
||||
assert.Equal(opts, testOpts)
|
||||
})
|
||||
t.Run("WithSkipAuthMethodCreation", func(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
opts := GetOpts(WithSkipAuthMethodCreation())
|
||||
@@ -151,4 +159,20 @@ func Test_GetOpts(t *testing.T) {
|
||||
testOpts.WithInterceptedToken = &s
|
||||
assert.Equal(opts, testOpts)
|
||||
})
|
||||
|
||||
t.Run("WithAuthUserTargetAuthorizeSessionGrant", func(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
opts := getDefaultOptions()
|
||||
assert.False(opts.withAuthUserTargetAuthorizeSessionGrant)
|
||||
opts = GetOpts(WithAuthUserTargetAuthorizeSessionGrant(true))
|
||||
assert.True(opts.withAuthUserTargetAuthorizeSessionGrant)
|
||||
})
|
||||
|
||||
t.Run("WithIamOptions", func(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
testOpts := getDefaultOptions()
|
||||
assert.Len(testOpts.withIamOptions, 0)
|
||||
opts := GetOpts(WithIamOptions(iam.WithSkipAdminRoleCreation(true)))
|
||||
assert.Len(opts.withIamOptions, 1)
|
||||
})
|
||||
}
|
||||
@@ -895,6 +895,21 @@ func initCommands(ui, serverCmdUi cli.Ui, runOpts *RunOptions) {
|
||||
Command: base.NewCommand(ui, opts...),
|
||||
Func: "remove-grants",
|
||||
}),
|
||||
"roles add-grant-scopes": clientCacheWrapper(
|
||||
&rolescmd.Command{
|
||||
Command: base.NewCommand(ui, opts...),
|
||||
Func: "add-grant-scopes",
|
||||
}),
|
||||
"roles set-grant-scopes": clientCacheWrapper(
|
||||
&rolescmd.Command{
|
||||
Command: base.NewCommand(ui, opts...),
|
||||
Func: "set-grant-scopes",
|
||||
}),
|
||||
"roles remove-grant-scopes": clientCacheWrapper(
|
||||
&rolescmd.Command{
|
||||
Command: base.NewCommand(ui, opts...),
|
||||
Func: "remove-grant-scopes",
|
||||
}),
|
||||
|
||||
"scopes": func() (cli.Command, error) {
|
||||
return &scopescmd.Command{
|
||||
|
||||
@@ -71,6 +71,13 @@ func (c *Command) Flags() *base.FlagSets {
|
||||
}
|
||||
|
||||
func (c *Command) Run(args []string) int {
|
||||
f := c.Flags()
|
||||
|
||||
if err := f.Parse(args); err != nil {
|
||||
c.PrintCliError(err)
|
||||
return base.CommandUserError
|
||||
}
|
||||
|
||||
client, err := c.Client(base.WithNoTokenScope(), base.WithNoTokenValue())
|
||||
if c.WrapperCleanupFunc != nil {
|
||||
defer func() {
|
||||
@@ -84,13 +91,6 @@ func (c *Command) Run(args []string) int {
|
||||
return base.CommandCliError
|
||||
}
|
||||
|
||||
f := c.Flags()
|
||||
|
||||
if err := f.Parse(args); err != nil {
|
||||
c.PrintCliError(err)
|
||||
return base.CommandUserError
|
||||
}
|
||||
|
||||
// Lookup the primary auth method ID in the global scope
|
||||
aClient := authmethods.NewClient(client)
|
||||
pri, err := getPrimaryAuthMethodId(c.Context, aClient, scope.Global.String(), "")
|
||||
|
||||
@@ -107,7 +107,7 @@ type RoleInfo struct {
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
func generateInitialRoleTableOutput(in *RoleInfo) string {
|
||||
func generateInitialLoginRoleTableOutput(in *RoleInfo) string {
|
||||
nonAttributeMap := map[string]any{
|
||||
"Role ID": in.RoleId,
|
||||
"Name": in.Name,
|
||||
@@ -129,6 +129,28 @@ func generateInitialRoleTableOutput(in *RoleInfo) string {
|
||||
return base.WrapForHelpText(ret)
|
||||
}
|
||||
|
||||
func generateInitialAuthenticatedUserRoleOutput(in *RoleInfo) string {
|
||||
nonAttributeMap := map[string]any{
|
||||
"Role ID": in.RoleId,
|
||||
"Name": in.Name,
|
||||
}
|
||||
|
||||
maxLength := 0
|
||||
for k := range nonAttributeMap {
|
||||
if len(k) > maxLength {
|
||||
maxLength = len(k)
|
||||
}
|
||||
}
|
||||
|
||||
ret := []string{
|
||||
"",
|
||||
"Initial authenticated user role information:",
|
||||
base.WrapMap(2, maxLength+2, nonAttributeMap),
|
||||
}
|
||||
|
||||
return base.WrapForHelpText(ret)
|
||||
}
|
||||
|
||||
type AuthInfo struct {
|
||||
AuthMethodId string `json:"auth_method_id"`
|
||||
AuthMethodName string `json:"auth_method_name"`
|
||||
|
||||
@@ -37,16 +37,17 @@ type InitCommand struct {
|
||||
// deferred function on the Run method.
|
||||
configWrapperCleanupFunc func() error
|
||||
|
||||
flagConfig []string
|
||||
flagConfigKms string
|
||||
flagLogLevel string
|
||||
flagLogFormat string
|
||||
flagMigrationUrl string
|
||||
flagSkipInitialLoginRoleCreation bool
|
||||
flagSkipAuthMethodCreation bool
|
||||
flagSkipScopesCreation bool
|
||||
flagSkipHostResourcesCreation bool
|
||||
flagSkipTargetCreation bool
|
||||
flagConfig []string
|
||||
flagConfigKms string
|
||||
flagLogLevel string
|
||||
flagLogFormat string
|
||||
flagMigrationUrl string
|
||||
flagSkipInitialLoginRoleCreation bool
|
||||
flagSkipInitialAuthenticatedUserRoleCreation bool
|
||||
flagSkipAuthMethodCreation bool
|
||||
flagSkipScopesCreation bool
|
||||
flagSkipHostResourcesCreation bool
|
||||
flagSkipTargetCreation bool
|
||||
}
|
||||
|
||||
func (c *InitCommand) Synopsis() string {
|
||||
@@ -124,31 +125,37 @@ func (c *InitCommand) Flags() *base.FlagSets {
|
||||
f.BoolVar(&base.BoolVar{
|
||||
Name: "skip-initial-login-role-creation",
|
||||
Target: &c.flagSkipInitialLoginRoleCreation,
|
||||
Usage: "If not set, a default role allowing necessary grants for logging in will not be created as part of initialization. If set, the recovery KMS will be needed to perform any actions.",
|
||||
Usage: "If set, a role providing necessary grants for logging in will not be created as part of initialization. If set, the recovery KMS will be needed to perform any actions.",
|
||||
})
|
||||
|
||||
f.BoolVar(&base.BoolVar{
|
||||
Name: "skip-initial-authenticated-user-role-creation",
|
||||
Target: &c.flagSkipInitialAuthenticatedUserRoleCreation,
|
||||
Usage: "If set, a role providing initial grants for any authenticated user will not be created as part of initialization.",
|
||||
})
|
||||
|
||||
f.BoolVar(&base.BoolVar{
|
||||
Name: "skip-auth-method-creation",
|
||||
Target: &c.flagSkipAuthMethodCreation,
|
||||
Usage: "If not set, an auth method will not be created as part of initialization. If set, the recovery KMS will be needed to perform any actions.",
|
||||
Usage: "If set, an auth method will not be created as part of initialization. If set, the recovery KMS will be needed to perform any actions.",
|
||||
})
|
||||
|
||||
f.BoolVar(&base.BoolVar{
|
||||
Name: "skip-scopes-creation",
|
||||
Target: &c.flagSkipScopesCreation,
|
||||
Usage: "If not set, scopes will not be created as part of initialization.",
|
||||
Usage: "If set, scopes will not be created as part of initialization.",
|
||||
})
|
||||
|
||||
f.BoolVar(&base.BoolVar{
|
||||
Name: "skip-host-resources-creation",
|
||||
Target: &c.flagSkipHostResourcesCreation,
|
||||
Usage: "If not set, host resources (host catalog, host set, host) will not be created as part of initialization.",
|
||||
Usage: "If set, host resources (host catalog, host set, host) will not be created as part of initialization.",
|
||||
})
|
||||
|
||||
f.BoolVar(&base.BoolVar{
|
||||
Name: "skip-target-creation",
|
||||
Target: &c.flagSkipTargetCreation,
|
||||
Usage: "If not set, a target will not be created as part of initialization.",
|
||||
Usage: "If set, a target will not be created as part of initialization.",
|
||||
})
|
||||
|
||||
f.StringVar(&base.StringVar{
|
||||
@@ -330,11 +337,32 @@ func (c *InitCommand) Run(args []string) (retCode int) {
|
||||
}
|
||||
switch base.Format(c.UI) {
|
||||
case "table":
|
||||
c.UI.Output(generateInitialRoleTableOutput(roleInfo))
|
||||
c.UI.Output(generateInitialLoginRoleTableOutput(roleInfo))
|
||||
case "json":
|
||||
jsonMap["login_role"] = roleInfo
|
||||
}
|
||||
|
||||
if c.flagSkipInitialAuthenticatedUserRoleCreation {
|
||||
return base.CommandSuccess
|
||||
}
|
||||
|
||||
role, err = c.CreateInitialAuthenticatedUserRole(c.Context)
|
||||
if err != nil {
|
||||
c.UI.Error(fmt.Errorf("Error creating initial global-scoped authenticated user role: %w", err).Error())
|
||||
return base.CommandCliError
|
||||
}
|
||||
|
||||
roleInfo = &RoleInfo{
|
||||
RoleId: role.PublicId,
|
||||
Name: role.Name,
|
||||
}
|
||||
switch base.Format(c.UI) {
|
||||
case "table":
|
||||
c.UI.Output(generateInitialAuthenticatedUserRoleOutput(roleInfo))
|
||||
case "json":
|
||||
jsonMap["authenticated_user_role"] = roleInfo
|
||||
}
|
||||
|
||||
if c.flagSkipAuthMethodCreation {
|
||||
return base.CommandSuccess
|
||||
}
|
||||
|
||||
@@ -79,7 +79,7 @@ type Command struct {
|
||||
flagTargetDefaultPort int
|
||||
flagTargetSessionMaxSeconds int
|
||||
flagTargetSessionConnectionLimit int
|
||||
flagControllerAPIListenAddr string
|
||||
flagControllerApiListenAddr string
|
||||
flagControllerClusterListenAddr string
|
||||
flagControllerPublicClusterAddr string
|
||||
flagControllerOnly bool
|
||||
@@ -102,6 +102,8 @@ type Command struct {
|
||||
flagCreateLoopbackPlugin bool
|
||||
flagPluginExecutionDir string
|
||||
flagSkipPlugins bool
|
||||
flagSkipOidcAuthMethodCreation bool
|
||||
flagSkipLdapAuthMethodCreation bool
|
||||
flagWorkerDnsServer string
|
||||
flagWorkerAuthMethod string
|
||||
flagWorkerAuthStorageDir string
|
||||
@@ -202,7 +204,7 @@ func (c *Command) Flags() *base.FlagSets {
|
||||
|
||||
f.StringVar(&base.StringVar{
|
||||
Name: "api-listen-address",
|
||||
Target: &c.flagControllerAPIListenAddr,
|
||||
Target: &c.flagControllerApiListenAddr,
|
||||
EnvVar: "BOUNDARY_DEV_CONTROLLER_API_LISTEN_ADDRESS",
|
||||
Usage: "Address to bind to for controller \"api\" purpose. If this begins with a forward slash, it will be assumed to be a Unix domain socket path.",
|
||||
})
|
||||
@@ -381,6 +383,16 @@ func (c *Command) Flags() *base.FlagSets {
|
||||
Usage: "Skip loading compiled-in plugins. This does not prevent loopback plugins from being loaded if enabled.",
|
||||
Hidden: true,
|
||||
})
|
||||
f.BoolVar(&base.BoolVar{
|
||||
Name: "skip-oidc-auth-method-creation",
|
||||
Target: &c.flagSkipOidcAuthMethodCreation,
|
||||
Usage: "Skip creating a test OIDC auth method. This is useful if e.g. running a Unix API listener.",
|
||||
})
|
||||
f.BoolVar(&base.BoolVar{
|
||||
Name: "skip-ldap-auth-method-creation",
|
||||
Target: &c.flagSkipLdapAuthMethodCreation,
|
||||
Usage: "Skip creating a test LDAP auth method. This is useful if e.g. running a Unix API listener.",
|
||||
})
|
||||
f.StringVar(&base.StringVar{
|
||||
Name: "worker-dns-server",
|
||||
Target: &c.flagWorkerDnsServer,
|
||||
@@ -594,8 +606,8 @@ func (c *Command) Run(args []string) int {
|
||||
}
|
||||
switch l.Purpose[0] {
|
||||
case "api":
|
||||
if c.flagControllerAPIListenAddr != "" {
|
||||
l.Address = c.flagControllerAPIListenAddr
|
||||
if c.flagControllerApiListenAddr != "" {
|
||||
l.Address = c.flagControllerApiListenAddr
|
||||
}
|
||||
if strings.HasPrefix(l.Address, "/") {
|
||||
l.Type = "unix"
|
||||
@@ -750,6 +762,12 @@ func (c *Command) Run(args []string) int {
|
||||
}
|
||||
|
||||
var opts []base.Option
|
||||
if c.flagSkipOidcAuthMethodCreation {
|
||||
opts = append(opts, base.WithSkipOidcAuthMethodCreation())
|
||||
}
|
||||
if c.flagSkipLdapAuthMethodCreation {
|
||||
opts = append(opts, base.WithSkipLdapAuthMethodCreation())
|
||||
}
|
||||
if c.flagCreateLoopbackPlugin {
|
||||
c.DevLoopbackPluginId = "pl_1234567890"
|
||||
c.EnabledPlugins = append(c.EnabledPlugins, base.EnabledPluginLoopback)
|
||||
|
||||
@@ -26,41 +26,42 @@ func init() {
|
||||
}
|
||||
|
||||
type extraCmdVars struct {
|
||||
flagGrantScopeId string
|
||||
flagPrincipals []string
|
||||
flagGrants []string
|
||||
flagGrantScopeIds []string
|
||||
flagPrincipals []string
|
||||
flagGrants []string
|
||||
}
|
||||
|
||||
func extraActionsFlagsMapFuncImpl() map[string][]string {
|
||||
return map[string][]string{
|
||||
"create": {"grant-scope-id"},
|
||||
"update": {"grant-scope-id"},
|
||||
"add-principals": {"id", "principal", "version"},
|
||||
"set-principals": {"id", "principal", "version"},
|
||||
"remove-principals": {"id", "principal", "version"},
|
||||
"add-grants": {"id", "grant", "version"},
|
||||
"set-grants": {"id", "grant", "version"},
|
||||
"remove-grants": {"id", "grant", "version"},
|
||||
"create": {"grant-scope-id"},
|
||||
"update": {"grant-scope-id"},
|
||||
"add-principals": {"id", "principal", "version"},
|
||||
"set-principals": {"id", "principal", "version"},
|
||||
"remove-principals": {"id", "principal", "version"},
|
||||
"add-grants": {"id", "grant", "version"},
|
||||
"set-grants": {"id", "grant", "version"},
|
||||
"remove-grants": {"id", "grant", "version"},
|
||||
"add-grant-scopes": {"id", "grant-scope-id", "version"},
|
||||
"set-grant-scopes": {"id", "grant-scope-id", "version"},
|
||||
"remove-grant-scopes": {"id", "grant-scope-id", "version"},
|
||||
}
|
||||
}
|
||||
|
||||
func extraSynopsisFuncImpl(c *Command) string {
|
||||
switch c.Func {
|
||||
case "add-principals", "set-principals", "remove-principals":
|
||||
return c.principalsGrantsSynopsisFunc(c.Func, true)
|
||||
return c.principalsGrantsSynopsisFunc(c.Func, "principals (users, groups)")
|
||||
case "add-grants", "set-grants", "remove-grants":
|
||||
return c.principalsGrantsSynopsisFunc(c.Func, false)
|
||||
return c.principalsGrantsSynopsisFunc(c.Func, "grants")
|
||||
case "add-grant-scopes":
|
||||
return c.principalsGrantsSynopsisFunc(c.Func, "grant scopes")
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
func (c *Command) principalsGrantsSynopsisFunc(inFunc string, principals bool) string {
|
||||
func (c *Command) principalsGrantsSynopsisFunc(inFunc, switchStr string) string {
|
||||
var in string
|
||||
switchStr := "principals (users, groups)"
|
||||
if !principals {
|
||||
switchStr = "grants"
|
||||
}
|
||||
switch {
|
||||
case strings.HasPrefix(inFunc, "add"):
|
||||
in = fmt.Sprintf("Add %s to", switchStr)
|
||||
@@ -141,6 +142,39 @@ func (c *Command) extraHelpFunc(helpMap map[string]func() string) string {
|
||||
"",
|
||||
})
|
||||
|
||||
case "add-grant-scopes":
|
||||
helpStr = base.WrapForHelpText([]string{
|
||||
"Usage: boundary roles add-grant-scopes [options] [args]",
|
||||
"",
|
||||
` Adds grant scopes to a role given its ID. The "grant-scope-id" flag can be specified multiple times. Example:`,
|
||||
"",
|
||||
` $ boundary roles add-grant-scopes -id o_1234567890 -grant-scope-id "this" -grant-scope-id "children"`,
|
||||
"",
|
||||
"",
|
||||
})
|
||||
|
||||
case "set-grant-scopes":
|
||||
helpStr = base.WrapForHelpText([]string{
|
||||
"Usage: boundary roles set-grant-scopes [options] [args]",
|
||||
"",
|
||||
` Sets the complete set of grant scopes on a role given its ID. The "grant-scope-id" flag can be specified multiple times. Example:`,
|
||||
"",
|
||||
` $ boundary roles set-grant-scopes -id o_1234567890 -grant-scope-id "this" -grant-scope-id "children"`,
|
||||
"",
|
||||
"",
|
||||
})
|
||||
|
||||
case "remove-grant-scopes":
|
||||
helpStr = base.WrapForHelpText([]string{
|
||||
"Usage: boundary roles remove-grant-scopes [options] [args]",
|
||||
"",
|
||||
` Removes grant scopes from a role given its ID. The "grant-scope-id" flags can be specified multiple times. Example:`,
|
||||
"",
|
||||
` $ boundary roles remove-grant-scopes -id o_1234567890 -grant-scope-id "this" -grant-scope-id "children"`,
|
||||
"",
|
||||
"",
|
||||
})
|
||||
|
||||
default:
|
||||
helpStr = helpMap["base"]()
|
||||
}
|
||||
@@ -151,10 +185,10 @@ func extraFlagsFuncImpl(c *Command, _ *base.FlagSets, f *base.FlagSet) {
|
||||
for _, name := range flagsMap[c.Func] {
|
||||
switch name {
|
||||
case "grant-scope-id":
|
||||
f.StringVar(&base.StringVar{
|
||||
f.StringSliceVar(&base.StringSliceVar{
|
||||
Name: "grant-scope-id",
|
||||
Target: &c.flagGrantScopeId,
|
||||
Usage: "The scope ID for grants set on the role",
|
||||
Target: &c.flagGrantScopeIds,
|
||||
Usage: "The scope IDs to inherit grants set on the role",
|
||||
})
|
||||
case "principal":
|
||||
f.StringSliceVar(&base.StringSliceVar{
|
||||
@@ -173,15 +207,21 @@ func extraFlagsFuncImpl(c *Command, _ *base.FlagSets, f *base.FlagSet) {
|
||||
}
|
||||
|
||||
func extraFlagsHandlingFuncImpl(c *Command, _ *base.FlagSets, opts *[]roles.Option) bool {
|
||||
switch c.flagGrantScopeId {
|
||||
case "":
|
||||
case "null":
|
||||
*opts = append(*opts, roles.DefaultGrantScopeId())
|
||||
default:
|
||||
*opts = append(*opts, roles.WithGrantScopeId(c.flagGrantScopeId))
|
||||
}
|
||||
|
||||
switch c.Func {
|
||||
case "create", "update":
|
||||
switch len(c.flagGrantScopeIds) {
|
||||
case 0:
|
||||
case 1:
|
||||
if c.flagGrantScopeIds[0] == "null" {
|
||||
*opts = append(*opts, roles.DefaultGrantScopeId())
|
||||
} else {
|
||||
*opts = append(*opts, roles.WithGrantScopeId(c.flagGrantScopeIds[0]))
|
||||
}
|
||||
default:
|
||||
c.UI.Error("-grant-scope-id cannot be specified multiple times when using the deprecated create/update grant_scope_id mechanism")
|
||||
return false
|
||||
}
|
||||
|
||||
case "add-principals", "remove-principals":
|
||||
if len(c.flagPrincipals) == 0 {
|
||||
c.UI.Error("No principals supplied via -principal")
|
||||
@@ -194,6 +234,12 @@ func extraFlagsHandlingFuncImpl(c *Command, _ *base.FlagSets, opts *[]roles.Opti
|
||||
return false
|
||||
}
|
||||
|
||||
case "add-grant-scopes", "remove-grant-scopes":
|
||||
if len(c.flagGrantScopeIds) == 0 {
|
||||
c.UI.Error("No grant scope IDs supplied via -grant-scope-id")
|
||||
return false
|
||||
}
|
||||
|
||||
case "set-principals":
|
||||
switch len(c.flagPrincipals) {
|
||||
case 0:
|
||||
@@ -215,6 +261,17 @@ func extraFlagsHandlingFuncImpl(c *Command, _ *base.FlagSets, opts *[]roles.Opti
|
||||
c.flagGrants = nil
|
||||
}
|
||||
}
|
||||
|
||||
case "set-grant-scopes":
|
||||
switch len(c.flagGrantScopeIds) {
|
||||
case 0:
|
||||
c.UI.Error("No grant scope IDs supplied via -grant-scope-id")
|
||||
return false
|
||||
case 1:
|
||||
if c.flagGrantScopeIds[0] == "null" {
|
||||
c.flagGrantScopeIds = nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(c.flagGrants) > 0 {
|
||||
@@ -277,6 +334,24 @@ func executeExtraActionsImpl(c *Command, origResp *api.Response, origItem *roles
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
return result.GetResponse(), result.GetItem(), nil, err
|
||||
case "add-grant-scopes":
|
||||
result, err := roleClient.AddGrantScopes(c.Context, c.FlagId, version, c.flagGrantScopeIds, opts...)
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
return result.GetResponse(), result.GetItem(), nil, err
|
||||
case "set-grant-scopes":
|
||||
result, err := roleClient.SetGrantScopes(c.Context, c.FlagId, version, c.flagGrantScopeIds, opts...)
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
return result.GetResponse(), result.GetItem(), nil, err
|
||||
case "remove-grant-scopes":
|
||||
result, err := roleClient.RemoveGrantScopes(c.Context, c.FlagId, version, c.flagGrantScopeIds, opts...)
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
return result.GetResponse(), result.GetItem(), nil, err
|
||||
}
|
||||
return origResp, origItem, origItems, origError
|
||||
}
|
||||
@@ -407,6 +482,17 @@ func printItemTable(item *roles.Role, resp *api.Response) string {
|
||||
fmt.Sprintf(" %s", grant.Canonical),
|
||||
)
|
||||
}
|
||||
if len(item.GrantScopeIds) > 0 {
|
||||
ret = append(ret,
|
||||
"",
|
||||
fmt.Sprintf(" Grant Scope IDs: %s", ""),
|
||||
)
|
||||
}
|
||||
for _, grantScope := range item.GrantScopeIds {
|
||||
ret = append(ret,
|
||||
fmt.Sprintf(" ID: %s", grantScope),
|
||||
)
|
||||
}
|
||||
|
||||
return base.WrapForHelpText(ret)
|
||||
}
|
||||
@@ -269,6 +269,30 @@ func (c *Command) Run(args []string) int {
|
||||
version = uint32(c.FlagVersion)
|
||||
}
|
||||
|
||||
case "add-grant-scopes":
|
||||
switch c.FlagVersion {
|
||||
case 0:
|
||||
opts = append(opts, roles.WithAutomaticVersioning(true))
|
||||
default:
|
||||
version = uint32(c.FlagVersion)
|
||||
}
|
||||
|
||||
case "remove-grant-scopes":
|
||||
switch c.FlagVersion {
|
||||
case 0:
|
||||
opts = append(opts, roles.WithAutomaticVersioning(true))
|
||||
default:
|
||||
version = uint32(c.FlagVersion)
|
||||
}
|
||||
|
||||
case "set-grant-scopes":
|
||||
switch c.FlagVersion {
|
||||
case 0:
|
||||
opts = append(opts, roles.WithAutomaticVersioning(true))
|
||||
default:
|
||||
version = uint32(c.FlagVersion)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if ok := extraFlagsHandlingFunc(c, f, &opts); !ok {
|
||||
|
||||
@@ -567,7 +567,7 @@ var inputStructs = map[string][]*cmdInfo{
|
||||
Container: "Scope",
|
||||
HasName: true,
|
||||
HasDescription: true,
|
||||
VersionedActions: []string{"update", "add-grants", "remove-grants", "set-grants", "add-principals", "remove-principals", "set-principals"},
|
||||
VersionedActions: []string{"update", "add-grants", "remove-grants", "set-grants", "add-principals", "remove-principals", "set-principals", "add-grant-scopes", "remove-grant-scopes", "set-grant-scopes"},
|
||||
},
|
||||
},
|
||||
"scopes": {
|
||||
|
||||
Reference in new issue
Block a user