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

feat: add a custom domain picker for auth0 test login #281

Merged
merged 1 commit into from
May 3, 2021
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
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