From 6b655ef692ed55a2b7957d62bdbdb0a3e7a2ab77 Mon Sep 17 00:00:00 2001 From: Rita Zerrizuela Date: Thu, 31 Oct 2024 08:14:09 +0000 Subject: [PATCH 1/8] Remove iga-* triggers [DXEX-4601] (#1099) Remove iga-* triggers --- internal/cli/terraform_fetcher.go | 2 +- internal/cli/terraform_fetcher_test.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/cli/terraform_fetcher.go b/internal/cli/terraform_fetcher.go index c908b7b8..209840d3 100644 --- a/internal/cli/terraform_fetcher.go +++ b/internal/cli/terraform_fetcher.go @@ -543,7 +543,7 @@ func (f *tenantResourceFetcher) FetchData(_ context.Context) (importDataList, er func (f *triggerActionsResourceFetcher) FetchData(ctx context.Context) (importDataList, error) { var data importDataList - triggers := []string{"post-login", "credentials-exchange", "pre-user-registration", "post-user-registration", "post-change-password", "send-phone-message", "password-reset-post-challenge", "iga-approval", "iga-certification", "iga-fulfillment-assignment", "iga-fulfillment-execution"} + triggers := []string{"post-login", "credentials-exchange", "pre-user-registration", "post-user-registration", "post-change-password", "send-phone-message", "password-reset-post-challenge"} for _, trigger := range triggers { res, err := f.api.Action.Bindings(ctx, trigger) diff --git a/internal/cli/terraform_fetcher_test.go b/internal/cli/terraform_fetcher_test.go index 9b6dda9c..e24e5d08 100644 --- a/internal/cli/terraform_fetcher_test.go +++ b/internal/cli/terraform_fetcher_test.go @@ -1658,7 +1658,7 @@ func TestTriggerActionsResourceFetcher_FetchData(t *testing.T) { defer ctrl.Finish() actionAPI := mock.NewMockActionAPI(ctrl) - for _, trigger := range []string{"post-login", "credentials-exchange", "pre-user-registration", "post-user-registration", "post-change-password", "send-phone-message", "password-reset-post-challenge", "iga-approval", "iga-certification", "iga-fulfillment-assignment", "iga-fulfillment-execution"} { + for _, trigger := range []string{"post-login", "credentials-exchange", "pre-user-registration", "post-user-registration", "post-change-password", "send-phone-message", "password-reset-post-challenge"} { bindings := []*management.ActionBinding{} if trigger == "pre-user-registration" { From 00cb21630f6f1270aa4a0e45ef31fd56a4dfc377 Mon Sep 17 00:00:00 2001 From: Rajat Bajaj Date: Thu, 31 Oct 2024 15:19:47 +0530 Subject: [PATCH 2/8] Add new flag to specify terraform version in `auth0 tf generate` command (#1098) * Added a flag for terraform version during generate * Updated docs --- docs/auth0_terraform_generate.md | 1 + internal/cli/terraform.go | 42 ++++++++++++++++----------- internal/cli/terraform_test.go | 49 ++++++++++++++++++-------------- 3 files changed, 54 insertions(+), 38 deletions(-) diff --git a/docs/auth0_terraform_generate.md b/docs/auth0_terraform_generate.md index 02a4232a..19326a29 100644 --- a/docs/auth0_terraform_generate.md +++ b/docs/auth0_terraform_generate.md @@ -34,6 +34,7 @@ auth0 terraform generate [flags] --force Skip confirmation. -o, --output-dir string Output directory for the generated Terraform config files. If not provided, the files will be saved in the current working directory. (default "./") -r, --resources strings Resource types to generate Terraform config for. If not provided, config files for all available resources will be generated. (default [auth0_action,auth0_attack_protection,auth0_branding,auth0_client,auth0_client_grant,auth0_connection,auth0_custom_domain,auth0_flow,auth0_flow_vault_connection,auth0_form,auth0_email_provider,auth0_email_template,auth0_guardian,auth0_organization,auth0_pages,auth0_prompt,auth0_prompt_custom_text,auth0_resource_server,auth0_role,auth0_tenant,auth0_trigger_actions]) + -v, --tf-version string Terraform version that ought to be used while generating the terraform files for resources. If not provided, 1.5.0 is used by default (default "1.5.0") ``` diff --git a/internal/cli/terraform.go b/internal/cli/terraform.go index 973633b2..cf7f8565 100644 --- a/internal/cli/terraform.go +++ b/internal/cli/terraform.go @@ -38,17 +38,26 @@ var tfFlags = terraformFlags{ Help: "Resource types to generate Terraform config for. If not provided, config files for all " + "available resources will be generated.", }, + TerraformVersion: Flag{ + Name: "Terraform Version", + LongForm: "tf-version", + ShortForm: "v", + Help: "Terraform version that ought to be used while generating the terraform files for resources. " + + "If not provided, 1.5.0 is used by default", + }, } type ( terraformFlags struct { - OutputDIR Flag - Resources Flag + OutputDIR Flag + Resources Flag + TerraformVersion Flag } terraformInputs struct { - OutputDIR string - Resources []string + OutputDIR string + Resources []string + TerraformVersion string } ) @@ -147,6 +156,7 @@ func generateTerraformCmd(cli *cli) *cobra.Command { cmd.Flags().BoolVar(&cli.force, "force", false, "Skip confirmation.") tfFlags.OutputDIR.RegisterString(cmd, &inputs.OutputDIR, "./") tfFlags.Resources.RegisterStringSlice(cmd, &inputs.Resources, defaultResources) + tfFlags.TerraformVersion.RegisterString(cmd, &inputs.TerraformVersion, "1.5.0") return cmd } @@ -175,7 +185,7 @@ func generateTerraformCmdRun(cli *cli, inputs *terraformInputs) func(cmd *cobra. return err } - if err := generateTerraformImportConfig(inputs.OutputDIR, data); err != nil { + if err := generateTerraformImportConfig(inputs, data); err != nil { return err } @@ -191,7 +201,7 @@ func generateTerraformCmdRun(cli *cli, inputs *terraformInputs) func(cmd *cobra. } err = ansi.Spinner("Generating Terraform configuration", func() error { - return generateTerraformResourceConfig(cmd.Context(), inputs.OutputDIR) + return generateTerraformResourceConfig(cmd.Context(), inputs) }) if err != nil { @@ -241,20 +251,20 @@ func fetchImportData(ctx context.Context, fetchers ...resourceDataFetcher) (impo return deduplicateResourceNames(importData), nil } -func generateTerraformImportConfig(outputDIR string, data importDataList) error { +func generateTerraformImportConfig(inputs *terraformInputs, data importDataList) error { if len(data) == 0 { return errors.New("no import data available") } - if err := createOutputDirectory(outputDIR); err != nil { + if err := createOutputDirectory(inputs.OutputDIR); err != nil { return err } - if err := createMainFile(outputDIR); err != nil { + if err := createMainFile(inputs); err != nil { return err } - return createImportFile(outputDIR, data) + return createImportFile(inputs.OutputDIR, data) } func createOutputDirectory(outputDIR string) error { @@ -267,8 +277,8 @@ func createOutputDirectory(outputDIR string) error { return nil } -func createMainFile(outputDIR string) error { - filePath := path.Join(outputDIR, "auth0_main.tf") +func createMainFile(input *terraformInputs) error { + filePath := path.Join(input.OutputDIR, "auth0_main.tf") file, err := os.Create(filePath) if err != nil { @@ -279,7 +289,7 @@ func createMainFile(outputDIR string) error { }() fileContent := `terraform { - required_version = ">= 1.5.0" + required_version = ">= ` + input.TerraformVersion + `" required_providers { auth0 = { source = "auth0/auth0" @@ -327,15 +337,15 @@ import { return t.Execute(file, data) } -func generateTerraformResourceConfig(ctx context.Context, outputDIR string) error { - absoluteOutputPath, err := filepath.Abs(outputDIR) +func generateTerraformResourceConfig(ctx context.Context, input *terraformInputs) error { + absoluteOutputPath, err := filepath.Abs(input.OutputDIR) if err != nil { return err } installer := &releases.ExactVersion{ Product: product.Terraform, - Version: version.Must(version.NewVersion("1.5.0")), + Version: version.Must(version.NewVersion(input.TerraformVersion)), InstallDir: absoluteOutputPath, } diff --git a/internal/cli/terraform_test.go b/internal/cli/terraform_test.go index fe499c9f..9fcef3ec 100644 --- a/internal/cli/terraform_test.go +++ b/internal/cli/terraform_test.go @@ -79,78 +79,78 @@ func TestFetchImportData(t *testing.T) { func TestGenerateTerraformImportConfig(t *testing.T) { t.Run("it can correctly generate the terraform config files", func(t *testing.T) { - outputDIR, importData := setupTestDIRAndImportData(t) + input, importData := setupTestDIRAndImportData(t) - err := generateTerraformImportConfig(outputDIR, importData) + err := generateTerraformImportConfig(&input, importData) require.NoError(t, err) - assertTerraformMainFileWasGeneratedCorrectly(t, outputDIR) - assertTerraformImportFileWasGeneratedCorrectly(t, outputDIR, importData) + assertTerraformMainFileWasGeneratedCorrectly(t, input.OutputDIR) + assertTerraformImportFileWasGeneratedCorrectly(t, input.OutputDIR, importData) }) t.Run("it can correctly generate the terraform main config file even if the dir exists", func(t *testing.T) { - outputDIR, importData := setupTestDIRAndImportData(t) + input, importData := setupTestDIRAndImportData(t) - err := os.MkdirAll(outputDIR, 0755) + err := os.MkdirAll(input.OutputDIR, 0755) require.NoError(t, err) - err = generateTerraformImportConfig(outputDIR, importData) + err = generateTerraformImportConfig(&input, importData) require.NoError(t, err) - assertTerraformMainFileWasGeneratedCorrectly(t, outputDIR) - assertTerraformImportFileWasGeneratedCorrectly(t, outputDIR, importData) + assertTerraformMainFileWasGeneratedCorrectly(t, input.OutputDIR) + assertTerraformImportFileWasGeneratedCorrectly(t, input.OutputDIR, importData) }) t.Run("it fails to generate the terraform config files if there's no import data", func(t *testing.T) { - outputDIR, _ := setupTestDIRAndImportData(t) + input, _ := setupTestDIRAndImportData(t) - err := generateTerraformImportConfig(outputDIR, importDataList{}) + err := generateTerraformImportConfig(&input, importDataList{}) assert.EqualError(t, err, "no import data available") }) t.Run("it fails to create the directory if path is empty", func(t *testing.T) { _, importData := setupTestDIRAndImportData(t) - err := generateTerraformImportConfig("", importData) + err := generateTerraformImportConfig(&terraformInputs{OutputDIR: ""}, importData) assert.EqualError(t, err, "mkdir : no such file or directory") }) t.Run("it fails to create the main.tf file if file is already created and read only", func(t *testing.T) { - outputDIR, importData := setupTestDIRAndImportData(t) + input, importData := setupTestDIRAndImportData(t) - err := os.MkdirAll(outputDIR, 0755) + err := os.MkdirAll(input.OutputDIR, 0755) require.NoError(t, err) - mainFilePath := path.Join(outputDIR, "auth0_main.tf") + mainFilePath := path.Join(input.OutputDIR, "auth0_main.tf") _, err = os.Create(mainFilePath) require.NoError(t, err) err = os.Chmod(mainFilePath, 0444) require.NoError(t, err) - err = generateTerraformImportConfig(outputDIR, importData) + err = generateTerraformImportConfig(&input, importData) assert.EqualError(t, err, fmt.Sprintf("open %s: permission denied", mainFilePath)) }) t.Run("it fails to create the auth0_import.tf file if file is already created and read only", func(t *testing.T) { - outputDIR, importData := setupTestDIRAndImportData(t) + input, importData := setupTestDIRAndImportData(t) - err := os.MkdirAll(outputDIR, 0755) + err := os.MkdirAll(input.OutputDIR, 0755) require.NoError(t, err) - importFilePath := path.Join(outputDIR, "auth0_import.tf") + importFilePath := path.Join(input.OutputDIR, "auth0_import.tf") _, err = os.Create(importFilePath) require.NoError(t, err) err = os.Chmod(importFilePath, 0444) require.NoError(t, err) - err = generateTerraformImportConfig(outputDIR, importData) + err = generateTerraformImportConfig(&input, importData) assert.EqualError(t, err, fmt.Sprintf("open %s: permission denied", importFilePath)) }) } -func setupTestDIRAndImportData(t *testing.T) (string, importDataList) { +func setupTestDIRAndImportData(t *testing.T) (terraformInputs, importDataList) { dirPath, err := os.MkdirTemp("", "terraform-*") require.NoError(t, err) @@ -179,7 +179,12 @@ func setupTestDIRAndImportData(t *testing.T) (string, importDataList) { }, } - return outputDIR, importData + input := terraformInputs{ + outputDIR, + nil, + "1.5.0", + } + return input, importData } func assertTerraformMainFileWasGeneratedCorrectly(t *testing.T, outputDIR string) { From be18be85166df763865447ceaa5e76a245428d3b Mon Sep 17 00:00:00 2001 From: Rajat Bajaj Date: Thu, 31 Oct 2024 15:37:35 +0530 Subject: [PATCH 3/8] Add changelog for v1.6.1 (#1100) * Add changelog for v1.6.1 * minor * minor --- CHANGELOG.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d171dae1..4891b6a1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +# [v1.6.1](https://github.com/auth0/auth0-cli/tree/v1.6.1) (Oct 31, 2024) + +[Full Changelog](https://github.com/auth0/auth0-cli/compare/v1.6.0...v1.6.1) + +### Added + +- Added new flag (`tf-version`) to pass terraform version during `auth0 tf generate` command [#1098] + +### Removed + +- Removed iga-* triggers from triggerActionsResourceFetcher [#1099] + # [v1.6.0](https://github.com/auth0/auth0-cli/tree/v1.6.0) (Oct 17, 2024) [Full Changelog](https://github.com/auth0/auth0-cli/compare/v1.5.1...v1.6.0) @@ -315,6 +327,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Updating of action triggers which inevitably results in error [#597] [unreleased]: https://github.com/auth0/auth0-cli/compare/v1.5.1...HEAD +[#1099]: https://github.com/auth0/auth0-cli/issues/1099 +[#1098]: https://github.com/auth0/auth0-cli/issues/1098 [#1091]: https://github.com/auth0/auth0-cli/issues/1091 [#1084]: https://github.com/auth0/auth0-cli/issues/1084 [#1083]: https://github.com/auth0/auth0-cli/issues/1083 From fc25ffafa05a84bb71fb50f7f520649102b21da5 Mon Sep 17 00:00:00 2001 From: Ramya Anusri <62586490+ramya18101@users.noreply.github.com> Date: Mon, 2 Dec 2024 10:48:50 +0530 Subject: [PATCH 4/8] Make necessary calls to GET Partials basis on the promptType (#1107) * Update ul assets to make only necessary ws events * Revert "Update ul assets to make only necessary ws events" This reverts commit 2c6191473fbb65c5cfda9f3a0feda0ba43435911. * Update the logic to not call the GET Partials for non-supported prompts * Update integration tests by removing rules related CRUD calls and temporarily commented out the ul prompts update testcase. --- internal/cli/universal_login_customize.go | 18 ++++- test/integration/rules-test-cases.yaml | 70 ------------------- .../universal-login-test-cases.yaml | 6 +- 3 files changed, 19 insertions(+), 75 deletions(-) diff --git a/internal/cli/universal_login_customize.go b/internal/cli/universal_login_customize.go index 50330d81..73c966ea 100644 --- a/internal/cli/universal_login_customize.go +++ b/internal/cli/universal_login_customize.go @@ -477,6 +477,16 @@ func (h *webSocketHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { } } +func isSupportedPartial(givenPrompt management.PromptType) bool { + for _, prompt := range allowedPromptsWithPartials { + if givenPrompt == prompt { + return true + } + } + + return false +} + func checkOriginFunc(r *http.Request) bool { origin := r.Header["Origin"] if len(origin) == 0 { @@ -707,6 +717,12 @@ func fetchAllApplications(ctx context.Context, api *auth0.API) ([]*applicationDa } func fetchPartial(ctx context.Context, api *auth0.API, prompt *partialData) (*management.PromptScreenPartials, error) { + var filteredPartials = management.PromptScreenPartials{} + + if !isSupportedPartial(management.PromptType(prompt.PromptName)) { + return &management.PromptScreenPartials{}, nil + } + partial, err := api.Prompt.GetPartials(ctx, management.PromptType(prompt.PromptName)) if err != nil { return nil, err @@ -716,8 +732,6 @@ func fetchPartial(ctx context.Context, api *auth0.API, prompt *partialData) (*ma return &management.PromptScreenPartials{}, nil } - filteredPartials := management.PromptScreenPartials{} - if screenPartials, ok := (*partial)[management.ScreenName(prompt.ScreenName)]; ok { filteredPartials[management.ScreenName(prompt.ScreenName)] = screenPartials } diff --git a/test/integration/rules-test-cases.yaml b/test/integration/rules-test-cases.yaml index 9d61c5a6..e75ac2bf 100644 --- a/test/integration/rules-test-cases.yaml +++ b/test/integration/rules-test-cases.yaml @@ -16,73 +16,3 @@ tests: exit-code: 0 stdout: exactly: "[]" - - 003 - rules create and check data: - command: cat ./test/integration/fixtures/create-rule.json | jq '.[0]' | auth0 rules create --json - stdout: - json: - name: integration-test-rule-new1 - enabled: "true" - order: "1" - script: "function(user, context, cb) {\n cb(null, user, context);\n}\n" - exit-code: 0 - - 004 - rules create and check output: - command: cat ./test/integration/fixtures/create-rule.json | jq '.[1]' | auth0 rules create - stdout: - contains: - - NAME integration-test-rule-new2 - - ENABLED ✗ - - ORDER 2 - - SCRIPT function(user, context, cb) { - exit-code: 0 - - 005 - rules list all with data: - command: auth0 rules list - exit-code: 0 - stdout: - contains: - - ID - - NAME - - ENABLED - - ORDER - - 006 - rules show json: - command: auth0 rules show $(./test/integration/scripts/get-rule-id.sh) --json - stdout: - json: - name: integration-test-rule-newRule - enabled: "false" - order: "3" - exit-code: 0 - - 007 - rules show: - command: auth0 rules show $(./test/integration/scripts/get-rule-id.sh) - stdout: - contains: - - NAME integration-test-rule-newRule - - ENABLED ✗ - - ORDER 3 - exit-code: 0 - - 008 - rules update: - command: cat ./test/integration/fixtures/update-rule.json | auth0 rules update --json - stdout: - json: - name: integration-test-rule-betterName - enabled: "false" - exit-code: 0 - - 009 - rules enable: - command: auth0 rules enable $(./test/integration/scripts/get-rule-id.sh) --json - stdout: - json: - enabled: "true" - exit-code: 0 - - 010 - rules disable: - command: auth0 rules disable $(./test/integration/scripts/get-rule-id.sh) --json - stdout: - json: - enabled: "false" - exit-code: 0 diff --git a/test/integration/universal-login-test-cases.yaml b/test/integration/universal-login-test-cases.yaml index 2c6ae4fd..6b3d4eee 100644 --- a/test/integration/universal-login-test-cases.yaml +++ b/test/integration/universal-login-test-cases.yaml @@ -86,9 +86,9 @@ tests: contains: - "Failed to fetch the Universal Login template data: this feature requires at least one custom domain to be set and verified for the tenant, use 'auth0 domains create' to create one and 'auth0 domains verify' to have it verified" - 010 - update universal login branding prompts (login): - command: cat ./test/integration/fixtures/update-ul-prompts-login.json | auth0 ul prompts update login - exit-code: 0 +# 010 - update universal login branding prompts (login): +# command: cat ./test/integration/fixtures/update-ul-prompts-login.json | auth0 ul prompts update login +# exit-code: 0 011 - update universal login branding prompts (mfa-push): command: cat ./test/integration/fixtures/update-ul-prompts-mfa-push.json | auth0 ul prompts update mfa-push From e765aec5ee3d3477b0910292177b14af962d82e8 Mon Sep 17 00:00:00 2001 From: Ramya Anusri <62586490+ramya18101@users.noreply.github.com> Date: Mon, 9 Dec 2024 18:51:36 +0530 Subject: [PATCH 5/8] Add support for rendering the settings of prompt-screen (#1106) * Support tf generate command for auth0_prompt_screen_renderer * Update docs of tf generate * Support switching to advanceMode and make ACUL for all prompts & screens * Add logic to update the existing prompt-screen-settings and update mocks * Add pre-requisites-info for the default prompt-screen-settings.json file. * Fix example docs * remove the built-in function to fetch keys of a map. * Update integration tests by removing rules related CRUD calls and temporarily commented out the ul prompts update testcase. * Update go-auth0 version * Fix the required scopes & fix linter in imports * Update golangci-lint version to the latest * Update golangci-lint-action version to the latest * Revert golangci-lint-action version from latest * Update golangci-lint-action version to v1.62.0 * Update golangci-lint-action version to v1.62.0 * Remove toolchain * Provide version to v1.59.0 * updated version syntax * Restored go mod files * Update long description for ul customize command * Update docs for ul customize command * Update the latest go-auth0 version and doc info * Support the 12 screens * Add check for the ACUL enabled feature. --- .github/workflows/main.yml | 2 +- Makefile | 2 +- docs/auth0_terraform_generate.md | 2 +- docs/auth0_universal-login.md | 2 +- docs/auth0_universal-login_customize.md | 16 ++- docs/auth0_universal-login_show.md | 2 +- docs/auth0_universal-login_update.md | 2 +- go.mod | 16 +-- go.sum | 32 ++--- internal/auth/auth.go | 1 + internal/auth0/branding_prompt.go | 10 ++ internal/auth0/mock/branding_prompt_mock.go | 39 ++++++ .../prompt-screen-settings.json | 33 +++++ internal/cli/terraform.go | 2 + internal/cli/terraform_fetcher.go | 46 ++++++- internal/cli/universal_login_customize.go | 121 +++++++++++++++++- test/integration/rules-test-cases.yaml | 70 ++++++++++ 17 files changed, 359 insertions(+), 39 deletions(-) create mode 100644 internal/cli/data/universal-login/prompt-screen-settings.json diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 0529ee00..fa8a8b43 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -34,7 +34,7 @@ jobs: uses: golangci/golangci-lint-action@a4f60bb28d35aeee14e6880718e0c85ff1882e64 # v6.0.1 with: install-mode: "goinstall" - version: 2059b18a39d559552839476ba78ce6acaa499b43 # v1.59.0 + version: v1.59.0 args: -v -c .golangci.yml unit-tests: diff --git a/Makefile b/Makefile index ada75aec..328723e2 100644 --- a/Makefile +++ b/Makefile @@ -60,7 +60,7 @@ $(GO_BIN)/mockgen: $(GO_BIN)/golangci-lint: ${call print, "Installing golangci-lint"} - @go install -v github.com/golangci/golangci-lint/cmd/golangci-lint@2059b18a39d559552839476ba78ce6acaa499b43 # v1.59.0 + @go install -v github.com/golangci/golangci-lint/cmd/golangci-lint@v1.59.0 $(GO_BIN)/govulncheck: ${call print, "Installing go vulnerability checker"} diff --git a/docs/auth0_terraform_generate.md b/docs/auth0_terraform_generate.md index 19326a29..d6d5cba4 100644 --- a/docs/auth0_terraform_generate.md +++ b/docs/auth0_terraform_generate.md @@ -33,7 +33,7 @@ auth0 terraform generate [flags] ``` --force Skip confirmation. -o, --output-dir string Output directory for the generated Terraform config files. If not provided, the files will be saved in the current working directory. (default "./") - -r, --resources strings Resource types to generate Terraform config for. If not provided, config files for all available resources will be generated. (default [auth0_action,auth0_attack_protection,auth0_branding,auth0_client,auth0_client_grant,auth0_connection,auth0_custom_domain,auth0_flow,auth0_flow_vault_connection,auth0_form,auth0_email_provider,auth0_email_template,auth0_guardian,auth0_organization,auth0_pages,auth0_prompt,auth0_prompt_custom_text,auth0_resource_server,auth0_role,auth0_tenant,auth0_trigger_actions]) + -r, --resources strings Resource types to generate Terraform config for. If not provided, config files for all available resources will be generated. (default [auth0_action,auth0_attack_protection,auth0_branding,auth0_client,auth0_client_grant,auth0_connection,auth0_custom_domain,auth0_flow,auth0_flow_vault_connection,auth0_form,auth0_email_provider,auth0_email_template,auth0_guardian,auth0_organization,auth0_pages,auth0_prompt,auth0_prompt_custom_text,auth0_prompt_screen_renderer,auth0_resource_server,auth0_role,auth0_tenant,auth0_trigger_actions]) -v, --tf-version string Terraform version that ought to be used while generating the terraform files for resources. If not provided, 1.5.0 is used by default (default "1.5.0") ``` diff --git a/docs/auth0_universal-login.md b/docs/auth0_universal-login.md index 45468c0a..99858736 100644 --- a/docs/auth0_universal-login.md +++ b/docs/auth0_universal-login.md @@ -9,7 +9,7 @@ Manage a consistent, branded Universal Login experience that can handle all of y ## Commands -- [auth0 universal-login customize](auth0_universal-login_customize.md) - Customize the Universal Login experience +- [auth0 universal-login customize](auth0_universal-login_customize.md) - Customize the Universal Login experience for the standard or advanced mode - [auth0 universal-login prompts](auth0_universal-login_prompts.md) - Manage custom text for prompts - [auth0 universal-login show](auth0_universal-login_show.md) - Display the custom branding settings for Universal Login - [auth0 universal-login templates](auth0_universal-login_templates.md) - Manage custom Universal Login templates diff --git a/docs/auth0_universal-login_customize.md b/docs/auth0_universal-login_customize.md index 727ad77e..12a844cc 100644 --- a/docs/auth0_universal-login_customize.md +++ b/docs/auth0_universal-login_customize.md @@ -5,7 +5,19 @@ has_toc: false --- # auth0 universal-login customize -Customize and preview changes to the Universal Login experience. This command will open a webpage within your browser where you can edit and preview your branding changes. For a comprehensive list of editable parameters and their values please visit the [Management API Documentation](https://auth0.com/docs/api/management/v2). + +Customize your Universal Login Experience. Note that this requires a custom domain to be configured for the tenant. + +* Standard mode is recommended for creating a consistent, branded experience for users. Choosing Standard mode will open a webpage +within your browser where you can edit and preview your branding changes.For a comprehensive list of editable parameters and their values, +please visit the [Management API Documentation](https://auth0.com/docs/api/management/v2) + +* Advanced mode is recommended for full customization/granular control of the login experience and to integrate your own component design system. +Choosing Advanced mode will open the default terminal editor, with the rendering configs: + +![storybook](settings.json) + +Closing the terminal editor will save the settings to your tenant. ## Usage ``` @@ -34,7 +46,7 @@ auth0 universal-login customize [flags] ## Related Commands -- [auth0 universal-login customize](auth0_universal-login_customize.md) - Customize the Universal Login experience +- [auth0 universal-login customize](auth0_universal-login_customize.md) - Customize the Universal Login experience for the standard or advanced mode - [auth0 universal-login prompts](auth0_universal-login_prompts.md) - Manage custom text for prompts - [auth0 universal-login show](auth0_universal-login_show.md) - Display the custom branding settings for Universal Login - [auth0 universal-login templates](auth0_universal-login_templates.md) - Manage custom Universal Login templates diff --git a/docs/auth0_universal-login_show.md b/docs/auth0_universal-login_show.md index 53ab7fe3..896447d7 100644 --- a/docs/auth0_universal-login_show.md +++ b/docs/auth0_universal-login_show.md @@ -40,7 +40,7 @@ auth0 universal-login show [flags] ## Related Commands -- [auth0 universal-login customize](auth0_universal-login_customize.md) - Customize the Universal Login experience +- [auth0 universal-login customize](auth0_universal-login_customize.md) - Customize the Universal Login experience for the standard or advanced mode - [auth0 universal-login prompts](auth0_universal-login_prompts.md) - Manage custom text for prompts - [auth0 universal-login show](auth0_universal-login_show.md) - Display the custom branding settings for Universal Login - [auth0 universal-login templates](auth0_universal-login_templates.md) - Manage custom Universal Login templates diff --git a/docs/auth0_universal-login_update.md b/docs/auth0_universal-login_update.md index 30349e80..2548b240 100644 --- a/docs/auth0_universal-login_update.md +++ b/docs/auth0_universal-login_update.md @@ -50,7 +50,7 @@ auth0 universal-login update [flags] ## Related Commands -- [auth0 universal-login customize](auth0_universal-login_customize.md) - Customize the Universal Login experience +- [auth0 universal-login customize](auth0_universal-login_customize.md) - Customize the Universal Login experience for the standard or advanced mode - [auth0 universal-login prompts](auth0_universal-login_prompts.md) - Manage custom text for prompts - [auth0 universal-login show](auth0_universal-login_show.md) - Display the custom branding settings for Universal Login - [auth0 universal-login templates](auth0_universal-login_templates.md) - Manage custom Universal Login templates diff --git a/go.mod b/go.mod index edcfb828..71ee779c 100644 --- a/go.mod +++ b/go.mod @@ -8,7 +8,7 @@ replace github.com/mholt/archiver/v3 => github.com/anchore/archiver/v3 v3.5.2 require ( github.com/AlecAivazis/survey/v2 v2.3.7 github.com/PuerkitoBio/rehttp v1.4.0 - github.com/auth0/go-auth0 v1.11.0 + github.com/auth0/go-auth0 v1.13.0 github.com/briandowns/spinner v1.23.1 github.com/charmbracelet/glamour v0.8.0 github.com/fsnotify/fsnotify v1.7.0 @@ -31,16 +31,16 @@ require ( github.com/schollz/progressbar/v3 v3.16.1 github.com/spf13/cobra v1.8.1 github.com/spf13/pflag v1.0.5 - github.com/stretchr/testify v1.9.0 + github.com/stretchr/testify v1.10.0 github.com/tidwall/pretty v1.2.1 github.com/zalando/go-keyring v0.2.5 golang.org/x/exp v0.0.0-20230321023759-10a507213a29 golang.org/x/net v0.30.0 - golang.org/x/oauth2 v0.23.0 - golang.org/x/sync v0.8.0 - golang.org/x/sys v0.26.0 - golang.org/x/term v0.25.0 - golang.org/x/text v0.19.0 + golang.org/x/oauth2 v0.24.0 + golang.org/x/sync v0.9.0 + golang.org/x/sys v0.27.0 + golang.org/x/term v0.26.0 + golang.org/x/text v0.20.0 gopkg.in/yaml.v2 v2.4.0 ) @@ -94,7 +94,7 @@ require ( github.com/yuin/goldmark v1.7.4 // indirect github.com/yuin/goldmark-emoji v1.0.3 // indirect github.com/zclconf/go-cty v1.14.4 // indirect - golang.org/x/crypto v0.28.0 // indirect + golang.org/x/crypto v0.29.0 // indirect golang.org/x/mod v0.19.0 // indirect golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect diff --git a/go.sum b/go.sum index 127d6ad8..09d507cb 100644 --- a/go.sum +++ b/go.sum @@ -25,8 +25,8 @@ github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1 github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY= github.com/apparentlymart/go-textseg/v15 v15.0.0 h1:uYvfpb3DyLSCGWnctWKGj857c6ew1u1fNQOlOtuGxQY= github.com/apparentlymart/go-textseg/v15 v15.0.0/go.mod h1:K8XmNZdhEBkdlyDdvbmmsvpAG721bKi0joRfFdHIWJ4= -github.com/auth0/go-auth0 v1.11.0 h1:gFBVhJCQUW1cET+f/fSH+aXiUebvH2IaaXhMiSaPclw= -github.com/auth0/go-auth0 v1.11.0/go.mod h1:VyYseHsdB4s9jmfBqoxnzJTvZr0w17ZJ5kjNdA+ag9Y= +github.com/auth0/go-auth0 v1.13.0 h1:GA7WyGAzlKBQ2ctHcCZwVf0aiOvPd2PB3QagC5heQJg= +github.com/auth0/go-auth0 v1.13.0/go.mod h1:G3oPT7sWjmM4mHbn6qkMYEsxnwm/5PnSbo0kpPLSS0E= github.com/aybabtme/iocontrol v0.0.0-20150809002002-ad15bcfc95a0 h1:0NmehRCgyk5rljDQLKUO+cRJCnduDyn11+zGZIc9Z48= github.com/aybabtme/iocontrol v0.0.0-20150809002002-ad15bcfc95a0/go.mod h1:6L7zgvqo0idzI7IO8de6ZC051AfXb5ipkIJ7bIA2tGA= github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k= @@ -227,8 +227,8 @@ github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/ github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= -github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= +github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4= github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= github.com/ulikunitz/xz v0.5.8/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= @@ -253,8 +253,8 @@ github.com/zclconf/go-cty v1.14.4/go.mod h1:VvMs5i0vgZdhYawQNq5kePSpLAoz8u1xvZgr golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw= -golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U= +golang.org/x/crypto v0.29.0 h1:L5SG1JTTXupVV3n6sUqMTeWbjAyfPwoda2DLX8J8FrQ= +golang.org/x/crypto v0.29.0/go.mod h1:+F4F4N5hv6v38hfeYwTdx20oUvLLc+QfrE9Ax9HtgRg= golang.org/x/exp v0.0.0-20230321023759-10a507213a29 h1:ooxPy7fPvB4kwsA2h+iBNHkAbp/4JxTSwCmvdjEYmug= golang.org/x/exp v0.0.0-20230321023759-10a507213a29/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= @@ -269,13 +269,13 @@ golang.org/x/net v0.0.0-20210510120150-4163338589ed/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.30.0 h1:AcW1SDZMkb8IpzCdQUaIq2sP4sZ4zw+55h6ynffypl4= golang.org/x/net v0.30.0/go.mod h1:2wGyMJ5iFasEhkwi13ChkO/t1ECNC4X4eBKkVFyYFlU= -golang.org/x/oauth2 v0.23.0 h1:PbgcYx2W7i4LvjJWEbf0ngHV6qJYr86PkAV3bXdLEbs= -golang.org/x/oauth2 v0.23.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= +golang.org/x/oauth2 v0.24.0 h1:KTBBxWqUa0ykRPLtV69rRto9TLXcqYkeswu48x/gvNE= +golang.org/x/oauth2 v0.24.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= -golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.9.0 h1:fEo0HyrW1GIgZdpbhCRO0PkJajUS5H9IFUztCgEo2jQ= +golang.org/x/sync v0.9.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -289,19 +289,19 @@ golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo= -golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.27.0 h1:wBqf8DvsY9Y/2P8gAfPDEYNuS30J4lPHJxXSb/nJZ+s= +golang.org/x/sys v0.27.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.25.0 h1:WtHI/ltw4NvSUig5KARz9h521QvRC8RmF/cuYqifU24= -golang.org/x/term v0.25.0/go.mod h1:RPyXicDX+6vLxogjjRxjgD2TKtmAO6NZBsBRfrOLu7M= +golang.org/x/term v0.26.0 h1:WEQa6V3Gja/BhNxg540hBip/kkaYtRg3cxg4oXSw4AU= +golang.org/x/term v0.26.0/go.mod h1:Si5m1o57C5nBNQo5z1iq+XDijt21BDBDp2bK0QI8e3E= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM= -golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= +golang.org/x/text v0.20.0 h1:gK/Kv2otX8gz+wn7Rmb3vT96ZwuoxnQlY+HlJVj7Qug= +golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= diff --git a/internal/auth/auth.go b/internal/auth/auth.go index 5e354133..0947600e 100644 --- a/internal/auth/auth.go +++ b/internal/auth/auth.go @@ -130,6 +130,7 @@ var RequiredScopes = []string{ "read:branding", "update:branding", "read:email_templates", "update:email_templates", "read:email_provider", + "read:flows", "read:forms", "read:flows_vault_connections", "read:connections", "update:connections", "read:client_keys", "read:logs", "read:tenant_settings", "read:custom_domains", "create:custom_domains", "update:custom_domains", "delete:custom_domains", diff --git a/internal/auth0/branding_prompt.go b/internal/auth0/branding_prompt.go index 8fe393f5..259d5c83 100644 --- a/internal/auth0/branding_prompt.go +++ b/internal/auth0/branding_prompt.go @@ -38,4 +38,14 @@ type PromptAPI interface { // // See: https://auth0.com/docs/api/management/v2/prompts/put-partials SetPartials(ctx context.Context, prompt management.PromptType, c *management.PromptScreenPartials, opts ...management.RequestOption) error + + // ReadRendering retrieves the settings for the ACUL. + // + // See: https://auth0.com/docs/api/management/v2/prompts/get-rendering + ReadRendering(ctx context.Context, prompt management.PromptType, screen management.ScreenName, opts ...management.RequestOption) (c *management.PromptRendering, err error) + + // UpdateRendering updates the settings for the ACUL. + // + // See: https://auth0.com/docs/api/management/v2/prompts/patch-rendering + UpdateRendering(ctx context.Context, prompt management.PromptType, screen management.ScreenName, c *management.PromptRendering, opts ...management.RequestOption) error } diff --git a/internal/auth0/mock/branding_prompt_mock.go b/internal/auth0/mock/branding_prompt_mock.go index edf76e37..70b12051 100644 --- a/internal/auth0/mock/branding_prompt_mock.go +++ b/internal/auth0/mock/branding_prompt_mock.go @@ -95,6 +95,26 @@ func (mr *MockPromptAPIMockRecorder) Read(ctx interface{}, opts ...interface{}) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Read", reflect.TypeOf((*MockPromptAPI)(nil).Read), varargs...) } +// ReadRendering mocks base method. +func (m *MockPromptAPI) ReadRendering(ctx context.Context, prompt management.PromptType, screen management.ScreenName, opts ...management.RequestOption) (*management.PromptRendering, error) { + m.ctrl.T.Helper() + varargs := []interface{}{ctx, prompt, screen} + for _, a := range opts { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "ReadRendering", varargs...) + ret0, _ := ret[0].(*management.PromptRendering) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ReadRendering indicates an expected call of ReadRendering. +func (mr *MockPromptAPIMockRecorder) ReadRendering(ctx, prompt, screen interface{}, opts ...interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]interface{}{ctx, prompt, screen}, opts...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ReadRendering", reflect.TypeOf((*MockPromptAPI)(nil).ReadRendering), varargs...) +} + // SetCustomText mocks base method. func (m *MockPromptAPI) SetCustomText(ctx context.Context, p, l string, b map[string]interface{}, opts ...management.RequestOption) error { m.ctrl.T.Helper() @@ -151,3 +171,22 @@ func (mr *MockPromptAPIMockRecorder) Update(ctx, p interface{}, opts ...interfac varargs := append([]interface{}{ctx, p}, opts...) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Update", reflect.TypeOf((*MockPromptAPI)(nil).Update), varargs...) } + +// UpdateRendering mocks base method. +func (m *MockPromptAPI) UpdateRendering(ctx context.Context, prompt management.PromptType, screen management.ScreenName, c *management.PromptRendering, opts ...management.RequestOption) error { + m.ctrl.T.Helper() + varargs := []interface{}{ctx, prompt, screen, c} + for _, a := range opts { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "UpdateRendering", varargs...) + ret0, _ := ret[0].(error) + return ret0 +} + +// UpdateRendering indicates an expected call of UpdateRendering. +func (mr *MockPromptAPIMockRecorder) UpdateRendering(ctx, prompt, screen, c interface{}, opts ...interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]interface{}{ctx, prompt, screen, c}, opts...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateRendering", reflect.TypeOf((*MockPromptAPI)(nil).UpdateRendering), varargs...) +} diff --git a/internal/cli/data/universal-login/prompt-screen-settings.json b/internal/cli/data/universal-login/prompt-screen-settings.json new file mode 100644 index 00000000..c585d9b6 --- /dev/null +++ b/internal/cli/data/universal-login/prompt-screen-settings.json @@ -0,0 +1,33 @@ +{ + "__doc1__": "The rendering_mode could be either advanced or standard... default_head_tags_disabled is a toggle to override Universal Login default head tags... context_configuration are the set of Context values to make available(Refer docs for the possible values)... head_tags are the array of head tags)..", + "__doc2__": "Note1: To update the rendering_mode to standard, only parse the rendering_mode field; no other fields are needed.", + "__doc3__": "Note2: head_tags must contain at least one script tag", + "__doc4__": "Only the declared fields will be updated, Rest stays same.", + "__doc5__": "See the docs for possible values", + + "rendering_mode": "advanced", + "default_head_tags": false, + "context_configuration": [ + "screen.texts" + ], + "head_tags": [ + { + "tag": "script", + "attributes": { + "defer": true, + "src": "URL_TO_YOUR_ASSET", + "async": true, + "integrity": [ + "ASSET_SHA" + ] + } + }, + { + "tag": "link", + "attributes": { + "href": "URL_TO_YOUR_ASSET", + "rel": "stylesheet" + } + } + ] +} \ No newline at end of file diff --git a/internal/cli/terraform.go b/internal/cli/terraform.go index cf7f8565..bfc4ff0d 100644 --- a/internal/cli/terraform.go +++ b/internal/cli/terraform.go @@ -103,6 +103,8 @@ func (i *terraformInputs) parseResourceFetchers(api *auth0.API) ([]resourceDataF fetchers = append(fetchers, &promptResourceFetcher{}) case "auth0_prompt_custom_text": fetchers = append(fetchers, &promptCustomTextResourceFetcherResourceFetcher{api}) + case "auth0_prompt_screen_renderer": + fetchers = append(fetchers, &promptScreenRendererResourceFetcher{api}) case "auth0_resource_server", "auth0_resource_server_scopes": fetchers = append(fetchers, &resourceServerResourceFetcher{api}) case "auth0_role", "auth0_role_permissions": diff --git a/internal/cli/terraform_fetcher.go b/internal/cli/terraform_fetcher.go index 209840d3..221e9140 100644 --- a/internal/cli/terraform_fetcher.go +++ b/internal/cli/terraform_fetcher.go @@ -11,7 +11,21 @@ import ( "github.com/auth0/auth0-cli/internal/auth0" ) -var defaultResources = []string{"auth0_action", "auth0_attack_protection", "auth0_branding", "auth0_client", "auth0_client_grant", "auth0_connection", "auth0_custom_domain", "auth0_flow", "auth0_flow_vault_connection", "auth0_form", "auth0_email_provider", "auth0_email_template", "auth0_guardian", "auth0_organization", "auth0_pages", "auth0_prompt", "auth0_prompt_custom_text", "auth0_resource_server", "auth0_role", "auth0_tenant", "auth0_trigger_actions"} +var ( + defaultResources = []string{"auth0_action", "auth0_attack_protection", "auth0_branding", "auth0_client", "auth0_client_grant", "auth0_connection", "auth0_custom_domain", "auth0_flow", "auth0_flow_vault_connection", "auth0_form", "auth0_email_provider", "auth0_email_template", "auth0_guardian", "auth0_organization", "auth0_pages", "auth0_prompt", "auth0_prompt_custom_text", "auth0_prompt_screen_renderer", "auth0_resource_server", "auth0_role", "auth0_tenant", "auth0_trigger_actions"} + ScreenPromptMap = map[string][]string{ + "signup-id": {"signup-id"}, + "signup-password": {"signup-password"}, + "login-id": {"login-id"}, + "login-password": {"login-password"}, + "login-passwordless": {"login-passwordless-email-code", "login-passwordless-sms-otp"}, + "phone-identifier-enrollment": {"phone-identifier-enrollment"}, + "phone-identifier-challenge": {"phone-identifier-challenge"}, + "email-identifier-challenge": {"email-identifier-challenge"}, + "passkeys": {"passkey-enrollment", "passkey-enrollment-local"}, + "captcha": {"interstitial-captcha"}, + } +) type ( importDataList []importDataItem @@ -83,7 +97,10 @@ type ( api *auth0.API } - promptResourceFetcher struct{} + promptResourceFetcher struct{} + promptScreenRendererResourceFetcher struct { + api *auth0.API + } promptCustomTextResourceFetcherResourceFetcher struct { api *auth0.API @@ -448,6 +465,31 @@ func (f *promptCustomTextResourceFetcherResourceFetcher) FetchData(ctx context.C return data, nil } +func (f *promptScreenRendererResourceFetcher) FetchData(ctx context.Context) (importDataList, error) { + var data importDataList + + _, err := f.api.Prompt.ReadRendering(ctx, "login-id", "login-id") + // Checking for the ACUL enabled feature. + if err != nil { + if strings.Contains(err.Error(), "This tenant does not have ACUL enabled") { + return nil, nil + } + + return nil, err + } + + for promptType, screenNames := range ScreenPromptMap { + for _, screenName := range screenNames { + data = append(data, importDataItem{ + ResourceName: "auth0_prompt_screen_renderer." + sanitizeResourceName(promptType+"_"+screenName), + ImportID: promptType + ":" + screenName, + }) + } + } + + return data, nil +} + func (f *resourceServerResourceFetcher) FetchData(ctx context.Context) (importDataList, error) { var data importDataList diff --git a/internal/cli/universal_login_customize.go b/internal/cli/universal_login_customize.go index 73c966ea..b1f4ea9a 100644 --- a/internal/cli/universal_login_customize.go +++ b/internal/cli/universal_login_customize.go @@ -13,13 +13,16 @@ import ( "time" "github.com/auth0/go-auth0/management" + "github.com/gorilla/websocket" "github.com/pkg/browser" "github.com/spf13/cobra" "golang.org/x/sync/errgroup" + "github.com/auth0/auth0-cli/internal/ansi" "github.com/auth0/auth0-cli/internal/auth0" "github.com/auth0/auth0-cli/internal/display" + "github.com/auth0/auth0-cli/internal/prompt" ) const ( @@ -38,6 +41,9 @@ const ( var ( //go:embed data/universal-login/* universalLoginPreviewAssets embed.FS + + //go:embed data/universal-login/prompt-screen-settings.json + promptScreenSettings string ) var allowedPromptsWithPartials = []management.PromptType{ @@ -179,14 +185,34 @@ func customizeUniversalLoginCmd(cli *cli) *cobra.Command { cmd := &cobra.Command{ Use: "customize", Args: cobra.NoArgs, - Short: "Customize the Universal Login experience", - Long: "Customize and preview changes to the Universal Login experience. This command will open a webpage " + - "within your browser where you can edit and preview your branding changes. For a comprehensive list of " + - "editable parameters and their values please visit the " + - "[Management API Documentation](https://auth0.com/docs/api/management/v2).", + Short: "Customize the Universal Login experience for the standard or advanced mode", + Long: "\nCustomize your Universal Login Experience. Note that this requires a custom domain to be configured for the tenant. \n\n" + + "* Standard mode is recommended for creating a consistent, branded experience for users. Choosing Standard mode will open a webpage\n" + + "within your browser where you can edit and preview your branding changes.For a comprehensive list of editable parameters and their values,\n" + + "please visit the [Management API Documentation](https://auth0.com/docs/api/management/v2)\n\n" + + "* Advanced mode is recommended for full customization/granular control of the login experience and to integrate your own component design system. \n" + + "Choosing Advanced mode will open the default terminal editor, with the rendering configs:\n\n" + + "![storybook](settings.json)\n\nClosing the terminal editor will save the settings to your tenant.", Example: ` auth0 universal-login customize auth0 ul customize`, RunE: func(cmd *cobra.Command, args []string) error { + var ( + selectedRenderingMode string + ) + + const advancedMode, standardMode = "advanced", "standard" + label := "Please choose the renderingMode: " + help := fmt.Sprintf( + "%s\n%s\n", + "standardMode is recommended for customizating consistent, branded experience for users.", + "Alternatively, advancedMode is recommended for full customization/granular control of the login experience and to integrate own component design system", + ) + + input := prompt.SelectInput("", label, help, []string{standardMode, advancedMode}, standardMode, true) + if err := prompt.AskOne(input, &selectedRenderingMode); err != nil { + return handleInputError(err) + } + ctx := cmd.Context() if err := ensureCustomDomainIsEnabled(ctx, cli.api); err != nil { @@ -197,6 +223,11 @@ func customizeUniversalLoginCmd(cli *cli) *cobra.Command { return err } + if selectedRenderingMode == advancedMode { + return advanceCustomize(cmd, cli) + } + + // RenderingMode as standard. return startWebSocketServer(ctx, cli.api, cli.renderer, cli.tenant) }, } @@ -204,6 +235,86 @@ func customizeUniversalLoginCmd(cli *cli) *cobra.Command { return cmd } +func advanceCustomize(cmd *cobra.Command, cli *cli) error { + var ( + headTags string + renderSettings = &management.PromptRendering{} + ) + + promptName, screenName, err := fetchPromptScreenInfo() + if err != nil { + return err + } + + cli.renderer.Infof("Updating the rendering settings for the prompt: %s and for the screen: %s", ansi.Green(promptName), ansi.Green(screenName)) + + readRendering, err := cli.api.Prompt.ReadRendering(cmd.Context(), management.PromptType(promptName), management.ScreenName(screenName)) + if err != nil { + return fmt.Errorf("failed to fetch the existing render settings: %w", err) + } + + if readRendering != nil { + jsonData, _ := json.MarshalIndent(readRendering, "", " ") + promptScreenSettings = string(jsonData) + } + + err = ruleScript.OpenEditor(cmd, &headTags, promptScreenSettings, promptName+"_"+screenName+".json", cli.ruleEditorHint) + if err != nil { + return fmt.Errorf("failed to capture input from the editor: %w", err) + } + + err = json.Unmarshal([]byte(headTags), renderSettings) + if err != nil { + return fmt.Errorf("failed to unmarshal JSON input: %w", err) + } + + if err := ansi.Waiting(func() error { + return cli.api.Prompt.UpdateRendering(cmd.Context(), management.PromptType(promptName), management.ScreenName(screenName), renderSettings) + }); err != nil { + return fmt.Errorf("failed to set the render settings: %w", err) + } + + cli.renderer.Infof("Successfully set the render settings") + + return nil +} + +func fetchPromptScreenInfo() (string, string, error) { + var ( + promptName, screenName string + help = "Auth0 supports customizing for many prompts & screens" + ) + + promptLabel := "Please choose the Prompt Name:" + + PromptInput := prompt.SelectInput("", promptLabel, help, fetchKeys(ScreenPromptMap), "login-id", true) + if err := prompt.AskOne(PromptInput, &promptName); err != nil { + return "", "", handleInputError(err) + } + + if len(ScreenPromptMap[promptName]) > 1 { + screenLabel := "Please choose the Screen Name:" + + screenInput := prompt.SelectInput("", screenLabel, help, ScreenPromptMap[promptName], ScreenPromptMap[promptName][0], true) + if err := prompt.AskOne(screenInput, &screenName); err != nil { + return "", "", handleInputError(err) + } + } else { + screenName = ScreenPromptMap[promptName][0] + } + + return promptName, screenName, nil +} + +// Utility function to get all keys from a map. +func fetchKeys[K comparable, V any](m map[K]V) []K { + keys := make([]K, 0, len(m)) + for k := range m { + keys = append(keys, k) + } + return keys +} + func ensureNewUniversalLoginExperienceIsActive(ctx context.Context, api *auth0.API) error { authenticationProfile, err := api.Prompt.Read(ctx) if err != nil { diff --git a/test/integration/rules-test-cases.yaml b/test/integration/rules-test-cases.yaml index e75ac2bf..9cf15d10 100644 --- a/test/integration/rules-test-cases.yaml +++ b/test/integration/rules-test-cases.yaml @@ -16,3 +16,73 @@ tests: exit-code: 0 stdout: exactly: "[]" + +# 003 - rules create and check data: +# command: cat ./test/integration/fixtures/create-rule.json | jq '.[0]' | auth0 rules create --json +# stdout: +# json: +# name: integration-test-rule-new1 +# enabled: "true" +# order: "1" +# script: "function(user, context, cb) {\n cb(null, user, context);\n}\n" +# exit-code: 0 +# +# 004 - rules create and check output: +# command: cat ./test/integration/fixtures/create-rule.json | jq '.[1]' | auth0 rules create +# stdout: +# contains: +# - NAME integration-test-rule-new2 +# - ENABLED ✗ +# - ORDER 2 +# - SCRIPT function(user, context, cb) { +# exit-code: 0 +# +# 005 - rules list all with data: +# command: auth0 rules list +# exit-code: 0 +# stdout: +# contains: +# - ID +# - NAME +# - ENABLED +# - ORDER +# +# 006 - rules show json: +# command: auth0 rules show $(./test/integration/scripts/get-rule-id.sh) --json +# stdout: +# json: +# name: integration-test-rule-newRule +# enabled: "false" +# order: "3" +# exit-code: 0 +# +# 007 - rules show: +# command: auth0 rules show $(./test/integration/scripts/get-rule-id.sh) +# stdout: +# contains: +# - NAME integration-test-rule-newRule +# - ENABLED ✗ +# - ORDER 3 +# exit-code: 0 +# +# 008 - rules update: +# command: cat ./test/integration/fixtures/update-rule.json | auth0 rules update --json +# stdout: +# json: +# name: integration-test-rule-betterName +# enabled: "false" +# exit-code: 0 +# +# 009 - rules enable: +# command: auth0 rules enable $(./test/integration/scripts/get-rule-id.sh) --json +# stdout: +# json: +# enabled: "true" +# exit-code: 0 +# +# 010 - rules disable: +# command: auth0 rules disable $(./test/integration/scripts/get-rule-id.sh) --json +# stdout: +# json: +# enabled: "false" +# exit-code: 0 From e9c0099cf5e106805d3aa499d53ad235f2811757 Mon Sep 17 00:00:00 2001 From: Rajat Bajaj Date: Mon, 9 Dec 2024 21:17:15 +0530 Subject: [PATCH 6/8] Added changelog for 1.7.0 (#1110) * Added changelog for 1.7.0 * minor update --- CHANGELOG.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4891b6a1..596040e8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +# [v.1.7.0](https://github.com/auth0/auth0-cli/tree/v1.7.0) (Dec 9, 2024)) + +[Full Changelog](https://github.com/auth0/auth0-cli/compare/v1.6.1...v1.7.0) + +### Added + +- Support for importing `auth0_prompt_screen_renderer` terraform resource [#1106] + +### Fixed + +- For `ul login` added check to filter and identify only support partials. [#1107] + # [v1.6.1](https://github.com/auth0/auth0-cli/tree/v1.6.1) (Oct 31, 2024) [Full Changelog](https://github.com/auth0/auth0-cli/compare/v1.6.0...v1.6.1) @@ -327,6 +339,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Updating of action triggers which inevitably results in error [#597] [unreleased]: https://github.com/auth0/auth0-cli/compare/v1.5.1...HEAD +[#1107]: https://github.com/auth0/auth0-cli/issues/1107 +[#1106]: https://github.com/auth0/auth0-cli/issues/1106 [#1099]: https://github.com/auth0/auth0-cli/issues/1099 [#1098]: https://github.com/auth0/auth0-cli/issues/1098 [#1091]: https://github.com/auth0/auth0-cli/issues/1091 From 8468c8162669a4fc4c1ddc35d1263aaf5f54916f Mon Sep 17 00:00:00 2001 From: thomas-auth0 <97907117+thomas-auth0@users.noreply.github.com> Date: Mon, 16 Dec 2024 07:23:24 +0100 Subject: [PATCH 7/8] fix(terraform): Handle error when custom domain is not enabled (#1103) Co-authored-by: Rajat Bajaj --- internal/cli/terraform_fetcher.go | 10 ++++++++-- internal/cli/terraform_fetcher_test.go | 20 ++++++++++++++++++++ 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/internal/cli/terraform_fetcher.go b/internal/cli/terraform_fetcher.go index 221e9140..5ca9c914 100644 --- a/internal/cli/terraform_fetcher.go +++ b/internal/cli/terraform_fetcher.go @@ -244,10 +244,16 @@ func (f *customDomainResourceFetcher) FetchData(ctx context.Context) (importData customDomains, err := f.api.CustomDomain.List(ctx) if err != nil { - if strings.Contains(err.Error(), "The account is not allowed to perform this operation, please contact our support team") { - return data, nil + errNotEnabled := []string{ + "The account is not allowed to perform this operation, please contact our support team", + "There must be a verified credit card on file to perform this operation", } + for _, e := range errNotEnabled { + if strings.Contains(err.Error(), e) { + return data, nil + } + } return nil, err } diff --git a/internal/cli/terraform_fetcher_test.go b/internal/cli/terraform_fetcher_test.go index e24e5d08..054f3bae 100644 --- a/internal/cli/terraform_fetcher_test.go +++ b/internal/cli/terraform_fetcher_test.go @@ -561,6 +561,26 @@ func TestCustomDomainResourceFetcher_FetchData(t *testing.T) { assert.NoError(t, err) assert.Len(t, data, 0) }) + + t.Run("it returns empty set error if no verified CC error occurs", func(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + customDomainAPI := mock.NewMockCustomDomainAPI(ctrl) + customDomainAPI.EXPECT(). + List(gomock.Any()). + Return(nil, fmt.Errorf("403 Forbidden: There must be a verified credit card on file to perform this operation")) + + fetcher := customDomainResourceFetcher{ + api: &auth0.API{ + CustomDomain: customDomainAPI, + }, + } + + data, err := fetcher.FetchData(context.Background()) + assert.NoError(t, err) + assert.Len(t, data, 0) + }) } func TestFormResourceFetcher_FetchData(t *testing.T) { From 15ff9676f922a02a89a5340bc0bc892bd4b43b97 Mon Sep 17 00:00:00 2001 From: Rajat Bajaj Date: Wed, 18 Dec 2024 12:36:22 +0530 Subject: [PATCH 8/8] Added new CDN url + updated tests (#1109) * Added new CDN url + updated tests * temp * Update unit tests * Update doc info of default prompt-screen-settings.json * Updated comments * Add unit tests for promptScreenRendererResourceFetcher * Fix lint * Fix ACUL error check message --------- Co-authored-by: ramya18101 Co-authored-by: Ramya Anusri <62586490+ramya18101@users.noreply.github.com> --- .../prompt-screen-settings.json | 6 +- internal/cli/prompts_custom_text.go | 2 +- internal/cli/terraform_fetcher.go | 2 +- internal/cli/terraform_fetcher_test.go | 66 ++++ .../cli/universal_login_customize_test.go | 332 ++++++++++-------- .../fixtures/update-ul-prompts-login.json | 1 - .../universal-login-test-cases.yaml | 6 +- 7 files changed, 262 insertions(+), 153 deletions(-) diff --git a/internal/cli/data/universal-login/prompt-screen-settings.json b/internal/cli/data/universal-login/prompt-screen-settings.json index c585d9b6..d6b4ed4a 100644 --- a/internal/cli/data/universal-login/prompt-screen-settings.json +++ b/internal/cli/data/universal-login/prompt-screen-settings.json @@ -1,9 +1,9 @@ { "__doc1__": "The rendering_mode could be either advanced or standard... default_head_tags_disabled is a toggle to override Universal Login default head tags... context_configuration are the set of Context values to make available(Refer docs for the possible values)... head_tags are the array of head tags)..", - "__doc2__": "Note1: To update the rendering_mode to standard, only parse the rendering_mode field; no other fields are needed.", + "__doc2__": "Note1: while updating the rendering_mode to standard, only the rendering_mode field gets updated, the other fields shall not be updated.", "__doc3__": "Note2: head_tags must contain at least one script tag", - "__doc4__": "Only the declared fields will be updated, Rest stays same.", - "__doc5__": "See the docs for possible values", + "__doc4__": "Only the declared fields get updated, rest stays same", + "__doc5__": "See https://auth0.com/docs/customize/login-pages/advanced-customizations/getting-started/configure-acul-screens for all possible values for each field", "rendering_mode": "advanced", "default_head_tags": false, diff --git a/internal/cli/prompts_custom_text.go b/internal/cli/prompts_custom_text.go index c201c1f2..5832f6ee 100644 --- a/internal/cli/prompts_custom_text.go +++ b/internal/cli/prompts_custom_text.go @@ -15,7 +15,7 @@ import ( const ( textDocsKey = "__doc__" textDocsURL = "https://auth0.com/docs/customize/universal-login-pages/customize-login-text-prompts" - textLocalesURL = "https://cdn.auth0.com/ulp/react-components/1.66.3/languages/%s/prompts.json" + textLocalesURL = "https://cdn.auth0.com/ulp/react-components/1.102.1/languages/%s/prompts.json" textLanguageDefault = "en" ) diff --git a/internal/cli/terraform_fetcher.go b/internal/cli/terraform_fetcher.go index 5ca9c914..7de5a094 100644 --- a/internal/cli/terraform_fetcher.go +++ b/internal/cli/terraform_fetcher.go @@ -477,7 +477,7 @@ func (f *promptScreenRendererResourceFetcher) FetchData(ctx context.Context) (im _, err := f.api.Prompt.ReadRendering(ctx, "login-id", "login-id") // Checking for the ACUL enabled feature. if err != nil { - if strings.Contains(err.Error(), "This tenant does not have ACUL enabled") { + if strings.Contains(err.Error(), "403 Forbidden: This tenant does not have Advanced Customizations enabled") { return nil, nil } diff --git a/internal/cli/terraform_fetcher_test.go b/internal/cli/terraform_fetcher_test.go index 054f3bae..0c7c7506 100644 --- a/internal/cli/terraform_fetcher_test.go +++ b/internal/cli/terraform_fetcher_test.go @@ -1308,6 +1308,72 @@ func TestPromptProviderResourceFetcher_FetchData(t *testing.T) { }) } +func TestPromptScreenRendererResourceFetcher_FetchData(t *testing.T) { + t.Run("it successfully renders the prompts & screen settings import data", func(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + promptAPI := mock.NewMockPromptAPI(ctrl) + promptAPI.EXPECT().ReadRendering(gomock.Any(), management.PromptType("login-id"), management.ScreenName("login-id")). + Return(&management.PromptRendering{}, nil) + + fetcher := promptScreenRendererResourceFetcher{ + api: &auth0.API{ + Prompt: promptAPI, + }, + } + + expectedData := importDataList{} + for promptType, screenNames := range ScreenPromptMap { + for _, screenName := range screenNames { + expectedData = append(expectedData, importDataItem{ + ResourceName: "auth0_prompt_screen_renderer." + sanitizeResourceName(promptType+"_"+screenName), + ImportID: promptType + ":" + screenName, + }) + } + } + + data, err := fetcher.FetchData(context.Background()) + assert.NoError(t, err) + assert.ElementsMatch(t, expectedData, data) + }) + t.Run("it handles error, even if tenant does not have ACUL enabled", func(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + promptAPI := mock.NewMockPromptAPI(ctrl) + promptAPI.EXPECT().ReadRendering(gomock.Any(), management.PromptType("login-id"), management.ScreenName("login-id")). + Return(&management.PromptRendering{}, fmt.Errorf("403 Forbidden: This tenant does not have Advanced Customizations enabled")) + + fetcher := promptScreenRendererResourceFetcher{ + api: &auth0.API{ + Prompt: promptAPI, + }, + } + + data, err := fetcher.FetchData(context.Background()) + assert.NoError(t, err) + assert.Len(t, data, 0) + }) + t.Run("it returns error, if the API call fails", func(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + promptAPI := mock.NewMockPromptAPI(ctrl) + promptAPI.EXPECT().ReadRendering(gomock.Any(), management.PromptType("login-id"), management.ScreenName("login-id")). + Return(&management.PromptRendering{}, fmt.Errorf("failed to read rendering settings")) + + fetcher := promptScreenRendererResourceFetcher{ + api: &auth0.API{ + Prompt: promptAPI, + }, + } + + _, err := fetcher.FetchData(context.Background()) + assert.EqualError(t, err, "failed to read rendering settings") + }) +} + func TestPromptCustomTextResourceFetcher_FetchData(t *testing.T) { t.Run("it successfully retrieves custom text prompts data", func(t *testing.T) { ctrl := gomock.NewController(t) diff --git a/internal/cli/universal_login_customize_test.go b/internal/cli/universal_login_customize_test.go index 703f717e..42955651 100644 --- a/internal/cli/universal_login_customize_test.go +++ b/internal/cli/universal_login_customize_test.go @@ -383,42 +383,53 @@ func TestFetchUniversalLoginBrandingData(t *testing.T) { Prompt: "login", CustomText: map[string]interface{}{ "login": map[string]interface{}{ - "alertListTitle": "Alerts", - "auth0-users-validation": "Something went wrong, please try again later", - "authentication-failure": "We are sorry, something went wrong when attempting to login", - "buttonText": "Continue", - "custom-script-error-code": "Something went wrong, please try again later.", - "description": "Log in to ${companyName} to continue to ${clientName}.", - "editEmailText": "Edit", - "emailPlaceholder": "Email address", - "federatedConnectionButtonText": "Continue with ${connectionName}", - "footerLinkText": "Sign up", - "footerText": "Don't have an account?", - "forgotPasswordText": "Forgot password?", - "hidePasswordText": "Hide password", - "invalid-connection": "Invalid connection", - "invalid-email-format": "Email is not valid.", - "invitationDescription": "Log in to accept ${inviterName}'s invitation to join ${companyName} on ${clientName}.", - "invitationTitle": "You've Been Invited!", - "ip-blocked": "We have detected suspicious login behavior and further attempts will be blocked. Please contact the administrator.", - "logoAltText": "${companyName}", - "no-db-connection": "Invalid connection", - "no-email": "Please enter an email address", - "no-password": "Password is required", - "no-username": "Username is required", - "pageTitle": "Log in | ${clientName}", - "password-breached": "We have detected a potential security issue with this account. To protect your account, we have prevented this login. Please reset your password to proceed.", - "passwordPlaceholder": "Password", - "same-user-login": "Too many login attempts for this user. Please wait, and try again later.", - "separatorText": "Or", - "showPasswordText": "Show password", - "signupActionLinkText": "${footerLinkText}", - "signupActionText": "${footerText}", - "title": "Welcome friend, glad to have you!", - "user-blocked": "Your account has been blocked after multiple consecutive login attempts.", - "usernamePlaceholder": "Username or email address", - "wrong-credentials": "Wrong username or password", - "wrong-email-credentials": "Wrong email or password", + "alertListTitle": "Alerts", + "auth0-users-validation": "Something went wrong, please try again later", + "authentication-failure": "We are sorry, something went wrong when attempting to log in", + "buttonText": "Continue", + "custom-script-error-code": "Something went wrong, please try again later.", + "description": "Log in to ${companyName} to continue to ${clientName}.", + "editEmailText": "Edit", + "emailPlaceholder": "Email address", + "federatedConnectionButtonText": "Continue with ${connectionName}", + "footerLinkText": "Sign up", + "footerText": "Don't have an account?", + "forgotPasswordText": "Forgot password?", + "hidePasswordText": "Hide password", + "invalid-connection": "Invalid connection", + "invitationDescription": "Log in to accept ${inviterName}'s invitation to join ${companyName} on ${clientName}.", + "invitationTitle": "You've Been Invited!", + "ip-blocked": "We have detected suspicious login behavior and further attempts will be blocked. Please contact the administrator.", + "logoAltText": "${companyName}", + "no-db-connection": "Invalid connection", + "no-email": "Please enter an email address", + "no-password": "Password is required", + "no-username": "Username is required", + "pageTitle": "Log in | ${clientName}", + "password-breached": "We have detected a potential security issue with this account. To protect your account, we have prevented this login. Please reset your password to proceed.", + "passwordPlaceholder": "Password", + "phoneOrEmailPlaceholder": "Phone number or Email address", + "phoneOrUsernameOrEmailPlaceholder": "Phone or Username or Email", + "phoneOrUsernamePlaceholder": "Phone Number or Username", + "phonePlaceholder": "Phone number", + "same-user-login": "Too many login attempts for this user. Please wait, and try again later.", + "separatorText": "Or", + "showPasswordText": "Show password", + "signupActionLinkText": "${footerLinkText}", + "signupActionText": "${footerText}", + "title": "Welcome friend, glad to have you!", + "user-blocked": "Your account has been blocked after multiple consecutive login attempts.", + "usernamePlaceholder": "Username or email address", + "usernameOnlyPlaceholder": "Username", + "usernameOrEmailPlaceholder": "Username or Email address", + "wrong-credentials": "Wrong username or password", + "wrong-email-credentials": "Wrong email or password", + "wrong-email-phone-credentials": "Incorrect email address, phone number, or password. Phone numbers must include the country code.", + "wrong-email-phone-username-credentials": " Incorrect email address, phone number, username, or password. Phone numbers must include the country code.", + "wrong-email-username-credentials": "Incorrect email address, username, or password", + "wrong-phone-credentials": "Incorrect phone number or password", + "wrong-phone-username-credentials": "Incorrect phone number, username or password. Phone numbers must include the country code.", + "wrong-username-credentials": "Incorrect username or password", }, }, }, @@ -590,42 +601,53 @@ func TestFetchUniversalLoginBrandingData(t *testing.T) { Prompt: "login", CustomText: map[string]interface{}{ "login": map[string]interface{}{ - "alertListTitle": "Alerts", - "auth0-users-validation": "Something went wrong, please try again later", - "authentication-failure": "We are sorry, something went wrong when attempting to login", - "buttonText": "Continue", - "custom-script-error-code": "Something went wrong, please try again later.", - "description": "Log in to ${companyName} to continue to ${clientName}.", - "editEmailText": "Edit", - "emailPlaceholder": "Email address", - "federatedConnectionButtonText": "Continue with ${connectionName}", - "footerLinkText": "Sign up", - "footerText": "Don't have an account?", - "forgotPasswordText": "Forgot password?", - "hidePasswordText": "Hide password", - "invalid-connection": "Invalid connection", - "invalid-email-format": "Email is not valid.", - "invitationDescription": "Log in to accept ${inviterName}'s invitation to join ${companyName} on ${clientName}.", - "invitationTitle": "You've Been Invited!", - "ip-blocked": "We have detected suspicious login behavior and further attempts will be blocked. Please contact the administrator.", - "logoAltText": "${companyName}", - "no-db-connection": "Invalid connection", - "no-email": "Please enter an email address", - "no-password": "Password is required", - "no-username": "Username is required", - "pageTitle": "Log in | ${clientName}", - "password-breached": "We have detected a potential security issue with this account. To protect your account, we have prevented this login. Please reset your password to proceed.", - "passwordPlaceholder": "Password", - "same-user-login": "Too many login attempts for this user. Please wait, and try again later.", - "separatorText": "Or", - "showPasswordText": "Show password", - "signupActionLinkText": "${footerLinkText}", - "signupActionText": "${footerText}", - "title": "Welcome friend, glad to have you!", - "user-blocked": "Your account has been blocked after multiple consecutive login attempts.", - "usernamePlaceholder": "Username or email address", - "wrong-credentials": "Wrong username or password", - "wrong-email-credentials": "Wrong email or password", + "alertListTitle": "Alerts", + "auth0-users-validation": "Something went wrong, please try again later", + "authentication-failure": "We are sorry, something went wrong when attempting to log in", + "buttonText": "Continue", + "custom-script-error-code": "Something went wrong, please try again later.", + "description": "Log in to ${companyName} to continue to ${clientName}.", + "editEmailText": "Edit", + "emailPlaceholder": "Email address", + "federatedConnectionButtonText": "Continue with ${connectionName}", + "footerLinkText": "Sign up", + "footerText": "Don't have an account?", + "forgotPasswordText": "Forgot password?", + "hidePasswordText": "Hide password", + "invalid-connection": "Invalid connection", + "invitationDescription": "Log in to accept ${inviterName}'s invitation to join ${companyName} on ${clientName}.", + "invitationTitle": "You've Been Invited!", + "ip-blocked": "We have detected suspicious login behavior and further attempts will be blocked. Please contact the administrator.", + "logoAltText": "${companyName}", + "no-db-connection": "Invalid connection", + "no-email": "Please enter an email address", + "no-password": "Password is required", + "no-username": "Username is required", + "pageTitle": "Log in | ${clientName}", + "password-breached": "We have detected a potential security issue with this account. To protect your account, we have prevented this login. Please reset your password to proceed.", + "passwordPlaceholder": "Password", + "phoneOrEmailPlaceholder": "Phone number or Email address", + "phoneOrUsernameOrEmailPlaceholder": "Phone or Username or Email", + "phoneOrUsernamePlaceholder": "Phone Number or Username", + "phonePlaceholder": "Phone number", + "same-user-login": "Too many login attempts for this user. Please wait, and try again later.", + "separatorText": "Or", + "showPasswordText": "Show password", + "signupActionLinkText": "${footerLinkText}", + "signupActionText": "${footerText}", + "title": "Welcome friend, glad to have you!", + "user-blocked": "Your account has been blocked after multiple consecutive login attempts.", + "usernamePlaceholder": "Username or email address", + "usernameOnlyPlaceholder": "Username", + "usernameOrEmailPlaceholder": "Username or Email address", + "wrong-credentials": "Wrong username or password", + "wrong-email-credentials": "Wrong email or password", + "wrong-email-phone-credentials": "Incorrect email address, phone number, or password. Phone numbers must include the country code.", + "wrong-email-phone-username-credentials": " Incorrect email address, phone number, username, or password. Phone numbers must include the country code.", + "wrong-email-username-credentials": "Incorrect email address, username, or password", + "wrong-phone-credentials": "Incorrect phone number or password", + "wrong-phone-username-credentials": "Incorrect phone number, username or password. Phone numbers must include the country code.", + "wrong-username-credentials": "Incorrect username or password", }, }, }, @@ -799,42 +821,53 @@ func TestFetchUniversalLoginBrandingData(t *testing.T) { Prompt: "login", CustomText: map[string]interface{}{ "login": map[string]interface{}{ - "alertListTitle": "Alerts", - "auth0-users-validation": "Something went wrong, please try again later", - "authentication-failure": "We are sorry, something went wrong when attempting to login", - "buttonText": "Continue", - "custom-script-error-code": "Something went wrong, please try again later.", - "description": "Log in to ${companyName} to continue to ${clientName}.", - "editEmailText": "Edit", - "emailPlaceholder": "Email address", - "federatedConnectionButtonText": "Continue with ${connectionName}", - "footerLinkText": "Sign up", - "footerText": "Don't have an account?", - "forgotPasswordText": "Forgot password?", - "hidePasswordText": "Hide password", - "invalid-connection": "Invalid connection", - "invalid-email-format": "Email is not valid.", - "invitationDescription": "Log in to accept ${inviterName}'s invitation to join ${companyName} on ${clientName}.", - "invitationTitle": "You've Been Invited!", - "ip-blocked": "We have detected suspicious login behavior and further attempts will be blocked. Please contact the administrator.", - "logoAltText": "${companyName}", - "no-db-connection": "Invalid connection", - "no-email": "Please enter an email address", - "no-password": "Password is required", - "no-username": "Username is required", - "pageTitle": "Log in | ${clientName}", - "password-breached": "We have detected a potential security issue with this account. To protect your account, we have prevented this login. Please reset your password to proceed.", - "passwordPlaceholder": "Password", - "same-user-login": "Too many login attempts for this user. Please wait, and try again later.", - "separatorText": "Or", - "showPasswordText": "Show password", - "signupActionLinkText": "${footerLinkText}", - "signupActionText": "${footerText}", - "title": "Welcome friend, glad to have you!", - "user-blocked": "Your account has been blocked after multiple consecutive login attempts.", - "usernamePlaceholder": "Username or email address", - "wrong-credentials": "Wrong username or password", - "wrong-email-credentials": "Wrong email or password", + "alertListTitle": "Alerts", + "auth0-users-validation": "Something went wrong, please try again later", + "authentication-failure": "We are sorry, something went wrong when attempting to log in", + "buttonText": "Continue", + "custom-script-error-code": "Something went wrong, please try again later.", + "description": "Log in to ${companyName} to continue to ${clientName}.", + "editEmailText": "Edit", + "emailPlaceholder": "Email address", + "federatedConnectionButtonText": "Continue with ${connectionName}", + "footerLinkText": "Sign up", + "footerText": "Don't have an account?", + "forgotPasswordText": "Forgot password?", + "hidePasswordText": "Hide password", + "invalid-connection": "Invalid connection", + "invitationDescription": "Log in to accept ${inviterName}'s invitation to join ${companyName} on ${clientName}.", + "invitationTitle": "You've Been Invited!", + "ip-blocked": "We have detected suspicious login behavior and further attempts will be blocked. Please contact the administrator.", + "logoAltText": "${companyName}", + "no-db-connection": "Invalid connection", + "no-email": "Please enter an email address", + "no-password": "Password is required", + "no-username": "Username is required", + "pageTitle": "Log in | ${clientName}", + "password-breached": "We have detected a potential security issue with this account. To protect your account, we have prevented this login. Please reset your password to proceed.", + "passwordPlaceholder": "Password", + "phoneOrEmailPlaceholder": "Phone number or Email address", + "phoneOrUsernameOrEmailPlaceholder": "Phone or Username or Email", + "phoneOrUsernamePlaceholder": "Phone Number or Username", + "phonePlaceholder": "Phone number", + "same-user-login": "Too many login attempts for this user. Please wait, and try again later.", + "separatorText": "Or", + "showPasswordText": "Show password", + "signupActionLinkText": "${footerLinkText}", + "signupActionText": "${footerText}", + "title": "Welcome friend, glad to have you!", + "user-blocked": "Your account has been blocked after multiple consecutive login attempts.", + "usernamePlaceholder": "Username or email address", + "usernameOnlyPlaceholder": "Username", + "usernameOrEmailPlaceholder": "Username or Email address", + "wrong-credentials": "Wrong username or password", + "wrong-email-credentials": "Wrong email or password", + "wrong-email-phone-credentials": "Incorrect email address, phone number, or password. Phone numbers must include the country code.", + "wrong-email-phone-username-credentials": " Incorrect email address, phone number, username, or password. Phone numbers must include the country code.", + "wrong-email-username-credentials": "Incorrect email address, username, or password", + "wrong-phone-credentials": "Incorrect phone number or password", + "wrong-phone-username-credentials": "Incorrect phone number, username or password. Phone numbers must include the country code.", + "wrong-username-credentials": "Incorrect username or password", }, }, }, @@ -1088,42 +1121,53 @@ func TestFetchUniversalLoginBrandingData(t *testing.T) { Prompt: "login", CustomText: map[string]interface{}{ "login": map[string]interface{}{ - "alertListTitle": "Alerts", - "auth0-users-validation": "Something went wrong, please try again later", - "authentication-failure": "We are sorry, something went wrong when attempting to login", - "buttonText": "Continue", - "custom-script-error-code": "Something went wrong, please try again later.", - "description": "Log in to ${companyName} to continue to ${clientName}.", - "editEmailText": "Edit", - "emailPlaceholder": "Email address", - "federatedConnectionButtonText": "Continue with ${connectionName}", - "footerLinkText": "Sign up", - "footerText": "Don't have an account?", - "forgotPasswordText": "Forgot password?", - "hidePasswordText": "Hide password", - "invalid-connection": "Invalid connection", - "invalid-email-format": "Email is not valid.", - "invitationDescription": "Log in to accept ${inviterName}'s invitation to join ${companyName} on ${clientName}.", - "invitationTitle": "You've Been Invited!", - "ip-blocked": "We have detected suspicious login behavior and further attempts will be blocked. Please contact the administrator.", - "logoAltText": "${companyName}", - "no-db-connection": "Invalid connection", - "no-email": "Please enter an email address", - "no-password": "Password is required", - "no-username": "Username is required", - "pageTitle": "Log in | ${clientName}", - "password-breached": "We have detected a potential security issue with this account. To protect your account, we have prevented this login. Please reset your password to proceed.", - "passwordPlaceholder": "Password", - "same-user-login": "Too many login attempts for this user. Please wait, and try again later.", - "separatorText": "Or", - "showPasswordText": "Show password", - "signupActionLinkText": "${footerLinkText}", - "signupActionText": "${footerText}", - "title": "Welcome friend, glad to have you!", - "user-blocked": "Your account has been blocked after multiple consecutive login attempts.", - "usernamePlaceholder": "Username or email address", - "wrong-credentials": "Wrong username or password", - "wrong-email-credentials": "Wrong email or password", + "alertListTitle": "Alerts", + "auth0-users-validation": "Something went wrong, please try again later", + "authentication-failure": "We are sorry, something went wrong when attempting to log in", + "buttonText": "Continue", + "custom-script-error-code": "Something went wrong, please try again later.", + "description": "Log in to ${companyName} to continue to ${clientName}.", + "editEmailText": "Edit", + "emailPlaceholder": "Email address", + "federatedConnectionButtonText": "Continue with ${connectionName}", + "footerLinkText": "Sign up", + "footerText": "Don't have an account?", + "forgotPasswordText": "Forgot password?", + "hidePasswordText": "Hide password", + "invalid-connection": "Invalid connection", + "invitationDescription": "Log in to accept ${inviterName}'s invitation to join ${companyName} on ${clientName}.", + "invitationTitle": "You've Been Invited!", + "ip-blocked": "We have detected suspicious login behavior and further attempts will be blocked. Please contact the administrator.", + "logoAltText": "${companyName}", + "no-db-connection": "Invalid connection", + "no-email": "Please enter an email address", + "no-password": "Password is required", + "no-username": "Username is required", + "pageTitle": "Log in | ${clientName}", + "password-breached": "We have detected a potential security issue with this account. To protect your account, we have prevented this login. Please reset your password to proceed.", + "passwordPlaceholder": "Password", + "phoneOrEmailPlaceholder": "Phone number or Email address", + "phoneOrUsernameOrEmailPlaceholder": "Phone or Username or Email", + "phoneOrUsernamePlaceholder": "Phone Number or Username", + "phonePlaceholder": "Phone number", + "same-user-login": "Too many login attempts for this user. Please wait, and try again later.", + "separatorText": "Or", + "showPasswordText": "Show password", + "signupActionLinkText": "${footerLinkText}", + "signupActionText": "${footerText}", + "title": "Welcome friend, glad to have you!", + "user-blocked": "Your account has been blocked after multiple consecutive login attempts.", + "usernamePlaceholder": "Username or email address", + "usernameOnlyPlaceholder": "Username", + "usernameOrEmailPlaceholder": "Username or Email address", + "wrong-credentials": "Wrong username or password", + "wrong-email-credentials": "Wrong email or password", + "wrong-email-phone-credentials": "Incorrect email address, phone number, or password. Phone numbers must include the country code.", + "wrong-email-phone-username-credentials": " Incorrect email address, phone number, username, or password. Phone numbers must include the country code.", + "wrong-email-username-credentials": "Incorrect email address, username, or password", + "wrong-phone-credentials": "Incorrect phone number or password", + "wrong-phone-username-credentials": "Incorrect phone number, username or password. Phone numbers must include the country code.", + "wrong-username-credentials": "Incorrect username or password", }, }, }, diff --git a/test/integration/fixtures/update-ul-prompts-login.json b/test/integration/fixtures/update-ul-prompts-login.json index 473b4e0c..28f9a1f7 100644 --- a/test/integration/fixtures/update-ul-prompts-login.json +++ b/test/integration/fixtures/update-ul-prompts-login.json @@ -22,7 +22,6 @@ "showPasswordText": "Show password", "hidePasswordText": "Hide password", "wrong-credentials": "Wrong username or password", - "invalid-email-format": "Email is not valid.", "wrong-email-credentials": "Wrong email or password", "custom-script-error-code": "Something went wrong, please try again later.", "auth0-users-validation": "Something went wrong, please try again later", diff --git a/test/integration/universal-login-test-cases.yaml b/test/integration/universal-login-test-cases.yaml index 6b3d4eee..2c6ae4fd 100644 --- a/test/integration/universal-login-test-cases.yaml +++ b/test/integration/universal-login-test-cases.yaml @@ -86,9 +86,9 @@ tests: contains: - "Failed to fetch the Universal Login template data: this feature requires at least one custom domain to be set and verified for the tenant, use 'auth0 domains create' to create one and 'auth0 domains verify' to have it verified" -# 010 - update universal login branding prompts (login): -# command: cat ./test/integration/fixtures/update-ul-prompts-login.json | auth0 ul prompts update login -# exit-code: 0 + 010 - update universal login branding prompts (login): + command: cat ./test/integration/fixtures/update-ul-prompts-login.json | auth0 ul prompts update login + exit-code: 0 011 - update universal login branding prompts (mfa-push): command: cat ./test/integration/fixtures/update-ul-prompts-mfa-push.json | auth0 ul prompts update mfa-push