diff --git a/internal/cli/apis.go b/internal/cli/apis.go index e8d5fc8c2..3c5650091 100644 --- a/internal/cli/apis.go +++ b/internal/cli/apis.go @@ -196,7 +196,7 @@ auth0 apis create -n myapi -e 6100 --offline-access=true`, return err } - if err :=apiOfflineAccess.AskBool(cmd, &inputs.AllowOfflineAccess, nil); err != nil { + if err := apiOfflineAccess.AskBool(cmd, &inputs.AllowOfflineAccess, nil); err != nil { return err } @@ -240,11 +240,11 @@ auth0 apis create -n myapi -e 6100 --offline-access=true`, func updateApiCmd(cli *cli) *cobra.Command { var inputs struct { - ID string - Name string - Scopes []string - TokenLifetime int - AllowOfflineAccess bool + ID string + Name string + Scopes []string + TokenLifetime int + AllowOfflineAccess bool } cmd := &cobra.Command{ @@ -497,6 +497,12 @@ func apiDefaultTokenLifetime() int { } func (c *cli) apiPickerOptions() (pickerOptions, error) { + return c.filteredAPIPickerOptions(func(r *management.ResourceServer) bool { + return true + }) +} + +func (c *cli) filteredAPIPickerOptions(include func(r *management.ResourceServer) bool) (pickerOptions, error) { list, err := c.api.ResourceServer.List() if err != nil { return nil, err @@ -506,6 +512,9 @@ func (c *cli) apiPickerOptions() (pickerOptions, error) { // labels. var opts pickerOptions for _, r := range list.ResourceServers { + if !include(r) { + continue + } label := fmt.Sprintf("%s %s", r.GetName(), ansi.Faint("("+r.GetIdentifier()+")")) opts = append(opts, pickerOption{value: r.GetID(), label: label}) diff --git a/internal/cli/flags.go b/internal/cli/flags.go index 35ff6a7e7..92a24e9c4 100644 --- a/internal/cli/flags.go +++ b/internal/cli/flags.go @@ -4,6 +4,7 @@ import ( "fmt" "github.com/AlecAivazis/survey/v2" + "github.com/auth0/auth0-cli/internal/ansi" "github.com/auth0/auth0-cli/internal/auth0" "github.com/auth0/auth0-cli/internal/prompt" "github.com/spf13/cobra" @@ -70,6 +71,28 @@ func (f *Flag) SelectU(cmd *cobra.Command, value interface{}, options []string, return selectFlag(cmd, f, value, options, defaultValue, true) } +func (f *Flag) Pick(cmd *cobra.Command, result *string, fn pickerOptionsFunc) error { + var opts pickerOptions + err := ansi.Waiting(func() error { + var err error + opts, err = fn() + return err + }) + + if err != nil { + return err + } + + defaultLabel := opts.defaultLabel() + var val string + if err := selectFlag(cmd, f, &val, opts.labels(), &defaultLabel, false); err != nil { + return err + } + + *result = opts.getValue(val) + return nil +} + func (f *Flag) EditorPrompt(cmd *cobra.Command, value *string, initialValue, filename string, infoFn func()) error { out, err := prompt.CaptureInputViaEditor( initialValue, diff --git a/internal/cli/roles_permissions.go b/internal/cli/roles_permissions.go index 0a72b4412..72d0e8859 100644 --- a/internal/cli/roles_permissions.go +++ b/internal/cli/roles_permissions.go @@ -2,12 +2,24 @@ package cli import ( "fmt" + "net/url" + "github.com/AlecAivazis/survey/v2" "github.com/auth0/auth0-cli/internal/ansi" "github.com/spf13/cobra" "gopkg.in/auth0.v5/management" ) +var ( + roleAPIIdentifier = Flag{ + Name: "API", + LongForm: "api-id", + ShortForm: "a", + Help: "API Identifier.", + IsRequired: true, + } +) + func rolePermissionsCmd(cli *cli) *cobra.Command { cmd := &cobra.Command{ Use: "permissions", @@ -18,7 +30,7 @@ func rolePermissionsCmd(cli *cli) *cobra.Command { cmd.SetUsageTemplate(resourceUsageTemplate()) cmd.AddCommand(listRolePermissionsCmd(cli)) - // cmd.AddCommand(associateRolePermissionsCmd(cli)) + cmd.AddCommand(associateRolePermissionsCmd(cli)) // cmd.AddCommand(removeRolePermissionsCmd(cli)) return cmd @@ -26,7 +38,8 @@ func rolePermissionsCmd(cli *cli) *cobra.Command { func listRolePermissionsCmd(cli *cli) *cobra.Command { var inputs struct { - ID string + ID string + APIIdentifier string } cmd := &cobra.Command{ @@ -48,6 +61,8 @@ auth0 roles permissions ls`, inputs.ID = args[0] } + roleAPIIdentifier.Pick(cmd, &inputs.APIIdentifier, cli.apiPickerOptionsWithoutAuth0) + var list *management.PermissionList if err := ansi.Waiting(func() error { @@ -65,3 +80,81 @@ auth0 roles permissions ls`, return cmd } + +func associateRolePermissionsCmd(cli *cli) *cobra.Command { + var inputs struct { + ID string + APIID string + Permissions map[string]string + } + + cmd := &cobra.Command{ + Use: "associate", + Aliases: []string{"assoc"}, + Args: cobra.MaximumNArgs(1), + Short: "Associate a permission to a role", + Long: `Associate an existing permission defined in one of your APIs. +To add a permission try: + + auth0 roles permissions associate -p =`, + Example: `auth0 roles permissions associate -p = +auth0 roles permissions assoc`, + RunE: func(cmd *cobra.Command, args []string) error { + if len(args) == 0 { + err := roleID.Pick(cmd, &inputs.ID, cli.rolePickerOptions) + if err != nil { + return err + } + } else { + inputs.ID = args[0] + } + + if err := roleAPIIdentifier.Pick(cmd, &inputs.APIID, cli.apiPickerOptionsWithoutAuth0); err != nil { + return err + } + + api, err := cli.api.ResourceServer.Read(inputs.APIID) + if err != nil { + return err + } + + var options []string + for _, s := range api.Scopes { + options = append(options, s.GetValue()) + } + + permissions := []string{} + prompt := &survey.MultiSelect{ + Message: "Permissions", + Options: options, + } + survey.AskOne(prompt, &permissions) + + return nil + }, + } + + cmd.Flags().StringToStringVarP(&inputs.Permissions, "permissions", "p", nil, "list of API Identifier permission pairs") + return cmd +} + +func (c *cli) apiPickerOptionsWithoutAuth0() (pickerOptions, error) { + ten, err := c.getTenant() + if err != nil { + return nil, err + } + + return c.filteredAPIPickerOptions(func(r *management.ResourceServer) bool { + u, err := url.Parse(r.GetIdentifier()) + if err != nil { + // We really should't get an error here, but for + // correctness it's indeterminate, therefore we return + // false. + return false + } + + // We only allow API Identifiers not matching the tenant + // domain, similar to the dashboard UX. + return u.Host != ten.Domain + }) +}