2022-07-21 15:21:31 -07:00
// Copyright (c) HashiCorp, Inc.
2021-02-23 19:06:39 -05:00
// SPDX-License-Identifier: BUSL-1.1
2023-02-02 17:15:17 -08:00
2021-02-23 19:06:39 -05:00
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"
2021-11-04 09:34:01 -04:00
"github.com/hashicorp/boundary/internal/types/scope"
2021-02-23 19:06:39 -05:00
"github.com/mitchellh/go-wordwrap"
)
func init () {
extraActionsFlagsMapFunc = extraActionsFlagsMapFuncImpl
extraSynopsisFunc = extraSynopsisFuncImpl
extraFlagsFunc = extraFlagsFuncImpl
extraFlagsHandlingFunc = extraFlagsHandlingFuncImpl
executeExtraActions = executeExtraActionsImpl
}
type extraCmdVars struct {
2024-01-23 14:33:09 -05:00
flagGrantScopeIds [] string
flagPrincipals [] string
flagGrants [] string
2021-02-23 19:06:39 -05:00
}
func extraActionsFlagsMapFuncImpl () map [ string ][] string {
return map [ string ][] string {
2024-01-23 14:33:09 -05:00
"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" },
2021-02-23 19:06:39 -05:00
}
}
func extraSynopsisFuncImpl ( c * Command ) string {
switch c . Func {
case "add-principals" , "set-principals" , "remove-principals" :
2024-01-23 14:33:09 -05:00
return c . principalsGrantsSynopsisFunc ( c . Func , "principals (users, groups)" )
2021-02-23 19:06:39 -05:00
case "add-grants" , "set-grants" , "remove-grants" :
2024-01-23 14:33:09 -05:00
return c . principalsGrantsSynopsisFunc ( c . Func , "grants" )
case "add-grant-scopes" :
return c . principalsGrantsSynopsisFunc ( c . Func , "grant scopes" )
2021-02-23 19:06:39 -05:00
}
return ""
}
2024-01-23 14:33:09 -05:00
func ( c * Command ) principalsGrantsSynopsisFunc ( inFunc , switchStr string ) string {
2021-02-23 19:06:39 -05:00
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:` ,
"" ,
2024-01-17 23:54:49 -08:00
` $ boundary roles add-grants -id r_1234567890 -grant "ids=*;type=*;actions=read"` ,
2021-02-23 19:06:39 -05:00
"" ,
"" ,
})
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:` ,
"" ,
2024-01-17 23:54:49 -08:00
` $ boundary roles set-grants -id r_1234567890 -grant "ids=*;type=*;actions=read" -grant "ids=*;type=*;actions=list"` ,
2021-02-23 19:06:39 -05:00
"" ,
"" ,
})
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:` ,
"" ,
2024-01-17 23:54:49 -08:00
` $ boundary roles remove-grants -id r_1234567890 -grant "ids=*;type=*;actions=read"` ,
2021-02-23 19:06:39 -05:00
"" ,
"" ,
})
2024-01-23 14:33:09 -05:00
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:` ,
"" ,
2024-02-03 09:35:05 +08:00
` $ boundary roles add-grant-scopes -id r_1234567890 -grant-scope-id "this" -grant-scope-id "children"` ,
2024-01-23 14:33:09 -05:00
"" ,
"" ,
})
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:` ,
"" ,
2024-02-03 09:35:05 +08:00
` $ boundary roles set-grant-scopes -id r_1234567890 -grant-scope-id "this" -grant-scope-id "children"` ,
2024-01-23 14:33:09 -05:00
"" ,
"" ,
})
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:` ,
"" ,
2024-02-03 09:35:05 +08:00
` $ boundary roles remove-grant-scopes -id r_1234567890 -grant-scope-id "this" -grant-scope-id "children"` ,
2024-01-23 14:33:09 -05:00
"" ,
"" ,
})
2021-02-23 19:06:39 -05:00
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" :
2024-01-23 14:33:09 -05:00
f . StringSliceVar ( & base . StringSliceVar {
2021-02-23 19:06:39 -05:00
Name : "grant-scope-id" ,
2024-01-23 14:33:09 -05:00
Target : & c . flagGrantScopeIds ,
Usage : "The scope IDs to inherit grants set on the role" ,
2021-02-23 19:06:39 -05:00
})
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)." ,
})
}
}
}
2021-04-08 20:54:32 -04:00
func extraFlagsHandlingFuncImpl ( c * Command , _ * base . FlagSets , opts * [] roles . Option ) bool {
2021-02-23 19:06:39 -05:00
switch c . Func {
case "add-principals" , "remove-principals" :
if len ( c . flagPrincipals ) == 0 {
c . UI . Error ( "No principals supplied via -principal" )
2021-03-04 20:05:17 -05:00
return false
2021-02-23 19:06:39 -05:00
}
case "add-grants" , "remove-grants" :
if len ( c . flagGrants ) == 0 {
c . UI . Error ( "No grants supplied via -grant" )
2021-03-04 20:05:17 -05:00
return false
2021-02-23 19:06:39 -05:00
}
2024-01-23 14:33:09 -05:00
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
}
2021-02-23 19:06:39 -05:00
case "set-principals" :
switch len ( c . flagPrincipals ) {
case 0 :
c . UI . Error ( "No principals supplied via -principal" )
2021-03-04 20:05:17 -05:00
return false
2021-02-23 19:06:39 -05:00
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" )
2021-03-04 20:05:17 -05:00
return false
2021-02-23 19:06:39 -05:00
case 1 :
if c . flagGrants [ 0 ] == "null" {
c . flagGrants = nil
}
}
2024-01-23 14:33:09 -05:00
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
}
}
2021-02-23 19:06:39 -05:00
}
if len ( c . flagGrants ) > 0 {
for _ , grant := range c . flagGrants {
2024-09-17 10:07:43 -04:00
parsed , err := perms . Parse ( c . Context , perms . GrantTuple { RoleScopeId : scope . Global . String (), GrantScopeId : scope . Global . String (), Grant : grant })
2021-02-23 19:06:39 -05:00
if err != nil {
c . UI . Error ( fmt . Errorf ( "Grant %q could not be parsed successfully: %w" , grant , err ). Error ())
2021-03-04 20:05:17 -05:00
return false
2021-02-23 19:06:39 -05:00
}
2023-06-06 16:13:44 -04:00
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
}
2021-02-23 19:06:39 -05:00
}
}
2021-03-04 20:05:17 -05:00
return true
2021-02-23 19:06:39 -05:00
}
2022-07-21 15:21:31 -07:00
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 ) {
2021-02-23 19:06:39 -05:00
switch c . Func {
case "add-principals" :
2022-07-21 15:21:31 -07:00
result , err := roleClient . AddPrincipals ( c . Context , c . FlagId , version , c . flagPrincipals , opts ... )
2022-07-27 10:00:00 -07:00
if err != nil {
return nil , nil , nil , err
}
2022-07-21 15:21:31 -07:00
return result . GetResponse (), result . GetItem (), nil , err
2021-02-23 19:06:39 -05:00
case "set-principals" :
2022-07-21 15:21:31 -07:00
result , err := roleClient . SetPrincipals ( c . Context , c . FlagId , version , c . flagPrincipals , opts ... )
2022-07-27 10:00:00 -07:00
if err != nil {
return nil , nil , nil , err
}
2022-07-21 15:21:31 -07:00
return result . GetResponse (), result . GetItem (), nil , err
2021-02-23 19:06:39 -05:00
case "remove-principals" :
2022-07-21 15:21:31 -07:00
result , err := roleClient . RemovePrincipals ( c . Context , c . FlagId , version , c . flagPrincipals , opts ... )
2022-07-27 10:00:00 -07:00
if err != nil {
return nil , nil , nil , err
}
2022-07-21 15:21:31 -07:00
return result . GetResponse (), result . GetItem (), nil , err
2021-02-23 19:06:39 -05:00
case "add-grants" :
2022-07-21 15:21:31 -07:00
result , err := roleClient . AddGrants ( c . Context , c . FlagId , version , c . flagGrants , opts ... )
2022-07-27 10:00:00 -07:00
if err != nil {
return nil , nil , nil , err
}
2022-07-21 15:21:31 -07:00
return result . GetResponse (), result . GetItem (), nil , err
2021-02-23 19:06:39 -05:00
case "set-grants" :
2022-07-21 15:21:31 -07:00
result , err := roleClient . SetGrants ( c . Context , c . FlagId , version , c . flagGrants , opts ... )
2022-07-27 10:00:00 -07:00
if err != nil {
return nil , nil , nil , err
}
2022-07-21 15:21:31 -07:00
return result . GetResponse (), result . GetItem (), nil , err
2021-02-23 19:06:39 -05:00
case "remove-grants" :
2022-07-21 15:21:31 -07:00
result , err := roleClient . RemoveGrants ( c . Context , c . FlagId , version , c . flagGrants , opts ... )
2022-07-27 10:00:00 -07:00
if err != nil {
return nil , nil , nil , err
}
2022-07-21 15:21:31 -07:00
return result . GetResponse (), result . GetItem (), nil , err
2024-01-23 14:33:09 -05:00
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
2021-02-23 19:06:39 -05:00
}
2022-07-21 15:21:31 -07:00
return origResp , origItem , origItems , origError
2021-02-23 19:06:39 -05:00
}
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 , "" )
}
2021-05-04 19:57:35 -05:00
if item . Id != "" {
2021-02-23 19:06:39 -05:00
output = append ( output ,
fmt . Sprintf ( " ID: %s" , item . Id ),
)
2021-05-04 19:57:35 -05:00
} else {
output = append ( output ,
fmt . Sprintf ( " ID: %s" , "(not available)" ),
)
2021-02-23 19:06:39 -05:00
}
2021-05-04 19:57:35 -05:00
if c . FlagRecursive && item . ScopeId != "" {
2021-02-23 19:06:39 -05:00
output = append ( output ,
2021-05-04 19:57:35 -05:00
fmt . Sprintf ( " Scope ID: %s" , item . ScopeId ),
2021-02-23 19:06:39 -05:00
)
}
2021-05-04 19:57:35 -05:00
if item . Version > 0 {
2021-02-23 19:06:39 -05:00
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 )
}
2022-07-21 15:21:31 -07:00
func printItemTable ( item * roles . Role , resp * api . Response ) string {
2022-10-25 18:29:38 -05:00
nonAttributeMap := map [ string ] any {}
2021-05-04 19:57:35 -05:00
if item . Id != "" {
nonAttributeMap [ "ID" ] = item . Id
2021-02-23 19:06:39 -05:00
}
2021-05-04 19:57:35 -05:00
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
2021-02-23 19:06:39 -05:00
}
2021-05-04 19:57:35 -05:00
if item . Description != "" {
nonAttributeMap [ "Description" ] = item . Description
2021-02-23 19:06:39 -05:00
}
maxLength := base . MaxAttributesLength ( nonAttributeMap , nil , nil )
ret := [] string {
"" ,
"Role information:" ,
base . WrapMap ( 2 , maxLength + 2 , nonAttributeMap ),
}
2021-05-04 19:57:35 -05:00
if item . Scope != nil {
ret = append ( ret ,
"" ,
" Scope:" ,
base . ScopeInfoForOutput ( item . Scope , maxLength ),
)
}
if len ( item . AuthorizedActions ) > 0 {
2021-02-23 19:06:39 -05:00
ret = append ( ret ,
"" ,
" Authorized Actions:" ,
2021-05-04 19:57:35 -05:00
base . WrapSlice ( 4 , item . AuthorizedActions ),
2021-02-23 19:06:39 -05:00
)
}
2021-05-04 19:57:35 -05:00
if len ( item . Principals ) > 0 {
2021-02-23 19:06:39 -05:00
ret = append ( ret ,
"" ,
fmt . Sprintf ( " Principals: %s" , "" ),
)
}
2021-05-04 19:57:35 -05:00
for _ , principal := range item . Principals {
2021-02-23 19:06:39 -05:00
ret = append ( ret ,
fmt . Sprintf ( " ID: %s" , principal . Id ),
fmt . Sprintf ( " Type: %s" , principal . Type ),
fmt . Sprintf ( " Scope ID: %s" , principal . ScopeId ),
)
}
2021-05-04 19:57:35 -05:00
if len ( item . Grants ) > 0 {
2021-02-23 19:06:39 -05:00
ret = append ( ret ,
"" ,
fmt . Sprintf ( " Canonical Grants: %s" , "" ),
)
}
2021-05-04 19:57:35 -05:00
for _ , grant := range item . Grants {
2021-02-23 19:06:39 -05:00
ret = append ( ret ,
fmt . Sprintf ( " %s" , grant . Canonical ),
)
}
2024-01-23 14:33:09 -05:00
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 ),
)
}
2021-02-23 19:06:39 -05:00
return base . WrapForHelpText ( ret )
}