From 4ad68f1c51155f256628ce792f35c8bce92f5472 Mon Sep 17 00:00:00 2001 From: Tanya Sinha Date: Tue, 3 Dec 2024 09:35:17 +0530 Subject: [PATCH] Added support for custom prompts (#680) --- .../com/auth0/client/mgmt/ManagementAPI.java | 8 + .../com/auth0/client/mgmt/PromptsEntity.java | 162 +++++++++++++++ .../com/auth0/json/mgmt/prompts/Prompt.java | 64 ++++++ .../java/com/auth0/client/MockServer.java | 3 + .../auth0/client/mgmt/PromptsEntityTest.java | 191 ++++++++++++++++++ .../resources/mgmt/custom_text_prompt.json | 5 + src/test/resources/mgmt/partials_prompt.json | 2 + src/test/resources/mgmt/prompt.json | 5 + 8 files changed, 440 insertions(+) create mode 100644 src/main/java/com/auth0/client/mgmt/PromptsEntity.java create mode 100644 src/main/java/com/auth0/json/mgmt/prompts/Prompt.java create mode 100644 src/test/java/com/auth0/client/mgmt/PromptsEntityTest.java create mode 100644 src/test/resources/mgmt/custom_text_prompt.json create mode 100644 src/test/resources/mgmt/partials_prompt.json create mode 100644 src/test/resources/mgmt/prompt.json diff --git a/src/main/java/com/auth0/client/mgmt/ManagementAPI.java b/src/main/java/com/auth0/client/mgmt/ManagementAPI.java index acffaeb3..bc2a2d8f 100644 --- a/src/main/java/com/auth0/client/mgmt/ManagementAPI.java +++ b/src/main/java/com/auth0/client/mgmt/ManagementAPI.java @@ -380,6 +380,14 @@ public SessionsEntity sessions() { return new SessionsEntity(client, baseUrl, tokenProvider); } + /** + * Getter for the Prompts Entity + * @return the Prompts Entity + */ + public PromptsEntity prompts() { + return new PromptsEntity(client, baseUrl, tokenProvider); + } + /** * Builder for {@link ManagementAPI} API client instances. */ diff --git a/src/main/java/com/auth0/client/mgmt/PromptsEntity.java b/src/main/java/com/auth0/client/mgmt/PromptsEntity.java new file mode 100644 index 00000000..5cf9f876 --- /dev/null +++ b/src/main/java/com/auth0/client/mgmt/PromptsEntity.java @@ -0,0 +1,162 @@ +package com.auth0.client.mgmt; + +import com.auth0.json.mgmt.prompts.Prompt; +import com.auth0.net.BaseRequest; +import com.auth0.net.Request; +import com.auth0.net.client.Auth0HttpClient; +import com.auth0.net.client.HttpMethod; +import com.auth0.utils.Asserts; +import com.fasterxml.jackson.core.type.TypeReference; +import okhttp3.HttpUrl; + +public class PromptsEntity extends BaseManagementEntity { + + private final static String ORGS_PATH = "api/v2/prompts"; + + PromptsEntity(Auth0HttpClient client, HttpUrl baseUrl, TokenProvider tokenProvider) { + super(client, baseUrl, tokenProvider); + } + + /** + * Get the prompt. + * A token with {@code read:prompts} scope is required. + * @return a Request to execute. + * + * @see https://auth0.com/docs/api/management/v2#!/prompts/get-prompts + */ + public Request getPrompt() { + HttpUrl.Builder builder = baseUrl.newBuilder() + .addPathSegments(ORGS_PATH); + String url = builder.build().toString(); + + return new BaseRequest<>(client, tokenProvider, url, HttpMethod.GET, new TypeReference() { + }); + } + + /** + * Update the prompt. + * A token with {@code update:prompts} scope is required. + * @param prompt the prompt to update. + * @return a Request to execute. + * + * @see https://auth0.com/docs/api/management/v2#!/prompts/patch-prompts + */ + public Request updatePrompt(Prompt prompt) { + Asserts.assertNotNull(prompt, "prompt"); + + HttpUrl.Builder builder = baseUrl.newBuilder() + .addPathSegments(ORGS_PATH); + String url = builder.build().toString(); + + BaseRequest request = new BaseRequest<>(client, tokenProvider, url, HttpMethod.PATCH, new TypeReference() { + }); + + request.setBody(prompt); + return request; + } + + /** + * Get the custom text for specific prompt and language. + * A token with {@code read:prompts} scope is required. + * @param prompt the prompt name. + * @param language the language. + * @return a Request to execute. + * + * @see https://auth0.com/docs/api/management/v2#!/prompts/get-custom-text-by-language + */ + public Request getCustomText(String prompt, String language) { + Asserts.assertNotNull(prompt, "prompt"); + Asserts.assertNotNull(language, "language"); + + HttpUrl.Builder builder = baseUrl.newBuilder() + .addPathSegments(ORGS_PATH) + .addPathSegment(prompt) + .addPathSegment("custom-text") + .addPathSegments(language); + + String url = builder.build().toString(); + + return new BaseRequest<>(client, tokenProvider, url, HttpMethod.GET, new TypeReference() { + }); + } + + /** + * Set the custom text for specific prompt and language. + * A token with {@code update:prompts} scope is required. + * @param prompt the prompt name. + * @param language the language. + * @param customText the custom text. + * @return a Request to execute. + * + * @see https://auth0.com/docs/api/management/v2#!/prompts/put-custom-text-by-language + */ + public Request setCustomText(String prompt, String language, Object customText) { + Asserts.assertNotNull(prompt, "prompt"); + Asserts.assertNotNull(language, "language"); + Asserts.assertNotNull(customText, "customText"); + + HttpUrl.Builder builder = baseUrl.newBuilder() + .addPathSegments(ORGS_PATH) + .addPathSegment(prompt) + .addPathSegment("custom-text") + .addPathSegments(language); + + String url = builder.build().toString(); + + BaseRequest request = new BaseRequest<>(client, tokenProvider, url, HttpMethod.PUT, new TypeReference() { + }); + + request.setBody(customText); + return request; + } + + /** + * Get the partials for specific prompt. + * A token with {@code read:prompts} scope is required. + * @param prompt the prompt name. + * @return a Request to execute. + * + * @see https://auth0.com/docs/api/management/v2#!/prompts/get-partials + */ + public Request getPartialsPrompt(String prompt) { + Asserts.assertNotNull(prompt, "prompt"); + + HttpUrl.Builder builder = baseUrl.newBuilder() + .addPathSegments(ORGS_PATH) + .addPathSegment(prompt) + .addPathSegment("partials"); + + String url = builder.build().toString(); + + return new BaseRequest<>(client, tokenProvider, url, HttpMethod.GET, new TypeReference() { + }); + } + + /** + * Set the partials for specific prompt. + * A token with {@code read:prompts} scope is required. + * @param prompt the prompt name. + * @param partials the partials. + * @return a Request to execute. + * + * @see https://auth0.com/docs/api/management/v2#!/prompts/put-partials + */ + public Request setPartialsPrompt(String prompt, Object partials) { + Asserts.assertNotNull(prompt, "prompt"); + Asserts.assertNotNull(partials, "partials"); + + HttpUrl.Builder builder = baseUrl.newBuilder() + .addPathSegments(ORGS_PATH) + .addPathSegment(prompt) + .addPathSegment("partials"); + + String url = builder.build().toString(); + + BaseRequest request = new BaseRequest<>(client, tokenProvider, url, HttpMethod.PUT, new TypeReference() { + }); + + request.setBody(partials); + return request; + } + +} diff --git a/src/main/java/com/auth0/json/mgmt/prompts/Prompt.java b/src/main/java/com/auth0/json/mgmt/prompts/Prompt.java new file mode 100644 index 00000000..b7e1ca3a --- /dev/null +++ b/src/main/java/com/auth0/json/mgmt/prompts/Prompt.java @@ -0,0 +1,64 @@ +package com.auth0.json.mgmt.prompts; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; + +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +public class Prompt { + @JsonProperty("universal_login_experience") + private String universalLoginExperience; + @JsonProperty("identifier_first") + private boolean identifierFirst; + @JsonProperty("webauthn_platform_first_factor") + private boolean webauthnPlatformFirstFactor; + + /** + * Getter for the universal login experience. + * @return the universal login experience. + */ + public String getUniversalLoginExperience() { + return universalLoginExperience; + } + + /** + * Setter for the universal login experience. + * @param universalLoginExperience the universal login experience to set. + */ + public void setUniversalLoginExperience(String universalLoginExperience) { + this.universalLoginExperience = universalLoginExperience; + } + + /** + * Getter for the identifier first. + * @return the identifier first. + */ + public boolean isIdentifierFirst() { + return identifierFirst; + } + + /** + * Setter for the identifier first. + * @param identifierFirst the identifier first to set. + */ + public void setIdentifierFirst(boolean identifierFirst) { + this.identifierFirst = identifierFirst; + } + + /** + * Getter for the webauthn platform first factor. + * @return the webauthn platform first factor. + */ + public boolean isWebauthnPlatformFirstFactor() { + return webauthnPlatformFirstFactor; + } + + /** + * Setter for the webauthn platform first factor. + * @param webauthnPlatformFirstFactor the webauthn platform first factor to set. + */ + public void setWebauthnPlatformFirstFactor(boolean webauthnPlatformFirstFactor) { + this.webauthnPlatformFirstFactor = webauthnPlatformFirstFactor; + } +} diff --git a/src/test/java/com/auth0/client/MockServer.java b/src/test/java/com/auth0/client/MockServer.java index 847cd7fa..cc65cab6 100644 --- a/src/test/java/com/auth0/client/MockServer.java +++ b/src/test/java/com/auth0/client/MockServer.java @@ -85,6 +85,9 @@ public class MockServer { public static final String MGMT_USER = "src/test/resources/mgmt/user.json"; public static final String MGMT_RECOVERY_CODE = "src/test/resources/mgmt/recovery_code.json"; public static final String MGMT_IDENTITIES_LIST = "src/test/resources/mgmt/identities_list.json"; + public static final String MGMT_PROMPT = "src/test/resources/mgmt/prompt.json"; + public static final String MGMT_CUSTOM_TEXT_PROMPT = "src/test/resources/mgmt/custom_text_prompt.json"; + public static final String MGMT_PARTIALS_PROMPT = "src/test/resources/mgmt/partials_prompt.json"; public static final String MGMT_GUARDIAN_AUTHENTICATION_POLICIES_LIST = "src/test/resources/mgmt/guardian_authentication_policies_list.json"; public static final String MGMT_GUARDIAN_ENROLLMENT = "src/test/resources/mgmt/guardian_enrollment.json"; public static final String MGMT_GUARDIAN_ENROLLMENTS_LIST = "src/test/resources/mgmt/guardian_enrollments_list.json"; diff --git a/src/test/java/com/auth0/client/mgmt/PromptsEntityTest.java b/src/test/java/com/auth0/client/mgmt/PromptsEntityTest.java new file mode 100644 index 00000000..435baf3c --- /dev/null +++ b/src/test/java/com/auth0/client/mgmt/PromptsEntityTest.java @@ -0,0 +1,191 @@ +package com.auth0.client.mgmt; + +import com.auth0.json.mgmt.prompts.Prompt; +import com.auth0.net.Request; +import com.auth0.net.client.HttpMethod; +import okhttp3.mockwebserver.RecordedRequest; +import org.junit.jupiter.api.Test; + +import java.util.HashMap; +import java.util.Map; + +import static com.auth0.client.MockServer.*; +import static com.auth0.client.RecordedRequestMatcher.hasHeader; +import static com.auth0.client.RecordedRequestMatcher.hasMethodAndPath; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.notNullValue; +import static com.auth0.AssertsUtil.verifyThrows; + +public class PromptsEntityTest extends BaseMgmtEntityTest{ + + @Test + public void shouldGetPrompts() throws Exception { + Request request = api.prompts().getPrompt(); + assertThat(request, is(notNullValue())); + + server.jsonResponse(MGMT_PROMPT, 200); + Prompt response = request.execute().getBody(); + RecordedRequest recordedRequest = server.takeRequest(); + + assertThat(recordedRequest, hasMethodAndPath(HttpMethod.GET, "/api/v2/prompts")); + assertThat(recordedRequest, hasHeader("Content-Type", "application/json")); + assertThat(recordedRequest, hasHeader("Authorization", "Bearer apiToken")); + + assertThat(response, is(notNullValue())); + } + + @Test + public void shouldThrowOnUpdatePromptsWhenPromptIsNull() throws Exception { + verifyThrows(IllegalArgumentException.class, + () -> api.prompts().updatePrompt(null), + "'prompt' cannot be null!"); + } + + @Test + public void shouldUpdatePrompts() throws Exception { + Prompt prompt = new Prompt(); + prompt.setIdentifierFirst(true); + prompt.setUniversalLoginExperience("new"); + prompt.setWebauthnPlatformFirstFactor(true); + + Request request = api.prompts().updatePrompt(prompt); + assertThat(request, is(notNullValue())); + + server.jsonResponse(MGMT_PROMPT, 200); + Prompt response = request.execute().getBody(); + RecordedRequest recordedRequest = server.takeRequest(); + + assertThat(recordedRequest, hasMethodAndPath(HttpMethod.PATCH, "/api/v2/prompts")); + assertThat(recordedRequest, hasHeader("Content-Type", "application/json")); + assertThat(recordedRequest, hasHeader("Authorization", "Bearer apiToken")); + + assertThat(response, is(notNullValue())); + assertThat(response.isIdentifierFirst(), is(true)); + assertThat(response.getUniversalLoginExperience(), is("new")); + assertThat(response.isWebauthnPlatformFirstFactor(), is(true)); + } + + @Test + public void shouldThrowOnGetCustomTextWhenPromptIsNull() throws Exception { + verifyThrows(IllegalArgumentException.class, + () -> api.prompts().getCustomText(null, "en"), + "'prompt' cannot be null!"); + } + + @Test + public void shouldThrowOnGetCustomTextWhenLanguageIsNull() throws Exception { + verifyThrows(IllegalArgumentException.class, + () -> api.prompts().getCustomText("login", null), + "'language' cannot be null!"); + } + + @Test + public void shouldGetCustomText() throws Exception { + Request request = api.prompts().getCustomText("login", "en"); + assertThat(request, is(notNullValue())); + + server.jsonResponse(MGMT_CUSTOM_TEXT_PROMPT, 200); + Object response = request.execute().getBody(); + RecordedRequest recordedRequest = server.takeRequest(); + + assertThat(recordedRequest, hasMethodAndPath(HttpMethod.GET, "/api/v2/prompts/login/custom-text/en")); + assertThat(recordedRequest, hasHeader("Content-Type", "application/json")); + assertThat(recordedRequest, hasHeader("Authorization", "Bearer apiToken")); + + assertThat(response, is(notNullValue())); + } + + @Test + public void shouldThrowOnSetCustomTextWhenPromptIsNull() throws Exception { + verifyThrows(IllegalArgumentException.class, + () -> api.prompts().getCustomText(null, "en"), + "'prompt' cannot be null!"); + } + + @Test + public void shouldThrowOnSetCustomTextWhenLanguageIsNull() throws Exception { + verifyThrows(IllegalArgumentException.class, + () -> api.prompts().getCustomText("login", null), + "'language' cannot be null!"); + } + + @Test + public void shouldThrowOnSetCustomTextWhenCustomTextIsNull() throws Exception { + verifyThrows(IllegalArgumentException.class, + () -> api.prompts().setCustomText("login", "en", null), + "'customText' cannot be null!"); + } + + @Test + public void shouldSetCustomText() throws Exception { + Map signup = new HashMap<>(); + signup.put("description", "Sign up to access amazing features for my login domain"); + + Map customText = new HashMap<>(); + customText.put("signup", signup); + + Request request = api.prompts().setCustomText("login", "en", customText); + assertThat(request, is(notNullValue())); + + server.jsonResponse(MGMT_CUSTOM_TEXT_PROMPT, 200); + request.execute(); + RecordedRequest recordedRequest = server.takeRequest(); + + assertThat(recordedRequest, hasMethodAndPath(HttpMethod.PUT, "/api/v2/prompts/login/custom-text/en")); + assertThat(recordedRequest, hasHeader("Content-Type", "application/json")); + assertThat(recordedRequest, hasHeader("Authorization", "Bearer apiToken")); + } + + @Test + public void shouldThrowOnGetPartialsWhenPromptIsNull() throws Exception { + verifyThrows(IllegalArgumentException.class, + () -> api.prompts().getPartialsPrompt(null), + "'prompt' cannot be null!"); + } + + @Test + public void shouldGetPartials() throws Exception { + Request request = api.prompts().getPartialsPrompt("login"); + assertThat(request, is(notNullValue())); + + server.jsonResponse(MGMT_PARTIALS_PROMPT, 200); + Object response = request.execute().getBody(); + RecordedRequest recordedRequest = server.takeRequest(); + + assertThat(recordedRequest, hasMethodAndPath(HttpMethod.GET, "/api/v2/prompts/login/partials")); + assertThat(recordedRequest, hasHeader("Content-Type", "application/json")); + assertThat(recordedRequest, hasHeader("Authorization", "Bearer apiToken")); + + assertThat(response, is(notNullValue())); + } + + @Test + public void shouldThrowOnSetPartialsWhenPromptIsNull() throws Exception { + verifyThrows(IllegalArgumentException.class, + () -> api.prompts().setPartialsPrompt(null, new Object()), + "'prompt' cannot be null!"); + } + + @Test + public void shouldThrowOnSetPartialsWhenPartialsIsNull() throws Exception { + verifyThrows(IllegalArgumentException.class, + () -> api.prompts().setPartialsPrompt("login", null), + "'partials' cannot be null!"); + } + + @Test + public void shouldSetPartials() throws Exception { + Map partials = new HashMap<>(); + Request request = api.prompts().setPartialsPrompt("login", partials); + assertThat(request, is(notNullValue())); + + server.jsonResponse(MGMT_PARTIALS_PROMPT, 200); + request.execute(); + RecordedRequest recordedRequest = server.takeRequest(); + + assertThat(recordedRequest, hasMethodAndPath(HttpMethod.PUT, "/api/v2/prompts/login/partials")); + assertThat(recordedRequest, hasHeader("Content-Type", "application/json")); + assertThat(recordedRequest, hasHeader("Authorization", "Bearer apiToken")); + } +} diff --git a/src/test/resources/mgmt/custom_text_prompt.json b/src/test/resources/mgmt/custom_text_prompt.json new file mode 100644 index 00000000..dd14ae92 --- /dev/null +++ b/src/test/resources/mgmt/custom_text_prompt.json @@ -0,0 +1,5 @@ +{ + "signup": { + "description": "Sign up to access amazing features for my login domain" + } +} diff --git a/src/test/resources/mgmt/partials_prompt.json b/src/test/resources/mgmt/partials_prompt.json new file mode 100644 index 00000000..2c63c085 --- /dev/null +++ b/src/test/resources/mgmt/partials_prompt.json @@ -0,0 +1,2 @@ +{ +} diff --git a/src/test/resources/mgmt/prompt.json b/src/test/resources/mgmt/prompt.json new file mode 100644 index 00000000..5dd9655c --- /dev/null +++ b/src/test/resources/mgmt/prompt.json @@ -0,0 +1,5 @@ +{ + "universal_login_experience": "new", + "identifier_first": true, + "webauthn_platform_first_factor": true +}