Skip to content

Commit

Permalink
feat: add a custom domain picker for auth0 test login (#281)
Browse files Browse the repository at this point in the history
  • Loading branch information
alejofernandez authored May 3, 2021
1 parent 82c739f commit b69b35a
Show file tree
Hide file tree
Showing 6 changed files with 106 additions and 3 deletions.
2 changes: 1 addition & 1 deletion internal/auth/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ var requiredScopes = []string{
"create:rules", "delete:rules", "read:rules", "update:rules",
"read:users", "update:users",
"read:branding", "update:branding",
"read:client_keys", "read:logs", "read:tenant_settings",
"read:client_keys", "read:logs", "read:tenant_settings", "read:custom_domains",
}

// RequiredScopes returns the scopes used for login.
Expand Down
2 changes: 2 additions & 0 deletions internal/auth0/auth0.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ type API struct {
ActionBinding ActionBindingAPI
Branding BrandingAPI
Client ClientAPI
CustomDomain CustomDomainAPI
Log LogAPI
ResourceServer ResourceServerAPI
Rule RuleAPI
Expand All @@ -29,6 +30,7 @@ func NewAPI(m *management.Management) *API {
ActionBinding: m.ActionBinding,
Branding: m.Branding,
Client: m.Client,
CustomDomain: m.CustomDomain,
Log: m.Log,
ResourceServer: m.ResourceServer,
Rule: m.Rule,
Expand Down
8 changes: 8 additions & 0 deletions internal/auth0/custom_domain.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
//go:generate mockgen -source=custom_domain.go -destination=custom_domain_mock.go -package=auth0
package auth0

import "gopkg.in/auth0.v5/management"

type CustomDomainAPI interface {
List(opts ...management.RequestOption) (c []*management.CustomDomain, err error)
}
25 changes: 25 additions & 0 deletions internal/cli/template.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package cli

import (
"context"
"errors"
"fmt"

"github.com/auth0/auth0-cli/internal/ansi"
Expand All @@ -27,6 +28,8 @@ var (
{"Login box + image", branding.ImageTemplate},
{"Page footers", branding.FooterTemplate},
}

errNotAllowed = errors.New("This feature requires at least one custom domain to be configured for the tenant.")
)

func brandingCmd(cli *cli) *cobra.Command {
Expand Down Expand Up @@ -178,6 +181,28 @@ func (cli *cli) obtainCustomTemplateData(ctx context.Context) (*branding.Templat
tenant *management.Tenant
)

g.Go(func() error {
var err error
domains, err := cli.api.CustomDomain.List()
if err != nil {
errStatus := err.(management.Error)
// 403 is a valid response for free tenants that don't have
// custom domains enabled
if errStatus != nil && errStatus.Status() == 403 {
return errNotAllowed
}

return err
}

for _, domain := range domains {
if domain.GetStatus() == "ready" {
return nil
}
}
return errNotAllowed
})

g.Go(func() error {
var err error
clients, err = cli.api.Client.List(management.Context(ctx), management.ExcludeFields(clientExcludedList...))
Expand Down
63 changes: 63 additions & 0 deletions internal/cli/test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package cli

import (
"errors"
"fmt"

"github.com/auth0/auth0-cli/internal/ansi"
Expand Down Expand Up @@ -50,6 +51,20 @@ var (
ShortForm: "s",
Help: "The list of scope you want to use to generate the token.",
}

testDomainArg = Argument{
Name: "Custom Domain",
Help: "One of your custom domains.",
}

testDomain = Flag{
Name: "Custom Domain",
LongForm: "domain",
ShortForm: "d",
Help: "One of your custom domains.",
}

errNoCustomDomains = errors.New("there are currently no custom domains")
)

func testCmd(cli *cli) *cobra.Command {
Expand All @@ -71,6 +86,7 @@ func testLoginCmd(cli *cli) *cobra.Command {
ClientID string
Audience string
ConnectionName string
CustomDomain string
}

cmd := &cobra.Command{
Expand Down Expand Up @@ -123,6 +139,13 @@ auth0 test login <client-id> --connection <connection>`,
return fmt.Errorf("Unable to find client %s; if you specified a client, please verify it exists, otherwise re-run the command", inputs.ClientID)
}

if inputs.CustomDomain == "" {
err = testDomainArg.Pick(cmd, &inputs.CustomDomain, cli.customDomainPickerOptions)
if err != nil && err != errNoCustomDomains {
return err
}
}

if proceed := runLoginFlowPreflightChecks(cli, client); !proceed {
return nil
}
Expand All @@ -135,6 +158,7 @@ auth0 test login <client-id> --connection <connection>`,
inputs.Audience, // audience is only supported for the test token command
"login", // force a login page when using the test login command
cliLoginTestingScopes,
inputs.CustomDomain,
)
if err != nil {
return fmt.Errorf("An unexpected error occurred while logging in to client %s: %w", inputs.ClientID, err)
Expand Down Expand Up @@ -172,6 +196,7 @@ auth0 test login <client-id> --connection <connection>`,
cmd.SetUsageTemplate(resourceUsageTemplate())
testAudience.RegisterString(cmd, &inputs.Audience, "")
testConnection.RegisterString(cmd, &inputs.ConnectionName, "")
testDomain.RegisterString(cmd, &inputs.CustomDomain, "")
return cmd
}

Expand Down Expand Up @@ -246,6 +271,7 @@ auth0 test token --client-id <id> --audience <audience> --scopes <scope1,scope2>
inputs.Audience,
"", // We don't want to force a prompt for the test token command
inputs.Scopes,
"",
)
if err != nil {
return fmt.Errorf("An unexpected error occurred when logging in to client %s: %w", inputs.ClientID, err)
Expand Down Expand Up @@ -274,3 +300,40 @@ func cleanupTempApplication(isTemp bool, cli *cli, id string) {
cli.renderer.Infof("Default test application removed")
}
}

func (c *cli) customDomainPickerOptions() (pickerOptions, error) {
var opts pickerOptions

domains, err := c.api.CustomDomain.List()
if err != nil {
errStatus := err.(management.Error)
// 403 is a valid response for free tenants that don't have
// custom domains enabled
if errStatus != nil && errStatus.Status() == 403 {
return nil, errNoCustomDomains
}

return nil, err
}

tenant, err := c.getTenant()
if err != nil {
return nil, err
}

for _, d := range domains {
if d.GetStatus() != "ready" {
continue
}

opts = append(opts, pickerOption{value: d.GetDomain(), label: d.GetDomain()})
}

if len(opts) == 0 {
return nil, errNoCustomDomains
}

opts = append(opts, pickerOption{value: "", label: fmt.Sprintf("none (use %s)", tenant.Domain)})

return opts, nil
}
9 changes: 7 additions & 2 deletions internal/cli/utils_shared.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ func runLoginFlowPreflightChecks(cli *cli, c *management.Client) (abort bool) {

// runLoginFlow initiates a full user-facing login flow, waits for a response
// and returns the retrieved tokens to the caller when done.
func runLoginFlow(cli *cli, t tenant, c *management.Client, connName, audience, prompt string, scopes []string) (*authutil.TokenResponse, error) {
func runLoginFlow(cli *cli, t tenant, c *management.Client, connName, audience, prompt string, scopes []string, customDomain string) (*authutil.TokenResponse, error) {
var tokenResponse *authutil.TokenResponse

err := ansi.Spinner("Waiting for login flow to complete", func() error {
Expand All @@ -122,8 +122,13 @@ func runLoginFlow(cli *cli, t tenant, c *management.Client, connName, audience,
return err
}

domain := t.Domain
if customDomain != "" {
domain = customDomain
}

// Build a login URL and initiate login in a browser window.
loginURL, err := authutil.BuildLoginURL(t.Domain, c.GetClientID(), cliLoginTestingCallbackURL, state, connName, audience, prompt, scopes)
loginURL, err := authutil.BuildLoginURL(domain, c.GetClientID(), cliLoginTestingCallbackURL, state, connName, audience, prompt, scopes)
if err != nil {
return err
}
Expand Down

0 comments on commit b69b35a

Please sign in to comment.