Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DXCDT-595: Add ability to update signing alg for apis #926

Merged
merged 2 commits into from
Nov 30, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion docs/auth0_apis_create.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ auth0 apis create [flags]
auth0 apis create --name myapi --identifier http://my-api --token-lifetime 6100
auth0 apis create --name myapi --identifier http://my-api --token-lifetime 6100 --offline-access=true
auth0 apis create --name myapi --identifier http://my-api --token-lifetime 6100 --offline-access=false --scopes "letter:write,letter:read"
auth0 apis create -n myapi -i http://my-api -t 6100 -o false -s "letter:write,letter:read" --json
auth0 apis create --name myapi --identifier http://my-api --token-lifetime 6100 --offline-access=false --scopes "letter:write,letter:read" --signing-alg "RS256"
auth0 apis create -n myapi -i http://my-api -t 6100 -o false -s "letter:write,letter:read" --signing-alg "RS256" --json
```


Expand All @@ -37,6 +38,7 @@ auth0 apis create [flags]
-n, --name string Name of the API.
-o, --offline-access Whether Refresh Tokens can be issued for this API (true) or not (false).
-s, --scopes strings Comma-separated list of scopes (permissions).
--signing-alg string Algorithm used to sign JWTs. Can be HS256 or RS256. PS256 available via addon. (default "RS256")
-l, --token-lifetime int The amount of time in seconds that the token will be valid after being issued. Default value is 86400 seconds (1 day).
```

Expand Down
5 changes: 3 additions & 2 deletions docs/auth0_apis_update.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ auth0 apis update [flags]
auth0 apis update <api-id|api-audience> --name myapi
auth0 apis update <api-id|api-audience> --name myapi --token-lifetime 6100
auth0 apis update <api-id|api-audience> --name myapi --token-lifetime 6100 --offline-access=false
auth0 apis update <api-id|api-audience> --name myapi --token-lifetime 6100 --offline-access=false --scopes "letter:write,letter:read"
auth0 apis update <api-id|api-audience> -n myapi -t 6100 -o false -s "letter:write,letter:read" --json
auth0 apis update <api-id|api-audience> --name myapi --token-lifetime 6100 --offline-access=false --scopes "letter:write,letter:read" --signing-alg "RS256"
auth0 apis update <api-id|api-audience> -n myapi -t 6100 -o false -s "letter:write,letter:read" --signing-alg "RS256" --json
```


Expand All @@ -36,6 +36,7 @@ auth0 apis update [flags]
-n, --name string Name of the API.
-o, --offline-access Whether Refresh Tokens can be issued for this API (true) or not (false).
-s, --scopes strings Comma-separated list of scopes (permissions).
--signing-alg string Algorithm used to sign JWTs. Can be HS256 or RS256. PS256 available via addon. (default "RS256")
-l, --token-lifetime int The amount of time in seconds that the token will be valid after being issued. Default value is 86400 seconds (1 day).
```

Expand Down
86 changes: 54 additions & 32 deletions internal/cli/apis.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ import (
"github.com/auth0/auth0-cli/internal/prompt"
)

const apiDefaultTokenLifetime = 86400

var (
apiID = Argument{
Name: "Id",
Expand Down Expand Up @@ -55,6 +57,11 @@ var (
Help: "Whether Refresh Tokens can be issued for this API (true) or not (false).",
AlwaysPrompt: true,
}
apiSigningAlgorithm = Flag{
Name: "Signing Algorithm",
LongForm: "signing-alg",
Help: "Algorithm used to sign JWTs. Can be HS256 or RS256. PS256 available via addon.",
}
apiNumber = Flag{
Name: "Number",
LongForm: "number",
Expand Down Expand Up @@ -204,6 +211,7 @@ func createAPICmd(cli *cli) *cobra.Command {
Scopes []string
TokenLifetime int
AllowOfflineAccess bool
SigningAlgorithm string
}

cmd := &cobra.Command{
Expand All @@ -220,7 +228,8 @@ func createAPICmd(cli *cli) *cobra.Command {
auth0 apis create --name myapi --identifier http://my-api --token-lifetime 6100
auth0 apis create --name myapi --identifier http://my-api --token-lifetime 6100 --offline-access=true
auth0 apis create --name myapi --identifier http://my-api --token-lifetime 6100 --offline-access=false --scopes "letter:write,letter:read"
auth0 apis create -n myapi -i http://my-api -t 6100 -o false -s "letter:write,letter:read" --json`,
auth0 apis create --name myapi --identifier http://my-api --token-lifetime 6100 --offline-access=false --scopes "letter:write,letter:read" --signing-alg "RS256"
auth0 apis create -n myapi -i http://my-api -t 6100 -o false -s "letter:write,letter:read" --signing-alg "RS256" --json`,
RunE: func(cmd *cobra.Command, args []string) error {
if err := apiName.Ask(cmd, &inputs.Name, nil); err != nil {
return err
Expand All @@ -234,7 +243,7 @@ func createAPICmd(cli *cli) *cobra.Command {
return err
}

defaultTokenLifetime := strconv.Itoa(apiDefaultTokenLifetime())
defaultTokenLifetime := strconv.Itoa(apiDefaultTokenLifetime)
if err := apiTokenLifetime.Ask(cmd, &inputs.TokenLifetime, &defaultTokenLifetime); err != nil {
return err
}
Expand All @@ -243,31 +252,41 @@ func createAPICmd(cli *cli) *cobra.Command {
return err
}

if err := apiSigningAlgorithm.Ask(cmd, &inputs.SigningAlgorithm, auth0.String("RS256")); err != nil {
return err
}

api := &management.ResourceServer{
Name: &inputs.Name,
Identifier: &inputs.Identifier,
AllowOfflineAccess: &inputs.AllowOfflineAccess,
TokenLifetime: &inputs.TokenLifetime,
SigningAlgorithm: &inputs.SigningAlgorithm,
}

if len(inputs.Scopes) > 0 {
api.Scopes = apiScopesFor(inputs.Scopes)
}

// Set token lifetime
if inputs.TokenLifetime <= 0 {
api.TokenLifetime = auth0.Int(apiDefaultTokenLifetime())
api.TokenLifetime = auth0.Int(apiDefaultTokenLifetime)
} else {
api.TokenLifetime = auth0.Int(inputs.TokenLifetime)
}

if err := ansi.Waiting(func() error {
return cli.api.ResourceServer.Create(cmd.Context(), api)
}); err != nil {
return fmt.Errorf("An unexpected error occurred while attempting to create an API with name '%s' and identifier '%s': %w", inputs.Name, inputs.Identifier, err)
return fmt.Errorf(
"failed to create an API with name '%s' and identifier '%s': %w",
inputs.Name,
inputs.Identifier,
err,
)
}

cli.renderer.APICreate(api)

return nil
},
}
Expand All @@ -278,6 +297,7 @@ func createAPICmd(cli *cli) *cobra.Command {
apiScopes.RegisterStringSlice(cmd, &inputs.Scopes, nil)
apiOfflineAccess.RegisterBool(cmd, &inputs.AllowOfflineAccess, false)
apiTokenLifetime.RegisterInt(cmd, &inputs.TokenLifetime, 0)
apiSigningAlgorithm.RegisterString(cmd, &inputs.SigningAlgorithm, "RS256")

return cmd
}
Expand All @@ -289,6 +309,7 @@ func updateAPICmd(cli *cli) *cobra.Command {
Scopes []string
TokenLifetime int
AllowOfflineAccess bool
SigningAlgorithm string
}

cmd := &cobra.Command{
Expand All @@ -304,26 +325,23 @@ func updateAPICmd(cli *cli) *cobra.Command {
auth0 apis update <api-id|api-audience> --name myapi
auth0 apis update <api-id|api-audience> --name myapi --token-lifetime 6100
auth0 apis update <api-id|api-audience> --name myapi --token-lifetime 6100 --offline-access=false
auth0 apis update <api-id|api-audience> --name myapi --token-lifetime 6100 --offline-access=false --scopes "letter:write,letter:read"
auth0 apis update <api-id|api-audience> -n myapi -t 6100 -o false -s "letter:write,letter:read" --json`,
auth0 apis update <api-id|api-audience> --name myapi --token-lifetime 6100 --offline-access=false --scopes "letter:write,letter:read" --signing-alg "RS256"
auth0 apis update <api-id|api-audience> -n myapi -t 6100 -o false -s "letter:write,letter:read" --signing-alg "RS256" --json`,
RunE: func(cmd *cobra.Command, args []string) error {
var current *management.ResourceServer

if len(args) == 0 {
err := apiID.Pick(cmd, &inputs.ID, cli.apiPickerOptions)
if err != nil {
if err := apiID.Pick(cmd, &inputs.ID, cli.apiPickerOptions); err != nil {
return err
}
} else {
inputs.ID = args[0]
}

if err := ansi.Waiting(func() error {
var err error
current, err = cli.api.ResourceServer.Read(cmd.Context(), url.PathEscape(inputs.ID))
var current *management.ResourceServer
if err := ansi.Waiting(func() (err error) {
current, err = cli.api.ResourceServer.Read(cmd.Context(), inputs.ID)
return err
}); err != nil {
return fmt.Errorf("Unable to load API: %w", err)
return fmt.Errorf("failed to find API with ID %q: %w", inputs.ID, err)
}

if err := apiName.AskU(cmd, &inputs.Name, current.Name); err != nil {
Expand All @@ -334,48 +352,55 @@ func updateAPICmd(cli *cli) *cobra.Command {
return err
}

currentTokenLifetime := strconv.Itoa(auth0.IntValue(current.TokenLifetime))
if err := apiTokenLifetime.AskU(cmd, &inputs.TokenLifetime, &currentTokenLifetime); err != nil {
currentTokenLifetime := strconv.Itoa(current.GetTokenLifetime())
if err := apiTokenLifetime.AskIntU(cmd, &inputs.TokenLifetime, &currentTokenLifetime); err != nil {
return err
}

if !apiOfflineAccess.IsSet(cmd) {
inputs.AllowOfflineAccess = auth0.BoolValue(current.AllowOfflineAccess)
inputs.AllowOfflineAccess = current.GetAllowOfflineAccess()
}

if err := apiOfflineAccess.AskBoolU(cmd, &inputs.AllowOfflineAccess, current.AllowOfflineAccess); err != nil {
return err
}

if err := apiSigningAlgorithm.AskU(cmd, &inputs.SigningAlgorithm, current.SigningAlgorithm); err != nil {
return err
}

api := &management.ResourceServer{
AllowOfflineAccess: &inputs.AllowOfflineAccess,
}

if len(inputs.Name) == 0 {
api.Name = current.Name
} else {
api.Name = current.Name
if len(inputs.Name) != 0 {
api.Name = &inputs.Name
}

if len(inputs.Scopes) == 0 {
api.Scopes = current.Scopes
} else {
api.Scopes = current.Scopes
if len(inputs.Scopes) != 0 {
api.Scopes = apiScopesFor(inputs.Scopes)
}

if inputs.TokenLifetime == 0 {
api.TokenLifetime = current.TokenLifetime
} else {
api.TokenLifetime = current.TokenLifetime
if inputs.TokenLifetime != 0 {
api.TokenLifetime = &inputs.TokenLifetime
}

api.SigningAlgorithm = current.SigningAlgorithm
if inputs.SigningAlgorithm != "" {
api.SigningAlgorithm = &inputs.SigningAlgorithm
}

if err := ansi.Waiting(func() error {
return cli.api.ResourceServer.Update(cmd.Context(), current.GetID(), api)
}); err != nil {
return fmt.Errorf("An unexpected error occurred while trying to update an API with Id '%s': %w", inputs.ID, err)
return fmt.Errorf("failed to update the API with ID %q: %w", inputs.ID, err)
}

cli.renderer.APIUpdate(api)

return nil
},
}
Expand All @@ -385,6 +410,7 @@ func updateAPICmd(cli *cli) *cobra.Command {
apiScopes.RegisterStringSliceU(cmd, &inputs.Scopes, nil)
apiOfflineAccess.RegisterBoolU(cmd, &inputs.AllowOfflineAccess, false)
apiTokenLifetime.RegisterIntU(cmd, &inputs.TokenLifetime, 0)
apiSigningAlgorithm.RegisterStringU(cmd, &inputs.SigningAlgorithm, "RS256")

return cmd
}
Expand Down Expand Up @@ -550,10 +576,6 @@ func apiScopesFor(scopes []string) *[]management.ResourceServerScope {
return &models
}

func apiDefaultTokenLifetime() int {
return 86400
}

func (c *cli) apiPickerOptions(ctx context.Context) (pickerOptions, error) {
return c.filteredAPIPickerOptions(ctx, func(r *management.ResourceServer) bool {
return true
Expand Down
30 changes: 16 additions & 14 deletions internal/display/apis.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,13 @@ import (
)

type apiView struct {
ID string
Name string
Identifier string
Scopes string
TokenLifetime int
OfflineAccess string
ID string
Name string
Identifier string
Scopes string
TokenLifetime int
OfflineAccess string
SigningAlgorithm string

raw interface{}
}
Expand All @@ -39,6 +40,7 @@ func (v *apiView) KeyValues() [][]string {
{"SCOPES", v.Scopes},
{"TOKEN LIFETIME", strconv.Itoa(v.TokenLifetime)},
{"ALLOW OFFLINE ACCESS", v.OfflineAccess},
{"SIGNING ALGORITHM", v.SigningAlgorithm},
}
}

Expand Down Expand Up @@ -111,14 +113,14 @@ func (r *Renderer) APIUpdate(api *management.ResourceServer) {
func makeAPIView(api *management.ResourceServer) (*apiView, bool) {
scopes, scopesTruncated := getScopes(api.GetScopes())
view := &apiView{
ID: ansi.Faint(api.GetID()),
Name: api.GetName(),
Identifier: api.GetIdentifier(),
Scopes: scopes,
TokenLifetime: api.GetTokenLifetime(),
OfflineAccess: boolean(api.GetAllowOfflineAccess()),

raw: api,
ID: ansi.Faint(api.GetID()),
Name: api.GetName(),
Identifier: api.GetIdentifier(),
Scopes: scopes,
TokenLifetime: api.GetTokenLifetime(),
OfflineAccess: boolean(api.GetAllowOfflineAccess()),
SigningAlgorithm: api.GetSigningAlgorithm(),
raw: api,
}
return view, scopesTruncated
}
Expand Down
13 changes: 11 additions & 2 deletions test/integration/apis-test-cases.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ tests:
- number flag invalid, please pass a number between 1 and 1000

003 - apis create and check data:
command: auth0 apis create --name integration-test-api-def1 --identifier http://integration-test-api-def1 --scopes read:todos,write:todos --json
command: auth0 apis create --name integration-test-api-def1 --identifier http://integration-test-api-def1 --scopes read:todos,write:todos --signing-alg RS256 --json
exit-code: 0
stdout:
json:
Expand All @@ -31,9 +31,10 @@ tests:
scopes: "[map[value:read:todos] map[value:write:todos]]"
token_lifetime: "86400"
allow_offline_access: "false"
signing_alg: "RS256"

004 - apis create and check output:
command: auth0 apis create --name integration-test-api-def2 --identifier http://integration-test-api-def2 --scopes read:todos,write:todos
command: auth0 apis create --name integration-test-api-def2 --identifier http://integration-test-api-def2 --scopes read:todos,write:todos --signing-alg RS256
exit-code: 0
stdout:
contains:
Expand All @@ -42,6 +43,7 @@ tests:
- SCOPES read:todos write:todos
- TOKEN LIFETIME 86400
- ALLOW OFFLINE ACCESS ✗
- SIGNING ALGORITHM RS256

# Test 'apis create' --token-lifetime flag
005 - apis create token lifetime 1000 and check data:
Expand Down Expand Up @@ -142,6 +144,13 @@ tests:
allow_offline_access: "false"
exit-code: 0

018 - apis update signing algorithm:
command: auth0 apis update $(./test/integration/scripts/get-api-id.sh) --signing-alg=HS256 --json
stdout:
json:
signing_alg: "HS256"
exit-code: 0

018 - it successfully prints out a URL to open:
command: auth0 apis open $(./test/integration/scripts/get-api-id.sh) --no-input
exit-code: 0
Expand Down