You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
boundary/internal/cmd/commands/rolescmd/funcs.go

477 lines
14 KiB

// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: BUSL-1.1
package rolescmd
import (
"fmt"
"strings"
"time"
"github.com/hashicorp/boundary/api"
"github.com/hashicorp/boundary/api/roles"
"github.com/hashicorp/boundary/internal/cmd/base"
"github.com/hashicorp/boundary/internal/perms"
"github.com/hashicorp/boundary/internal/types/scope"
"github.com/mitchellh/go-wordwrap"
)
func init() {
extraActionsFlagsMapFunc = extraActionsFlagsMapFuncImpl
extraSynopsisFunc = extraSynopsisFuncImpl
extraFlagsFunc = extraFlagsFuncImpl
extraFlagsHandlingFunc = extraFlagsHandlingFuncImpl
executeExtraActions = executeExtraActionsImpl
}
type extraCmdVars struct {
flagGrantScopeIds []string
flagPrincipals []string
flagGrants []string
}
func extraActionsFlagsMapFuncImpl() map[string][]string {
return map[string][]string{
"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, "principals (users, groups)")
case "add-grants", "set-grants", "remove-grants":
return c.principalsGrantsSynopsisFunc(c.Func, "grants")
case "add-grant-scopes":
return c.principalsGrantsSynopsisFunc(c.Func, "grant scopes")
}
return ""
}
func (c *Command) principalsGrantsSynopsisFunc(inFunc, switchStr string) string {
var in string
switch {
case strings.HasPrefix(inFunc, "add"):
in = fmt.Sprintf("Add %s to", switchStr)
case strings.HasPrefix(inFunc, "set"):
in = fmt.Sprintf("Set the full contents of the %s on", switchStr)
case strings.HasPrefix(inFunc, "remove"):
in = fmt.Sprintf("Remove %s from", switchStr)
}
return wordwrap.WrapString(fmt.Sprintf("%s a role", in), base.TermWidth)
}
func (c *Command) extraHelpFunc(helpMap map[string]func() string) string {
var helpStr string
switch c.Func {
case "add-principals":
helpStr = base.WrapForHelpText([]string{
"Usage: boundary roles add-principals [options] [args]",
"",
` Adds principals (users, groups) to a role given its ID. The "principal" flag can be specified multiple times. Example:`,
"",
` $ boundary roles add-principals -id r_1234567890 -principal u_1234567890`,
"",
"",
})
case "set-principals":
helpStr = base.WrapForHelpText([]string{
"Usage: boundary roles set-principals [options] [args]",
"",
` Sets the complete set of principals (users, groups) on a role given its ID. The "principal" flag can be specified multiple times. Example:`,
"",
` $ boundary roles set-principals -id r_1234567890 -principal u_anon -principal sg_1234567890`,
"",
"",
})
case "remove-principals":
helpStr = base.WrapForHelpText([]string{
"Usage: boundary roles remove-principals [options] [args]",
"",
` Removes principals (users, groups) from a role given its ID. The "principal" flags can be specified multiple times. Example:`,
"",
` $ boundary roles remove-principals -id r_1234567890 -principal sg_1234567890`,
"",
"",
})
case "add-grants":
helpStr = base.WrapForHelpText([]string{
"Usage: boundary roles add-grants [options] [args]",
"",
` Adds grants to a role given its ID. The "grant" flag can be specified multiple times. Example:`,
"",
` $ boundary roles add-grants -id r_1234567890 -grant "ids=*;type=*;actions=read"`,
"",
"",
})
case "set-grants":
helpStr = base.WrapForHelpText([]string{
"Usage: boundary roles set-grants [options] [args]",
"",
` Sets the complete set of grants on a role given its ID. The "grant" flag can be specified multiple times. Example:`,
"",
` $ boundary roles set-grants -id r_1234567890 -grant "ids=*;type=*;actions=read" -grant "ids=*;type=*;actions=list"`,
"",
"",
})
case "remove-grants":
helpStr = base.WrapForHelpText([]string{
"Usage: boundary roles remove-grants [options] [args]",
"",
` Removes grants from a role given its ID. The "grant" flags can be specified multiple times. Example:`,
"",
` $ boundary roles remove-grants -id r_1234567890 -grant "ids=*;type=*;actions=read"`,
"",
"",
})
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 r_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 r_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 r_1234567890 -grant-scope-id "this" -grant-scope-id "children"`,
"",
"",
})
default:
helpStr = helpMap["base"]()
}
return helpStr + c.Flags().Help()
}
func extraFlagsFuncImpl(c *Command, _ *base.FlagSets, f *base.FlagSet) {
for _, name := range flagsMap[c.Func] {
switch name {
case "grant-scope-id":
f.StringSliceVar(&base.StringSliceVar{
Name: "grant-scope-id",
Target: &c.flagGrantScopeIds,
Usage: "The scope IDs to inherit grants set on the role",
})
case "principal":
f.StringSliceVar(&base.StringSliceVar{
Name: "principal",
Target: &c.flagPrincipals,
Usage: "The principals (users or groups) to add, remove, or set. May be specified multiple times.",
})
case "grant":
f.StringSliceVar(&base.StringSliceVar{
Name: "grant",
Target: &c.flagGrants,
Usage: "The grants to add, remove, or set. May be specified multiple times. Can be in compact string format or JSON (be sure to escape JSON properly).",
})
}
}
}
func extraFlagsHandlingFuncImpl(c *Command, _ *base.FlagSets, opts *[]roles.Option) bool {
switch c.Func {
case "add-principals", "remove-principals":
if len(c.flagPrincipals) == 0 {
c.UI.Error("No principals supplied via -principal")
return false
}
case "add-grants", "remove-grants":
if len(c.flagGrants) == 0 {
c.UI.Error("No grants supplied via -grant")
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:
c.UI.Error("No principals supplied via -principal")
return false
case 1:
if c.flagPrincipals[0] == "null" {
c.flagPrincipals = nil
}
}
case "set-grants":
switch len(c.flagGrants) {
case 0:
c.UI.Error("No grants supplied via -grant")
return false
case 1:
if c.flagGrants[0] == "null" {
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 {
for _, grant := range c.flagGrants {
parsed, err := perms.Parse(c.Context, scope.Global.String(), grant)
if err != nil {
c.UI.Error(fmt.Errorf("Grant %q could not be parsed successfully: %w", grant, err).Error())
return false
}
switch {
case parsed.Id() == "":
// Nothing
default:
c.UI.Error(fmt.Sprintf("Grant %q uses the %q field which is no longer supported. Please use %q instead.", grant, "id", "ids"))
return false
}
}
}
return true
}
func executeExtraActionsImpl(c *Command, origResp *api.Response, origItem *roles.Role, origItems []*roles.Role, origError error, roleClient *roles.Client, version uint32, opts []roles.Option) (*api.Response, *roles.Role, []*roles.Role, error) {
switch c.Func {
case "add-principals":
result, err := roleClient.AddPrincipals(c.Context, c.FlagId, version, c.flagPrincipals, opts...)
if err != nil {
return nil, nil, nil, err
}
return result.GetResponse(), result.GetItem(), nil, err
case "set-principals":
result, err := roleClient.SetPrincipals(c.Context, c.FlagId, version, c.flagPrincipals, opts...)
if err != nil {
return nil, nil, nil, err
}
return result.GetResponse(), result.GetItem(), nil, err
case "remove-principals":
result, err := roleClient.RemovePrincipals(c.Context, c.FlagId, version, c.flagPrincipals, opts...)
if err != nil {
return nil, nil, nil, err
}
return result.GetResponse(), result.GetItem(), nil, err
case "add-grants":
result, err := roleClient.AddGrants(c.Context, c.FlagId, version, c.flagGrants, opts...)
if err != nil {
return nil, nil, nil, err
}
return result.GetResponse(), result.GetItem(), nil, err
case "set-grants":
result, err := roleClient.SetGrants(c.Context, c.FlagId, version, c.flagGrants, opts...)
if err != nil {
return nil, nil, nil, err
}
return result.GetResponse(), result.GetItem(), nil, err
case "remove-grants":
result, err := roleClient.RemoveGrants(c.Context, c.FlagId, version, c.flagGrants, opts...)
if err != nil {
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
}
func (c *Command) printListTable(items []*roles.Role) string {
if len(items) == 0 {
return "No roles found"
}
var output []string
output = []string{
"",
"Role information:",
}
for i, item := range items {
if i > 0 {
output = append(output, "")
}
if item.Id != "" {
output = append(output,
fmt.Sprintf(" ID: %s", item.Id),
)
} else {
output = append(output,
fmt.Sprintf(" ID: %s", "(not available)"),
)
}
if c.FlagRecursive && item.ScopeId != "" {
output = append(output,
fmt.Sprintf(" Scope ID: %s", item.ScopeId),
)
}
if item.Version > 0 {
output = append(output,
fmt.Sprintf(" Version: %d", item.Version),
)
}
if item.Name != "" {
output = append(output,
fmt.Sprintf(" Name: %s", item.Name),
)
}
if item.Description != "" {
output = append(output,
fmt.Sprintf(" Description: %s", item.Description),
)
}
if len(item.AuthorizedActions) > 0 {
output = append(output,
" Authorized Actions:",
base.WrapSlice(6, item.AuthorizedActions),
)
}
}
return base.WrapForHelpText(output)
}
func printItemTable(item *roles.Role, resp *api.Response) string {
nonAttributeMap := map[string]any{}
if item.Id != "" {
nonAttributeMap["ID"] = item.Id
}
if item.Version != 0 {
nonAttributeMap["Version"] = item.Version
}
if !item.CreatedTime.IsZero() {
nonAttributeMap["Created Time"] = item.CreatedTime.Local().Format(time.RFC1123)
}
if !item.UpdatedTime.IsZero() {
nonAttributeMap["Updated Time"] = item.UpdatedTime.Local().Format(time.RFC1123)
}
if item.Name != "" {
nonAttributeMap["Name"] = item.Name
}
if item.Description != "" {
nonAttributeMap["Description"] = item.Description
}
maxLength := base.MaxAttributesLength(nonAttributeMap, nil, nil)
ret := []string{
"",
"Role information:",
base.WrapMap(2, maxLength+2, nonAttributeMap),
}
if item.Scope != nil {
ret = append(ret,
"",
" Scope:",
base.ScopeInfoForOutput(item.Scope, maxLength),
)
}
if len(item.AuthorizedActions) > 0 {
ret = append(ret,
"",
" Authorized Actions:",
base.WrapSlice(4, item.AuthorizedActions),
)
}
if len(item.Principals) > 0 {
ret = append(ret,
"",
fmt.Sprintf(" Principals: %s", ""),
)
}
for _, principal := range item.Principals {
ret = append(ret,
fmt.Sprintf(" ID: %s", principal.Id),
fmt.Sprintf(" Type: %s", principal.Type),
fmt.Sprintf(" Scope ID: %s", principal.ScopeId),
)
}
if len(item.Grants) > 0 {
ret = append(ret,
"",
fmt.Sprintf(" Canonical Grants: %s", ""),
)
}
for _, grant := range item.Grants {
ret = append(ret,
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)
}