From a9c17fb9e7a94fd742c42ff9a66206091d33de81 Mon Sep 17 00:00:00 2001 From: Steven Wong Date: Thu, 25 Jul 2024 22:24:56 +0800 Subject: [PATCH 01/32] Update codeowner file with new GitHub team name --- .github/CODEOWNERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 60f116c0..7958e8bd 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1 +1 @@ -* @auth0/dx-sdks-engineer +* @auth0/project-dx-sdks-engineer-codeowner From 7c036e750467f7f8eca523a2f33859ab5970c44e Mon Sep 17 00:00:00 2001 From: Jak Spalding <191585+jak@users.noreply.github.com> Date: Wed, 26 Jun 2024 16:24:39 +0100 Subject: [PATCH 02/32] feat: add sessions and refresh tokens --- .../com/auth0/client/mgmt/UsersEntity.java | 99 +++++++++++ .../filter/CheckpointPaginationFilter.java | 38 +++++ .../users/refreshtokens/RefreshToken.java | 97 +++++++++++ .../refreshtokens/RefreshTokensPage.java | 44 +++++ .../users/refreshtokens/ResourceServer.java | 30 ++++ .../mgmt/users/sessions/Authentication.java | 21 +++ .../users/sessions/AuthenticationMethod.java | 39 +++++ .../json/mgmt/users/sessions/Client.java | 19 +++ .../json/mgmt/users/sessions/Device.java | 55 ++++++ .../json/mgmt/users/sessions/Session.java | 104 ++++++++++++ .../mgmt/users/sessions/SessionsPage.java | 44 +++++ .../java/com/auth0/client/MockServer.java | 2 + .../auth0/client/mgmt/UsersEntityTest.java | 157 ++++++++++++++++++ .../CheckpointPaginationFilterTest.java | 37 +++++ .../refreshtokens/RefreshTokensPageTest.java | 44 +++++ .../mgmt/users/sessions/SessionsPageTest.java | 50 ++++++ .../resources/mgmt/user_refresh_tokens.json | 44 +++++ src/test/resources/mgmt/user_sessions.json | 35 ++++ 18 files changed, 959 insertions(+) create mode 100644 src/main/java/com/auth0/client/mgmt/filter/CheckpointPaginationFilter.java create mode 100644 src/main/java/com/auth0/json/mgmt/users/refreshtokens/RefreshToken.java create mode 100644 src/main/java/com/auth0/json/mgmt/users/refreshtokens/RefreshTokensPage.java create mode 100644 src/main/java/com/auth0/json/mgmt/users/refreshtokens/ResourceServer.java create mode 100644 src/main/java/com/auth0/json/mgmt/users/sessions/Authentication.java create mode 100644 src/main/java/com/auth0/json/mgmt/users/sessions/AuthenticationMethod.java create mode 100644 src/main/java/com/auth0/json/mgmt/users/sessions/Client.java create mode 100644 src/main/java/com/auth0/json/mgmt/users/sessions/Device.java create mode 100644 src/main/java/com/auth0/json/mgmt/users/sessions/Session.java create mode 100644 src/main/java/com/auth0/json/mgmt/users/sessions/SessionsPage.java create mode 100644 src/test/java/com/auth0/client/mgmt/filter/CheckpointPaginationFilterTest.java create mode 100644 src/test/java/com/auth0/json/mgmt/users/refreshtokens/RefreshTokensPageTest.java create mode 100644 src/test/java/com/auth0/json/mgmt/users/sessions/SessionsPageTest.java create mode 100644 src/test/resources/mgmt/user_refresh_tokens.json create mode 100644 src/test/resources/mgmt/user_sessions.json diff --git a/src/main/java/com/auth0/client/mgmt/UsersEntity.java b/src/main/java/com/auth0/client/mgmt/UsersEntity.java index 6d06a3b6..9ee4bfa6 100644 --- a/src/main/java/com/auth0/client/mgmt/UsersEntity.java +++ b/src/main/java/com/auth0/client/mgmt/UsersEntity.java @@ -13,6 +13,8 @@ import com.auth0.json.mgmt.users.RecoveryCode; import com.auth0.json.mgmt.users.User; import com.auth0.json.mgmt.users.UsersPage; +import com.auth0.json.mgmt.users.refreshtokens.RefreshTokensPage; +import com.auth0.json.mgmt.users.sessions.SessionsPage; import com.auth0.net.EmptyBodyRequest; import com.auth0.net.BaseRequest; import com.auth0.net.Request; @@ -787,6 +789,103 @@ public Request updateAuthenticationMethodById(String userI return request; } + /** + * Get refresh tokens for a user + * A token with {@code read:refresh_tokens} is needed. + * See https://auth0.com/docs/api/management/v2/users/get-refresh-tokens-for-user + * + * @param userId the role id + * @param filter an optional pagination filter + * @return a Request to execute + */ + public Request listRefreshTokens(String userId, CheckpointPaginationFilter filter) { + Asserts.assertNotNull(userId, "user id"); + HttpUrl.Builder builder = baseUrl + .newBuilder() + .addPathSegments("api/v2/users") + .addPathSegment(userId) + .addPathSegment("refresh-tokens"); + if (filter != null) { + for (Map.Entry e : filter.getAsMap().entrySet()) { + builder.addQueryParameter(e.getKey(), String.valueOf(e.getValue())); + } + } + String url = builder.build().toString(); + return new BaseRequest<>(client, tokenProvider, url, HttpMethod.GET, new TypeReference() { + }); + } + + /** + * Delete all refresh tokens for a user. + * A token with scope {@code delete:refresh_tokens} is needed. + * See https://auth0.com/docs/api/management/v2/users/delete-refresh-tokens-for-user + * + * @param userId the user to delete the refresh tokens for + * @return a Request to execute. + */ + public Request deleteRefreshTokens(String userId) { + Asserts.assertNotNull(userId, "user ID"); + + String url = baseUrl + .newBuilder() + .addPathSegments("api/v2/users") + .addPathSegment(userId) + .addPathSegment("refresh-tokens") + .build() + .toString(); + + return new VoidRequest(this.client, tokenProvider, url, HttpMethod.DELETE); + } + + + /** + * Get sessions for user + * A token with {@code read:sessions} is needed. + * See https://auth0.com/docs/api/management/v2/users/get-sessions-for-user + * + * @param userId the role id + * @param filter an optional pagination filter + * @return a Request to execute + */ + public Request listSessions(String userId, CheckpointPaginationFilter filter) { + Asserts.assertNotNull(userId, "user id"); + HttpUrl.Builder builder = baseUrl + .newBuilder() + .addPathSegments("api/v2/users") + .addPathSegment(userId) + .addPathSegment("sessions"); + if (filter != null) { + for (Map.Entry e : filter.getAsMap().entrySet()) { + builder.addQueryParameter(e.getKey(), String.valueOf(e.getValue())); + } + } + String url = builder.build().toString(); + return new BaseRequest<>(client, tokenProvider, url, HttpMethod.GET, new TypeReference() { + }); + } + + /** + * Delete sessions for user + * A token with scope {@code delete:sessions} is needed. + * See https://auth0.com/docs/api/management/v2/users/delete-sessions-for-user + * + * @param userId the user to delete the sessions for + * @return a Request to execute. + */ + public Request deleteSessions(String userId) { + Asserts.assertNotNull(userId, "user ID"); + + String url = baseUrl + .newBuilder() + .addPathSegments("api/v2/users") + .addPathSegment(userId) + .addPathSegment("sessions") + .build() + .toString(); + + return new VoidRequest(this.client, tokenProvider, url, HttpMethod.DELETE); + } + private static void encodeAndAddQueryParam(HttpUrl.Builder builder, BaseFilter filter) { if (filter != null) { for (Map.Entry e : filter.getAsMap().entrySet()) { diff --git a/src/main/java/com/auth0/client/mgmt/filter/CheckpointPaginationFilter.java b/src/main/java/com/auth0/client/mgmt/filter/CheckpointPaginationFilter.java new file mode 100644 index 00000000..1f881b7c --- /dev/null +++ b/src/main/java/com/auth0/client/mgmt/filter/CheckpointPaginationFilter.java @@ -0,0 +1,38 @@ +package com.auth0.client.mgmt.filter; + +public class CheckpointPaginationFilter extends BaseFilter { + + /** + * Return results inside an object that contains the total result count (true) or as a direct array of results (false, default). + * + * @param includeTotals whether to include or not total result count. + * @return this filter instance + */ + public CheckpointPaginationFilter withTotals(boolean includeTotals) { + parameters.put("include_totals", includeTotals); + return this; + } + + /** + * Optional ID from which to start selection (exclusive). + * + * @param from the ID from which to start selection. This can be obtained from the {@code next} field returned from + * a checkpoint-paginated result. + * @return this filter instance. + */ + public CheckpointPaginationFilter withFrom(String from) { + parameters.put("from", from); + return this; + } + + /** + * Number of results per page. Defaults to 50. + * + * @param take the amount of entries to retrieve per page. + * @return this filter instance. + */ + public CheckpointPaginationFilter withTake(int take) { + parameters.put("take", take); + return this; + } +} diff --git a/src/main/java/com/auth0/json/mgmt/users/refreshtokens/RefreshToken.java b/src/main/java/com/auth0/json/mgmt/users/refreshtokens/RefreshToken.java new file mode 100644 index 00000000..1551f4dd --- /dev/null +++ b/src/main/java/com/auth0/json/mgmt/users/refreshtokens/RefreshToken.java @@ -0,0 +1,97 @@ +package com.auth0.json.mgmt.users.refreshtokens; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; + +import java.util.Date; +import java.util.List; + +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +public class RefreshToken { + @JsonProperty("id") + private String id; + @JsonProperty("user_id") + private String userId; + @JsonProperty("created_at") + private Date createdAt; + @JsonProperty("idle_expires_at") + private Date idleExpiresAt; + @JsonProperty("expires_at") + private Date expiresAt; + @JsonProperty("client_id") + private String clientId; + @JsonProperty("session_id") + private String sessionId; + @JsonProperty("rotating") + private Boolean rotating; + @JsonProperty("resource_servers") + private List resourceServers; + + /** + * @return The ID of the refresh token + */ + public String getId() { + return id; + } + + /** + * @return ID of the user which can be used when interacting with other APIs. + */ + public String getUserId() { + return userId; + } + + /** + * @return The date and time when the refresh token was created + */ + public Date getCreatedAt() { + return createdAt; + } + + /** + * + * @return The date and time when the refresh token will expire if idle + */ + public Date getIdleExpiresAt() { + return idleExpiresAt; + } + + /** + * + * @return The date and time when the refresh token will expire + */ + public Date getExpiresAt() { + return expiresAt; + } + + /** + * @return ID of the client application granted with this refresh token + */ + public String getClientId() { + return clientId; + } + + /** + * + * @return ID of the authenticated session used to obtain this refresh-token + */ + public String getSessionId() { + return sessionId; + } + + /** + * @return True if the token is a rotating refresh token + */ + public Boolean isRotating() { + return rotating; + } + + /** + * @return A list of the resource server IDs associated to this refresh-token and their granted scopes + */ + public List getResourceServers() { + return resourceServers; + } +} diff --git a/src/main/java/com/auth0/json/mgmt/users/refreshtokens/RefreshTokensPage.java b/src/main/java/com/auth0/json/mgmt/users/refreshtokens/RefreshTokensPage.java new file mode 100644 index 00000000..224c0b62 --- /dev/null +++ b/src/main/java/com/auth0/json/mgmt/users/refreshtokens/RefreshTokensPage.java @@ -0,0 +1,44 @@ +package com.auth0.json.mgmt.users.refreshtokens; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; + +import java.util.List; + +/** + * This does not extend com.auth0.json.mgmt.Page because the URL only supports "next" and "take" pagination. + */ +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +public class RefreshTokensPage { + @JsonProperty("total") + private Integer total; + + @JsonProperty("next") + private String next; + + @JsonProperty("tokens") + private List tokens; + + /** + * @return the total number of refresh tokens. This is only present when `include_totals` is passed as a query parameter. + */ + public Integer getTotal() { + return total; + } + + /** + * @return the token ID from which to start selection for a new page + */ + public String getNext() { + return next; + } + + /** + * @return the list of Tokens + */ + public List getTokens() { + return tokens; + } +} diff --git a/src/main/java/com/auth0/json/mgmt/users/refreshtokens/ResourceServer.java b/src/main/java/com/auth0/json/mgmt/users/refreshtokens/ResourceServer.java new file mode 100644 index 00000000..b423de41 --- /dev/null +++ b/src/main/java/com/auth0/json/mgmt/users/refreshtokens/ResourceServer.java @@ -0,0 +1,30 @@ +package com.auth0.json.mgmt.users.refreshtokens; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; + +import java.util.List; + +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +public class ResourceServer { + @JsonProperty("audience") + private String audience; + @JsonProperty("scopes") + private List scopes; + + /** + * @return Resource server ID + */ + public String getAudience() { + return audience; + } + + /** + * @return List of scopes for the refresh token + */ + public List getScopes() { + return scopes; + } +} diff --git a/src/main/java/com/auth0/json/mgmt/users/sessions/Authentication.java b/src/main/java/com/auth0/json/mgmt/users/sessions/Authentication.java new file mode 100644 index 00000000..dd9ba115 --- /dev/null +++ b/src/main/java/com/auth0/json/mgmt/users/sessions/Authentication.java @@ -0,0 +1,21 @@ +package com.auth0.json.mgmt.users.sessions; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; + +import java.util.List; + +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +public class Authentication { + @JsonProperty("methods") + private List methods; + + /** + * @return Contains the authentication methods a user has completed during their session + */ + public List getMethods() { + return methods; + } +} diff --git a/src/main/java/com/auth0/json/mgmt/users/sessions/AuthenticationMethod.java b/src/main/java/com/auth0/json/mgmt/users/sessions/AuthenticationMethod.java new file mode 100644 index 00000000..c55634c5 --- /dev/null +++ b/src/main/java/com/auth0/json/mgmt/users/sessions/AuthenticationMethod.java @@ -0,0 +1,39 @@ +package com.auth0.json.mgmt.users.sessions; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; + +import java.util.Date; + +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +public class AuthenticationMethod { + @JsonProperty("name") + private String name; + @JsonProperty("timestamp") + private Date timestamp; + @JsonProperty("type") + private String type; + + /** + * @return One of: "federated", "passkey", "pwd", "sms", "email", "mfa", "mock" or a custom method denoted by a URL + */ + public String getName() { + return name; + } + + /** + * @return Timestamp of when the signal was received + */ + public Date getTimestamp() { + return timestamp; + } + + /** + * @return A specific MFA factor. Only present when "name" is set to "mfa" + */ + public String getType() { + return type; + } +} diff --git a/src/main/java/com/auth0/json/mgmt/users/sessions/Client.java b/src/main/java/com/auth0/json/mgmt/users/sessions/Client.java new file mode 100644 index 00000000..aa51c6e9 --- /dev/null +++ b/src/main/java/com/auth0/json/mgmt/users/sessions/Client.java @@ -0,0 +1,19 @@ +package com.auth0.json.mgmt.users.sessions; + +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 Client { + @JsonProperty("client_id") + private String clientId; + + /** + * @return ID of client for the session + */ + public String getClientId() { + return clientId; + } +} diff --git a/src/main/java/com/auth0/json/mgmt/users/sessions/Device.java b/src/main/java/com/auth0/json/mgmt/users/sessions/Device.java new file mode 100644 index 00000000..1665c6ed --- /dev/null +++ b/src/main/java/com/auth0/json/mgmt/users/sessions/Device.java @@ -0,0 +1,55 @@ +package com.auth0.json.mgmt.users.sessions; + +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 Device { + @JsonProperty("initial_ip") + private String initialIP; + @JsonProperty("initial_asn") + private String initialASN; + @JsonProperty("last_user_agent") + private String lastUserAgent; + @JsonProperty("last_ip") + private String lastIP; + @JsonProperty("last_asn") + private String lastASN; + + /** + * @return First IP address associated with this session + */ + public String getInitialIP() { + return initialIP; + } + + /** + * @return First autonomous system number associated with this session + */ + public String getInitialASN() { + return initialASN; + } + + /** + * @return Last user agent of the device from which this user logged in + */ + public String getLastUserAgent() { + return lastUserAgent; + } + + /** + * @return Last IP address from which this user logged in + */ + public String getLastIP() { + return lastIP; + } + + /** + * @return Last autonomous system number from which this user logged in + */ + public String getLastASN() { + return lastASN; + } +} diff --git a/src/main/java/com/auth0/json/mgmt/users/sessions/Session.java b/src/main/java/com/auth0/json/mgmt/users/sessions/Session.java new file mode 100644 index 00000000..ae0fe6c6 --- /dev/null +++ b/src/main/java/com/auth0/json/mgmt/users/sessions/Session.java @@ -0,0 +1,104 @@ +package com.auth0.json.mgmt.users.sessions; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; + +import java.util.Date; +import java.util.List; + +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +public class Session { + @JsonProperty("id") + private String id; + @JsonProperty("user_id") + private String userId; + @JsonProperty("created_at") + private Date createdAt; + @JsonProperty("updated_at") + private Date updatedAt; + @JsonProperty("authenticated_at") + private Date authenticatedAt; + @JsonProperty("idle_expires_at") + private Date idleExpiresAt; + @JsonProperty("expires_at") + private Date expiresAt; + @JsonProperty("device") + private Device device; + @JsonProperty("clients") + private List clients; + @JsonProperty("authentication") + private Authentication authentication; + + /** + * @return The ID of the session + */ + public String getId() { + return id; + } + + /** + * @return ID of the user which can be used when interacting with other APIs. + */ + public String getUserId() { + return userId; + } + + /** + * + * @return The date and time when the session was created + */ + public Date getCreatedAt() { + return createdAt; + } + + /** + * @return The date and time when the session was last updated + */ + public Date getUpdatedAt() { + return updatedAt; + } + + /** + * @return The date and time when the session was last authenticated + */ + public Date getAuthenticatedAt() { + return authenticatedAt; + } + + /** + * @return The date and time when the session will expire if idle + */ + public Date getIdleExpiresAt() { + return idleExpiresAt; + } + + /** + * @return The date and time when the session will expire + */ + public Date getExpiresAt() { + return expiresAt; + } + + /** + * @return Metadata related to the device used in the session + */ + public Device getDevice() { + return device; + } + + /** + * @return List of client details for the session + */ + public List getClients() { + return clients; + } + + /** + * @return Details about authentication signals obtained during the login flow + */ + public Authentication getAuthentication() { + return authentication; + } +} diff --git a/src/main/java/com/auth0/json/mgmt/users/sessions/SessionsPage.java b/src/main/java/com/auth0/json/mgmt/users/sessions/SessionsPage.java new file mode 100644 index 00000000..da536451 --- /dev/null +++ b/src/main/java/com/auth0/json/mgmt/users/sessions/SessionsPage.java @@ -0,0 +1,44 @@ +package com.auth0.json.mgmt.users.sessions; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; + +import java.util.List; + +/** + * This does not extend com.auth0.json.mgmt.Page because the URL only supports "next" and "take" pagination. + */ +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +public class SessionsPage { + @JsonProperty("total") + private Integer total; + + @JsonProperty("next") + private String next; + + @JsonProperty("sessions") + private List sessions; + + /** + * @return the total number of refresh tokens. This is only present when `include_totals` is passed as a query parameter. + */ + public Integer getTotal() { + return total; + } + + /** + * @return the token ID from which to start selection for a new page + */ + public String getNext() { + return next; + } + + /** + * @return the list of Sessions + */ + public List getSessions() { + return sessions; + } +} diff --git a/src/test/java/com/auth0/client/MockServer.java b/src/test/java/com/auth0/client/MockServer.java index 9df874b2..5b162e67 100644 --- a/src/test/java/com/auth0/client/MockServer.java +++ b/src/test/java/com/auth0/client/MockServer.java @@ -78,6 +78,8 @@ public class MockServer { public static final String MGMT_USERS_PAGED_LIST = "src/test/resources/mgmt/users_paged_list.json"; public static final String MGMT_USER_PERMISSIONS_PAGED_LIST = "src/test/resources/mgmt/user_permissions_paged_list.json"; public static final String MGMT_USER_ROLES_PAGED_LIST = "src/test/resources/mgmt/user_roles_paged_list.json"; + public static final String MGMT_USER_REFRESH_TOKENS = "src/test/resources/mgmt/user_refresh_tokens.json"; + public static final String MGMT_USER_SESSIONS = "src/test/resources/mgmt/user_sessions.json"; 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"; diff --git a/src/test/java/com/auth0/client/mgmt/UsersEntityTest.java b/src/test/java/com/auth0/client/mgmt/UsersEntityTest.java index 61f519c9..a2556ee5 100644 --- a/src/test/java/com/auth0/client/mgmt/UsersEntityTest.java +++ b/src/test/java/com/auth0/client/mgmt/UsersEntityTest.java @@ -4,6 +4,7 @@ import com.auth0.client.mgmt.filter.LogEventFilter; import com.auth0.client.mgmt.filter.PageFilter; import com.auth0.client.mgmt.filter.UserFilter; +import com.auth0.client.mgmt.filter.CheckpointPaginationFilter; import com.auth0.json.mgmt.guardian.Enrollment; import com.auth0.json.mgmt.logevents.LogEvent; import com.auth0.json.mgmt.logevents.LogEventsPage; @@ -17,6 +18,8 @@ import com.auth0.json.mgmt.users.UsersPage; import com.auth0.json.mgmt.users.authenticationmethods.AuthenticationMethod; import com.auth0.json.mgmt.users.authenticationmethods.AuthenticationMethodsPage; +import com.auth0.json.mgmt.users.refreshtokens.RefreshTokensPage; +import com.auth0.json.mgmt.users.sessions.SessionsPage; import com.auth0.net.Request; import com.auth0.net.client.HttpMethod; import okhttp3.mockwebserver.RecordedRequest; @@ -1348,4 +1351,158 @@ public void shouldInvalidateRememberedBrowsers() throws Exception { assertThat(recordedRequest, hasMethodAndPath(HttpMethod.POST, "/api/v2/users/userId/multifactor/actions/invalidate-remember-browser")); assertThat(recordedRequest, hasHeader("Authorization", "Bearer apiToken")); } + + @Test + public void shouldListRefreshTokensWithoutFilter() throws Exception { + Request request = api.users().listRefreshTokens("1", null); + assertThat(request, is(notNullValue())); + + server.jsonResponse(MGMT_USER_REFRESH_TOKENS, 200); + RefreshTokensPage response = request.execute().getBody(); + RecordedRequest recordedRequest = server.takeRequest(); + + assertThat(recordedRequest, hasMethodAndPath(HttpMethod.GET, "/api/v2/users/1/refresh-tokens")); + assertThat(recordedRequest, hasHeader("Content-Type", "application/json")); + assertThat(recordedRequest, hasHeader("Authorization", "Bearer apiToken")); + + assertThat(response, is(notNullValue())); + assertThat(response.getTokens(), hasSize(2)); + } + + @Test + public void shouldListRefreshTokensWithPage() throws Exception { + CheckpointPaginationFilter filter = new CheckpointPaginationFilter().withFrom("tokenId2").withTake(5); + Request request = api.users().listRefreshTokens("1", filter); + assertThat(request, is(notNullValue())); + + server.jsonResponse(MGMT_USER_REFRESH_TOKENS, 200); + RefreshTokensPage response = request.execute().getBody(); + RecordedRequest recordedRequest = server.takeRequest(); + + assertThat(recordedRequest, hasMethodAndPath(HttpMethod.GET, "/api/v2/users/1/refresh-tokens")); + assertThat(recordedRequest, hasHeader("Content-Type", "application/json")); + assertThat(recordedRequest, hasHeader("Authorization", "Bearer apiToken")); + assertThat(recordedRequest, hasQueryParameter("from", "tokenId2")); + assertThat(recordedRequest, hasQueryParameter("take", "5")); + + assertThat(response, is(notNullValue())); + assertThat(response.getTokens(), hasSize(2)); + } + + @Test + public void shouldListRefreshTokensWithTotal() throws Exception { + CheckpointPaginationFilter filter = new CheckpointPaginationFilter().withTotals(true); + Request request = api.users().listRefreshTokens("1", filter); + assertThat(request, is(notNullValue())); + + server.jsonResponse(MGMT_USER_REFRESH_TOKENS, 200); + RefreshTokensPage response = request.execute().getBody(); + RecordedRequest recordedRequest = server.takeRequest(); + + assertThat(recordedRequest, hasMethodAndPath(HttpMethod.GET, "/api/v2/users/1/refresh-tokens")); + assertThat(recordedRequest, hasHeader("Content-Type", "application/json")); + assertThat(recordedRequest, hasHeader("Authorization", "Bearer apiToken")); + assertThat(recordedRequest, hasQueryParameter("include_totals", "true")); + + assertThat(response, is(notNullValue())); + assertThat(response.getTokens(), hasSize(2)); + assertThat(response.getTotal(), is(11)); + } + + @Test + public void shouldNotDeleteRefreshTokensWithNullUserId() { + verifyThrows(IllegalArgumentException.class, + () -> api.users().deleteRefreshTokens(null), + "'user ID' cannot be null!"); + } + + @Test + public void shouldDeleteRefreshTokens() throws Exception { + Request request = api.users().deleteRefreshTokens("1"); + assertThat(request, is(notNullValue())); + + server.noContentResponse(); + request.execute().getBody(); + RecordedRequest recordedRequest = server.takeRequest(); + + assertThat(recordedRequest, hasMethodAndPath(HttpMethod.DELETE, "/api/v2/users/1/refresh-tokens")); + assertThat(recordedRequest, hasHeader("Authorization", "Bearer apiToken")); + } + + @Test + public void shouldListSessionsWithoutFilter() throws Exception { + Request request = api.users().listSessions("1", null); + assertThat(request, is(notNullValue())); + + server.jsonResponse(MGMT_USER_SESSIONS, 200); + SessionsPage response = request.execute().getBody(); + RecordedRequest recordedRequest = server.takeRequest(); + + assertThat(recordedRequest, hasMethodAndPath(HttpMethod.GET, "/api/v2/users/1/sessions")); + assertThat(recordedRequest, hasHeader("Content-Type", "application/json")); + assertThat(recordedRequest, hasHeader("Authorization", "Bearer apiToken")); + + assertThat(response, is(notNullValue())); + assertThat(response.getSessions(), hasSize(1)); + } + + @Test + public void shouldListSessionsWithPage() throws Exception { + CheckpointPaginationFilter filter = new CheckpointPaginationFilter().withFrom("sessionId3").withTake(9); + Request request = api.users().listSessions("1", filter); + assertThat(request, is(notNullValue())); + + server.jsonResponse(MGMT_USER_SESSIONS, 200); + SessionsPage response = request.execute().getBody(); + RecordedRequest recordedRequest = server.takeRequest(); + + assertThat(recordedRequest, hasMethodAndPath(HttpMethod.GET, "/api/v2/users/1/sessions")); + assertThat(recordedRequest, hasHeader("Content-Type", "application/json")); + assertThat(recordedRequest, hasHeader("Authorization", "Bearer apiToken")); + assertThat(recordedRequest, hasQueryParameter("from", "sessionId3")); + assertThat(recordedRequest, hasQueryParameter("take", "9")); + + assertThat(response, is(notNullValue())); + assertThat(response.getSessions(), hasSize(1)); + } + + @Test + public void shouldListSessionsWithTotal() throws Exception { + CheckpointPaginationFilter filter = new CheckpointPaginationFilter().withTotals(true); + Request request = api.users().listSessions("1", filter); + assertThat(request, is(notNullValue())); + + server.jsonResponse(MGMT_USER_SESSIONS, 200); + SessionsPage response = request.execute().getBody(); + RecordedRequest recordedRequest = server.takeRequest(); + + assertThat(recordedRequest, hasMethodAndPath(HttpMethod.GET, "/api/v2/users/1/sessions")); + assertThat(recordedRequest, hasHeader("Content-Type", "application/json")); + assertThat(recordedRequest, hasHeader("Authorization", "Bearer apiToken")); + assertThat(recordedRequest, hasQueryParameter("include_totals", "true")); + + assertThat(response, is(notNullValue())); + assertThat(response.getSessions(), hasSize(1)); + assertThat(response.getTotal(), is(9)); + } + + @Test + public void shouldNotDeleteSessionsWithNullUserId() { + verifyThrows(IllegalArgumentException.class, + () -> api.users().deleteRefreshTokens(null), + "'user ID' cannot be null!"); + } + + @Test + public void shouldDeleteSessions() throws Exception { + Request request = api.users().deleteSessions("1"); + assertThat(request, is(notNullValue())); + + server.noContentResponse(); + request.execute().getBody(); + RecordedRequest recordedRequest = server.takeRequest(); + + assertThat(recordedRequest, hasMethodAndPath(HttpMethod.DELETE, "/api/v2/users/1/sessions")); + assertThat(recordedRequest, hasHeader("Authorization", "Bearer apiToken")); + } } diff --git a/src/test/java/com/auth0/client/mgmt/filter/CheckpointPaginationFilterTest.java b/src/test/java/com/auth0/client/mgmt/filter/CheckpointPaginationFilterTest.java new file mode 100644 index 00000000..69cb4641 --- /dev/null +++ b/src/test/java/com/auth0/client/mgmt/filter/CheckpointPaginationFilterTest.java @@ -0,0 +1,37 @@ +package com.auth0.client.mgmt.filter; + +import org.hamcrest.Matchers; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.notNullValue; +import static org.hamcrest.MatcherAssert.assertThat; + +public class CheckpointPaginationFilterTest { + + private CheckpointPaginationFilter filter; + + @BeforeEach + public void setUp() { + filter = new CheckpointPaginationFilter(); + } + + @Test + public void shouldIncludeTotals() { + CheckpointPaginationFilter instance = filter.withTotals(true); + + assertThat(filter, is(instance)); + assertThat(filter.getAsMap(), is(notNullValue())); + assertThat(filter.getAsMap(), Matchers.hasEntry("include_totals", true)); + } + + @Test + public void shouldIncludeCheckpointParams() { + CheckpointPaginationFilter instance = filter.withFrom("abc123").withTake(2); + + assertThat(filter.getAsMap(), is(notNullValue())); + assertThat(filter.getAsMap(), Matchers.hasEntry("from", "abc123")); + assertThat(filter.getAsMap(), Matchers.hasEntry("take", 2)); + } +} diff --git a/src/test/java/com/auth0/json/mgmt/users/refreshtokens/RefreshTokensPageTest.java b/src/test/java/com/auth0/json/mgmt/users/refreshtokens/RefreshTokensPageTest.java new file mode 100644 index 00000000..b0e701eb --- /dev/null +++ b/src/test/java/com/auth0/json/mgmt/users/refreshtokens/RefreshTokensPageTest.java @@ -0,0 +1,44 @@ +package com.auth0.json.mgmt.users.refreshtokens; + +import com.auth0.json.JsonTest; +import org.junit.jupiter.api.Test; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.nullValue; + +public class RefreshTokensPageTest extends JsonTest { + private static final String json = "{\n\"tokens\": [\n{\n\"id\": \"tokenId1\",\n\"user_id\": \"userId1\",\n\"created_at\": \"2024-06-26T09:10:26.643Z\",\n\"updated_at\": \"2024-06-26T09:10:27.131Z\",\n\"expires_at\": \"2024-07-03T09:10:26.643Z\",\n\"client_id\": \"clientId1\",\n\"session_id\": \"sessionId1\",\n\"rotating\": false,\n\"resource_servers\": [\n{\n\"audience\": \"https://api.example.com\",\n\"scopes\": [\n\"read:examples\",\n\"write:examples\"\n]\n}\n]\n},\n{\n\"id\": \"tokenId2\",\n\"user_id\": \"userId1\",\n\"created_at\": \"2024-06-26T09:10:26.643Z\",\n\"updated_at\": \"2024-06-26T09:10:27.131Z\",\n\"expires_at\": \"2024-07-03T09:10:26.643Z\",\n\"client_id\": \"clientId2\",\n\"session_id\": \"sessionId2\",\n\"rotating\": true,\n\"resource_servers\": [\n{\n\"audience\": \"https://api.example.com\",\n\"scopes\": [\n\"read:examples\",\n\"write:examples\"\n]\n}\n]\n}\n],\n\"next\": \"token1\"\n}\n"; + private static final String jsonWithTotal = "{\n\"tokens\": [\n{\n\"id\": \"tokenId1\",\n\"user_id\": \"userId1\",\n\"created_at\": \"2024-06-26T09:10:26.643Z\",\n\"updated_at\": \"2024-06-26T09:10:27.131Z\",\n\"expires_at\": \"2024-07-03T09:10:26.643Z\",\n\"client_id\": \"clientId1\",\n\"session_id\": \"sessionId1\",\n\"rotating\": false,\n\"resource_servers\": [\n{\n\"audience\": \"https://api.example.com\",\n\"scopes\": [\n\"read:examples\",\n\"write:examples\"\n]\n}\n]\n},\n{\n\"id\": \"tokenId2\",\n\"user_id\": \"userId1\",\n\"created_at\": \"2024-06-26T09:10:26.643Z\",\n\"updated_at\": \"2024-06-26T09:10:27.131Z\",\n\"expires_at\": \"2024-07-03T09:10:26.643Z\",\n\"client_id\": \"clientId2\",\n\"session_id\": \"sessionId2\",\n\"rotating\": true,\n\"resource_servers\": [\n{\n\"audience\": \"https://api.example.com\",\n\"scopes\": [\n\"read:examples\",\n\"write:examples\"\n]\n}\n]\n}\n],\n\"next\": \"token1\",\n\"total\": 11\n}\n"; + + @Test + public void shouldDeserialize() throws Exception { + RefreshTokensPage page = fromJSON(json, RefreshTokensPage.class); + + assertThat(page.getTotal(), is(nullValue())); + assertThat(page.getNext(), is("token1")); + + assertThat(page.getTokens().size(), is(2)); + assertThat(page.getTokens().get(0).getId(), is("tokenId1")); + assertThat(page.getTokens().get(0).getUserId(), is("userId1")); + assertThat(page.getTokens().get(0).getCreatedAt(), is(parseJSONDate("2024-06-26T09:10:26.643Z"))); + assertThat(page.getTokens().get(0).getIdleExpiresAt(), is(nullValue())); + assertThat(page.getTokens().get(0).getExpiresAt(), is(parseJSONDate("2024-07-03T09:10:26.643Z"))); + assertThat(page.getTokens().get(0).getClientId(), is("clientId1")); + assertThat(page.getTokens().get(0).getSessionId(), is("sessionId1")); + assertThat(page.getTokens().get(0).isRotating(), is(false)); + + assertThat(page.getTokens().get(0).getResourceServers().size(), is(1)); + assertThat(page.getTokens().get(0).getResourceServers().get(0).getAudience(), is("https://api.example.com")); + assertThat(page.getTokens().get(0).getResourceServers().get(0).getScopes().size(), is(2)); + assertThat(page.getTokens().get(0).getResourceServers().get(0).getScopes().get(0), is("read:examples")); + assertThat(page.getTokens().get(0).getResourceServers().get(0).getScopes().get(1), is("write:examples")); + } + + @Test + public void shouldDeserializeWithTotal() throws Exception { + RefreshTokensPage page = fromJSON(jsonWithTotal, RefreshTokensPage.class); + + assertThat(page.getTotal(), is(11)); + } +} diff --git a/src/test/java/com/auth0/json/mgmt/users/sessions/SessionsPageTest.java b/src/test/java/com/auth0/json/mgmt/users/sessions/SessionsPageTest.java new file mode 100644 index 00000000..6fdcf2dc --- /dev/null +++ b/src/test/java/com/auth0/json/mgmt/users/sessions/SessionsPageTest.java @@ -0,0 +1,50 @@ +package com.auth0.json.mgmt.users.sessions; + +import com.auth0.json.JsonTest; +import org.junit.jupiter.api.Test; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.nullValue; + +public class SessionsPageTest extends JsonTest { + private static final String json = "{\"sessions\":[{\"id\":\"sessionId1\",\n\"user_id\":\"userId1\",\n\"created_at\":\"2024-06-26T09:10:26.643Z\",\n\"updated_at\":\"2024-06-26T09:10:27.131Z\",\n\"authenticated_at\":\"2024-06-26T09:10:26.643Z\",\n\"authentication\":{\n\"methods\":[\n{\n\"name\":\"pwd\",\n\"timestamp\":\"2024-06-26T09:10:26.643Z\"\n}\n]\n},\n\"idle_expires_at\":\"2024-06-26T09:40:27.131Z\",\n\"expires_at\":\"2024-07-03T09:10:26.643Z\",\n\"device\":{\n\"initial_asn\":\"1234\",\n\"initial_ip\":\"203.0.113.1\",\n\"last_user_agent\":\"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36\",\n\"last_ip\":\"203.0.113.1\",\n\"last_asn\":\"1234\"\n},\n\"clients\":[\n{\n\"client_id\":\"clientId1\"\n}\n]\n}\n],\n\"next\":\"sessionId1\"\n}\n"; + private static final String jsonWithTotals = "{\"sessions\":[{\"id\":\"sessionId1\",\n\"user_id\":\"userId1\",\n\"created_at\":\"2024-06-26T09:10:26.643Z\",\n\"updated_at\":\"2024-06-26T09:10:27.131Z\",\n\"authenticated_at\":\"2024-06-26T09:10:26.643Z\",\n\"authentication\":{\n\"methods\":[\n{\n\"name\":\"pwd\",\n\"timestamp\":\"2024-06-26T09:10:26.643Z\"\n}\n]\n},\n\"idle_expires_at\":\"2024-06-26T09:40:27.131Z\",\n\"expires_at\":\"2024-07-03T09:10:26.643Z\",\n\"device\":{\n\"initial_asn\":\"1234\",\n\"initial_ip\":\"203.0.113.1\",\n\"last_user_agent\":\"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36\",\n\"last_ip\":\"203.0.113.1\",\n\"last_asn\":\"1234\"\n},\n\"clients\":[\n{\n\"client_id\":\"clientId1\"\n}\n]\n}\n],\n\"next\":\"sessionId1\",\n\"total\":11\n}\n"; + + @Test + public void shouldDeserialize() throws Exception { + SessionsPage page = fromJSON(json, SessionsPage.class); + + assertThat(page.getTotal(), is(nullValue())); + assertThat(page.getNext(), is("sessionId1")); + assertThat(page.getSessions().size(), is(1)); + assertThat(page.getSessions().get(0).getId(), is("sessionId1")); + assertThat(page.getSessions().get(0).getUserId(), is("userId1")); + assertThat(page.getSessions().get(0).getCreatedAt(), is(parseJSONDate("2024-06-26T09:10:26.643Z"))); + assertThat(page.getSessions().get(0).getUpdatedAt(), is(parseJSONDate("2024-06-26T09:10:27.131Z"))); + assertThat(page.getSessions().get(0).getAuthenticatedAt(), is(parseJSONDate("2024-06-26T09:10:26.643Z"))); + assertThat(page.getSessions().get(0).getIdleExpiresAt(), is(parseJSONDate("2024-06-26T09:40:27.131Z"))); + assertThat(page.getSessions().get(0).getExpiresAt(), is(parseJSONDate("2024-07-03T09:10:26.643Z"))); + + assertThat(page.getSessions().get(0).getDevice().getInitialASN(), is("1234")); + assertThat(page.getSessions().get(0).getDevice().getInitialIP(), is("203.0.113.1")); + assertThat(page.getSessions().get(0).getDevice().getLastUserAgent(), is("Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36")); + assertThat(page.getSessions().get(0).getDevice().getLastIP(), is("203.0.113.1")); + assertThat(page.getSessions().get(0).getDevice().getLastASN(), is("1234")); + + assertThat(page.getSessions().get(0).getClients().size(), is(1)); + assertThat(page.getSessions().get(0).getClients().get(0).getClientId(), is("clientId1")); + + assertThat(page.getSessions().get(0).getAuthentication().getMethods().size(), is(1)); + assertThat(page.getSessions().get(0).getAuthentication().getMethods().get(0).getName(), is("pwd")); + assertThat(page.getSessions().get(0).getAuthentication().getMethods().get(0).getTimestamp(), is(parseJSONDate("2024-06-26T09:10:26.643Z"))); + assertThat(page.getSessions().get(0).getAuthentication().getMethods().get(0).getType(), is(nullValue())); + } + + @Test + public void shouldDeserializeWithTotals() throws Exception { + SessionsPage page = fromJSON(jsonWithTotals, SessionsPage.class); + + assertThat(page.getTotal(), is(11)); + } +} diff --git a/src/test/resources/mgmt/user_refresh_tokens.json b/src/test/resources/mgmt/user_refresh_tokens.json new file mode 100644 index 00000000..c1ed7aa9 --- /dev/null +++ b/src/test/resources/mgmt/user_refresh_tokens.json @@ -0,0 +1,44 @@ +{ + "tokens": [ + { + "id": "tokenId1", + "user_id": "userId1", + "created_at": "2024-06-26T09:10:26.643Z", + "updated_at": "2024-06-26T09:10:27.131Z", + "expires_at": "2024-07-03T09:10:26.643Z", + "client_id": "clientId1", + "session_id": "sessionId1", + "rotating": false, + "resource_servers": [ + { + "audience": "https://api.example.com", + "scopes": [ + "read:examples", + "write:examples" + ] + } + ] + }, + { + "id": "tokenId2", + "user_id": "userId1", + "created_at": "2024-06-26T09:10:26.643Z", + "updated_at": "2024-06-26T09:10:27.131Z", + "expires_at": "2024-07-03T09:10:26.643Z", + "client_id": "clientId2", + "session_id": "sessionId2", + "rotating": true, + "resource_servers": [ + { + "audience": "https://api.example.com", + "scopes": [ + "read:examples", + "write:examples" + ] + } + ] + } + ], + "next": "token1", + "total": 11 +} diff --git a/src/test/resources/mgmt/user_sessions.json b/src/test/resources/mgmt/user_sessions.json new file mode 100644 index 00000000..750b127e --- /dev/null +++ b/src/test/resources/mgmt/user_sessions.json @@ -0,0 +1,35 @@ +{ + "sessions": [ + { + "id": "sessionId1", + "user_id": "userId1", + "created_at": "2024-06-26T09:10:26.643Z", + "updated_at": "2024-06-26T09:10:27.131Z", + "authenticated_at": "2024-06-26T09:10:26.643Z", + "authentication": { + "methods": [ + { + "name": "pwd", + "timestamp": "2024-06-26T09:10:26.643Z" + } + ] + }, + "idle_expires_at": "2024-06-26T09:40:27.131Z", + "expires_at": "2024-07-03T09:10:26.643Z", + "device": { + "initial_asn": "1234", + "initial_ip": "203.0.113.1", + "last_user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36", + "last_ip": "203.0.113.1", + "last_asn": "1234" + }, + "clients": [ + { + "client_id": "clientId1" + } + ] + } + ], + "next": "sessionId1", + "total": 9 +} From e03801f9556bb198f386a0a6c75b75183c5874eb Mon Sep 17 00:00:00 2001 From: Jak S <191585+jak@users.noreply.github.com> Date: Tue, 6 Aug 2024 13:16:46 +0100 Subject: [PATCH 03/32] Merge branch 'master' into add-user-refresh-tokens From e2e099ce9c9fc9c7a9bae456b86503dd226ba0bc Mon Sep 17 00:00:00 2001 From: Tanya Sinha Date: Mon, 2 Sep 2024 13:20:12 +0530 Subject: [PATCH 04/32] =?UTF-8?q?Changed=20pull=5Frequest=5Ftarget=20to=20?= =?UTF-8?q?pull=5Frequest=20and=20removed=20the=20authorize=E2=80=A6=20(#6?= =?UTF-8?q?60)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/semgrep.yml | 10 +--------- .github/workflows/snyk.yml | 10 +--------- build.gradle | 2 +- 3 files changed, 3 insertions(+), 19 deletions(-) diff --git a/.github/workflows/semgrep.yml b/.github/workflows/semgrep.yml index fc7d2eeb..202d6af6 100644 --- a/.github/workflows/semgrep.yml +++ b/.github/workflows/semgrep.yml @@ -2,7 +2,7 @@ name: Semgrep on: merge_group: - pull_request_target: + pull_request: types: - opened - synchronize @@ -20,16 +20,8 @@ concurrency: cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} jobs: - authorize: - name: Authorize - environment: ${{ github.actor != 'dependabot[bot]' && github.event_name == 'pull_request_target' && github.event.pull_request.head.repo.full_name != github.repository && 'external' || 'internal' }} - runs-on: ubuntu-latest - steps: - - run: true run: - needs: authorize # Require approval before running on forked pull requests - name: Check for Vulnerabilities runs-on: ubuntu-latest diff --git a/.github/workflows/snyk.yml b/.github/workflows/snyk.yml index 3a4a8709..186ff3f2 100644 --- a/.github/workflows/snyk.yml +++ b/.github/workflows/snyk.yml @@ -3,7 +3,7 @@ name: Snyk on: merge_group: workflow_dispatch: - pull_request_target: + pull_request: types: - opened - synchronize @@ -21,16 +21,8 @@ concurrency: cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} jobs: - authorize: - name: Authorize - environment: ${{ github.actor != 'dependabot[bot]' && github.event_name == 'pull_request_target' && github.event.pull_request.head.repo.full_name != github.repository && 'external' || 'internal' }} - runs-on: ubuntu-latest - steps: - - run: true check: - needs: authorize - name: Check for Vulnerabilities runs-on: ubuntu-latest diff --git a/build.gradle b/build.gradle index c5f9e54e..c91c8fcc 100644 --- a/build.gradle +++ b/build.gradle @@ -85,7 +85,7 @@ dependencies { implementation "com.squareup.okio:okio:3.5.0" implementation "com.squareup.okhttp3:logging-interceptor:${okhttpVersion}" - implementation "com.fasterxml.jackson.core:jackson-databind:2.14.2" + implementation "com.fasterxml.jackson.core:jackson-databind:2.15.0" implementation "com.auth0:java-jwt:4.4.0" implementation "net.jodah:failsafe:2.4.4" From a0b5c6bb00ac175a9be17527f83830b7c1e87d5c Mon Sep 17 00:00:00 2001 From: tanya-sinha_atko Date: Tue, 3 Sep 2024 21:33:12 +0530 Subject: [PATCH 05/32] Added few fields in RefreshToken and Session and modified minor changes --- .../com/auth0/client/mgmt/UsersEntity.java | 8 +-- .../json/mgmt/users/refreshtokens/Device.java | 64 +++++++++++++++++++ .../users/refreshtokens/RefreshToken.java | 18 ++++++ .../refreshtokens/RefreshTokensPage.java | 2 +- .../json/mgmt/users/sessions/Device.java | 9 +++ .../json/mgmt/users/sessions/Session.java | 2 + .../mgmt/users/sessions/SessionsPage.java | 2 +- .../auth0/client/mgmt/UsersEntityTest.java | 9 +-- 8 files changed, 104 insertions(+), 10 deletions(-) create mode 100644 src/main/java/com/auth0/json/mgmt/users/refreshtokens/Device.java diff --git a/src/main/java/com/auth0/client/mgmt/UsersEntity.java b/src/main/java/com/auth0/client/mgmt/UsersEntity.java index 9ee4bfa6..450069e1 100644 --- a/src/main/java/com/auth0/client/mgmt/UsersEntity.java +++ b/src/main/java/com/auth0/client/mgmt/UsersEntity.java @@ -798,8 +798,8 @@ public Request updateAuthenticationMethodById(String userI * @param filter an optional pagination filter * @return a Request to execute */ - public Request listRefreshTokens(String userId, CheckpointPaginationFilter filter) { - Asserts.assertNotNull(userId, "user id"); + public Request listRefreshTokens(String userId, PageFilter filter) { + Asserts.assertNotNull(userId, "user ID"); HttpUrl.Builder builder = baseUrl .newBuilder() .addPathSegments("api/v2/users") @@ -847,8 +847,8 @@ public Request deleteRefreshTokens(String userId) { * @param filter an optional pagination filter * @return a Request to execute */ - public Request listSessions(String userId, CheckpointPaginationFilter filter) { - Asserts.assertNotNull(userId, "user id"); + public Request listSessions(String userId, PageFilter filter) { + Asserts.assertNotNull(userId, "user ID"); HttpUrl.Builder builder = baseUrl .newBuilder() .addPathSegments("api/v2/users") diff --git a/src/main/java/com/auth0/json/mgmt/users/refreshtokens/Device.java b/src/main/java/com/auth0/json/mgmt/users/refreshtokens/Device.java new file mode 100644 index 00000000..7b2bc23c --- /dev/null +++ b/src/main/java/com/auth0/json/mgmt/users/refreshtokens/Device.java @@ -0,0 +1,64 @@ +package com.auth0.json.mgmt.users.refreshtokens; + +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 Device { + @JsonProperty("initial_ip") + private String initialIp; + @JsonProperty("initial_asn") + private String initialAsn; + @JsonProperty("initial_user_agent") + private String initialUserAgent; + @JsonProperty("last_ip") + private String lastIp; + @JsonProperty("last_asn") + private String lastAsn; + @JsonProperty("last_user_agent") + private String lastUserAgent; + + /** + * @return First IP address associated with this session + */ + public String getInitialIp() { + return initialIp; + } + + /** + * @return First autonomous system number associated with this session + */ + public String getInitialAsn() { + return initialAsn; + } + + /** + * @return First user agent associated with this session + */ + public String getInitialUserAgent() { + return initialUserAgent; + } + + /** + * @return Last IP address from which this user logged in + */ + public String getLastIp() { + return lastIp; + } + + /** + * @return Last autonomous system number from which this user logged in + */ + public String getLastAsn() { + return lastAsn; + } + + /** + * @return Last user agent of the device from which this user logged in + */ + public String getLastUserAgent() { + return lastUserAgent; + } +} diff --git a/src/main/java/com/auth0/json/mgmt/users/refreshtokens/RefreshToken.java b/src/main/java/com/auth0/json/mgmt/users/refreshtokens/RefreshToken.java index 1551f4dd..23536b88 100644 --- a/src/main/java/com/auth0/json/mgmt/users/refreshtokens/RefreshToken.java +++ b/src/main/java/com/auth0/json/mgmt/users/refreshtokens/RefreshToken.java @@ -20,6 +20,8 @@ public class RefreshToken { private Date idleExpiresAt; @JsonProperty("expires_at") private Date expiresAt; + @JsonProperty("device") + private Device device; @JsonProperty("client_id") private String clientId; @JsonProperty("session_id") @@ -28,6 +30,8 @@ public class RefreshToken { private Boolean rotating; @JsonProperty("resource_servers") private List resourceServers; + @JsonProperty("last_exchanged_at") + private Date lastExchangedAt; /** * @return The ID of the refresh token @@ -66,6 +70,13 @@ public Date getExpiresAt() { return expiresAt; } + /** + * @return Device information + */ + public Device getDevice() { + return device; + } + /** * @return ID of the client application granted with this refresh token */ @@ -94,4 +105,11 @@ public Boolean isRotating() { public List getResourceServers() { return resourceServers; } + + /** + * @return The date and time when the refresh token was last exchanged + */ + public Date getLastExchangedAt() { + return lastExchangedAt; + } } diff --git a/src/main/java/com/auth0/json/mgmt/users/refreshtokens/RefreshTokensPage.java b/src/main/java/com/auth0/json/mgmt/users/refreshtokens/RefreshTokensPage.java index 224c0b62..06d7fd0e 100644 --- a/src/main/java/com/auth0/json/mgmt/users/refreshtokens/RefreshTokensPage.java +++ b/src/main/java/com/auth0/json/mgmt/users/refreshtokens/RefreshTokensPage.java @@ -7,7 +7,7 @@ import java.util.List; /** - * This does not extend com.auth0.json.mgmt.Page because the URL only supports "next" and "take" pagination. + * Class that represents a page of Refresh Tokens. */ @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) diff --git a/src/main/java/com/auth0/json/mgmt/users/sessions/Device.java b/src/main/java/com/auth0/json/mgmt/users/sessions/Device.java index 1665c6ed..590dc8cc 100644 --- a/src/main/java/com/auth0/json/mgmt/users/sessions/Device.java +++ b/src/main/java/com/auth0/json/mgmt/users/sessions/Device.java @@ -7,6 +7,8 @@ @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) public class Device { + @JsonProperty("initial_user_agent") + private String initialUserAgent; @JsonProperty("initial_ip") private String initialIP; @JsonProperty("initial_asn") @@ -18,6 +20,13 @@ public class Device { @JsonProperty("last_asn") private String lastASN; + /** + * @return First user agent associated with this session + */ + public String getInitialUserAgent() { + return initialUserAgent; + } + /** * @return First IP address associated with this session */ diff --git a/src/main/java/com/auth0/json/mgmt/users/sessions/Session.java b/src/main/java/com/auth0/json/mgmt/users/sessions/Session.java index ae0fe6c6..f8d4b916 100644 --- a/src/main/java/com/auth0/json/mgmt/users/sessions/Session.java +++ b/src/main/java/com/auth0/json/mgmt/users/sessions/Session.java @@ -24,6 +24,8 @@ public class Session { private Date idleExpiresAt; @JsonProperty("expires_at") private Date expiresAt; + @JsonProperty("last_interacted_at") + private Date lastInteractedAt; @JsonProperty("device") private Device device; @JsonProperty("clients") diff --git a/src/main/java/com/auth0/json/mgmt/users/sessions/SessionsPage.java b/src/main/java/com/auth0/json/mgmt/users/sessions/SessionsPage.java index da536451..8d763ecd 100644 --- a/src/main/java/com/auth0/json/mgmt/users/sessions/SessionsPage.java +++ b/src/main/java/com/auth0/json/mgmt/users/sessions/SessionsPage.java @@ -7,7 +7,7 @@ import java.util.List; /** - * This does not extend com.auth0.json.mgmt.Page because the URL only supports "next" and "take" pagination. + * Class that represents a given Page of Sessions. Related to the {@link com.auth0.client.mgmt.UsersEntity} entity. */ @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) diff --git a/src/test/java/com/auth0/client/mgmt/UsersEntityTest.java b/src/test/java/com/auth0/client/mgmt/UsersEntityTest.java index a2556ee5..1630ee34 100644 --- a/src/test/java/com/auth0/client/mgmt/UsersEntityTest.java +++ b/src/test/java/com/auth0/client/mgmt/UsersEntityTest.java @@ -5,6 +5,7 @@ import com.auth0.client.mgmt.filter.PageFilter; import com.auth0.client.mgmt.filter.UserFilter; import com.auth0.client.mgmt.filter.CheckpointPaginationFilter; +import com.auth0.json.mgmt.Page; import com.auth0.json.mgmt.guardian.Enrollment; import com.auth0.json.mgmt.logevents.LogEvent; import com.auth0.json.mgmt.logevents.LogEventsPage; @@ -1371,7 +1372,7 @@ public void shouldListRefreshTokensWithoutFilter() throws Exception { @Test public void shouldListRefreshTokensWithPage() throws Exception { - CheckpointPaginationFilter filter = new CheckpointPaginationFilter().withFrom("tokenId2").withTake(5); + PageFilter filter = new PageFilter().withFrom("tokenId2").withTake(5); Request request = api.users().listRefreshTokens("1", filter); assertThat(request, is(notNullValue())); @@ -1391,7 +1392,7 @@ public void shouldListRefreshTokensWithPage() throws Exception { @Test public void shouldListRefreshTokensWithTotal() throws Exception { - CheckpointPaginationFilter filter = new CheckpointPaginationFilter().withTotals(true); + PageFilter filter = new PageFilter().withTotals(true); Request request = api.users().listRefreshTokens("1", filter); assertThat(request, is(notNullValue())); @@ -1448,7 +1449,7 @@ public void shouldListSessionsWithoutFilter() throws Exception { @Test public void shouldListSessionsWithPage() throws Exception { - CheckpointPaginationFilter filter = new CheckpointPaginationFilter().withFrom("sessionId3").withTake(9); + PageFilter filter = new PageFilter().withFrom("sessionId3").withTake(9); Request request = api.users().listSessions("1", filter); assertThat(request, is(notNullValue())); @@ -1468,7 +1469,7 @@ public void shouldListSessionsWithPage() throws Exception { @Test public void shouldListSessionsWithTotal() throws Exception { - CheckpointPaginationFilter filter = new CheckpointPaginationFilter().withTotals(true); + PageFilter filter = new PageFilter().withTotals(true); Request request = api.users().listSessions("1", filter); assertThat(request, is(notNullValue())); From 507f8c38834a5c76bb7a46f69472bff15c1d131c Mon Sep 17 00:00:00 2001 From: tanya-sinha_atko Date: Thu, 5 Sep 2024 14:29:23 +0530 Subject: [PATCH 06/32] added support for /session and /refreshTokens API's and updated relevant test cases --- .../com/auth0/client/mgmt/ManagementAPI.java | 16 ++ .../client/mgmt/RefreshTokensEntity.java | 66 +++++++ .../com/auth0/client/mgmt/SessionsEntity.java | 67 +++++++ .../com/auth0/client/mgmt/UsersEntity.java | 4 +- .../filter/CheckpointPaginationFilter.java | 38 ---- .../{users => }/refreshtokens/Device.java | 2 +- .../refreshtokens/RefreshToken.java | 2 +- .../refreshtokens/RefreshTokensPage.java | 2 +- .../refreshtokens/ResourceServer.java | 2 +- .../{users => }/sessions/Authentication.java | 2 +- .../sessions/AuthenticationMethod.java | 2 +- .../mgmt/{users => }/sessions/Client.java | 2 +- .../mgmt/{users => }/sessions/Device.java | 2 +- .../mgmt/{users => }/sessions/Session.java | 2 +- .../{users => }/sessions/SessionsPage.java | 2 +- .../java/com/auth0/client/MockServer.java | 2 + .../client/mgmt/RefreshTokensEntityTest.java | 61 ++++++ .../auth0/client/mgmt/SessionsEntityTest.java | 61 ++++++ .../auth0/client/mgmt/UsersEntityTest.java | 6 +- .../CheckpointPaginationFilterTest.java | 37 ---- .../mgmt/refreshtokens/RefreshTokenTest.java | 86 +++++++++ .../refreshtokens/RefreshTokensPageTest.java | 175 ++++++++++++++++++ .../auth0/json/mgmt/sessions/SessionTest.java | 91 +++++++++ .../json/mgmt/sessions/SessionsPageTest.java | 121 ++++++++++++ .../refreshtokens/RefreshTokensPageTest.java | 44 ----- .../mgmt/users/sessions/SessionsPageTest.java | 50 ----- src/test/resources/mgmt/refresh_token.json | 28 +++ src/test/resources/mgmt/session.json | 30 +++ .../resources/mgmt/user_refresh_tokens.json | 25 ++- src/test/resources/mgmt/user_sessions.json | 1 + 30 files changed, 841 insertions(+), 188 deletions(-) create mode 100644 src/main/java/com/auth0/client/mgmt/RefreshTokensEntity.java create mode 100644 src/main/java/com/auth0/client/mgmt/SessionsEntity.java delete mode 100644 src/main/java/com/auth0/client/mgmt/filter/CheckpointPaginationFilter.java rename src/main/java/com/auth0/json/mgmt/{users => }/refreshtokens/Device.java (97%) rename src/main/java/com/auth0/json/mgmt/{users => }/refreshtokens/RefreshToken.java (98%) rename src/main/java/com/auth0/json/mgmt/{users => }/refreshtokens/RefreshTokensPage.java (95%) rename src/main/java/com/auth0/json/mgmt/{users => }/refreshtokens/ResourceServer.java (93%) rename src/main/java/com/auth0/json/mgmt/{users => }/sessions/Authentication.java (92%) rename src/main/java/com/auth0/json/mgmt/{users => }/sessions/AuthenticationMethod.java (95%) rename src/main/java/com/auth0/json/mgmt/{users => }/sessions/Client.java (91%) rename src/main/java/com/auth0/json/mgmt/{users => }/sessions/Device.java (97%) rename src/main/java/com/auth0/json/mgmt/{users => }/sessions/Session.java (98%) rename src/main/java/com/auth0/json/mgmt/{users => }/sessions/SessionsPage.java (96%) create mode 100644 src/test/java/com/auth0/client/mgmt/RefreshTokensEntityTest.java create mode 100644 src/test/java/com/auth0/client/mgmt/SessionsEntityTest.java delete mode 100644 src/test/java/com/auth0/client/mgmt/filter/CheckpointPaginationFilterTest.java create mode 100644 src/test/java/com/auth0/json/mgmt/refreshtokens/RefreshTokenTest.java create mode 100644 src/test/java/com/auth0/json/mgmt/refreshtokens/RefreshTokensPageTest.java create mode 100644 src/test/java/com/auth0/json/mgmt/sessions/SessionTest.java create mode 100644 src/test/java/com/auth0/json/mgmt/sessions/SessionsPageTest.java delete mode 100644 src/test/java/com/auth0/json/mgmt/users/refreshtokens/RefreshTokensPageTest.java delete mode 100644 src/test/java/com/auth0/json/mgmt/users/sessions/SessionsPageTest.java create mode 100644 src/test/resources/mgmt/refresh_token.json create mode 100644 src/test/resources/mgmt/session.json diff --git a/src/main/java/com/auth0/client/mgmt/ManagementAPI.java b/src/main/java/com/auth0/client/mgmt/ManagementAPI.java index cf7ec088..5ac89afb 100644 --- a/src/main/java/com/auth0/client/mgmt/ManagementAPI.java +++ b/src/main/java/com/auth0/client/mgmt/ManagementAPI.java @@ -364,6 +364,22 @@ public KeysEntity keys() { return new KeysEntity(client, baseUrl, tokenProvider); } + /** + * Getter for the Prompts Entity + * @return the Prompts Entity + */ + public RefreshTokensEntity refreshTokens() { + return new RefreshTokensEntity(client, baseUrl, tokenProvider); + } + + /** + * Getter for the Prompts Entity + * @return the Prompts Entity + */ + public SessionsEntity sessions() { + return new SessionsEntity(client, baseUrl, tokenProvider); + } + /** * Builder for {@link ManagementAPI} API client instances. */ diff --git a/src/main/java/com/auth0/client/mgmt/RefreshTokensEntity.java b/src/main/java/com/auth0/client/mgmt/RefreshTokensEntity.java new file mode 100644 index 00000000..6911aef2 --- /dev/null +++ b/src/main/java/com/auth0/client/mgmt/RefreshTokensEntity.java @@ -0,0 +1,66 @@ +package com.auth0.client.mgmt; + +import com.auth0.json.mgmt.refreshtokens.RefreshToken; +import com.auth0.net.BaseRequest; +import com.auth0.net.Request; +import com.auth0.net.VoidRequest; +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; + +/** + * Class that provides an implementation of the Refresh Tokens methods of the Management API as defined in https://auth0.com/docs/api/management/v2#!/Refresh_Tokens + *

+ * This class is not thread-safe. + * @see ManagementAPI + */ +@SuppressWarnings("WeakerAccess") +public class RefreshTokensEntity extends BaseManagementEntity{ + + RefreshTokensEntity(Auth0HttpClient client, HttpUrl baseUrl, TokenProvider tokenProvider) { + super(client, baseUrl, tokenProvider); + } + + /** + * Request the refresh token for a given refresh token ID. + * A token with scope {@code read:refresh_tokens} is needed. + * See https://auth0.com/docs/api/management/v2/refresh-tokens/get-refresh-token + * @param refreshTokenId the refresh token ID. + * @return a Request to execute. + */ + public Request get(String refreshTokenId){ + Asserts.assertNotNull(refreshTokenId, "refresh token ID"); + + String url = baseUrl + .newBuilder() + .addPathSegments("api/v2/refresh-tokens") + .addPathSegment(refreshTokenId) + .build() + .toString(); + + return new BaseRequest<>(client, tokenProvider, url, HttpMethod.GET, new TypeReference() { + }); + } + + /** + * Delete the refresh token for a given refresh token ID. + * * A token with scope {@code delete:refresh_tokens} is needed. + * See https://auth0.com/docs/api/management/v2/refresh-tokens/delete-refresh-token + * @param refreshTokenId the refresh token ID. + * @return a Request to execute. + */ + public Request delete(String refreshTokenId){ + Asserts.assertNotNull(refreshTokenId, "refresh token ID"); + + String url = baseUrl + .newBuilder() + .addPathSegments("api/v2/refresh-tokens") + .addPathSegment(refreshTokenId) + .build() + .toString(); + + return new VoidRequest(client, tokenProvider, url, HttpMethod.DELETE); + } +} diff --git a/src/main/java/com/auth0/client/mgmt/SessionsEntity.java b/src/main/java/com/auth0/client/mgmt/SessionsEntity.java new file mode 100644 index 00000000..6ed853ee --- /dev/null +++ b/src/main/java/com/auth0/client/mgmt/SessionsEntity.java @@ -0,0 +1,67 @@ +package com.auth0.client.mgmt; + +import com.auth0.json.mgmt.sessions.Session; +import com.auth0.net.BaseRequest; +import com.auth0.net.Request; +import com.auth0.net.VoidRequest; +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; + + +/** + * Class that provides an implementation of the Sessions methods of the Management API as defined in https://auth0.com/docs/api/management/v2#!/Sessions + *

+ * This class is not thread-safe. + * @see ManagementAPI + */ +@SuppressWarnings("WeakerAccess") +public class SessionsEntity extends BaseManagementEntity{ + + SessionsEntity(Auth0HttpClient client, HttpUrl baseUrl, TokenProvider tokenProvider) { + super(client, baseUrl, tokenProvider); + } + + /** + * Request the session for a given session ID. + * A token with scope {@code read:sessions} is needed. + * See https://auth0.com/docs/api/management/v2/sessions/get-session + * @param sessionId the session ID. + * @return a Request to execute. + */ + public Request get(String sessionId){ + Asserts.assertNotNull(sessionId, "session ID"); + + String url = baseUrl + .newBuilder() + .addPathSegments("api/v2/sessions") + .addPathSegment(sessionId) + .build() + .toString(); + + return new BaseRequest<>(client, tokenProvider, url, HttpMethod.GET, new TypeReference() { + }); + } + + /** + * Delete the session for a given session ID. + * A token with scope {@code delete:sessions} is needed. + * See https://auth0.com/docs/api/management/v2/sessions/delete-session + * @param sessionId the session ID. + * @return a Request to execute. + */ + public Request delete(String sessionId){ + Asserts.assertNotNull(sessionId, "session ID"); + + String url = baseUrl + .newBuilder() + .addPathSegments("api/v2/sessions") + .addPathSegment(sessionId) + .build() + .toString(); + + return new VoidRequest(client, tokenProvider, url, HttpMethod.DELETE); + } +} diff --git a/src/main/java/com/auth0/client/mgmt/UsersEntity.java b/src/main/java/com/auth0/client/mgmt/UsersEntity.java index 450069e1..ac3e3548 100644 --- a/src/main/java/com/auth0/client/mgmt/UsersEntity.java +++ b/src/main/java/com/auth0/client/mgmt/UsersEntity.java @@ -13,8 +13,8 @@ import com.auth0.json.mgmt.users.RecoveryCode; import com.auth0.json.mgmt.users.User; import com.auth0.json.mgmt.users.UsersPage; -import com.auth0.json.mgmt.users.refreshtokens.RefreshTokensPage; -import com.auth0.json.mgmt.users.sessions.SessionsPage; +import com.auth0.json.mgmt.refreshtokens.RefreshTokensPage; +import com.auth0.json.mgmt.sessions.SessionsPage; import com.auth0.net.EmptyBodyRequest; import com.auth0.net.BaseRequest; import com.auth0.net.Request; diff --git a/src/main/java/com/auth0/client/mgmt/filter/CheckpointPaginationFilter.java b/src/main/java/com/auth0/client/mgmt/filter/CheckpointPaginationFilter.java deleted file mode 100644 index 1f881b7c..00000000 --- a/src/main/java/com/auth0/client/mgmt/filter/CheckpointPaginationFilter.java +++ /dev/null @@ -1,38 +0,0 @@ -package com.auth0.client.mgmt.filter; - -public class CheckpointPaginationFilter extends BaseFilter { - - /** - * Return results inside an object that contains the total result count (true) or as a direct array of results (false, default). - * - * @param includeTotals whether to include or not total result count. - * @return this filter instance - */ - public CheckpointPaginationFilter withTotals(boolean includeTotals) { - parameters.put("include_totals", includeTotals); - return this; - } - - /** - * Optional ID from which to start selection (exclusive). - * - * @param from the ID from which to start selection. This can be obtained from the {@code next} field returned from - * a checkpoint-paginated result. - * @return this filter instance. - */ - public CheckpointPaginationFilter withFrom(String from) { - parameters.put("from", from); - return this; - } - - /** - * Number of results per page. Defaults to 50. - * - * @param take the amount of entries to retrieve per page. - * @return this filter instance. - */ - public CheckpointPaginationFilter withTake(int take) { - parameters.put("take", take); - return this; - } -} diff --git a/src/main/java/com/auth0/json/mgmt/users/refreshtokens/Device.java b/src/main/java/com/auth0/json/mgmt/refreshtokens/Device.java similarity index 97% rename from src/main/java/com/auth0/json/mgmt/users/refreshtokens/Device.java rename to src/main/java/com/auth0/json/mgmt/refreshtokens/Device.java index 7b2bc23c..e83e6133 100644 --- a/src/main/java/com/auth0/json/mgmt/users/refreshtokens/Device.java +++ b/src/main/java/com/auth0/json/mgmt/refreshtokens/Device.java @@ -1,4 +1,4 @@ -package com.auth0.json.mgmt.users.refreshtokens; +package com.auth0.json.mgmt.refreshtokens; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; diff --git a/src/main/java/com/auth0/json/mgmt/users/refreshtokens/RefreshToken.java b/src/main/java/com/auth0/json/mgmt/refreshtokens/RefreshToken.java similarity index 98% rename from src/main/java/com/auth0/json/mgmt/users/refreshtokens/RefreshToken.java rename to src/main/java/com/auth0/json/mgmt/refreshtokens/RefreshToken.java index 23536b88..2efc36b0 100644 --- a/src/main/java/com/auth0/json/mgmt/users/refreshtokens/RefreshToken.java +++ b/src/main/java/com/auth0/json/mgmt/refreshtokens/RefreshToken.java @@ -1,4 +1,4 @@ -package com.auth0.json.mgmt.users.refreshtokens; +package com.auth0.json.mgmt.refreshtokens; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; diff --git a/src/main/java/com/auth0/json/mgmt/users/refreshtokens/RefreshTokensPage.java b/src/main/java/com/auth0/json/mgmt/refreshtokens/RefreshTokensPage.java similarity index 95% rename from src/main/java/com/auth0/json/mgmt/users/refreshtokens/RefreshTokensPage.java rename to src/main/java/com/auth0/json/mgmt/refreshtokens/RefreshTokensPage.java index 06d7fd0e..9aea796c 100644 --- a/src/main/java/com/auth0/json/mgmt/users/refreshtokens/RefreshTokensPage.java +++ b/src/main/java/com/auth0/json/mgmt/refreshtokens/RefreshTokensPage.java @@ -1,4 +1,4 @@ -package com.auth0.json.mgmt.users.refreshtokens; +package com.auth0.json.mgmt.refreshtokens; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; diff --git a/src/main/java/com/auth0/json/mgmt/users/refreshtokens/ResourceServer.java b/src/main/java/com/auth0/json/mgmt/refreshtokens/ResourceServer.java similarity index 93% rename from src/main/java/com/auth0/json/mgmt/users/refreshtokens/ResourceServer.java rename to src/main/java/com/auth0/json/mgmt/refreshtokens/ResourceServer.java index b423de41..748b2e1d 100644 --- a/src/main/java/com/auth0/json/mgmt/users/refreshtokens/ResourceServer.java +++ b/src/main/java/com/auth0/json/mgmt/refreshtokens/ResourceServer.java @@ -1,4 +1,4 @@ -package com.auth0.json.mgmt.users.refreshtokens; +package com.auth0.json.mgmt.refreshtokens; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; diff --git a/src/main/java/com/auth0/json/mgmt/users/sessions/Authentication.java b/src/main/java/com/auth0/json/mgmt/sessions/Authentication.java similarity index 92% rename from src/main/java/com/auth0/json/mgmt/users/sessions/Authentication.java rename to src/main/java/com/auth0/json/mgmt/sessions/Authentication.java index dd9ba115..177c1469 100644 --- a/src/main/java/com/auth0/json/mgmt/users/sessions/Authentication.java +++ b/src/main/java/com/auth0/json/mgmt/sessions/Authentication.java @@ -1,4 +1,4 @@ -package com.auth0.json.mgmt.users.sessions; +package com.auth0.json.mgmt.sessions; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; diff --git a/src/main/java/com/auth0/json/mgmt/users/sessions/AuthenticationMethod.java b/src/main/java/com/auth0/json/mgmt/sessions/AuthenticationMethod.java similarity index 95% rename from src/main/java/com/auth0/json/mgmt/users/sessions/AuthenticationMethod.java rename to src/main/java/com/auth0/json/mgmt/sessions/AuthenticationMethod.java index c55634c5..012a29d6 100644 --- a/src/main/java/com/auth0/json/mgmt/users/sessions/AuthenticationMethod.java +++ b/src/main/java/com/auth0/json/mgmt/sessions/AuthenticationMethod.java @@ -1,4 +1,4 @@ -package com.auth0.json.mgmt.users.sessions; +package com.auth0.json.mgmt.sessions; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; diff --git a/src/main/java/com/auth0/json/mgmt/users/sessions/Client.java b/src/main/java/com/auth0/json/mgmt/sessions/Client.java similarity index 91% rename from src/main/java/com/auth0/json/mgmt/users/sessions/Client.java rename to src/main/java/com/auth0/json/mgmt/sessions/Client.java index aa51c6e9..7ac383e6 100644 --- a/src/main/java/com/auth0/json/mgmt/users/sessions/Client.java +++ b/src/main/java/com/auth0/json/mgmt/sessions/Client.java @@ -1,4 +1,4 @@ -package com.auth0.json.mgmt.users.sessions; +package com.auth0.json.mgmt.sessions; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; diff --git a/src/main/java/com/auth0/json/mgmt/users/sessions/Device.java b/src/main/java/com/auth0/json/mgmt/sessions/Device.java similarity index 97% rename from src/main/java/com/auth0/json/mgmt/users/sessions/Device.java rename to src/main/java/com/auth0/json/mgmt/sessions/Device.java index 590dc8cc..cf3fe395 100644 --- a/src/main/java/com/auth0/json/mgmt/users/sessions/Device.java +++ b/src/main/java/com/auth0/json/mgmt/sessions/Device.java @@ -1,4 +1,4 @@ -package com.auth0.json.mgmt.users.sessions; +package com.auth0.json.mgmt.sessions; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; diff --git a/src/main/java/com/auth0/json/mgmt/users/sessions/Session.java b/src/main/java/com/auth0/json/mgmt/sessions/Session.java similarity index 98% rename from src/main/java/com/auth0/json/mgmt/users/sessions/Session.java rename to src/main/java/com/auth0/json/mgmt/sessions/Session.java index f8d4b916..c231770e 100644 --- a/src/main/java/com/auth0/json/mgmt/users/sessions/Session.java +++ b/src/main/java/com/auth0/json/mgmt/sessions/Session.java @@ -1,4 +1,4 @@ -package com.auth0.json.mgmt.users.sessions; +package com.auth0.json.mgmt.sessions; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; diff --git a/src/main/java/com/auth0/json/mgmt/users/sessions/SessionsPage.java b/src/main/java/com/auth0/json/mgmt/sessions/SessionsPage.java similarity index 96% rename from src/main/java/com/auth0/json/mgmt/users/sessions/SessionsPage.java rename to src/main/java/com/auth0/json/mgmt/sessions/SessionsPage.java index 8d763ecd..10d58e9d 100644 --- a/src/main/java/com/auth0/json/mgmt/users/sessions/SessionsPage.java +++ b/src/main/java/com/auth0/json/mgmt/sessions/SessionsPage.java @@ -1,4 +1,4 @@ -package com.auth0.json.mgmt.users.sessions; +package com.auth0.json.mgmt.sessions; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; diff --git a/src/test/java/com/auth0/client/MockServer.java b/src/test/java/com/auth0/client/MockServer.java index 5b162e67..f8ee2189 100644 --- a/src/test/java/com/auth0/client/MockServer.java +++ b/src/test/java/com/auth0/client/MockServer.java @@ -78,6 +78,8 @@ public class MockServer { public static final String MGMT_USERS_PAGED_LIST = "src/test/resources/mgmt/users_paged_list.json"; public static final String MGMT_USER_PERMISSIONS_PAGED_LIST = "src/test/resources/mgmt/user_permissions_paged_list.json"; public static final String MGMT_USER_ROLES_PAGED_LIST = "src/test/resources/mgmt/user_roles_paged_list.json"; + public static final String MGMT_REFRESH_TOKEN = "src/test/resources/mgmt/refresh_token.json"; + public static final String MGMT_SESSION = "src/test/resources/mgmt/session.json"; public static final String MGMT_USER_REFRESH_TOKENS = "src/test/resources/mgmt/user_refresh_tokens.json"; public static final String MGMT_USER_SESSIONS = "src/test/resources/mgmt/user_sessions.json"; public static final String MGMT_USER = "src/test/resources/mgmt/user.json"; diff --git a/src/test/java/com/auth0/client/mgmt/RefreshTokensEntityTest.java b/src/test/java/com/auth0/client/mgmt/RefreshTokensEntityTest.java new file mode 100644 index 00000000..69ef2684 --- /dev/null +++ b/src/test/java/com/auth0/client/mgmt/RefreshTokensEntityTest.java @@ -0,0 +1,61 @@ +package com.auth0.client.mgmt; + +import com.auth0.json.mgmt.refreshtokens.RefreshToken; +import com.auth0.net.Request; +import com.auth0.net.client.HttpMethod; +import okhttp3.mockwebserver.RecordedRequest; +import org.junit.jupiter.api.Test; + +import static com.auth0.AssertsUtil.verifyThrows; +import static com.auth0.client.MockServer.MGMT_REFRESH_TOKEN; +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; + +public class RefreshTokensEntityTest extends BaseMgmtEntityTest{ + + @Test + public void shouldThrowOnGetWithNullRefreshTokenId() { + verifyThrows(IllegalArgumentException.class, + () -> api.refreshTokens().get(null), + "'refresh token ID' cannot be null!"); + } + + @Test + public void shouldGetRefreshToken() throws Exception { + Request request = api.refreshTokens().get("refresh_token_ID"); + assertThat(request, is(notNullValue())); + + server.jsonResponse(MGMT_REFRESH_TOKEN, 200); + RefreshToken response =request.execute().getBody(); + RecordedRequest recordedRequest = server.takeRequest(); + + assertThat(recordedRequest, hasMethodAndPath(HttpMethod.GET, "/api/v2/refresh-tokens/refresh_token_ID")); + assertThat(recordedRequest, hasHeader("Content-Type", "application/json")); + assertThat(recordedRequest, hasHeader("Authorization", "Bearer apiToken")); + + assertThat(response, is(notNullValue())); + } + + @Test + public void shouldThrowOnDeleteWithNullRefreshTokenId() { + verifyThrows(IllegalArgumentException.class, + () -> api.refreshTokens().delete(null), + "'refresh token ID' cannot be null!"); + } + + @Test + public void shouldDeleteRefreshToken() throws Exception { + Request request = api.refreshTokens().delete("refresh_token_ID"); + assertThat(request, is(notNullValue())); + + server.noContentResponse(); + request.execute().getBody(); + RecordedRequest recordedRequest = server.takeRequest(); + + assertThat(recordedRequest, hasMethodAndPath(HttpMethod.DELETE, "/api/v2/refresh-tokens/refresh_token_ID")); + assertThat(recordedRequest, hasHeader("Authorization", "Bearer apiToken")); + } +} diff --git a/src/test/java/com/auth0/client/mgmt/SessionsEntityTest.java b/src/test/java/com/auth0/client/mgmt/SessionsEntityTest.java new file mode 100644 index 00000000..a1e847ff --- /dev/null +++ b/src/test/java/com/auth0/client/mgmt/SessionsEntityTest.java @@ -0,0 +1,61 @@ +package com.auth0.client.mgmt; + +import com.auth0.json.mgmt.sessions.Session; +import com.auth0.net.Request; +import com.auth0.net.client.HttpMethod; +import okhttp3.mockwebserver.RecordedRequest; +import org.junit.jupiter.api.Test; + +import static com.auth0.AssertsUtil.verifyThrows; +import static com.auth0.client.MockServer.MGMT_SESSION; +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; + +public class SessionsEntityTest extends BaseMgmtEntityTest{ + @Test + public void getSessionShouldThrowOnNullSessionId() { + verifyThrows(IllegalArgumentException.class, + () -> api.sessions().get(null), + "'session ID' cannot be null!"); + } + + @Test + public void shouldGetSession() throws Exception { + Request request = api.sessions().get("session_ID"); + assertThat(request, is(notNullValue())); + + server.jsonResponse(MGMT_SESSION, 200); + Session response = request.execute().getBody(); + RecordedRequest recordedRequest = server.takeRequest(); + + assertThat(recordedRequest, hasMethodAndPath(HttpMethod.GET, "/api/v2/sessions/session_ID")); + assertThat(recordedRequest, hasHeader("Content-Type", "application/json")); + assertThat(recordedRequest, hasHeader("Authorization", "Bearer apiToken")); + + assertThat(response, is(notNullValue())); + } + + @Test + public void deleteSessionShouldThrowOnNullSessionId() { + verifyThrows(IllegalArgumentException.class, + () -> api.sessions().delete(null), + "'session ID' cannot be null!"); + } + + @Test + public void shouldDeleteSession() throws Exception { + Request request = api.sessions().delete("session_ID"); + assertThat(request, is(notNullValue())); + + server.noContentResponse(); + request.execute().getBody(); + RecordedRequest recordedRequest = server.takeRequest(); + + assertThat(recordedRequest, hasMethodAndPath(HttpMethod.DELETE, "/api/v2/sessions/session_ID")); + assertThat(recordedRequest, hasHeader("Authorization", "Bearer apiToken")); + } + +} diff --git a/src/test/java/com/auth0/client/mgmt/UsersEntityTest.java b/src/test/java/com/auth0/client/mgmt/UsersEntityTest.java index 1630ee34..59da2b86 100644 --- a/src/test/java/com/auth0/client/mgmt/UsersEntityTest.java +++ b/src/test/java/com/auth0/client/mgmt/UsersEntityTest.java @@ -4,8 +4,6 @@ import com.auth0.client.mgmt.filter.LogEventFilter; import com.auth0.client.mgmt.filter.PageFilter; import com.auth0.client.mgmt.filter.UserFilter; -import com.auth0.client.mgmt.filter.CheckpointPaginationFilter; -import com.auth0.json.mgmt.Page; import com.auth0.json.mgmt.guardian.Enrollment; import com.auth0.json.mgmt.logevents.LogEvent; import com.auth0.json.mgmt.logevents.LogEventsPage; @@ -19,8 +17,8 @@ import com.auth0.json.mgmt.users.UsersPage; import com.auth0.json.mgmt.users.authenticationmethods.AuthenticationMethod; import com.auth0.json.mgmt.users.authenticationmethods.AuthenticationMethodsPage; -import com.auth0.json.mgmt.users.refreshtokens.RefreshTokensPage; -import com.auth0.json.mgmt.users.sessions.SessionsPage; +import com.auth0.json.mgmt.refreshtokens.RefreshTokensPage; +import com.auth0.json.mgmt.sessions.SessionsPage; import com.auth0.net.Request; import com.auth0.net.client.HttpMethod; import okhttp3.mockwebserver.RecordedRequest; diff --git a/src/test/java/com/auth0/client/mgmt/filter/CheckpointPaginationFilterTest.java b/src/test/java/com/auth0/client/mgmt/filter/CheckpointPaginationFilterTest.java deleted file mode 100644 index 69cb4641..00000000 --- a/src/test/java/com/auth0/client/mgmt/filter/CheckpointPaginationFilterTest.java +++ /dev/null @@ -1,37 +0,0 @@ -package com.auth0.client.mgmt.filter; - -import org.hamcrest.Matchers; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.CoreMatchers.notNullValue; -import static org.hamcrest.MatcherAssert.assertThat; - -public class CheckpointPaginationFilterTest { - - private CheckpointPaginationFilter filter; - - @BeforeEach - public void setUp() { - filter = new CheckpointPaginationFilter(); - } - - @Test - public void shouldIncludeTotals() { - CheckpointPaginationFilter instance = filter.withTotals(true); - - assertThat(filter, is(instance)); - assertThat(filter.getAsMap(), is(notNullValue())); - assertThat(filter.getAsMap(), Matchers.hasEntry("include_totals", true)); - } - - @Test - public void shouldIncludeCheckpointParams() { - CheckpointPaginationFilter instance = filter.withFrom("abc123").withTake(2); - - assertThat(filter.getAsMap(), is(notNullValue())); - assertThat(filter.getAsMap(), Matchers.hasEntry("from", "abc123")); - assertThat(filter.getAsMap(), Matchers.hasEntry("take", 2)); - } -} diff --git a/src/test/java/com/auth0/json/mgmt/refreshtokens/RefreshTokenTest.java b/src/test/java/com/auth0/json/mgmt/refreshtokens/RefreshTokenTest.java new file mode 100644 index 00000000..35e7d700 --- /dev/null +++ b/src/test/java/com/auth0/json/mgmt/refreshtokens/RefreshTokenTest.java @@ -0,0 +1,86 @@ +package com.auth0.json.mgmt.refreshtokens; + +import com.auth0.json.JsonTest; +import org.junit.jupiter.api.Test; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.*; + +public class RefreshTokenTest extends JsonTest { + + private static final String json = "{\n" + + " \"id\": \"tokenId1\",\n" + + " \"user_id\": \"userId1\",\n" + + " \"created_at\": \"2024-06-26T09:10:26.643Z\",\n" + + " \"idle_expires_at\": \"2024-06-26T09:10:27.131Z\",\n" + + " \"expires_at\": \"2024-07-03T09:10:26.643Z\",\n" + + " \"device\": {\n" + + " \"initial_asn\": \"1234\",\n" + + " \"initial_ip\": \"203.0.113.1\",\n" + + " \"initial_user_agent\": \"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36\",\n" + + " \"last_user_agent\": \"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36\",\n" + + " \"last_ip\": \"203.0.113.1\",\n" + + " \"last_asn\": \"1234\"\n" + + " },\n" + + " \"client_id\": \"clientId1\",\n" + + " \"session_id\": \"sessionId1\",\n" + + " \"rotating\": false,\n" + + " \"resource_servers\": [\n" + + " {\n" + + " \"audience\": \"https://api.example.com\",\n" + + " \"scopes\": [\n" + + " \"read:examples\",\n" + + " \"write:examples\"\n" + + " ]\n" + + " }\n" + + " ],\n" + + " \"last_exchanged_at\": \"2024-07-03T09:10:26.643Z\"\n" + + "}"; + + private static final String readOnlyJson = "{\n" + + " \"user_id\": \"userId1\",\n" + + " \"client_id\": \"clientId1\",\n" + + " \"session_id\": \"sessionId1\"\n" + + "}"; + + @Test + public void shouldDeserialize() throws Exception { + RefreshToken refreshToken = fromJSON(json, RefreshToken.class); + assertThat(refreshToken, is(notNullValue())); + + assertThat(refreshToken.getId(), is("tokenId1")); + assertThat(refreshToken.getUserId(), is("userId1")); + assertThat(refreshToken.getCreatedAt(), is(parseJSONDate("2024-06-26T09:10:26.643Z"))); + assertThat(refreshToken.getIdleExpiresAt(), is(parseJSONDate("2024-06-26T09:10:27.131Z"))); + assertThat(refreshToken.getExpiresAt(), is(parseJSONDate("2024-07-03T09:10:26.643Z"))); + + assertThat(refreshToken.getDevice(), is(notNullValue())); + assertThat(refreshToken.getDevice().getInitialAsn(), is("1234")); + assertThat(refreshToken.getDevice().getInitialIp(), is("203.0.113.1")); + assertThat(refreshToken.getDevice().getInitialUserAgent(), is("Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36")); + assertThat(refreshToken.getDevice().getLastUserAgent(), is("Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36")); + assertThat(refreshToken.getDevice().getLastIp(), is("203.0.113.1")); + assertThat(refreshToken.getDevice().getLastAsn(), is("1234")); + + assertThat(refreshToken.getClientId(), is("clientId1")); + assertThat(refreshToken.getSessionId(), is("sessionId1")); + assertThat(refreshToken.isRotating(), is(false)); + + assertThat(refreshToken.getResourceServers(), is(notNullValue())); + assertThat(refreshToken.getResourceServers().get(0).getAudience(), is("https://api.example.com")); + assertThat(refreshToken.getResourceServers().get(0).getScopes(), is(notNullValue())); + assertThat(refreshToken.getResourceServers().get(0).getScopes().get(0), is("read:examples")); + assertThat(refreshToken.getResourceServers().get(0).getScopes().get(1), is("write:examples")); + + assertThat(refreshToken.getLastExchangedAt(), is(parseJSONDate("2024-07-03T09:10:26.643Z"))); + } + + @Test + public void shouldIncludeReadOnlyValuesOnDeserialize() throws Exception { + RefreshToken refreshToken = fromJSON(readOnlyJson, RefreshToken.class); + assertThat(refreshToken, is(notNullValue())); + assertThat(refreshToken.getUserId(), is("userId1")); + assertThat(refreshToken.getClientId(), is("clientId1")); + assertThat(refreshToken.getSessionId(), is("sessionId1")); + } +} diff --git a/src/test/java/com/auth0/json/mgmt/refreshtokens/RefreshTokensPageTest.java b/src/test/java/com/auth0/json/mgmt/refreshtokens/RefreshTokensPageTest.java new file mode 100644 index 00000000..f86c7df7 --- /dev/null +++ b/src/test/java/com/auth0/json/mgmt/refreshtokens/RefreshTokensPageTest.java @@ -0,0 +1,175 @@ +package com.auth0.json.mgmt.refreshtokens; + +import com.auth0.json.JsonTest; +import org.junit.jupiter.api.Test; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.nullValue; + +public class RefreshTokensPageTest extends JsonTest { + private static final String json = "{\n" + + " \"tokens\": [\n" + + " {\n" + + " \"id\": \"tokenId1\",\n" + + " \"user_id\": \"userId1\",\n" + + " \"created_at\": \"2024-06-26T09:10:26.643Z\",\n" + + " \"updated_at\": \"2024-06-26T09:10:27.131Z\",\n" + + " \"expires_at\": \"2024-07-03T09:10:26.643Z\",\n" + + " \"device\": {\n" + + " \"initial_asn\": \"1234\",\n" + + " \"initial_ip\": \"203.0.113.1\",\n" + + " \"initial_user_agent\": \"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36\",\n" + + " \"last_user_agent\": \"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36\",\n" + + " \"last_ip\": \"203.0.113.1\",\n" + + " \"last_asn\": \"1234\"\n" + + " },\n" + + " \"client_id\": \"clientId1\",\n" + + " \"session_id\": \"sessionId1\",\n" + + " \"rotating\": false,\n" + + " \"resource_servers\": [\n" + + " {\n" + + " \"audience\": \"https://api.example.com\",\n" + + " \"scopes\": [\n" + + " \"read:examples\",\n" + + " \"write:examples\"\n" + + " ]\n" + + " }\n" + + " ],\n" + + " \"last_exchanged_at\": \"2024-07-03T09:10:26.643Z\"\n" + + " },\n" + + " {\n" + + " \"id\": \"tokenId2\",\n" + + " \"user_id\": \"userId1\",\n" + + " \"created_at\": \"2024-06-26T09:10:26.643Z\",\n" + + " \"updated_at\": \"2024-06-26T09:10:27.131Z\",\n" + + " \"expires_at\": \"2024-07-03T09:10:26.643Z\",\n" + + " \"device\": {\n" + + " \"initial_asn\": \"1234\",\n" + + " \"initial_ip\": \"203.0.113.1\",\n" + + " \"initial_user_agent\": \"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36\",\n" + + " \"last_user_agent\": \"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36\",\n" + + " \"last_ip\": \"203.0.113.1\",\n" + + " \"last_asn\": \"1234\"\n" + + " },\n" + + " \"client_id\": \"clientId2\",\n" + + " \"session_id\": \"sessionId2\",\n" + + " \"rotating\": true,\n" + + " \"resource_servers\": [\n" + + " {\n" + + " \"audience\": \"https://api.example.com\",\n" + + " \"scopes\": [\n" + + " \"read:examples\",\n" + + " \"write:examples\"\n" + + " ]\n" + + " }\n" + + " ],\n" + + " \"last_exchanged_at\": \"2024-07-03T09:10:26.643Z\"\n" + + " }\n" + + " ],\n" + + " \"next\": \"token1\"\n" + + "}"; + + private static final String jsonWithTotal = "{\n" + + " \"tokens\": [\n" + + " {\n" + + " \"id\": \"tokenId1\",\n" + + " \"user_id\": \"userId1\",\n" + + " \"created_at\": \"2024-06-26T09:10:26.643Z\",\n" + + " \"updated_at\": \"2024-06-26T09:10:27.131Z\",\n" + + " \"expires_at\": \"2024-07-03T09:10:26.643Z\",\n" + + " \"device\": {\n" + + " \"initial_asn\": \"1234\",\n" + + " \"initial_ip\": \"203.0.113.1\",\n" + + " \"initial_user_agent\": \"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36\",\n" + + " \"last_user_agent\": \"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36\",\n" + + " \"last_ip\": \"203.0.113.1\",\n" + + " \"last_asn\": \"1234\"\n" + + " },\n" + + " \"client_id\": \"clientId1\",\n" + + " \"session_id\": \"sessionId1\",\n" + + " \"rotating\": false,\n" + + " \"resource_servers\": [\n" + + " {\n" + + " \"audience\": \"https://api.example.com\",\n" + + " \"scopes\": [\n" + + " \"read:examples\",\n" + + " \"write:examples\"\n" + + " ]\n" + + " }\n" + + " ],\n" + + " \"last_exchanged_at\": \"2024-07-03T09:10:26.643Z\"\n" + + " },\n" + + " {\n" + + " \"id\": \"tokenId2\",\n" + + " \"user_id\": \"userId1\",\n" + + " \"created_at\": \"2024-06-26T09:10:26.643Z\",\n" + + " \"updated_at\": \"2024-06-26T09:10:27.131Z\",\n" + + " \"expires_at\": \"2024-07-03T09:10:26.643Z\",\n" + + " \"device\": {\n" + + " \"initial_asn\": \"1234\",\n" + + " \"initial_ip\": \"203.0.113.1\",\n" + + " \"initial_user_agent\": \"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36\",\n" + + " \"last_user_agent\": \"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36\",\n" + + " \"last_ip\": \"203.0.113.1\",\n" + + " \"last_asn\": \"1234\"\n" + + " },\n" + + " \"client_id\": \"clientId2\",\n" + + " \"session_id\": \"sessionId2\",\n" + + " \"rotating\": true,\n" + + " \"resource_servers\": [\n" + + " {\n" + + " \"audience\": \"https://api.example.com\",\n" + + " \"scopes\": [\n" + + " \"read:examples\",\n" + + " \"write:examples\"\n" + + " ]\n" + + " }\n" + + " ],\n" + + " \"last_exchanged_at\": \"2024-07-03T09:10:26.643Z\"\n" + + " }\n" + + " ],\n" + + " \"next\": \"token1\",\n" + + " \"total\": 11\n" + + "}"; + @Test + public void shouldDeserialize() throws Exception { + RefreshTokensPage page = fromJSON(json, RefreshTokensPage.class); + + assertThat(page.getTotal(), is(nullValue())); + assertThat(page.getNext(), is("token1")); + + assertThat(page.getTokens().size(), is(2)); + assertThat(page.getTokens().get(0).getId(), is("tokenId1")); + assertThat(page.getTokens().get(0).getUserId(), is("userId1")); + assertThat(page.getTokens().get(0).getCreatedAt(), is(parseJSONDate("2024-06-26T09:10:26.643Z"))); + assertThat(page.getTokens().get(0).getIdleExpiresAt(), is(nullValue())); + assertThat(page.getTokens().get(0).getExpiresAt(), is(parseJSONDate("2024-07-03T09:10:26.643Z"))); + + assertThat(page.getTokens().get(0).getDevice().getInitialIp(), is("203.0.113.1")); + assertThat(page.getTokens().get(0).getDevice().getInitialAsn(), is("1234")); + assertThat(page.getTokens().get(0).getDevice().getInitialUserAgent(), is("Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36")); + assertThat(page.getTokens().get(0).getDevice().getLastIp(), is("203.0.113.1")); + assertThat(page.getTokens().get(0).getDevice().getLastAsn(), is("1234")); + assertThat(page.getTokens().get(0).getDevice().getLastUserAgent(), is("Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36")); + + assertThat(page.getTokens().get(0).getClientId(), is("clientId1")); + assertThat(page.getTokens().get(0).getSessionId(), is("sessionId1")); + assertThat(page.getTokens().get(0).isRotating(), is(false)); + + assertThat(page.getTokens().get(0).getResourceServers().size(), is(1)); + assertThat(page.getTokens().get(0).getResourceServers().get(0).getAudience(), is("https://api.example.com")); + assertThat(page.getTokens().get(0).getResourceServers().get(0).getScopes().size(), is(2)); + assertThat(page.getTokens().get(0).getResourceServers().get(0).getScopes().get(0), is("read:examples")); + assertThat(page.getTokens().get(0).getResourceServers().get(0).getScopes().get(1), is("write:examples")); + + assertThat(page.getTokens().get(0).getLastExchangedAt(), is(parseJSONDate("2024-07-03T09:10:26.643Z"))); + } + + @Test + public void shouldDeserializeWithTotal() throws Exception { + RefreshTokensPage page = fromJSON(jsonWithTotal, RefreshTokensPage.class); + + assertThat(page.getTotal(), is(11)); + } +} diff --git a/src/test/java/com/auth0/json/mgmt/sessions/SessionTest.java b/src/test/java/com/auth0/json/mgmt/sessions/SessionTest.java new file mode 100644 index 00000000..8ed3d2c2 --- /dev/null +++ b/src/test/java/com/auth0/json/mgmt/sessions/SessionTest.java @@ -0,0 +1,91 @@ +package com.auth0.json.mgmt.sessions; + +import com.auth0.json.JsonTest; +import org.junit.jupiter.api.Test; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.notNullValue; + +public class SessionTest extends JsonTest { + + private static final String json = "{\n" + + " \"id\": \"sessionId1\",\n" + + " \"user_id\": \"userId1\",\n" + + " \"created_at\": \"2024-09-04T06:41:46.145Z\",\n" + + " \"updated_at\": \"2024-09-04T06:41:46.621Z\",\n" + + " \"authenticated_at\": \"2024-09-04T06:41:46.145Z\",\n" + + " \"authentication\": {\n" + + " \"methods\": [\n" + + " {\n" + + " \"name\": \"federated\",\n" + + " \"timestamp\": \"2024-09-04T06:41:46.145Z\"\n" + + " }\n" + + " ]\n" + + " },\n" + + " \"idle_expires_at\": \"2024-09-07T06:41:46.622Z\",\n" + + " \"expires_at\": \"2024-09-11T06:41:46.145Z\",\n" + + " \"device\": {\n" + + " \"initial_user_agent\": \"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36\",\n" + + " \"initial_asn\": \"1234\",\n" + + " \"initial_ip\": \"134.1.15.0\",\n" + + " \"last_user_agent\": \"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36\",\n" + + " \"last_ip\": \"134.1.15.0\",\n" + + " \"last_asn\": \"1234\"\n" + + " },\n" + + " \"clients\": [\n" + + " {\n" + + " \"client_id\": \"clientId1\"\n" + + " }\n" + + " ]\n" + + "}"; + + private static final String readOnlyJson = "{\n" + + " \"user_id\": \"userId1\",\n" + + " \"clients\": [\n" + + " {\n" + + " \"client_id\": \"clientId1\"\n" + + " }\n" + + " ]\n" + + "}"; + + @Test + public void shouldDeserialize() throws Exception { + Session session = fromJSON(json, Session.class); + + assertThat(session, is(notNullValue())); + assertThat(session.getId(), is("sessionId1")); + assertThat(session.getUserId(), is("userId1")); + assertThat(session.getCreatedAt(), is(parseJSONDate("2024-09-04T06:41:46.145Z"))); + assertThat(session.getUpdatedAt(), is(parseJSONDate("2024-09-04T06:41:46.621Z"))); + assertThat(session.getAuthenticatedAt(), is(parseJSONDate("2024-09-04T06:41:46.145Z"))); + + assertThat(session.getAuthentication().getMethods(), is(notNullValue())); + assertThat(session.getAuthentication().getMethods().get(0).getName(), is("federated")); + assertThat(session.getAuthentication().getMethods().get(0).getTimestamp(), is(parseJSONDate("2024-09-04T06:41:46.145Z"))); + + assertThat(session.getIdleExpiresAt(), is(parseJSONDate("2024-09-07T06:41:46.622Z"))); + assertThat(session.getExpiresAt(), is(parseJSONDate("2024-09-11T06:41:46.145Z"))); + + assertThat(session.getDevice(), is(notNullValue())); + assertThat(session.getDevice().getInitialASN(), is("1234")); + assertThat(session.getDevice().getInitialIP(), is("134.1.15.0")); + assertThat(session.getDevice().getInitialUserAgent(), is("Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36")); + assertThat(session.getDevice().getLastASN(), is("1234")); + assertThat(session.getDevice().getLastIP(), is("134.1.15.0")); + assertThat(session.getDevice().getLastUserAgent(), is("Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36")); + + assertThat(session.getClients(), is(notNullValue())); + assertThat(session.getClients().get(0).getClientId(), is("clientId1")); + } + + @Test + public void shouldIncludeReadOnlyValuesOnDeserialize() throws Exception { + Session session = fromJSON(readOnlyJson, Session.class); + assertThat(session, is(notNullValue())); + assertThat(session.getUserId(), is("userId1")); + assertThat(session.getClients().get(0).getClientId(), is("clientId1")); + } + + +} diff --git a/src/test/java/com/auth0/json/mgmt/sessions/SessionsPageTest.java b/src/test/java/com/auth0/json/mgmt/sessions/SessionsPageTest.java new file mode 100644 index 00000000..12d28899 --- /dev/null +++ b/src/test/java/com/auth0/json/mgmt/sessions/SessionsPageTest.java @@ -0,0 +1,121 @@ +package com.auth0.json.mgmt.sessions; + +import com.auth0.json.JsonTest; +import com.auth0.json.mgmt.sessions.SessionsPage; +import org.junit.jupiter.api.Test; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.nullValue; + +public class SessionsPageTest extends JsonTest { + private static final String json = "{\n" + + " \"sessions\": [\n" + + " {\n" + + " \"id\": \"sessionId1\",\n" + + " \"user_id\": \"userId1\",\n" + + " \"created_at\": \"2024-06-26T09:10:26.643Z\",\n" + + " \"updated_at\": \"2024-06-26T09:10:27.131Z\",\n" + + " \"authenticated_at\": \"2024-06-26T09:10:26.643Z\",\n" + + " \"authentication\": {\n" + + " \"methods\": [\n" + + " {\n" + + " \"name\": \"pwd\",\n" + + " \"timestamp\": \"2024-06-26T09:10:26.643Z\"\n" + + " }\n" + + " ]\n" + + " },\n" + + " \"idle_expires_at\": \"2024-06-26T09:40:27.131Z\",\n" + + " \"expires_at\": \"2024-07-03T09:10:26.643Z\",\n" + + " \"device\": {\n" + + " \"initial_asn\": \"1234\",\n" + + " \"initial_ip\": \"203.0.113.1\",\n" + + " \"initial_user_agent\": \"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36\",\n" + + " \"last_user_agent\": \"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36\",\n" + + " \"last_ip\": \"203.0.113.1\",\n" + + " \"last_asn\": \"1234\"\n" + + " },\n" + + " \"clients\": [\n" + + " {\n" + + " \"client_id\": \"clientId1\"\n" + + " }\n" + + " ]\n" + + " }\n" + + " ],\n" + + " \"next\": \"sessionId1\"\n" + + "}"; + private static final String jsonWithTotals = "{\n" + + " \"sessions\": [\n" + + " {\n" + + " \"id\": \"sessionId1\",\n" + + " \"user_id\": \"userId1\",\n" + + " \"created_at\": \"2024-06-26T09:10:26.643Z\",\n" + + " \"updated_at\": \"2024-06-26T09:10:27.131Z\",\n" + + " \"authenticated_at\": \"2024-06-26T09:10:26.643Z\",\n" + + " \"authentication\": {\n" + + " \"methods\": [\n" + + " {\n" + + " \"name\": \"pwd\",\n" + + " \"timestamp\": \"2024-06-26T09:10:26.643Z\"\n" + + " }\n" + + " ]\n" + + " },\n" + + " \"idle_expires_at\": \"2024-06-26T09:40:27.131Z\",\n" + + " \"expires_at\": \"2024-07-03T09:10:26.643Z\",\n" + + " \"device\": {\n" + + " \"initial_user_agent\": \"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36\",\n" + + " \"initial_asn\": \"1234\",\n" + + " \"initial_ip\": \"203.0.113.1\",\n" + + " \"last_user_agent\": \"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36\",\n" + + " \"last_ip\": \"203.0.113.1\",\n" + + " \"last_asn\": \"1234\"\n" + + " },\n" + + " \"clients\": [\n" + + " {\n" + + " \"client_id\": \"clientId1\"\n" + + " }\n" + + " ]\n" + + " }\n" + + " ],\n" + + " \"next\": \"sessionId1\",\n" + + " \"total\": 11\n" + + "}"; + + @Test + public void shouldDeserialize() throws Exception { + SessionsPage page = fromJSON(json, SessionsPage.class); + + assertThat(page.getTotal(), is(nullValue())); + assertThat(page.getNext(), is("sessionId1")); + assertThat(page.getSessions().size(), is(1)); + assertThat(page.getSessions().get(0).getId(), is("sessionId1")); + assertThat(page.getSessions().get(0).getUserId(), is("userId1")); + assertThat(page.getSessions().get(0).getCreatedAt(), is(parseJSONDate("2024-06-26T09:10:26.643Z"))); + assertThat(page.getSessions().get(0).getUpdatedAt(), is(parseJSONDate("2024-06-26T09:10:27.131Z"))); + assertThat(page.getSessions().get(0).getAuthenticatedAt(), is(parseJSONDate("2024-06-26T09:10:26.643Z"))); + assertThat(page.getSessions().get(0).getIdleExpiresAt(), is(parseJSONDate("2024-06-26T09:40:27.131Z"))); + assertThat(page.getSessions().get(0).getExpiresAt(), is(parseJSONDate("2024-07-03T09:10:26.643Z"))); + + assertThat(page.getSessions().get(0).getDevice().getInitialASN(), is("1234")); + assertThat(page.getSessions().get(0).getDevice().getInitialIP(), is("203.0.113.1")); + assertThat(page.getSessions().get(0).getDevice().getLastUserAgent(), is("Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36")); + assertThat(page.getSessions().get(0).getDevice().getLastIP(), is("203.0.113.1")); + assertThat(page.getSessions().get(0).getDevice().getLastASN(), is("1234")); + assertThat(page.getSessions().get(0).getDevice().getLastUserAgent(), is("Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36")); + + assertThat(page.getSessions().get(0).getClients().size(), is(1)); + assertThat(page.getSessions().get(0).getClients().get(0).getClientId(), is("clientId1")); + + assertThat(page.getSessions().get(0).getAuthentication().getMethods().size(), is(1)); + assertThat(page.getSessions().get(0).getAuthentication().getMethods().get(0).getName(), is("pwd")); + assertThat(page.getSessions().get(0).getAuthentication().getMethods().get(0).getTimestamp(), is(parseJSONDate("2024-06-26T09:10:26.643Z"))); + assertThat(page.getSessions().get(0).getAuthentication().getMethods().get(0).getType(), is(nullValue())); + } + + @Test + public void shouldDeserializeWithTotals() throws Exception { + SessionsPage page = fromJSON(jsonWithTotals, SessionsPage.class); + + assertThat(page.getTotal(), is(11)); + } +} diff --git a/src/test/java/com/auth0/json/mgmt/users/refreshtokens/RefreshTokensPageTest.java b/src/test/java/com/auth0/json/mgmt/users/refreshtokens/RefreshTokensPageTest.java deleted file mode 100644 index b0e701eb..00000000 --- a/src/test/java/com/auth0/json/mgmt/users/refreshtokens/RefreshTokensPageTest.java +++ /dev/null @@ -1,44 +0,0 @@ -package com.auth0.json.mgmt.users.refreshtokens; - -import com.auth0.json.JsonTest; -import org.junit.jupiter.api.Test; - -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.is; -import static org.hamcrest.Matchers.nullValue; - -public class RefreshTokensPageTest extends JsonTest { - private static final String json = "{\n\"tokens\": [\n{\n\"id\": \"tokenId1\",\n\"user_id\": \"userId1\",\n\"created_at\": \"2024-06-26T09:10:26.643Z\",\n\"updated_at\": \"2024-06-26T09:10:27.131Z\",\n\"expires_at\": \"2024-07-03T09:10:26.643Z\",\n\"client_id\": \"clientId1\",\n\"session_id\": \"sessionId1\",\n\"rotating\": false,\n\"resource_servers\": [\n{\n\"audience\": \"https://api.example.com\",\n\"scopes\": [\n\"read:examples\",\n\"write:examples\"\n]\n}\n]\n},\n{\n\"id\": \"tokenId2\",\n\"user_id\": \"userId1\",\n\"created_at\": \"2024-06-26T09:10:26.643Z\",\n\"updated_at\": \"2024-06-26T09:10:27.131Z\",\n\"expires_at\": \"2024-07-03T09:10:26.643Z\",\n\"client_id\": \"clientId2\",\n\"session_id\": \"sessionId2\",\n\"rotating\": true,\n\"resource_servers\": [\n{\n\"audience\": \"https://api.example.com\",\n\"scopes\": [\n\"read:examples\",\n\"write:examples\"\n]\n}\n]\n}\n],\n\"next\": \"token1\"\n}\n"; - private static final String jsonWithTotal = "{\n\"tokens\": [\n{\n\"id\": \"tokenId1\",\n\"user_id\": \"userId1\",\n\"created_at\": \"2024-06-26T09:10:26.643Z\",\n\"updated_at\": \"2024-06-26T09:10:27.131Z\",\n\"expires_at\": \"2024-07-03T09:10:26.643Z\",\n\"client_id\": \"clientId1\",\n\"session_id\": \"sessionId1\",\n\"rotating\": false,\n\"resource_servers\": [\n{\n\"audience\": \"https://api.example.com\",\n\"scopes\": [\n\"read:examples\",\n\"write:examples\"\n]\n}\n]\n},\n{\n\"id\": \"tokenId2\",\n\"user_id\": \"userId1\",\n\"created_at\": \"2024-06-26T09:10:26.643Z\",\n\"updated_at\": \"2024-06-26T09:10:27.131Z\",\n\"expires_at\": \"2024-07-03T09:10:26.643Z\",\n\"client_id\": \"clientId2\",\n\"session_id\": \"sessionId2\",\n\"rotating\": true,\n\"resource_servers\": [\n{\n\"audience\": \"https://api.example.com\",\n\"scopes\": [\n\"read:examples\",\n\"write:examples\"\n]\n}\n]\n}\n],\n\"next\": \"token1\",\n\"total\": 11\n}\n"; - - @Test - public void shouldDeserialize() throws Exception { - RefreshTokensPage page = fromJSON(json, RefreshTokensPage.class); - - assertThat(page.getTotal(), is(nullValue())); - assertThat(page.getNext(), is("token1")); - - assertThat(page.getTokens().size(), is(2)); - assertThat(page.getTokens().get(0).getId(), is("tokenId1")); - assertThat(page.getTokens().get(0).getUserId(), is("userId1")); - assertThat(page.getTokens().get(0).getCreatedAt(), is(parseJSONDate("2024-06-26T09:10:26.643Z"))); - assertThat(page.getTokens().get(0).getIdleExpiresAt(), is(nullValue())); - assertThat(page.getTokens().get(0).getExpiresAt(), is(parseJSONDate("2024-07-03T09:10:26.643Z"))); - assertThat(page.getTokens().get(0).getClientId(), is("clientId1")); - assertThat(page.getTokens().get(0).getSessionId(), is("sessionId1")); - assertThat(page.getTokens().get(0).isRotating(), is(false)); - - assertThat(page.getTokens().get(0).getResourceServers().size(), is(1)); - assertThat(page.getTokens().get(0).getResourceServers().get(0).getAudience(), is("https://api.example.com")); - assertThat(page.getTokens().get(0).getResourceServers().get(0).getScopes().size(), is(2)); - assertThat(page.getTokens().get(0).getResourceServers().get(0).getScopes().get(0), is("read:examples")); - assertThat(page.getTokens().get(0).getResourceServers().get(0).getScopes().get(1), is("write:examples")); - } - - @Test - public void shouldDeserializeWithTotal() throws Exception { - RefreshTokensPage page = fromJSON(jsonWithTotal, RefreshTokensPage.class); - - assertThat(page.getTotal(), is(11)); - } -} diff --git a/src/test/java/com/auth0/json/mgmt/users/sessions/SessionsPageTest.java b/src/test/java/com/auth0/json/mgmt/users/sessions/SessionsPageTest.java deleted file mode 100644 index 6fdcf2dc..00000000 --- a/src/test/java/com/auth0/json/mgmt/users/sessions/SessionsPageTest.java +++ /dev/null @@ -1,50 +0,0 @@ -package com.auth0.json.mgmt.users.sessions; - -import com.auth0.json.JsonTest; -import org.junit.jupiter.api.Test; - -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.is; -import static org.hamcrest.Matchers.nullValue; - -public class SessionsPageTest extends JsonTest { - private static final String json = "{\"sessions\":[{\"id\":\"sessionId1\",\n\"user_id\":\"userId1\",\n\"created_at\":\"2024-06-26T09:10:26.643Z\",\n\"updated_at\":\"2024-06-26T09:10:27.131Z\",\n\"authenticated_at\":\"2024-06-26T09:10:26.643Z\",\n\"authentication\":{\n\"methods\":[\n{\n\"name\":\"pwd\",\n\"timestamp\":\"2024-06-26T09:10:26.643Z\"\n}\n]\n},\n\"idle_expires_at\":\"2024-06-26T09:40:27.131Z\",\n\"expires_at\":\"2024-07-03T09:10:26.643Z\",\n\"device\":{\n\"initial_asn\":\"1234\",\n\"initial_ip\":\"203.0.113.1\",\n\"last_user_agent\":\"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36\",\n\"last_ip\":\"203.0.113.1\",\n\"last_asn\":\"1234\"\n},\n\"clients\":[\n{\n\"client_id\":\"clientId1\"\n}\n]\n}\n],\n\"next\":\"sessionId1\"\n}\n"; - private static final String jsonWithTotals = "{\"sessions\":[{\"id\":\"sessionId1\",\n\"user_id\":\"userId1\",\n\"created_at\":\"2024-06-26T09:10:26.643Z\",\n\"updated_at\":\"2024-06-26T09:10:27.131Z\",\n\"authenticated_at\":\"2024-06-26T09:10:26.643Z\",\n\"authentication\":{\n\"methods\":[\n{\n\"name\":\"pwd\",\n\"timestamp\":\"2024-06-26T09:10:26.643Z\"\n}\n]\n},\n\"idle_expires_at\":\"2024-06-26T09:40:27.131Z\",\n\"expires_at\":\"2024-07-03T09:10:26.643Z\",\n\"device\":{\n\"initial_asn\":\"1234\",\n\"initial_ip\":\"203.0.113.1\",\n\"last_user_agent\":\"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36\",\n\"last_ip\":\"203.0.113.1\",\n\"last_asn\":\"1234\"\n},\n\"clients\":[\n{\n\"client_id\":\"clientId1\"\n}\n]\n}\n],\n\"next\":\"sessionId1\",\n\"total\":11\n}\n"; - - @Test - public void shouldDeserialize() throws Exception { - SessionsPage page = fromJSON(json, SessionsPage.class); - - assertThat(page.getTotal(), is(nullValue())); - assertThat(page.getNext(), is("sessionId1")); - assertThat(page.getSessions().size(), is(1)); - assertThat(page.getSessions().get(0).getId(), is("sessionId1")); - assertThat(page.getSessions().get(0).getUserId(), is("userId1")); - assertThat(page.getSessions().get(0).getCreatedAt(), is(parseJSONDate("2024-06-26T09:10:26.643Z"))); - assertThat(page.getSessions().get(0).getUpdatedAt(), is(parseJSONDate("2024-06-26T09:10:27.131Z"))); - assertThat(page.getSessions().get(0).getAuthenticatedAt(), is(parseJSONDate("2024-06-26T09:10:26.643Z"))); - assertThat(page.getSessions().get(0).getIdleExpiresAt(), is(parseJSONDate("2024-06-26T09:40:27.131Z"))); - assertThat(page.getSessions().get(0).getExpiresAt(), is(parseJSONDate("2024-07-03T09:10:26.643Z"))); - - assertThat(page.getSessions().get(0).getDevice().getInitialASN(), is("1234")); - assertThat(page.getSessions().get(0).getDevice().getInitialIP(), is("203.0.113.1")); - assertThat(page.getSessions().get(0).getDevice().getLastUserAgent(), is("Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36")); - assertThat(page.getSessions().get(0).getDevice().getLastIP(), is("203.0.113.1")); - assertThat(page.getSessions().get(0).getDevice().getLastASN(), is("1234")); - - assertThat(page.getSessions().get(0).getClients().size(), is(1)); - assertThat(page.getSessions().get(0).getClients().get(0).getClientId(), is("clientId1")); - - assertThat(page.getSessions().get(0).getAuthentication().getMethods().size(), is(1)); - assertThat(page.getSessions().get(0).getAuthentication().getMethods().get(0).getName(), is("pwd")); - assertThat(page.getSessions().get(0).getAuthentication().getMethods().get(0).getTimestamp(), is(parseJSONDate("2024-06-26T09:10:26.643Z"))); - assertThat(page.getSessions().get(0).getAuthentication().getMethods().get(0).getType(), is(nullValue())); - } - - @Test - public void shouldDeserializeWithTotals() throws Exception { - SessionsPage page = fromJSON(jsonWithTotals, SessionsPage.class); - - assertThat(page.getTotal(), is(11)); - } -} diff --git a/src/test/resources/mgmt/refresh_token.json b/src/test/resources/mgmt/refresh_token.json new file mode 100644 index 00000000..8ea37353 --- /dev/null +++ b/src/test/resources/mgmt/refresh_token.json @@ -0,0 +1,28 @@ +{ + "id": "tokenId1", + "user_id": "userId1", + "created_at": "2024-06-26T09:10:26.643Z", + "idle_expires_at": "2024-06-26T09:10:27.131Z", + "expires_at": "2024-07-03T09:10:26.643Z", + "device": { + "initial_asn": "1234", + "initial_ip": "203.0.113.1", + "initial_user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36", + "last_user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36", + "last_ip": "203.0.113.1", + "last_asn": "1234" + }, + "client_id": "clientId1", + "session_id": "sessionId1", + "rotating": false, + "resource_servers": [ + { + "audience": "https://api.example.com", + "scopes": [ + "read:examples", + "write:examples" + ] + } + ], + "last_exchanged_at": "2024-07-03T09:10:26.643Z" +} diff --git a/src/test/resources/mgmt/session.json b/src/test/resources/mgmt/session.json new file mode 100644 index 00000000..07251c3c --- /dev/null +++ b/src/test/resources/mgmt/session.json @@ -0,0 +1,30 @@ +{ + "id": "sessionId1", + "user_id": "userId1", + "created_at": "2024-09-04T06:41:46.145Z", + "updated_at": "2024-09-04T06:41:46.621Z", + "authenticated_at": "2024-09-04T06:41:46.145Z", + "authentication": { + "methods": [ + { + "name": "federated", + "timestamp": "2024-09-04T06:41:46.145Z" + } + ] + }, + "idle_expires_at": "2024-09-07T06:41:46.622Z", + "expires_at": "2024-09-11T06:41:46.145Z", + "device": { + "initial_user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36", + "initial_asn": "1234", + "initial_ip": "134.1.15.0", + "last_user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36", + "last_ip": "134.1.15.0", + "last_asn": "1234" + }, + "clients": [ + { + "client_id": "clientId1" + } + ] +} diff --git a/src/test/resources/mgmt/user_refresh_tokens.json b/src/test/resources/mgmt/user_refresh_tokens.json index c1ed7aa9..18c77eb6 100644 --- a/src/test/resources/mgmt/user_refresh_tokens.json +++ b/src/test/resources/mgmt/user_refresh_tokens.json @@ -4,8 +4,16 @@ "id": "tokenId1", "user_id": "userId1", "created_at": "2024-06-26T09:10:26.643Z", - "updated_at": "2024-06-26T09:10:27.131Z", + "idle_expires_at": "2024-06-26T09:10:27.131Z", "expires_at": "2024-07-03T09:10:26.643Z", + "device": { + "initial_asn": "1234", + "initial_ip": "203.0.113.1", + "initial_user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36", + "last_user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36", + "last_ip": "203.0.113.1", + "last_asn": "1234" + }, "client_id": "clientId1", "session_id": "sessionId1", "rotating": false, @@ -17,14 +25,24 @@ "write:examples" ] } - ] + ], + "last_exchanged_at": "2024-07-03T09:10:26.643Z" }, { "id": "tokenId2", "user_id": "userId1", "created_at": "2024-06-26T09:10:26.643Z", "updated_at": "2024-06-26T09:10:27.131Z", + "idle_expires_at": "2024-06-26T09:10:27.131Z", "expires_at": "2024-07-03T09:10:26.643Z", + "device": { + "initial_asn": "1234", + "initial_ip": "203.0.113.1", + "initial_user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36", + "last_user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36", + "last_ip": "203.0.113.1", + "last_asn": "1234" + }, "client_id": "clientId2", "session_id": "sessionId2", "rotating": true, @@ -36,7 +54,8 @@ "write:examples" ] } - ] + ], + "last_exchanged_at": "2024-07-03T09:10:26.643Z" } ], "next": "token1", diff --git a/src/test/resources/mgmt/user_sessions.json b/src/test/resources/mgmt/user_sessions.json index 750b127e..71c9b754 100644 --- a/src/test/resources/mgmt/user_sessions.json +++ b/src/test/resources/mgmt/user_sessions.json @@ -17,6 +17,7 @@ "idle_expires_at": "2024-06-26T09:40:27.131Z", "expires_at": "2024-07-03T09:10:26.643Z", "device": { + "initial_user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36", "initial_asn": "1234", "initial_ip": "203.0.113.1", "last_user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36", From 35195d5ee7f6fd22913421616ebde2f69f5fa037 Mon Sep 17 00:00:00 2001 From: tanya-sinha_atko Date: Fri, 6 Sep 2024 14:03:16 +0530 Subject: [PATCH 07/32] Updated javadoc to correctly state the entity type --- src/main/java/com/auth0/client/mgmt/ManagementAPI.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/auth0/client/mgmt/ManagementAPI.java b/src/main/java/com/auth0/client/mgmt/ManagementAPI.java index 5ac89afb..acffaeb3 100644 --- a/src/main/java/com/auth0/client/mgmt/ManagementAPI.java +++ b/src/main/java/com/auth0/client/mgmt/ManagementAPI.java @@ -365,16 +365,16 @@ public KeysEntity keys() { } /** - * Getter for the Prompts Entity - * @return the Prompts Entity + * Getter for the RefreshTokens Entity + * @return the RefreshTokens Entity */ public RefreshTokensEntity refreshTokens() { return new RefreshTokensEntity(client, baseUrl, tokenProvider); } /** - * Getter for the Prompts Entity - * @return the Prompts Entity + * Getter for the Sessions Entity + * @return the Sessions Entity */ public SessionsEntity sessions() { return new SessionsEntity(client, baseUrl, tokenProvider); From 0da62969324cb7b1dd1ea698612fd5569a0342df Mon Sep 17 00:00:00 2001 From: tanya-sinha_atko Date: Mon, 9 Sep 2024 17:32:15 +0530 Subject: [PATCH 08/32] updated workflow secrets to use ossr-token --- .github/actions/maven-publish/action.yml | 6 +++--- .github/workflows/java-release.yml | 4 ++-- .github/workflows/release.yml | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/actions/maven-publish/action.yml b/.github/actions/maven-publish/action.yml index ee477061..2152527e 100644 --- a/.github/actions/maven-publish/action.yml +++ b/.github/actions/maven-publish/action.yml @@ -3,7 +3,7 @@ name: Publish release to Java inputs: ossr-username: required: true - ossr-password: + ossr-token: required: true signing-key: required: true @@ -36,9 +36,9 @@ runs: - name: Publish Java shell: bash if: inputs.is-android == 'false' - run: ./gradlew clean assemble sign publishMavenJavaPublicationToMavenRepository -PisSnapshot=false -Pversion="${{ inputs.version }}" -PossrhUsername="${{ inputs.ossr-username }}" -PossrhPassword="${{ inputs.ossr-password }}" -PsigningKey="${{ inputs.signing-key }}" -PsigningPassword="${{ inputs.signing-password }}" + run: ./gradlew clean assemble sign publishMavenJavaPublicationToMavenRepository -PisSnapshot=false -Pversion="${{ inputs.version }}" -PossrhUsername="${{ inputs.ossr-username }}" -PossrhPassword="${{ inputs.ossr-token }}" -PsigningKey="${{ inputs.signing-key }}" -PsigningPassword="${{ inputs.signing-password }}" - name: Publish Android shell: bash if: inputs.is-android == 'true' - run: ./gradlew clean assemble sign publishAndroidLibraryPublicationToMavenRepository -PisSnapshot=false -Pversion="${{ inputs.version }}" -PossrhUsername="${{ inputs.ossr-username }}" -PossrhPassword="${{ inputs.ossr-password }}" -PsigningKey="${{ inputs.signing-key }}" -PsigningPassword="${{ inputs.signing-password }}" + run: ./gradlew clean assemble sign publishAndroidLibraryPublicationToMavenRepository -PisSnapshot=false -Pversion="${{ inputs.version }}" -PossrhUsername="${{ inputs.ossr-username }}" -PossrhPassword="${{ inputs.ossr-token }}" -PsigningKey="${{ inputs.signing-key }}" -PsigningPassword="${{ inputs.signing-password }}" diff --git a/.github/workflows/java-release.yml b/.github/workflows/java-release.yml index 3f81eb14..6795ffa0 100644 --- a/.github/workflows/java-release.yml +++ b/.github/workflows/java-release.yml @@ -12,7 +12,7 @@ on: secrets: ossr-username: required: true - ossr-password: + ossr-token: required: true signing-key: required: true @@ -73,7 +73,7 @@ jobs: is-android: ${{ inputs.is-android }} version: ${{ steps.get_version.outputs.version }} ossr-username: ${{ secrets.ossr-username }} - ossr-password: ${{ secrets.ossr-password }} + ossr-token: ${{ secrets.ossr-token }} signing-key: ${{ secrets.signing-key }} signing-password: ${{ secrets.signing-password }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 63482cca..17648ff4 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -21,7 +21,7 @@ jobs: is-android: false secrets: ossr-username: ${{ secrets.OSSR_USERNAME }} - ossr-password: ${{ secrets.OSSR_PASSWORD }} + ossr-token: ${{ secrets.OSSR_TOKEN }} signing-key: ${{ secrets.SIGNING_KEY }} signing-password: ${{ secrets.SIGNING_PASSWORD }} github-token: ${{ secrets.GITHUB_TOKEN }} From 51a8f82e3e3f005bd150be16cb54fb37c8ca2ac8 Mon Sep 17 00:00:00 2001 From: tanya-sinha_atko Date: Mon, 9 Sep 2024 18:34:45 +0530 Subject: [PATCH 09/32] updated action.yml file --- .github/actions/maven-publish/action.yml | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/.github/actions/maven-publish/action.yml b/.github/actions/maven-publish/action.yml index 2152527e..33336593 100644 --- a/.github/actions/maven-publish/action.yml +++ b/.github/actions/maven-publish/action.yml @@ -33,12 +33,11 @@ runs: - uses: gradle/wrapper-validation-action@56b90f209b02bf6d1deae490e9ef18b21a389cd4 # pin@1.1.0 - - name: Publish Java + - name: Publish Android/Java Packages to Maven shell: bash - if: inputs.is-android == 'false' - run: ./gradlew clean assemble sign publishMavenJavaPublicationToMavenRepository -PisSnapshot=false -Pversion="${{ inputs.version }}" -PossrhUsername="${{ inputs.ossr-username }}" -PossrhPassword="${{ inputs.ossr-token }}" -PsigningKey="${{ inputs.signing-key }}" -PsigningPassword="${{ inputs.signing-password }}" - - - name: Publish Android - shell: bash - if: inputs.is-android == 'true' - run: ./gradlew clean assemble sign publishAndroidLibraryPublicationToMavenRepository -PisSnapshot=false -Pversion="${{ inputs.version }}" -PossrhUsername="${{ inputs.ossr-username }}" -PossrhPassword="${{ inputs.ossr-token }}" -PsigningKey="${{ inputs.signing-key }}" -PsigningPassword="${{ inputs.signing-password }}" + run: ./gradlew publish -PisSnapshot=false --stacktrace + env: + MAVEN_USERNAME: ${{ inputs.ossr-username }} + MAVEN_PASSWORD: ${{ inputs.ossr-token }} + SIGNING_KEY: ${{ inputs.signing-key}} + SIGNING_PASSWORD: ${{ inputs.signing-password}} From 34b83534d996b08f0df352be54789ce659831f30 Mon Sep 17 00:00:00 2001 From: Tanya Sinha Date: Wed, 11 Sep 2024 18:27:07 +0530 Subject: [PATCH 10/32] Release 2.13.0 (#663) --- .version | 2 +- CHANGELOG.md | 6 ++++++ README.md | 4 ++-- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/.version b/.version index d8b69897..fb2c0766 100644 --- a/.version +++ b/.version @@ -1 +1 @@ -2.12.0 +2.13.0 diff --git a/CHANGELOG.md b/CHANGELOG.md index f255a77a..f9a6f400 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Change Log +## [2.13.0](https://github.com/auth0/auth0-java/tree/2.13.0) (2024-09-11) +[Full Changelog](https://github.com/auth0/auth0-java/compare/2.12.0...2.13.0) + +**Added** +- Add sessions and refresh tokens to Users Management API [\#661](https://github.com/auth0/auth0-java/pull/661) ([tanya732](https://github.com/tanya732)) + ## [2.12.0](https://github.com/auth0/auth0-java/tree/2.12.0) (2024-05-29) [Full Changelog](https://github.com/auth0/auth0-java/compare/2.11.0...2.12.0) diff --git a/README.md b/README.md index 0b52bb87..dc686268 100644 --- a/README.md +++ b/README.md @@ -34,14 +34,14 @@ Add the dependency via Maven: com.auth0 auth0 - 2.12.0 + 2.13.0 ``` or Gradle: ```gradle -implementation 'com.auth0:auth0:2.12.0' +implementation 'com.auth0:auth0:2.13.0' ``` ### Configure the SDK From 8671a1df93965bdcf49cf86375e950434e6458e0 Mon Sep 17 00:00:00 2001 From: Tanya Sinha Date: Fri, 20 Sep 2024 17:20:05 +0530 Subject: [PATCH 11/32] Fix maven release changes (#665) --- .github/actions/maven-publish/action.yml | 9 +- .github/workflows/java-release.yml | 6 +- build.gradle | 107 ++++++++++++++++------ gradle.properties | 21 +++++ gradle/maven-publish.gradle | 111 +++++++++++++++++++++++ gradle/versioning.gradle | 17 ++++ settings.gradle | 3 - 7 files changed, 230 insertions(+), 44 deletions(-) create mode 100644 gradle.properties create mode 100644 gradle/maven-publish.gradle create mode 100644 gradle/versioning.gradle diff --git a/.github/actions/maven-publish/action.yml b/.github/actions/maven-publish/action.yml index 33336593..2e0c5412 100644 --- a/.github/actions/maven-publish/action.yml +++ b/.github/actions/maven-publish/action.yml @@ -1,6 +1,8 @@ name: Publish release to Java inputs: + java-version: + required: true ossr-username: required: true ossr-token: @@ -9,12 +11,7 @@ inputs: required: true signing-password: required: true - java-version: - required: true - is-android: - required: true - version: - required: true + runs: using: composite diff --git a/.github/workflows/java-release.yml b/.github/workflows/java-release.yml index 6795ffa0..cc38e928 100644 --- a/.github/workflows/java-release.yml +++ b/.github/workflows/java-release.yml @@ -6,9 +6,7 @@ on: java-version: required: true type: string - is-android: - required: true - type: string + secrets: ossr-username: required: true @@ -70,8 +68,6 @@ jobs: - uses: ./.github/actions/maven-publish with: java-version: ${{ inputs.java-version }} - is-android: ${{ inputs.is-android }} - version: ${{ steps.get_version.outputs.version }} ossr-username: ${{ secrets.ossr-username }} ossr-token: ${{ secrets.ossr-token }} signing-key: ${{ secrets.signing-key }} diff --git a/build.gradle b/build.gradle index c91c8fcc..21a25440 100644 --- a/build.gradle +++ b/build.gradle @@ -1,43 +1,30 @@ +buildscript { + repositories { + jcenter() + } + + dependencies { + // https://github.com/melix/japicmp-gradle-plugin/issues/36 + classpath 'com.google.guava:guava:31.1-jre' + } +} + + plugins { id 'java' id 'jacoco' - id 'com.auth0.gradle.oss-library.java' + id 'me.champeau.gradle.japicmp' version '0.2.9' } repositories { mavenCentral() } -group = 'com.auth0' -logger.lifecycle("Using version ${version} for ${name} group $group") - -def signingKey = findProperty('signingKey') -def signingKeyPwd = findProperty('signingPassword') - -oss { - name 'auth0' - repository 'auth0-java' - organization 'auth0' - description 'Java client library for the Auth0 platform.' - baselineCompareVersion '2.0.0' - testInJavaVersions = [8, 11, 17] - skipAssertSigningConfiguration true - - developers { - auth0 { - displayName = 'Auth0' - email = 'oss@auth0.com' - } - lbalmaceda { - displayName = 'Luciano Balmaceda' - email = 'luciano.balmaceda@auth0.com' - } - } -} +apply from: rootProject.file('gradle/versioning.gradle') -signing { - useInMemoryPgpKeys(signingKey, signingKeyPwd) -} +version = getVersionFromFile() +group = GROUP +logger.lifecycle("Using version ${version} for ${name} group $group") jacocoTestReport { reports { @@ -63,6 +50,61 @@ compileTestJava { options.compilerArgs << "-Xlint:deprecation" << "-Werror" } +import me.champeau.gradle.japicmp.JapicmpTask + +project.afterEvaluate { + + def versions = project.ext.testInJavaVersions + for (pluginJavaTestVersion in versions) { + def taskName = "testInJava-${pluginJavaTestVersion}" + tasks.register(taskName, Test) { + def versionToUse = taskName.split("-").getAt(1) as Integer + description = "Runs unit tests on Java version ${versionToUse}." + project.logger.quiet("Test will be running in ${versionToUse}") + group = 'verification' + javaLauncher.set(javaToolchains.launcherFor { + languageVersion = JavaLanguageVersion.of(versionToUse) + }) + shouldRunAfter(tasks.named('test')) + } + tasks.named('check') { + dependsOn(taskName) + } + } + + project.configure(project) { + def baselineVersion = project.ext.baselineCompareVersion + task('apiDiff', type: JapicmpTask, dependsOn: 'jar') { + oldClasspath = files(getBaselineJar(project, baselineVersion)) + newClasspath = files(jar.archiveFile) + onlyModified = true + failOnModification = true + ignoreMissingClasses = true + htmlOutputFile = file("$buildDir/reports/apiDiff/apiDiff.html") + txtOutputFile = file("$buildDir/reports/apiDiff/apiDiff.txt") + doLast { + project.logger.quiet("Comparing against baseline version ${baselineVersion}") + } + } + } +} + +private static File getBaselineJar(Project project, String baselineVersion) { + // Use detached configuration: https://github.com/square/okhttp/blob/master/build.gradle#L270 + def group = project.group + try { + def baseline = "${project.group}:${project.name}:$baselineVersion" + project.group = 'virtual_group_for_japicmp' + def dependency = project.dependencies.create(baseline + "@jar") + return project.configurations.detachedConfiguration(dependency).files.find { + it.name == "${project.name}-${baselineVersion}.jar" + } + } finally { + project.group = group + } +} + + test { testLogging { events "skipped", "failed" @@ -75,6 +117,9 @@ ext { okhttpVersion = '4.11.0' hamcrestVersion = '2.2' jupiterVersion = '5.9.3' + + baselineCompareVersion = '2.0.0' + testInJavaVersions = [8, 11, 17, 21] } dependencies { @@ -105,3 +150,5 @@ dependencies { } } } + +apply from: rootProject.file('gradle/maven-publish.gradle') diff --git a/gradle.properties b/gradle.properties new file mode 100644 index 00000000..69714a96 --- /dev/null +++ b/gradle.properties @@ -0,0 +1,21 @@ +GROUP=com.auth0 +POM_ARTIFACT_ID=auth0 +VERSION_NAME=2.12.0 + +POM_NAME=auth0-java +POM_DESCRIPTION=Java client library for the Auth0 platform +POM_PACKAGING=jar + +POM_URL=https://github.com/auth0/auth0-java +POM_SCM_URL=https://github.com/auth0/auth0-java + +POM_SCM_CONNECTION=scm:git:https://github.com/auth0/auth0-java.git +POM_SCM_DEV_CONNECTION=scm:git:https://github.com/auth0/auth0-java.git + +POM_LICENCE_NAME=The MIT License (MIT) +POM_LICENCE_URL=https://raw.githubusercontent.com/auth0/auth0-java/master/LICENSE +POM_LICENCE_DIST=repo + +POM_DEVELOPER_ID=auth0 +POM_DEVELOPER_NAME=Auth0 +POM_DEVELOPER_EMAIL=oss@auth0.com diff --git a/gradle/maven-publish.gradle b/gradle/maven-publish.gradle new file mode 100644 index 00000000..beb5f464 --- /dev/null +++ b/gradle/maven-publish.gradle @@ -0,0 +1,111 @@ +apply plugin: 'maven-publish' +apply plugin: 'signing' + +task('sourcesJar', type: Jar, dependsOn: classes) { + archiveClassifier = 'sources' + from sourceSets.main.allSource +} + +task('javadocJar', type: Jar, dependsOn: javadoc) { + archiveClassifier = 'javadoc' + from javadoc.getDestinationDir() +} +tasks.withType(Javadoc).configureEach { + javadocTool = javaToolchains.javadocToolFor { + // Use latest JDK for javadoc generation + languageVersion = JavaLanguageVersion.of(17) + } +} + +javadoc { + // Specify the Java version that the project will use + options.addStringOption('-release', "8") +} +artifacts { + archives sourcesJar, javadocJar +} + + +final releaseRepositoryUrl = "https://oss.sonatype.org/service/local/staging/deploy/maven2/" +final snapshotRepositoryUrl = "https://oss.sonatype.org/content/repositories/snapshots/" + +publishing { + publications { + mavenJava(MavenPublication) { + + groupId = GROUP + artifactId = POM_ARTIFACT_ID + version = getVersionName() + + artifact("$buildDir/libs/${project.name}-${version}.jar") + artifact sourcesJar + artifact javadocJar + + pom { + name = POM_NAME + packaging = POM_PACKAGING + description = POM_DESCRIPTION + url = POM_URL + + licenses { + license { + name = POM_LICENCE_NAME + url = POM_LICENCE_URL + distribution = POM_LICENCE_DIST + } + } + + developers { + developer { + id = POM_DEVELOPER_ID + name = POM_DEVELOPER_NAME + email = POM_DEVELOPER_EMAIL + } + } + + scm { + url = POM_SCM_URL + connection = POM_SCM_CONNECTION + developerConnection = POM_SCM_DEV_CONNECTION + } + + pom.withXml { + def dependenciesNode = asNode().appendNode('dependencies') + + project.configurations.implementation.allDependencies.each { + def dependencyNode = dependenciesNode.appendNode('dependency') + dependencyNode.appendNode('groupId', it.group) + dependencyNode.appendNode('artifactId', it.name) + dependencyNode.appendNode('version', it.version) + } + } + } + } + } + repositories { + maven { + name = "sonatype" + url = version.endsWith('SNAPSHOT') ? snapshotRepositoryUrl : releaseRepositoryUrl + credentials { + username = System.getenv("MAVEN_USERNAME") + password = System.getenv("MAVEN_PASSWORD") + } + } + } +} + +signing { + def signingKey = System.getenv("SIGNING_KEY") + def signingPassword = System.getenv("SIGNING_PASSWORD") + useInMemoryPgpKeys(signingKey, signingPassword) + + sign publishing.publications.mavenJava +} + +javadoc { + if(JavaVersion.current().isJava9Compatible()) { + options.addBooleanOption('html5', true) + } +} + + diff --git a/gradle/versioning.gradle b/gradle/versioning.gradle new file mode 100644 index 00000000..9a8dae58 --- /dev/null +++ b/gradle/versioning.gradle @@ -0,0 +1,17 @@ +def getVersionFromFile() { + def versionFile = rootProject.file('.version') + return versionFile.text.readLines().first().trim() +} + +def isSnapshot() { + return hasProperty('isSnapshot') ? isSnapshot.toBoolean() : true +} + +def getVersionName() { + return isSnapshot() ? project.version+"-SNAPSHOT" : project.version +} + +ext { + getVersionName = this.&getVersionName + getVersionFromFile = this.&getVersionFromFile +} diff --git a/settings.gradle b/settings.gradle index ed6821be..a32c80c4 100644 --- a/settings.gradle +++ b/settings.gradle @@ -2,9 +2,6 @@ pluginManagement { repositories { gradlePluginPortal() } - plugins { - id 'com.auth0.gradle.oss-library.java' version '0.18.0' - } } rootProject.name = 'auth0' From 0bb7cba9b529441b1fcbadf356216d8c0728f07c Mon Sep 17 00:00:00 2001 From: Tanya Sinha Date: Fri, 20 Sep 2024 17:40:40 +0530 Subject: [PATCH 12/32] Updated release.yml workflow (#666) --- .github/workflows/release.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 17648ff4..715a0bc8 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -18,7 +18,6 @@ jobs: uses: ./.github/workflows/java-release.yml with: java-version: 8.0.382-tem - is-android: false secrets: ossr-username: ${{ secrets.OSSR_USERNAME }} ossr-token: ${{ secrets.OSSR_TOKEN }} From ae24b7abfe68d347beac0c183aabed71a56ca759 Mon Sep 17 00:00:00 2001 From: Tanya Sinha Date: Mon, 23 Sep 2024 11:03:43 +0530 Subject: [PATCH 13/32] Updated gradle config (#667) --- gradle/maven-publish.gradle | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/gradle/maven-publish.gradle b/gradle/maven-publish.gradle index beb5f464..bec9fc5a 100644 --- a/gradle/maven-publish.gradle +++ b/gradle/maven-publish.gradle @@ -108,4 +108,8 @@ javadoc { } } +tasks.named('publish').configure { + dependsOn tasks.named('assemble') +} + From f6df9ce28e7e81a7a97a1a51231b5bec5a6c78b2 Mon Sep 17 00:00:00 2001 From: Tanya Sinha Date: Tue, 1 Oct 2024 12:51:03 +0530 Subject: [PATCH 14/32] Added support for HRI phase 2 changes (#668) --- .../com/auth0/json/mgmt/client/Client.java | 17 ++++++ .../resourceserver/ProofOfPossession.java | 54 +++++++++++++++++++ .../mgmt/resourceserver/ResourceServer.java | 17 ++++++ .../auth0/json/mgmt/ResourceServerTest.java | 7 +++ .../auth0/json/mgmt/client/ClientTest.java | 5 ++ src/test/resources/mgmt/client.json | 3 +- src/test/resources/mgmt/resource_server.json | 4 ++ 7 files changed, 106 insertions(+), 1 deletion(-) create mode 100644 src/main/java/com/auth0/json/mgmt/resourceserver/ProofOfPossession.java diff --git a/src/main/java/com/auth0/json/mgmt/client/Client.java b/src/main/java/com/auth0/json/mgmt/client/Client.java index 5fa11169..99ffeefa 100644 --- a/src/main/java/com/auth0/json/mgmt/client/Client.java +++ b/src/main/java/com/auth0/json/mgmt/client/Client.java @@ -100,6 +100,8 @@ public class Client { private SignedRequest signedRequest; @JsonProperty("compliance_level") private String complianceLevel; + @JsonProperty("require_proof_of_possession") + private Boolean requireProofOfPossession; /** * Getter for the name of the tenant this client belongs to. @@ -872,5 +874,20 @@ public String getComplianceLevel() { public void setComplianceLevel(String complianceLevel) { this.complianceLevel = complianceLevel; } + + /** + * @return the value of the {@code require_proof_of_possession} field + */ + public Boolean getRequireProofOfPossession() { + return requireProofOfPossession; + } + + /** + * Sets the value of the {@code require_proof_of_possession} field + * @param requireProofOfPossession the value of the {@code require_proof_of_possession} field + */ + public void setRequireProofOfPossession(Boolean requireProofOfPossession) { + this.requireProofOfPossession = requireProofOfPossession; + } } diff --git a/src/main/java/com/auth0/json/mgmt/resourceserver/ProofOfPossession.java b/src/main/java/com/auth0/json/mgmt/resourceserver/ProofOfPossession.java new file mode 100644 index 00000000..5c7be6eb --- /dev/null +++ b/src/main/java/com/auth0/json/mgmt/resourceserver/ProofOfPossession.java @@ -0,0 +1,54 @@ +package com.auth0.json.mgmt.resourceserver; + +import com.fasterxml.jackson.annotation.JsonCreator; +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 ProofOfPossession { + + @JsonProperty("mechanism") + private String mechanism; + @JsonProperty("required") + private Boolean required; + + @JsonCreator + public ProofOfPossession(@JsonProperty("mechanism") String mechanism, @JsonProperty("required") Boolean required) { + this.mechanism = mechanism; + this.required = required; + } + + /** + * Getter for the mechanism of the Proof of Possession. + * @return the mechanism of the Proof of Possession. + */ + public String getMechanism() { + return mechanism; + } + + /** + * Setter for the mechanism of the Proof of Possession. + * @param mechanism the mechanism of the Proof of Possession. + */ + public void setMechanism(String mechanism) { + this.mechanism = mechanism; + } + + /** + * Getter for the required flag of the Proof of Possession. + * @return the required flag of the Proof of Possession. + */ + public Boolean getRequired() { + return required; + } + + /** + * Setter for the required flag of the Proof of Possession. + * @param required the required flag of the Proof of Possession. + */ + public void setRequired(Boolean required) { + this.required = required; + } +} diff --git a/src/main/java/com/auth0/json/mgmt/resourceserver/ResourceServer.java b/src/main/java/com/auth0/json/mgmt/resourceserver/ResourceServer.java index 6161eb3e..0c80f5c0 100644 --- a/src/main/java/com/auth0/json/mgmt/resourceserver/ResourceServer.java +++ b/src/main/java/com/auth0/json/mgmt/resourceserver/ResourceServer.java @@ -45,6 +45,8 @@ public class ResourceServer { private List authorizationDetails; @JsonProperty("token_encryption") private TokenEncryption tokenEncryption; + @JsonProperty("proof_of_possession") + private ProofOfPossession proofOfPossession; @JsonCreator public ResourceServer(@JsonProperty("identifier") String identifier) { @@ -228,4 +230,19 @@ public TokenEncryption getTokenEncryption() { public void setTokenEncryption(TokenEncryption tokenEncryption) { this.tokenEncryption = tokenEncryption; } + + /** + * @return the value of the {@code proof_of_possession} field. + */ + public ProofOfPossession getProofOfPossession() { + return proofOfPossession; + } + + /** + * Sets the value of the {@code proof_of_possession} field. + * @param proofOfPossession the value of the {@code proof_of_possession} field. + */ + public void setProofOfPossession(ProofOfPossession proofOfPossession) { + this.proofOfPossession = proofOfPossession; + } } diff --git a/src/test/java/com/auth0/json/mgmt/ResourceServerTest.java b/src/test/java/com/auth0/json/mgmt/ResourceServerTest.java index 66e52359..a5e6bd04 100644 --- a/src/test/java/com/auth0/json/mgmt/ResourceServerTest.java +++ b/src/test/java/com/auth0/json/mgmt/ResourceServerTest.java @@ -1,5 +1,6 @@ package com.auth0.json.mgmt; +import com.auth0.json.JsonMatcher; import com.auth0.json.JsonTest; import com.auth0.json.mgmt.resourceserver.*; import org.junit.jupiter.api.Test; @@ -12,6 +13,7 @@ import static com.auth0.json.JsonMatcher.hasEntry; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.*; +import static org.hamcrest.Matchers.containsString; public class ResourceServerTest extends JsonTest { private final static String RESOURCE_SERVER_JSON = "src/test/resources/mgmt/resource_server.json"; @@ -42,6 +44,8 @@ public void deserialize() throws Exception { assertThat(deserialized.getTokenEncryption().getEncryptionKey().getKid(), is("my kid")); assertThat(deserialized.getTokenEncryption().getEncryptionKey().getName(), is("my JWE public key")); assertThat(deserialized.getTokenEncryption().getEncryptionKey().getThumbprintSha256(), is("thumbprint")); + assertThat(deserialized.getProofOfPossession().getMechanism(), is("mtls")); + assertThat(deserialized.getProofOfPossession().getRequired(), is(true)); } @Test @@ -77,6 +81,8 @@ public void serialize() throws Exception { encryptionKey.setPem("pem"); TokenEncryption tokenEncryption = new TokenEncryption("format", encryptionKey); entity.setTokenEncryption(tokenEncryption); + ProofOfPossession proofOfPossession = new ProofOfPossession("mtls", true); + entity.setProofOfPossession(proofOfPossession); String json = toJSON(entity); @@ -96,5 +102,6 @@ public void serialize() throws Exception { assertThat(json, hasEntry("consent_policy", "transactional-authorization-with-mfa")); assertThat(json, hasEntry("authorization_details", notNullValue())); assertThat(json, hasEntry("token_encryption", containsString("{\"format\":\"format\",\"encryption_key\":{\"name\":\"name\",\"alg\":\"alg\",\"pem\":\"pem\",\"kid\":\"kid\"}}"))); + assertThat(json, hasEntry("proof_of_possession", containsString("{\"mechanism\":\"mtls\",\"required\":true}"))); } } diff --git a/src/test/java/com/auth0/json/mgmt/client/ClientTest.java b/src/test/java/com/auth0/json/mgmt/client/ClientTest.java index 307f82b8..11f901ba 100644 --- a/src/test/java/com/auth0/json/mgmt/client/ClientTest.java +++ b/src/test/java/com/auth0/json/mgmt/client/ClientTest.java @@ -135,6 +135,7 @@ public class ClientTest extends JsonTest { " }\n" + " ]\n" + " },\n" + + " \"require_proof_of_possession\": true,\n" + " \"compliance_level\": \"fapi1_adv_pkj_par\"\n" + "}"; @@ -179,6 +180,7 @@ public void shouldSerialize() throws Exception { client.setRefreshToken(refreshToken); client.setOrganizationUsage("require"); client.setOrganizationRequireBehavior("pre_login_prompt"); + client.setRequireProofOfPossession(true); Credential credential = new Credential("public_key", "PEM"); PrivateKeyJwt privateKeyJwt = new PrivateKeyJwt(Collections.singletonList(credential)); @@ -251,6 +253,7 @@ public void shouldSerialize() throws Exception { assertThat(serialized, JsonMatcher.hasEntry("oidc_backchannel_logout", containsString("{\"backchannel_logout_urls\":[\"http://acme.eu.auth0.com/events\"]}"))); assertThat(serialized, JsonMatcher.hasEntry("signed_request_object", containsString("{\"required\":true,\"credentials\":[{\"credential_type\":\"public_key\",\"name\":\"cred name\",\"pem\":\"pem\"}]}"))); assertThat(serialized, JsonMatcher.hasEntry("compliance_level", "fapi1_adv_pkj_par")); + assertThat(serialized, JsonMatcher.hasEntry("require_proof_of_possession", true)); } @Test @@ -326,6 +329,8 @@ public void shouldDeserialize() throws Exception { assertThat(client.getSignedRequest().getCredentials().get(0).getName(), is("My JAR credential")); assertThat(client.getSignedRequest().getCredentials().get(0).getCreatedAt(), is(Date.from(Instant.parse("2024-03-14T11:34:28.893Z")))); assertThat(client.getSignedRequest().getCredentials().get(0).getUpdatedAt(), is(Date.from(Instant.parse("2024-03-14T11:34:28.893Z")))); + + assertThat(client.getRequireProofOfPossession(), is(true)); } @Test diff --git a/src/test/resources/mgmt/client.json b/src/test/resources/mgmt/client.json index daca48ca..a3395042 100644 --- a/src/test/resources/mgmt/client.json +++ b/src/test/resources/mgmt/client.json @@ -90,5 +90,6 @@ } ] }, - "compliance_level": "fapi1_adv_pkj_par" + "compliance_level": "fapi1_adv_pkj_par", + "require_proof_of_possession": true } diff --git a/src/test/resources/mgmt/resource_server.json b/src/test/resources/mgmt/resource_server.json index a383d78f..75284b5a 100644 --- a/src/test/resources/mgmt/resource_server.json +++ b/src/test/resources/mgmt/resource_server.json @@ -36,5 +36,9 @@ "alg": "RSA-OAEP-256", "thumbprint_sha256": "thumbprint" } + }, + "proof_of_possession": { + "mechanism": "mtls", + "required": true } } From 625b068aecd113ac1e1f1597aa3b620ec565de19 Mon Sep 17 00:00:00 2001 From: Tanya Sinha Date: Wed, 16 Oct 2024 14:46:57 +0530 Subject: [PATCH 15/32] Added client credentials changes (#670) --- .../client/mgmt/filter/ClientFilter.java | 11 ++ .../OrganizationClientGrantsFilter.java | 11 ++ .../mgmt/filter/ResourceServersFilter.java | 24 ++++ .../com/auth0/json/mgmt/client/Client.java | 18 +++ .../client/ClientDefaultOrganization.java | 57 ++++++++ .../auth0/client/mgmt/ClientsEntityTest.java | 19 +++ .../client/mgmt/OrganizationEntityTest.java | 136 +++++++++++++++++- .../client/mgmt/ResourceServerEntityTest.java | 46 ++++++ .../auth0/json/mgmt/client/ClientTest.java | 12 +- 9 files changed, 329 insertions(+), 5 deletions(-) create mode 100644 src/main/java/com/auth0/json/mgmt/client/ClientDefaultOrganization.java diff --git a/src/main/java/com/auth0/client/mgmt/filter/ClientFilter.java b/src/main/java/com/auth0/client/mgmt/filter/ClientFilter.java index 00e53e2f..0ce98687 100644 --- a/src/main/java/com/auth0/client/mgmt/filter/ClientFilter.java +++ b/src/main/java/com/auth0/client/mgmt/filter/ClientFilter.java @@ -71,4 +71,15 @@ public ClientFilter withFields(String fields, boolean includeFields) { super.withFields(fields, includeFields); return this; } + + /** + * Filter by custom query + * + * @param query the query string using Lucene query syntax + * @return this filter instance + */ + public ClientFilter withQuery(String query) { + parameters.put("q", query); + return this; + } } diff --git a/src/main/java/com/auth0/client/mgmt/filter/OrganizationClientGrantsFilter.java b/src/main/java/com/auth0/client/mgmt/filter/OrganizationClientGrantsFilter.java index e607da02..5230a414 100644 --- a/src/main/java/com/auth0/client/mgmt/filter/OrganizationClientGrantsFilter.java +++ b/src/main/java/com/auth0/client/mgmt/filter/OrganizationClientGrantsFilter.java @@ -51,4 +51,15 @@ public OrganizationClientGrantsFilter withTotals(boolean includeTotals) { parameters.put("include_totals", includeTotals); return this; } + + /** + * Filter by grant IDs + * + * @param grantIds comma-separated list of grant IDs to filter results on. + * @return this filter instance + */ + public OrganizationClientGrantsFilter withGrantIds(String grantIds) { + parameters.put("grant_ids", grantIds); + return this; + } } diff --git a/src/main/java/com/auth0/client/mgmt/filter/ResourceServersFilter.java b/src/main/java/com/auth0/client/mgmt/filter/ResourceServersFilter.java index 4ff64843..ddf81daf 100644 --- a/src/main/java/com/auth0/client/mgmt/filter/ResourceServersFilter.java +++ b/src/main/java/com/auth0/client/mgmt/filter/ResourceServersFilter.java @@ -33,4 +33,28 @@ public ResourceServersFilter withTotals(boolean includeTotals) { return this; } + /** + * Filter by specific identifier IDs (i.e. audience) + * + * @param identifiers the identifier IDs to filter by + * @return this filter instance + */ + public ResourceServersFilter withIdentifiers(String identifiers) { + parameters.put("identifiers", identifiers); + return this; + } + + /** + * Filter by checkpoint pagination support + * + * @param from the starting index identifier + * @param take the number of items to retrieve + * @return this filter instance + */ + public ResourceServersFilter withCheckpointPagination(String from, int take) { + parameters.put("from", from); + parameters.put("take", take); + return this; + } + } diff --git a/src/main/java/com/auth0/json/mgmt/client/Client.java b/src/main/java/com/auth0/json/mgmt/client/Client.java index 99ffeefa..0b0e705e 100644 --- a/src/main/java/com/auth0/json/mgmt/client/Client.java +++ b/src/main/java/com/auth0/json/mgmt/client/Client.java @@ -102,6 +102,8 @@ public class Client { private String complianceLevel; @JsonProperty("require_proof_of_possession") private Boolean requireProofOfPossession; + @JsonProperty("default_organization") + private ClientDefaultOrganization defaultOrganization; /** * Getter for the name of the tenant this client belongs to. @@ -889,5 +891,21 @@ public Boolean getRequireProofOfPossession() { public void setRequireProofOfPossession(Boolean requireProofOfPossession) { this.requireProofOfPossession = requireProofOfPossession; } + + /** + * Getter for the default organization configuration. + * @return the default organization configuration. + */ + public ClientDefaultOrganization getDefaultOrganization() { + return defaultOrganization; + } + + /** + * Setter for the default organization configuration. + * @param defaultOrganization the default organization configuration to set. + */ + public void setDefaultOrganization(ClientDefaultOrganization defaultOrganization) { + this.defaultOrganization = defaultOrganization; + } } diff --git a/src/main/java/com/auth0/json/mgmt/client/ClientDefaultOrganization.java b/src/main/java/com/auth0/json/mgmt/client/ClientDefaultOrganization.java new file mode 100644 index 00000000..3512f6b8 --- /dev/null +++ b/src/main/java/com/auth0/json/mgmt/client/ClientDefaultOrganization.java @@ -0,0 +1,57 @@ +package com.auth0.json.mgmt.client; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; + +import java.util.List; + +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +public class ClientDefaultOrganization { + @JsonProperty("flows") + private List flows; + @JsonProperty("organization_id") + private String organizationId; + + public ClientDefaultOrganization() { + + } + + public ClientDefaultOrganization(List flows, String organizationId) { + this.flows = flows; + this.organizationId = organizationId; + } + + /** + * Getter for the supported flows. + * @return the supported flows. + */ + public List getFlows() { + return flows; + } + + /** + * Setter for the supported flows. + * @param flows the supported flows to set. + */ + public void setFlows(List flows) { + this.flows = flows; + } + + /** + * Getter for the organization_id. + * @return the organization_id. + */ + public String getOrganizationId() { + return organizationId; + } + + /** + * Setter for the organization_id. + * @param organizationId the organization_id to set. + */ + public void setOrganizationId(String organizationId) { + this.organizationId = organizationId; + } +} diff --git a/src/test/java/com/auth0/client/mgmt/ClientsEntityTest.java b/src/test/java/com/auth0/client/mgmt/ClientsEntityTest.java index a04ecfc3..4e574254 100644 --- a/src/test/java/com/auth0/client/mgmt/ClientsEntityTest.java +++ b/src/test/java/com/auth0/client/mgmt/ClientsEntityTest.java @@ -125,6 +125,25 @@ public void shouldListClientsWithAdditionalProperties() throws Exception { assertThat(response.getItems(), hasSize(2)); } + @Test + public void shouldListClientsWithQuery() throws Exception { + ClientFilter filter = new ClientFilter().withQuery("client_grant.organization_id:" + "org_123"); + Request request = api.clients().list(filter); + assertThat(request, is(notNullValue())); + + server.jsonResponse(MGMT_CLIENTS_PAGED_LIST, 200); + ClientsPage response = request.execute().getBody(); + RecordedRequest recordedRequest = server.takeRequest(); + + assertThat(recordedRequest, hasMethodAndPath(HttpMethod.GET, "/api/v2/clients")); + assertThat(recordedRequest, hasHeader("Content-Type", "application/json")); + assertThat(recordedRequest, hasHeader("Authorization", "Bearer apiToken")); + assertThat(recordedRequest, hasQueryParameter("q", "client_grant.organization_id:" + "org_123")); + + assertThat(response, is(notNullValue())); + assertThat(response.getItems(), hasSize(2)); + } + @Test public void shouldThrowOnGetClientWithNullId() { verifyThrows(IllegalArgumentException.class, diff --git a/src/test/java/com/auth0/client/mgmt/OrganizationEntityTest.java b/src/test/java/com/auth0/client/mgmt/OrganizationEntityTest.java index 7dc06479..bfa20956 100644 --- a/src/test/java/com/auth0/client/mgmt/OrganizationEntityTest.java +++ b/src/test/java/com/auth0/client/mgmt/OrganizationEntityTest.java @@ -1,11 +1,15 @@ package com.auth0.client.mgmt; import com.auth0.client.MockServer; -import com.auth0.client.mgmt.filter.FieldsFilter; -import com.auth0.client.mgmt.filter.InvitationsFilter; -import com.auth0.client.mgmt.filter.OrganizationClientGrantsFilter; -import com.auth0.client.mgmt.filter.PageFilter; +import com.auth0.client.mgmt.filter.*; +import com.auth0.exception.Auth0Exception; +import com.auth0.json.mgmt.client.Client; +import com.auth0.json.mgmt.client.ClientDefaultOrganization; +import com.auth0.json.mgmt.client.ClientsPage; +import com.auth0.json.mgmt.clientgrants.ClientGrant; +import com.auth0.json.mgmt.clientgrants.ClientGrantsPage; import com.auth0.json.mgmt.organizations.*; +import com.auth0.json.mgmt.resourceserver.ResourceServer; import com.auth0.json.mgmt.roles.RolesPage; import com.auth0.net.Request; import com.auth0.net.client.HttpMethod; @@ -1082,6 +1086,32 @@ public void shouldListClientGrantsWithFilter() throws Exception { assertThat(response.getItems(), hasSize(1)); } + @Test + public void shouldListClientGrantsWithGrantIds() throws Exception { + OrganizationClientGrantsFilter filter = new OrganizationClientGrantsFilter(); + filter + .withClientId("clientId") + .withAudience("https://api-identifier/") + .withGrantIds("cgr_123456789012,cgr_abcdefghijkl"); + + Request request = api.organizations().listClientGrants("orgId", filter); + assertThat(request, is(notNullValue())); + + server.jsonResponse(ORGANIZATION_CLIENT_GRANTS_PAGED_LIST, 200); + OrganizationClientGrantsPage response = request.execute().getBody(); + RecordedRequest recordedRequest = server.takeRequest(); + + assertThat(recordedRequest, hasMethodAndPath(HttpMethod.GET, "/api/v2/organizations/orgId/client-grants")); + assertThat(recordedRequest, hasHeader("Content-Type", "application/json")); + assertThat(recordedRequest, hasHeader("Authorization", "Bearer apiToken")); + assertThat(recordedRequest, hasQueryParameter("grant_ids", "cgr_123456789012,cgr_abcdefghijkl")); + assertThat(recordedRequest, hasQueryParameter("audience", "https://api-identifier/")); + assertThat(recordedRequest, hasQueryParameter("client_id", "clientId")); + + assertThat(response, is(notNullValue())); + assertThat(response.getItems(), hasSize(1)); + } + @Test public void shouldThrowOnGetClientGrantsWithNullOrgId() { verifyThrows(IllegalArgumentException.class, @@ -1153,4 +1183,102 @@ public void shouldThrowOnDeleteClientGreatWithNullGrant() { () -> api.organizations().deleteClientGrant("org_1213", null), "'client grant ID' cannot be null!"); } + + @Test + public void testClientGrantsWithOrg() throws Auth0Exception { + + Organization organization = null; + ResourceServer resourceServer = null; + Client client = null; + ClientGrant clientGrant = null; + OrganizationClientGrant organizationClientGrant = null; + + try { + //Create organization + organization = givenAnOrganization(); + + //Create resource server + resourceServer = givenAResourceServer(); + + //Create client + client = createNewClient(organization.getId()); + + //Create client grants + clientGrant = createNewClientGrant(client, resourceServer); + + //Associates the grant with an organization. + organizationClientGrant = api.organizations().addClientGrant(organization.getId(), new CreateOrganizationClientGrantRequestBody(clientGrant.getId())).execute().getBody(); + + ClientFilter clientFilter = new ClientFilter(); + clientFilter.withQuery("client_grant.organization_id:" + organization.getId()); + + // List all clients associated with a ClientGrant given an organizationID as query param + ClientsPage clientsPage = api.clients().list(clientFilter).execute().getBody(); + + for (Client c : clientsPage.getItems()) { + assertThat(organization.getId(), is(c.getDefaultOrganization().getOrganizationId())); + } + + OrganizationClientGrantsFilter filter = new OrganizationClientGrantsFilter(); + filter.withGrantIds(clientGrant.getId()); + + // List all ClientGrants given a list of grant_ids as query param + OrganizationClientGrantsPage organizationClientGrantsPage = api.organizations().listClientGrants(organization.getId(), filter).execute().getBody(); + + assertThat(organizationClientGrantsPage.getItems().size(), is(1)); + assertThat(organizationClientGrantsPage.getItems().get(0).getClientId(), is(clientGrant.getClientId())); + + // Remove the associated ClientGrants + api.organizations().deleteClientGrant(organization.getId(), organizationClientGrant.getId()).execute(); + + // List all ClientGrants which should be an empty list since grant has been removed from the organization. + OrganizationClientGrantsPage organizationClientGrantsPage1 = api.organizations().listClientGrants(organization.getId(), filter).execute().getBody(); + assertThat(organizationClientGrantsPage1.getItems().size(), is(0)); + + // Delete the ClientGrant. + api.clientGrants().delete(clientGrant.getId()).execute(); + + // Retrieve the ClientGrant and ensure error is return since grant has been deleted. + ClientGrantsPage clientGrantsPage = api.clientGrants().list(new ClientGrantsFilter().withClientId(client.getClientId())).execute().getBody(); + assertThat(clientGrantsPage.getItems().size(), is(0)); + } + catch (Exception ex){ + ex.printStackTrace(); + } + } + + private ClientGrant createNewClientGrant(Client client, ResourceServer resourceServer) throws Auth0Exception { + ClientGrant clientGrant = new ClientGrant(); + clientGrant.setClientId(client.getClientId()); + clientGrant.setAudience(resourceServer.getIdentifier()); + clientGrant.setScope(Arrays.asList("create:resource", "create:organization_client_grants")); + clientGrant.setAllowAnyOrganization(true); + clientGrant.setOrganizationUsage("allow"); + + return api.clientGrants().create(client.getClientId(), resourceServer.getIdentifier(), new String[]{"create:resource", "create:organization_client_grants"}).execute().getBody(); + } + + private Client createNewClient(String orgId) throws Auth0Exception { + Client client = new Client("Test Client (" + System.currentTimeMillis() + ")"); + client.setDescription("This is just a test client."); + client.setOrganizationUsage("allow"); + client.setDefaultOrganization(new ClientDefaultOrganization(Arrays.asList("client_credentials"), orgId)); + + return api.clients().create(client).execute().getBody(); + } + + private Organization givenAnOrganization() throws Auth0Exception { + Organization organization = new Organization(); + organization.setName("test-organization"); + organization.setDisplayName("test-organization"); + + return api.organizations().create(organization).execute().getBody(); + } + + private ResourceServer givenAResourceServer() throws Auth0Exception { + ResourceServer resourceServer = new ResourceServer("https://www.tanyaisawesome.com"); + resourceServer.setName("tanyaisawesome"); + + return api.resourceServers().create(resourceServer).execute().getBody(); + } } diff --git a/src/test/java/com/auth0/client/mgmt/ResourceServerEntityTest.java b/src/test/java/com/auth0/client/mgmt/ResourceServerEntityTest.java index e88c7a0f..e4f7d9fe 100644 --- a/src/test/java/com/auth0/client/mgmt/ResourceServerEntityTest.java +++ b/src/test/java/com/auth0/client/mgmt/ResourceServerEntityTest.java @@ -80,6 +80,52 @@ public void shouldListResourceServerWithTotals() throws Exception { assertThat(response.getLimit(), is(50)); } + @Test + public void shouldListResourceServerWithIdentifiers() throws Exception { + ResourceServersFilter filter = new ResourceServersFilter().withIdentifiers("identifier"); + Request request = api.resourceServers().list(filter); + assertThat(request, is(notNullValue())); + + server.jsonResponse(MGMT_RESOURCE_SERVERS_PAGED_LIST, 200); + ResourceServersPage response = request.execute().getBody(); + RecordedRequest recordedRequest = server.takeRequest(); + + assertThat(recordedRequest, hasMethodAndPath(HttpMethod.GET, "/api/v2/resource-servers")); + assertThat(recordedRequest, hasHeader("Content-Type", "application/json")); + assertThat(recordedRequest, hasHeader("Authorization", "Bearer apiToken")); + assertThat(recordedRequest, hasQueryParameter("identifiers", "identifier")); + + assertThat(response, is(notNullValue())); + assertThat(response.getItems(), hasSize(2)); + assertThat(response.getStart(), is(0)); + assertThat(response.getLength(), is(14)); + assertThat(response.getTotal(), is(14)); + assertThat(response.getLimit(), is(50)); + } + + @Test + public void shouldListResourceServerWithCheckpointPagination() throws Exception { + ResourceServersFilter filter = new ResourceServersFilter().withCheckpointPagination("tokenId2", 5); + Request request = api.resourceServers().list(filter); + assertThat(request, is(notNullValue())); + + server.jsonResponse(MGMT_RESOURCE_SERVERS_PAGED_LIST, 200); + ResourceServersPage response = request.execute().getBody(); + RecordedRequest recordedRequest = server.takeRequest(); + + assertThat(recordedRequest, hasMethodAndPath(HttpMethod.GET, "/api/v2/resource-servers")); + assertThat(recordedRequest, hasHeader("Content-Type", "application/json")); + assertThat(recordedRequest, hasHeader("Authorization", "Bearer apiToken")); + assertThat(recordedRequest, hasQueryParameter("from", "tokenId2")); + assertThat(recordedRequest, hasQueryParameter("take", "5")); + assertThat(response, is(notNullValue())); + assertThat(response.getItems(), hasSize(2)); + assertThat(response.getStart(), is(0)); + assertThat(response.getLength(), is(14)); + assertThat(response.getTotal(), is(14)); + assertThat(response.getLimit(), is(50)); + } + @Test public void shouldUpdateResourceServer() throws Exception { ResourceServer resourceServer = new ResourceServer("https://api.my-company.com/api/v2/"); diff --git a/src/test/java/com/auth0/json/mgmt/client/ClientTest.java b/src/test/java/com/auth0/json/mgmt/client/ClientTest.java index 11f901ba..05bbd465 100644 --- a/src/test/java/com/auth0/json/mgmt/client/ClientTest.java +++ b/src/test/java/com/auth0/json/mgmt/client/ClientTest.java @@ -136,7 +136,11 @@ public class ClientTest extends JsonTest { " ]\n" + " },\n" + " \"require_proof_of_possession\": true,\n" + - " \"compliance_level\": \"fapi1_adv_pkj_par\"\n" + + " \"compliance_level\": \"fapi1_adv_pkj_par\",\n" + + " \"default_organization\": {\n" + + " \"flows\": [\"client_credentials\"],\n" + + " \"organizations_id\": \"org_id\"\n" + + " }\n" + "}"; @Test @@ -214,6 +218,11 @@ public void shouldSerialize() throws Exception { client.setSignedRequest(signedRequest); client.setComplianceLevel("fapi1_adv_pkj_par"); + ClientDefaultOrganization defaultOrganization = new ClientDefaultOrganization(); + defaultOrganization.setFlows(Collections.singletonList("client_credentials")); + defaultOrganization.setOrganizationId("org_id"); + client.setDefaultOrganization(defaultOrganization); + String serialized = toJSON(client); assertThat(serialized, is(notNullValue())); @@ -254,6 +263,7 @@ public void shouldSerialize() throws Exception { assertThat(serialized, JsonMatcher.hasEntry("signed_request_object", containsString("{\"required\":true,\"credentials\":[{\"credential_type\":\"public_key\",\"name\":\"cred name\",\"pem\":\"pem\"}]}"))); assertThat(serialized, JsonMatcher.hasEntry("compliance_level", "fapi1_adv_pkj_par")); assertThat(serialized, JsonMatcher.hasEntry("require_proof_of_possession", true)); + assertThat(serialized, JsonMatcher.hasEntry("default_organization", notNullValue())); } @Test From 2a31b29fc7f6ee2d7884859c82ce1114e6782cd2 Mon Sep 17 00:00:00 2001 From: Tanya Sinha Date: Wed, 16 Oct 2024 14:53:51 +0530 Subject: [PATCH 16/32] SDKs support for Control Your Own Key (#671) --- .../com/auth0/client/mgmt/KeysEntity.java | 17 ++++++ .../com/auth0/net/EmptyBodyVoidRequest.java | 42 +++++++++++++++ .../com/auth0/client/mgmt/KeysEntityTest.java | 14 +++++ .../auth0/net/EmptyBodyVoidRequestTest.java | 53 +++++++++++++++++++ 4 files changed, 126 insertions(+) create mode 100644 src/main/java/com/auth0/net/EmptyBodyVoidRequest.java create mode 100644 src/test/java/com/auth0/net/EmptyBodyVoidRequestTest.java diff --git a/src/main/java/com/auth0/client/mgmt/KeysEntity.java b/src/main/java/com/auth0/client/mgmt/KeysEntity.java index bbac2b13..993ee8f7 100644 --- a/src/main/java/com/auth0/client/mgmt/KeysEntity.java +++ b/src/main/java/com/auth0/client/mgmt/KeysEntity.java @@ -3,6 +3,7 @@ import com.auth0.json.mgmt.keys.Key; import com.auth0.net.EmptyBodyRequest; import com.auth0.net.BaseRequest; +import com.auth0.net.EmptyBodyVoidRequest; import com.auth0.net.Request; import com.auth0.net.client.Auth0HttpClient; import com.auth0.net.client.HttpMethod; @@ -100,4 +101,20 @@ public Request revoke(String kid) { return new EmptyBodyRequest<>(this.client, tokenProvider, url, HttpMethod.PUT, new TypeReference() { }); } + + /** + * Perform rekeying operation on the key hierarchy. + * A token with scope create:encryption_keys and update:encryption_keys is needed + * See https://auth0.com/docs/api/management/v2#!/Keys/post-encryption-rekey + * @return a Request to execute. + */ + public Request postEncryptionRekey(){ + String url = baseUrl + .newBuilder() + .addPathSegments("api/v2/keys/encryption/rekey") + .build() + .toString(); + + return new EmptyBodyVoidRequest<>(this.client, tokenProvider, url, HttpMethod.POST, new TypeReference() {}); + } } diff --git a/src/main/java/com/auth0/net/EmptyBodyVoidRequest.java b/src/main/java/com/auth0/net/EmptyBodyVoidRequest.java new file mode 100644 index 00000000..f93f8825 --- /dev/null +++ b/src/main/java/com/auth0/net/EmptyBodyVoidRequest.java @@ -0,0 +1,42 @@ +package com.auth0.net; + +import com.auth0.client.mgmt.TokenProvider; +import com.auth0.exception.Auth0Exception; +import com.auth0.net.client.Auth0HttpClient; +import com.auth0.net.client.Auth0HttpResponse; +import com.auth0.net.client.HttpMethod; +import com.auth0.net.client.HttpRequestBody; +import com.fasterxml.jackson.core.type.TypeReference; + +/** + * Request class that does not accept parameters to be sent as part of its body and request doesn't return any value on its success. + * The content type of this request is "application/json". + * + * @param The type expected to be received as part of the response. + * @see BaseRequest + */ +public class EmptyBodyVoidRequest extends BaseRequest { + public EmptyBodyVoidRequest(Auth0HttpClient client, TokenProvider tokenProvider, String url, HttpMethod method, TypeReference tType) { + super(client, tokenProvider, url, method, tType); + } + + @Override + @SuppressWarnings("deprecation") + protected HttpRequestBody createRequestBody() { + return HttpRequestBody.create("application/json", new byte[0]); + } + + @Override + public EmptyBodyVoidRequest addParameter(String name, Object value) { + //do nothing + return this; + } + @Override + protected T parseResponseBody(Auth0HttpResponse response) throws Auth0Exception { + if (!response.isSuccessful()) { + throw super.createResponseException(response); + } + return null; + } + +} diff --git a/src/test/java/com/auth0/client/mgmt/KeysEntityTest.java b/src/test/java/com/auth0/client/mgmt/KeysEntityTest.java index 42243205..ef1e81c7 100644 --- a/src/test/java/com/auth0/client/mgmt/KeysEntityTest.java +++ b/src/test/java/com/auth0/client/mgmt/KeysEntityTest.java @@ -95,4 +95,18 @@ public void shouldRevokeKey() throws Exception { assertThat(response, is(notNullValue())); } + + @Test + public void shouldRekey() throws Exception { + Request request = api.keys().postEncryptionRekey(); + assertThat(request, is(notNullValue())); + + server.emptyResponse(204); + request.execute().getBody(); + RecordedRequest recordedRequest = server.takeRequest(); + + assertThat(recordedRequest, hasMethodAndPath(HttpMethod.POST, "/api/v2/keys/encryption/rekey")); + assertThat(recordedRequest, hasHeader("Content-Type", "application/json")); + assertThat(recordedRequest, hasHeader("Authorization", "Bearer apiToken")); + } } diff --git a/src/test/java/com/auth0/net/EmptyBodyVoidRequestTest.java b/src/test/java/com/auth0/net/EmptyBodyVoidRequestTest.java new file mode 100644 index 00000000..ba356b36 --- /dev/null +++ b/src/test/java/com/auth0/net/EmptyBodyVoidRequestTest.java @@ -0,0 +1,53 @@ +package com.auth0.net; + +import com.auth0.client.MockServer; +import com.auth0.client.mgmt.TokenProvider; +import com.auth0.net.client.Auth0HttpClient; +import com.auth0.net.client.DefaultHttpClient; +import com.auth0.net.client.HttpMethod; +import com.fasterxml.jackson.core.type.TypeReference; +import okhttp3.mockwebserver.RecordedRequest; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.util.concurrent.CompletableFuture; + +import static com.auth0.client.MockServer.AUTH_TOKENS; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.*; + +public class EmptyBodyVoidRequestTest { + + private Auth0HttpClient client; + private TokenProvider tokenProvider; + private MockServer server; + + @BeforeEach + public void setUp() throws Exception { + client = new DefaultHttpClient.Builder().build(); + server = new MockServer(); + tokenProvider = new TokenProvider() { + @Override + public String getToken() { + return "Bearer abc"; + } + + @Override + public CompletableFuture getTokenAsync() { + return CompletableFuture.completedFuture("Bearer abc"); + } + }; + } + + @Test + public void shouldCreatePOSTRequest() throws Exception { + EmptyBodyVoidRequest request = new EmptyBodyVoidRequest<>(client, tokenProvider, server.getBaseUrl(), HttpMethod.POST, new TypeReference() {}); + assertThat(request, is(notNullValue())); + + server.jsonResponse(AUTH_TOKENS, 200); + Void execute = request.execute().getBody(); + RecordedRequest recordedRequest = server.takeRequest(); + assertThat(recordedRequest.getMethod(), is(HttpMethod.POST.toString())); + assertThat(execute, is(nullValue())); + } +} From 8ae4042d2830b3acaa5a41215d26a199f4837959 Mon Sep 17 00:00:00 2001 From: Tanya Sinha Date: Wed, 16 Oct 2024 15:43:50 +0530 Subject: [PATCH 17/32] Release 2.14.0 (#672) --- .version | 2 +- CHANGELOG.md | 8 ++++++++ README.md | 4 ++-- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/.version b/.version index fb2c0766..edcfe40d 100644 --- a/.version +++ b/.version @@ -1 +1 @@ -2.13.0 +2.14.0 diff --git a/CHANGELOG.md b/CHANGELOG.md index f9a6f400..ff8707a7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Change Log +## [2.14.0](https://github.com/auth0/auth0-java/tree/2.14.0) (2024-10-16) +[Full Changelog](https://github.com/auth0/auth0-java/compare/2.13.0...2.14.0) + +**Added** +- SDKs support for Control Your Own Key [\#671](https://github.com/auth0/auth0-java/pull/671) ([tanya732](https://github.com/tanya732)) +- Added client credentials changes [\#670](https://github.com/auth0/auth0-java/pull/670) ([tanya732](https://github.com/tanya732)) +- Added support for HRI phase 2 changes [\#668](https://github.com/auth0/auth0-java/pull/668) ([tanya732](https://github.com/tanya732)) + ## [2.13.0](https://github.com/auth0/auth0-java/tree/2.13.0) (2024-09-11) [Full Changelog](https://github.com/auth0/auth0-java/compare/2.12.0...2.13.0) diff --git a/README.md b/README.md index dc686268..9528b907 100644 --- a/README.md +++ b/README.md @@ -34,14 +34,14 @@ Add the dependency via Maven: com.auth0 auth0 - 2.13.0 + 2.14.0 ``` or Gradle: ```gradle -implementation 'com.auth0:auth0:2.13.0' +implementation 'com.auth0:auth0:2.14.0' ``` ### Configure the SDK From 4a3c0cff39f38f89ac605903c195aaf5d3f7f649 Mon Sep 17 00:00:00 2001 From: KunalOfficial <35455566+developerkunal@users.noreply.github.com> Date: Wed, 30 Oct 2024 17:57:27 +0530 Subject: [PATCH 18/32] Added Rl-Scanner to Workflows (DON'T MERGE THIS) (#655) --- .github/actions/rl-scanner/action.yml | 71 +++++++++++++++++++++++++++ .github/workflows/release.yml | 14 ++++++ .github/workflows/rl-scanner.yml | 69 ++++++++++++++++++++++++++ 3 files changed, 154 insertions(+) create mode 100644 .github/actions/rl-scanner/action.yml create mode 100644 .github/workflows/rl-scanner.yml diff --git a/.github/actions/rl-scanner/action.yml b/.github/actions/rl-scanner/action.yml new file mode 100644 index 00000000..03c378a0 --- /dev/null +++ b/.github/actions/rl-scanner/action.yml @@ -0,0 +1,71 @@ +name: "Reversing Labs Scanner" +description: "Runs the Reversing Labs scanner on a specified artifact." +inputs: + artifact-path: + description: "Path to the artifact to be scanned." + required: true + version: + description: "Version of the artifact." + required: true + +runs: + using: "composite" + steps: + - name: Set up Python + uses: actions/setup-python@v4 + with: + python-version: "3.10" + + - name: Install Python dependencies + shell: bash + run: | + pip install boto3 requests + + - name: Configure AWS credentials + uses: aws-actions/configure-aws-credentials@v1 + with: + role-to-assume: ${{ env.PRODSEC_TOOLS_ARN }} + aws-region: us-east-1 + mask-aws-account-id: true + + - name: Install RL Wrapper + shell: bash + run: | + pip install rl-wrapper>=1.0.0 --index-url "https://${{ env.PRODSEC_TOOLS_USER }}:${{ env.PRODSEC_TOOLS_TOKEN }}@a0us.jfrog.io/artifactory/api/pypi/python-local/simple" + + - name: Run RL Scanner + shell: bash + env: + RLSECURE_LICENSE: ${{ env.RLSECURE_LICENSE }} + RLSECURE_SITE_KEY: ${{ env.RLSECURE_SITE_KEY }} + SIGNAL_HANDLER_TOKEN: ${{ env.SIGNAL_HANDLER_TOKEN }} + PYTHONUNBUFFERED: 1 + run: | + if [ ! -f "${{ inputs.artifact-path }}" ]; then + echo "Artifact not found: ${{ inputs.artifact-path }}" + exit 1 + fi + + rl-wrapper \ + --artifact "${{ inputs.artifact-path }}" \ + --name "${{ github.event.repository.name }}" \ + --version "${{ inputs.version }}" \ + --repository "${{ github.repository }}" \ + --commit "${{ github.sha }}" \ + --build-env "github_actions" \ + --suppress_output + + # Check the outcome of the scanner + if [ $? -ne 0 ]; then + echo "RL Scanner failed." + echo "scan-status=failed" >> $GITHUB_ENV + exit 1 + else + echo "RL Scanner passed." + echo "scan-status=success" >> $GITHUB_ENV + fi + +outputs: + scan-status: + description: "The outcome of the scan process." + value: ${{ env.scan-status }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 715a0bc8..7e1b1baf 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -8,14 +8,28 @@ on: permissions: contents: write + id-token: write # This is required for requesting the JWT ### TODO: Replace instances of './.github/workflows/' w/ `auth0/dx-sdk-actions/workflows/` and append `@latest` after the common `dx-sdk-actions` repo is made public. ### TODO: Also remove `get-prerelease`, `get-release-notes`, `get-version`, `maven-publish`, `release-create`, and `tag-exists` actions from this repo's .github/actions folder once the repo is public. ### TODO: Also remove `java-release` workflow from this repo's .github/workflows folder once the repo is public. jobs: + rl-scanner: + uses: ./.github/workflows/rl-scanner.yml + with: + java-version: 8 + artifact-name: "auth0-react.tgz" + secrets: + RLSECURE_LICENSE: ${{ secrets.RLSECURE_LICENSE }} + RLSECURE_SITE_KEY: ${{ secrets.RLSECURE_SITE_KEY }} + SIGNAL_HANDLER_TOKEN: ${{ secrets.SIGNAL_HANDLER_TOKEN }} + PRODSEC_TOOLS_USER: ${{ secrets.PRODSEC_TOOLS_USER }} + PRODSEC_TOOLS_TOKEN: ${{ secrets.PRODSEC_TOOLS_TOKEN }} + PRODSEC_TOOLS_ARN: ${{ secrets.PRODSEC_TOOLS_ARN }} release: uses: ./.github/workflows/java-release.yml + needs: rl-scanner with: java-version: 8.0.382-tem secrets: diff --git a/.github/workflows/rl-scanner.yml b/.github/workflows/rl-scanner.yml new file mode 100644 index 00000000..fd5d97a5 --- /dev/null +++ b/.github/workflows/rl-scanner.yml @@ -0,0 +1,69 @@ +name: RL-Secure Workflow + +on: + workflow_call: + inputs: + java-version: + required: true + type: string + artifact-name: + required: true + type: string + secrets: + RLSECURE_LICENSE: + required: true + RLSECURE_SITE_KEY: + required: true + SIGNAL_HANDLER_TOKEN: + required: true + PRODSEC_TOOLS_USER: + required: true + PRODSEC_TOOLS_TOKEN: + required: true + PRODSEC_TOOLS_ARN: + required: true +jobs: + checkout-build-scan-only: + if: github.event_name == 'workflow_dispatch' || (github.event_name == 'pull_request' && github.event.pull_request.merged && startsWith(github.event.pull_request.head.ref, 'release/')) + runs-on: ubuntu-latest + outputs: + scan-status: ${{ steps.rl-scan-conclusion.outcome }} + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up Java + uses: actions/setup-java@v4 + with: + distribution: temurin + java-version: ${{ inputs.java-version }} + + - name: Build with Gradle + uses: gradle/gradle-build-action@4c39dd82cd5e1ec7c6fa0173bb41b4b6bb3b86ff + with: + arguments: assemble apiDiff check jacocoTestReport --continue --console=plain + + - id: get_version + uses: ./.github/actions/get-version + + - name: Create tgz build artifact + run: | + tar -czvf ${{ inputs.artifact-name }} * + + - name: Run RL Scanner + id: rl-scan-conclusion + uses: ./.github/actions/rl-scanner + with: + artifact-path: "$(pwd)/${{ inputs.artifact-name }}" + version: "${{ steps.get_version.outputs.version }}" + env: + RLSECURE_LICENSE: ${{ secrets.RLSECURE_LICENSE }} + RLSECURE_SITE_KEY: ${{ secrets.RLSECURE_SITE_KEY }} + SIGNAL_HANDLER_TOKEN: ${{ secrets.SIGNAL_HANDLER_TOKEN }} + PRODSEC_TOOLS_USER: ${{ secrets.PRODSEC_TOOLS_USER }} + PRODSEC_TOOLS_TOKEN: ${{ secrets.PRODSEC_TOOLS_TOKEN }} + PRODSEC_TOOLS_ARN: ${{ secrets.PRODSEC_TOOLS_ARN }} + + - name: Output scan result + run: echo "scan-status=${{ steps.rl-scan-conclusion.outcome }}" >> $GITHUB_ENV From 70775ea71317c679ec1dbb40067b64bf44d0ebbd Mon Sep 17 00:00:00 2001 From: KunalOfficial <35455566+developerkunal@users.noreply.github.com> Date: Thu, 31 Oct 2024 13:07:04 +0530 Subject: [PATCH 19/32] Reversing Labs Scanner artifact name fix (#674) --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 7e1b1baf..5bab2bc7 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -19,7 +19,7 @@ jobs: uses: ./.github/workflows/rl-scanner.yml with: java-version: 8 - artifact-name: "auth0-react.tgz" + artifact-name: "auth0-java.tgz" secrets: RLSECURE_LICENSE: ${{ secrets.RLSECURE_LICENSE }} RLSECURE_SITE_KEY: ${{ secrets.RLSECURE_SITE_KEY }} From eb61afdaae5380c2ec7921da063b881938f6253a Mon Sep 17 00:00:00 2001 From: Tanya Sinha Date: Thu, 31 Oct 2024 15:58:56 +0530 Subject: [PATCH 20/32] Added support for byok (#673) --- .../com/auth0/client/mgmt/KeysEntity.java | 142 ++++++++++++++++ .../mgmt/filter/EncryptionKeyFilter.java | 29 ++++ .../auth0/json/mgmt/keys/EncryptionKey.java | 136 +++++++++++++++ .../json/mgmt/keys/EncryptionKeysPage.java | 24 +++ .../keys/EncryptionKeysPageDeserializer.java | 23 +++ .../keys/EncryptionWrappingKeyResponse.java | 46 +++++ .../java/com/auth0/client/MockServer.java | 2 + .../com/auth0/client/mgmt/KeysEntityTest.java | 157 +++++++++++++++++- .../json/mgmt/keys/EncryptionKeyTest.java | 70 ++++++++ .../mgmt/keys/EncryptionKeysPageTest.java | 94 +++++++++++ .../EncryptionWrappingKeyResponseTest.java | 49 ++++++ .../auth0/json/mgmt/{ => keys}/KeyTest.java | 3 +- src/test/resources/mgmt/encryption_key.json | 9 + .../resources/mgmt/encryption_keys_list.json | 29 ++++ 14 files changed, 809 insertions(+), 4 deletions(-) create mode 100644 src/main/java/com/auth0/client/mgmt/filter/EncryptionKeyFilter.java create mode 100644 src/main/java/com/auth0/json/mgmt/keys/EncryptionKey.java create mode 100644 src/main/java/com/auth0/json/mgmt/keys/EncryptionKeysPage.java create mode 100644 src/main/java/com/auth0/json/mgmt/keys/EncryptionKeysPageDeserializer.java create mode 100644 src/main/java/com/auth0/json/mgmt/keys/EncryptionWrappingKeyResponse.java create mode 100644 src/test/java/com/auth0/json/mgmt/keys/EncryptionKeyTest.java create mode 100644 src/test/java/com/auth0/json/mgmt/keys/EncryptionKeysPageTest.java create mode 100644 src/test/java/com/auth0/json/mgmt/keys/EncryptionWrappingKeyResponseTest.java rename src/test/java/com/auth0/json/mgmt/{ => keys}/KeyTest.java (98%) create mode 100644 src/test/resources/mgmt/encryption_key.json create mode 100644 src/test/resources/mgmt/encryption_keys_list.json diff --git a/src/main/java/com/auth0/client/mgmt/KeysEntity.java b/src/main/java/com/auth0/client/mgmt/KeysEntity.java index 993ee8f7..65c7db8f 100644 --- a/src/main/java/com/auth0/client/mgmt/KeysEntity.java +++ b/src/main/java/com/auth0/client/mgmt/KeysEntity.java @@ -1,5 +1,9 @@ package com.auth0.client.mgmt; +import com.auth0.client.mgmt.filter.EncryptionKeyFilter; +import com.auth0.json.mgmt.keys.EncryptionKey; +import com.auth0.json.mgmt.keys.EncryptionKeysPage; +import com.auth0.json.mgmt.keys.EncryptionWrappingKeyResponse; import com.auth0.json.mgmt.keys.Key; import com.auth0.net.EmptyBodyRequest; import com.auth0.net.BaseRequest; @@ -12,6 +16,7 @@ import okhttp3.HttpUrl; import java.util.List; +import java.util.Map; /** * Class that provides an implementation of the Keys methods of the Management API as defined in https://auth0.com/docs/api/management/v2#!/Keys @@ -117,4 +122,141 @@ public Request postEncryptionRekey(){ return new EmptyBodyVoidRequest<>(this.client, tokenProvider, url, HttpMethod.POST, new TypeReference() {}); } + + /** + * Get all encryption keys. + * A token with scope read:encryption_keys is needed + * See https://auth0.com/docs/api/management/v2#!/Keys/get-encryption-keys + * @param filter Filter to apply. Use null to get all encryption keys. + * @return a Request to execute. + */ + public Request listEncryptionKeys(EncryptionKeyFilter filter){ + + HttpUrl.Builder builder = baseUrl + .newBuilder() + .addPathSegments("api/v2/keys/encryption"); + + if (filter != null) { + for (Map.Entry e : filter.getAsMap().entrySet()) { + builder.addQueryParameter(e.getKey(), String.valueOf(e.getValue())); + } + } + + String url = builder.build().toString(); + return new BaseRequest<>(client, tokenProvider, url, HttpMethod.GET, new TypeReference() { + }); + } + + /** + * Get the encryption key with the given kid. + * A token with scope read:encryption_keys is needed + * See https://auth0.com/docs/api/management/v2#!/Keys/get-encryption-key + * @param kid Encryption key ID + * @return A Request to execute + */ + public Request getEncryptionKey(String kid){ + Asserts.assertNotNull(kid, "kid"); + + String url = baseUrl + .newBuilder() + .addPathSegments("api/v2/keys/encryption") + .addPathSegment(kid) + .build() + .toString(); + + return new BaseRequest<>(client, tokenProvider, url, HttpMethod.GET, new TypeReference() { + }); + } + + /** + * Create a new encryption key. + * A token with scope create:encryption_keys is needed + * See https://auth0.com/docs/api/management/v2#!/Keys/post-encryption + * @param type key type + * @return a Request to execute. + */ + public Request createEncryptionKey(String type) { + Asserts.assertNotNull(type, "type"); + + String url = baseUrl + .newBuilder() + .addPathSegments("api/v2/keys/encryption") + .build() + .toString(); + + BaseRequest request = new BaseRequest<>(client, tokenProvider, url, HttpMethod.POST, new TypeReference() { + }); + + request.addParameter("type", type); + return request; + } + + /** + * Import an encryption key. + * A token with scope update:encryption_keys is needed + * See https://auth0.com/docs/api/management/v2#!/Keys/post-encryption-key + * @param wrappedKey Base64 encoded ciphertext of key material wrapped by public wrapping key. + * @param kid Encryption key ID + * @return A Request to execute + */ + public Request importEncryptionKey(String wrappedKey, String kid) { + Asserts.assertNotNull(wrappedKey, "wrappedKey"); + Asserts.assertNotNull(kid, "kid"); + + String url = baseUrl + .newBuilder() + .addPathSegments("api/v2/keys/encryption") + .addPathSegment(kid) + .build() + .toString(); + + BaseRequest request = new BaseRequest<>(client, tokenProvider, url, HttpMethod.POST, new TypeReference() { + }); + + request.addParameter("wrapped_key", wrappedKey); + return request; + } + + /** + * Delete the encryption key with the given kid. + * A token with scope delete:encryption_keys is needed + * See https://auth0.com/docs/api/management/v2#!/delete-encryption-key + * @param kid Encryption key ID + * @return a Request to execute. + */ + public Request deleteEncryptionKey(String kid) { + Asserts.assertNotNull(kid, "kid"); + + String url = baseUrl + .newBuilder() + .addPathSegments("api/v2/keys/encryption") + .addPathSegment(kid) + .build() + .toString(); + + return new EmptyBodyVoidRequest<>(client, tokenProvider, url, HttpMethod.DELETE, new TypeReference() { + }); + } + + /** + * Create a new encryption wrapping key. + * A token with scope create:encryption_keys is needed + * See https://auth0.com/docs/api/management/v2#!/Keys/post-encryption-wrapping-key + * @param kid Encryption key ID + * @return a Request to execute. + */ + public Request createEncryptionWrappingKey(String kid) { + Asserts.assertNotNull(kid, "kid"); + + String url = baseUrl + .newBuilder() + .addPathSegments("api/v2/keys/encryption") + .addPathSegment(kid) + .addPathSegment("wrapping-key") + .build() + .toString(); + + return new EmptyBodyRequest<>(client, tokenProvider, url, HttpMethod.POST, new TypeReference() { + }); + } } diff --git a/src/main/java/com/auth0/client/mgmt/filter/EncryptionKeyFilter.java b/src/main/java/com/auth0/client/mgmt/filter/EncryptionKeyFilter.java new file mode 100644 index 00000000..2d9b18ff --- /dev/null +++ b/src/main/java/com/auth0/client/mgmt/filter/EncryptionKeyFilter.java @@ -0,0 +1,29 @@ +package com.auth0.client.mgmt.filter; + +public class EncryptionKeyFilter extends BaseFilter { + + /** + * Filter by page + * + * @param pageNumber the page number to retrieve. + * @param amountPerPage the amount of items per page to retrieve. + * @return this filter instance + */ + public EncryptionKeyFilter withPage(int pageNumber, int amountPerPage) { + parameters.put("page", pageNumber); + parameters.put("per_page", amountPerPage); + return this; + } + + /** + * Include the query summary + * + * @param includeTotals whether to include or not the query summary. + * @return this filter instance + */ + public EncryptionKeyFilter withTotals(boolean includeTotals) { + parameters.put("include_totals", includeTotals); + return this; + } + +} diff --git a/src/main/java/com/auth0/json/mgmt/keys/EncryptionKey.java b/src/main/java/com/auth0/json/mgmt/keys/EncryptionKey.java new file mode 100644 index 00000000..00f52fe1 --- /dev/null +++ b/src/main/java/com/auth0/json/mgmt/keys/EncryptionKey.java @@ -0,0 +1,136 @@ +package com.auth0.json.mgmt.keys; + +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 EncryptionKey { + @JsonProperty("kid") + private String kid; + @JsonProperty("type") + private String type; + @JsonProperty("state") + private String state; + @JsonProperty("created_at") + private String createdAt; + @JsonProperty("updated_at") + private String updatedAt; + @JsonProperty("parent_kid") + private String parentKid; + @JsonProperty("public_key") + private String publicKey; + + /** + * Getter for the key id. + * @return + */ + public String getKid() { + return kid; + } + + /** + * Setter for the key id. + * @param kid + */ + public void setKid(String kid) { + this.kid = kid; + } + + /** + * Getter for the key type. + * @return + */ + public String getType() { + return type; + } + + /** + * Setter for the key type. + * @param type + */ + public void setType(String type) { + this.type = type; + } + + /** + * Getter for the key state. + * @return + */ + public String getState() { + return state; + } + + /** + * Setter for the key state. + * @param state + */ + public void setState(String state) { + this.state = state; + } + + /** + * Getter for the key creation date. + * @return + */ + public String getCreatedAt() { + return createdAt; + } + + /** + * Setter for the key creation date. + * @param createdAt + */ + public void setCreatedAt(String createdAt) { + this.createdAt = createdAt; + } + + /** + * Getter for the key update date. + * @return + */ + public String getUpdatedAt() { + return updatedAt; + } + + /** + * Setter for the key update date. + * @param updatedAt + */ + public void setUpdatedAt(String updatedAt) { + this.updatedAt = updatedAt; + } + + /** + * Getter for the parent key id. + * @return + */ + public String getParentKid() { + return parentKid; + } + + /** + * Setter for the parent key id. + * @param parentKid + */ + public void setParentKid(String parentKid) { + this.parentKid = parentKid; + } + + /** + * Getter for the public key. + * @return + */ + public String getPublicKey() { + return publicKey; + } + + /** + * Setter for the public key. + * @param publicKey + */ + public void setPublicKey(String publicKey) { + this.publicKey = publicKey; + } +} diff --git a/src/main/java/com/auth0/json/mgmt/keys/EncryptionKeysPage.java b/src/main/java/com/auth0/json/mgmt/keys/EncryptionKeysPage.java new file mode 100644 index 00000000..283a5aa3 --- /dev/null +++ b/src/main/java/com/auth0/json/mgmt/keys/EncryptionKeysPage.java @@ -0,0 +1,24 @@ +package com.auth0.json.mgmt.keys; + +import com.auth0.json.mgmt.Page; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; + +import java.util.List; + +@SuppressWarnings({"unused", "WeakerAccess"}) +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonDeserialize(using = EncryptionKeysPageDeserializer.class) +public class EncryptionKeysPage extends Page { + + public EncryptionKeysPage(List items) { + super(items); + } + + public EncryptionKeysPage(Integer start, Integer length, Integer total, Integer limit, List items) { + super(start, length, total, limit, items); + } + +} diff --git a/src/main/java/com/auth0/json/mgmt/keys/EncryptionKeysPageDeserializer.java b/src/main/java/com/auth0/json/mgmt/keys/EncryptionKeysPageDeserializer.java new file mode 100644 index 00000000..797255e1 --- /dev/null +++ b/src/main/java/com/auth0/json/mgmt/keys/EncryptionKeysPageDeserializer.java @@ -0,0 +1,23 @@ +package com.auth0.json.mgmt.keys; + +import com.auth0.json.mgmt.PageDeserializer; + +import java.util.List; + +public class EncryptionKeysPageDeserializer extends PageDeserializer { + + protected EncryptionKeysPageDeserializer() { + super(EncryptionKey.class, "keys"); + } + + @Override + protected EncryptionKeysPage createPage(List items) { + return new EncryptionKeysPage(items); + } + + @Override + protected EncryptionKeysPage createPage(Integer start, Integer length, Integer total, Integer limit, List items) { + return new EncryptionKeysPage(start, length, total, limit, items); + } + +} diff --git a/src/main/java/com/auth0/json/mgmt/keys/EncryptionWrappingKeyResponse.java b/src/main/java/com/auth0/json/mgmt/keys/EncryptionWrappingKeyResponse.java new file mode 100644 index 00000000..49de2869 --- /dev/null +++ b/src/main/java/com/auth0/json/mgmt/keys/EncryptionWrappingKeyResponse.java @@ -0,0 +1,46 @@ +package com.auth0.json.mgmt.keys; + +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 EncryptionWrappingKeyResponse { + @JsonProperty("public_key") + private String publicKey; + @JsonProperty("algorithm") + private String algorithm; + + /** + * Getter for the public key. + * @return the public key. + */ + public String getPublicKey() { + return publicKey; + } + + /** + * Setter for the public key. + * @param publicKey the public key. + */ + public void setPublicKey(String publicKey) { + this.publicKey = publicKey; + } + + /** + * Getter for the algorithm. + * @return the algorithm. + */ + public String getAlgorithm() { + return algorithm; + } + + /** + * Setter for the algorithm. + * @param algorithm the algorithm. + */ + public void setAlgorithm(String algorithm) { + this.algorithm = algorithm; + } +} diff --git a/src/test/java/com/auth0/client/MockServer.java b/src/test/java/com/auth0/client/MockServer.java index f8ee2189..847cd7fa 100644 --- a/src/test/java/com/auth0/client/MockServer.java +++ b/src/test/java/com/auth0/client/MockServer.java @@ -151,6 +151,8 @@ public class MockServer { public static final String KEY_LIST = "src/test/resources/mgmt/key_list.json"; public static final String KEY_REVOKE = "src/test/resources/mgmt/key_revoke.json"; public static final String KEY_ROTATE = "src/test/resources/mgmt/key_rotate.json"; + public static final String ENCRYPTION_KEY = "src/test/resources/mgmt/encryption_key.json"; + public static final String ENCRYPTION_KEYS_LIST = "src/test/resources/mgmt/encryption_keys_list.json"; public static final String RATE_LIMIT_ERROR = "src/test/resources/mgmt/rate_limit_error.json"; private final MockWebServer server; diff --git a/src/test/java/com/auth0/client/mgmt/KeysEntityTest.java b/src/test/java/com/auth0/client/mgmt/KeysEntityTest.java index ef1e81c7..98d54dcb 100644 --- a/src/test/java/com/auth0/client/mgmt/KeysEntityTest.java +++ b/src/test/java/com/auth0/client/mgmt/KeysEntityTest.java @@ -1,5 +1,9 @@ package com.auth0.client.mgmt; +import com.auth0.client.mgmt.filter.EncryptionKeyFilter; +import com.auth0.json.mgmt.keys.EncryptionKey; +import com.auth0.json.mgmt.keys.EncryptionKeysPage; +import com.auth0.json.mgmt.keys.EncryptionWrappingKeyResponse; import com.auth0.json.mgmt.keys.Key; import com.auth0.net.Request; import com.auth0.net.client.HttpMethod; @@ -7,11 +11,11 @@ import org.junit.jupiter.api.Test; import java.util.List; +import java.util.Map; import static com.auth0.AssertsUtil.verifyThrows; import static com.auth0.client.MockServer.*; -import static com.auth0.client.RecordedRequestMatcher.hasHeader; -import static com.auth0.client.RecordedRequestMatcher.hasMethodAndPath; +import static com.auth0.client.RecordedRequestMatcher.*; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.*; @@ -109,4 +113,153 @@ public void shouldRekey() throws Exception { assertThat(recordedRequest, hasHeader("Content-Type", "application/json")); assertThat(recordedRequest, hasHeader("Authorization", "Bearer apiToken")); } + + @Test + public void shouldListEncryptionKeysWithoutFilter() throws Exception { + Request request = api.keys().listEncryptionKeys(null); + assertThat(request, is(notNullValue())); + + server.jsonResponse(ENCRYPTION_KEYS_LIST, 200); + EncryptionKeysPage response = request.execute().getBody(); + RecordedRequest recordedRequest = server.takeRequest(); + + assertThat(recordedRequest, hasMethodAndPath(HttpMethod.GET, "/api/v2/keys/encryption")); + assertThat(recordedRequest, hasHeader("Content-Type", "application/json")); + assertThat(recordedRequest, hasHeader("Authorization", "Bearer apiToken")); + + assertThat(response, is(notNullValue())); + assertThat(response.getItems(), hasSize(3)); + } + + @Test + public void shouldListEncryptionKeysWithPage() throws Exception { + EncryptionKeyFilter filter = new EncryptionKeyFilter().withPage(1, 5); + Request request = api.keys().listEncryptionKeys(filter); + assertThat(request, is(notNullValue())); + + server.jsonResponse(ENCRYPTION_KEYS_LIST, 200); + EncryptionKeysPage response = request.execute().getBody(); + RecordedRequest recordedRequest = server.takeRequest(); + + assertThat(recordedRequest, hasMethodAndPath(HttpMethod.GET, "/api/v2/keys/encryption")); + assertThat(recordedRequest, hasHeader("Content-Type", "application/json")); + assertThat(recordedRequest, hasHeader("Authorization", "Bearer apiToken")); + assertThat(recordedRequest, hasQueryParameter("page", "1")); + assertThat(recordedRequest, hasQueryParameter("per_page", "5")); + + assertThat(response, is(notNullValue())); + assertThat(response.getItems(), hasSize(3)); + } + + @Test + public void shouldListEncryptionKeysWithTotals() throws Exception { + EncryptionKeyFilter filter = new EncryptionKeyFilter().withTotals(true); + Request request = api.keys().listEncryptionKeys(filter); + assertThat(request, is(notNullValue())); + + server.jsonResponse(ENCRYPTION_KEYS_LIST, 200); + EncryptionKeysPage response = request.execute().getBody(); + RecordedRequest recordedRequest = server.takeRequest(); + + assertThat(recordedRequest, hasMethodAndPath(HttpMethod.GET, "/api/v2/keys/encryption")); + assertThat(recordedRequest, hasHeader("Content-Type", "application/json")); + assertThat(recordedRequest, hasHeader("Authorization", "Bearer apiToken")); + assertThat(recordedRequest, hasQueryParameter("include_totals", "true")); + + assertThat(response, is(notNullValue())); + assertThat(response.getItems(), hasSize(3)); + } + + @Test + public void shouldGetEncryptionKeyWithKid() throws Exception { + Request request = api.keys().getEncryptionKey("123"); + assertThat(request, is(notNullValue())); + + server.jsonResponse(ENCRYPTION_KEY, 200); + EncryptionKey response = request.execute().getBody(); + RecordedRequest recordedRequest = server.takeRequest(); + + assertThat(recordedRequest, hasMethodAndPath(HttpMethod.GET, "/api/v2/keys/encryption/123")); + assertThat(recordedRequest, hasHeader("Content-Type", "application/json")); + assertThat(recordedRequest, hasHeader("Authorization", "Bearer apiToken")); + + assertThat(response, is(notNullValue())); + } + + @Test + public void shouldCreateEncryptionKey() throws Exception { + Request request = api.keys().createEncryptionKey("tenant-master-key"); + assertThat(request, is(notNullValue())); + + server.jsonResponse(ENCRYPTION_KEY, 201); + EncryptionKey response = request.execute().getBody(); + RecordedRequest recordedRequest = server.takeRequest(); + + assertThat(recordedRequest, hasMethodAndPath(HttpMethod.POST, "/api/v2/keys/encryption")); + assertThat(recordedRequest, hasHeader("Content-Type", "application/json")); + assertThat(recordedRequest, hasHeader("Authorization", "Bearer apiToken")); + + Map body = bodyFromRequest(recordedRequest); + assertThat(body.size(), is(1)); + assertThat(body, hasEntry("type", "tenant-master-key")); + + assertThat(response, is(notNullValue())); + } + + @Test + public void shouldImportEncryptionKey() throws Exception { + Request request = api.keys().importEncryptionKey("key@1234", "123"); + assertThat(request, is(notNullValue())); + + server.jsonResponse(ENCRYPTION_KEY, 201); + EncryptionKey response = request.execute().getBody(); + RecordedRequest recordedRequest = server.takeRequest(); + + assertThat(recordedRequest, hasMethodAndPath(HttpMethod.POST, "/api/v2/keys/encryption/123")); + assertThat(recordedRequest, hasHeader("Content-Type", "application/json")); + assertThat(recordedRequest, hasHeader("Authorization", "Bearer apiToken")); + + Map body = bodyFromRequest(recordedRequest); + assertThat(body.size(), is(1)); + assertThat(body, hasEntry("wrapped_key", "key@1234")); + + assertThat(response, is(notNullValue())); + } + + @Test + public void shouldCreateEncryptionWrappingKey() throws Exception { + Request request = api.keys().createEncryptionWrappingKey("123"); + assertThat(request, is(notNullValue())); + + server.jsonResponse(ENCRYPTION_KEY, 201); + EncryptionWrappingKeyResponse response = request.execute().getBody(); + RecordedRequest recordedRequest = server.takeRequest(); + + assertThat(recordedRequest, hasMethodAndPath(HttpMethod.POST, "/api/v2/keys/encryption/123/wrapping-key")); + assertThat(recordedRequest, hasHeader("Content-Type", "application/json")); + assertThat(recordedRequest, hasHeader("Authorization", "Bearer apiToken")); + + assertThat(response, is(notNullValue())); + } + + @Test + public void shouldDeleteEncryptionKey() throws Exception { + Request request = api.keys().deleteEncryptionKey("123"); + assertThat(request, is(notNullValue())); + + server.jsonResponse(ENCRYPTION_KEY, 200); + request.execute().getBody(); + RecordedRequest recordedRequest = server.takeRequest(); + + assertThat(recordedRequest, hasMethodAndPath(HttpMethod.DELETE, "/api/v2/keys/encryption/123")); + assertThat(recordedRequest, hasHeader("Content-Type", "application/json")); + assertThat(recordedRequest, hasHeader("Authorization", "Bearer apiToken")); + } + + @Test + public void shouldThrowOnDeleteEncryptionKeyWithNullKid(){ + verifyThrows(IllegalArgumentException.class, + () -> api.keys().deleteEncryptionKey(null), + "'kid' cannot be null!"); + } } diff --git a/src/test/java/com/auth0/json/mgmt/keys/EncryptionKeyTest.java b/src/test/java/com/auth0/json/mgmt/keys/EncryptionKeyTest.java new file mode 100644 index 00000000..31d08a46 --- /dev/null +++ b/src/test/java/com/auth0/json/mgmt/keys/EncryptionKeyTest.java @@ -0,0 +1,70 @@ +package com.auth0.json.mgmt.keys; + +import com.auth0.json.JsonMatcher; +import com.auth0.json.JsonTest; +import org.junit.jupiter.api.Test; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.notNullValue; + +public class EncryptionKeyTest extends JsonTest { + + private static final String json = "{\n" + + " \"kid\": \"kid\",\n" + + " \"type\": \"tenant-master-key\",\n" + + " \"state\": \"active\",\n" + + " \"created_at\": \"2024-10-16T10:50:44.107Z\",\n" + + " \"updated_at\": \"2024-10-24T06:47:24.899Z\",\n" + + " \"parent_kid\": \"pkid\",\n" + + " \"public_key\": \"pkey\"\n" + + "}"; + + private static final String readOnlyJson = "{\n" + + " \"kid\": \"kid\"\n" + + "}"; + + @Test + public void shouldDeserialize() throws Exception { + EncryptionKey key = fromJSON(json, EncryptionKey.class); + + assertThat(key, is(notNullValue())); + assertThat(key.getKid(), is("kid")); + assertThat(key.getType(), is("tenant-master-key")); + assertThat(key.getState(), is("active")); + assertThat(key.getCreatedAt(), is("2024-10-16T10:50:44.107Z")); + assertThat(key.getUpdatedAt(), is("2024-10-24T06:47:24.899Z")); + assertThat(key.getParentKid(), is("pkid")); + assertThat(key.getPublicKey(), is("pkey")); + } + + @Test + public void shouldSerialize() throws Exception { + EncryptionKey key = new EncryptionKey(); + key.setKid("kid"); + key.setType("tenant-master-key"); + key.setState("active"); + key.setCreatedAt("2024-10-16T10:50:44.107Z"); + key.setUpdatedAt("2024-10-24T06:47:24.899Z"); + key.setParentKid("pkid"); + key.setPublicKey("pkey"); + + String serialized = toJSON(key); + assertThat(serialized, is(notNullValue())); + assertThat(serialized, JsonMatcher.hasEntry("kid", "kid")); + assertThat(serialized, JsonMatcher.hasEntry("type", "tenant-master-key")); + assertThat(serialized, JsonMatcher.hasEntry("state", "active")); + assertThat(serialized, JsonMatcher.hasEntry("created_at", "2024-10-16T10:50:44.107Z")); + assertThat(serialized, JsonMatcher.hasEntry("updated_at", "2024-10-24T06:47:24.899Z")); + assertThat(serialized, JsonMatcher.hasEntry("parent_kid", "pkid")); + assertThat(serialized, JsonMatcher.hasEntry("public_key", "pkey")); + } + + @Test + public void shouldIncludeReadOnlyValuesOnDeserialize() throws Exception { + EncryptionKey key = fromJSON(readOnlyJson, EncryptionKey.class); + + assertThat(key, is(notNullValue())); + assertThat(key.getKid(), is("kid")); + } +} diff --git a/src/test/java/com/auth0/json/mgmt/keys/EncryptionKeysPageTest.java b/src/test/java/com/auth0/json/mgmt/keys/EncryptionKeysPageTest.java new file mode 100644 index 00000000..07ed0935 --- /dev/null +++ b/src/test/java/com/auth0/json/mgmt/keys/EncryptionKeysPageTest.java @@ -0,0 +1,94 @@ +package com.auth0.json.mgmt.keys; + +import com.auth0.json.JsonTest; +import org.junit.jupiter.api.Test; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.notNullValue; + +public class EncryptionKeysPageTest extends JsonTest { + + private static final String jsonWithTotal = "{\n" + + " \"start\": 0,\n" + + " \"total\": 20,\n" + + " \"limit\": 50,\n" + + " \"keys\": [\n" + + " {\n" + + " \"kid\": \"kid-1\",\n" + + " \"type\": \"customer-provided-root-key\",\n" + + " \"state\": \"pre-activation\",\n" + + " \"created_at\": \"2024-10-24T08:02:18.029Z\",\n" + + " \"updated_at\": \"2024-10-24T08:02:18.029Z\",\n" + + " \"parent_kid\": null,\n" + + " \"public_key\": null\n" + + " },\n" + + " {\n" + + " \"kid\": \"kid-2\",\n" + + " \"type\": \"tenant-master-key\",\n" + + " \"state\": \"active\",\n" + + " \"created_at\": \"2024-10-24T06:47:23.749Z\",\n" + + " \"updated_at\": \"2024-10-24T06:47:23.749Z\",\n" + + " \"parent_kid\": \"pkid-1\",\n" + + " \"public_key\": null\n" + + " }\n" + + " ]\n" + + "}"; + + private static final String jsonWithoutTotal = "{\n" + + " \"start\": 0,\n" + + " \"limit\": 50,\n" + + " \"keys\": [\n" + + " {\n" + + " \"kid\": \"kid-1\",\n" + + " \"type\": \"customer-provided-root-key\",\n" + + " \"state\": \"pre-activation\",\n" + + " \"created_at\": \"2024-10-24T08:02:18.029Z\",\n" + + " \"updated_at\": \"2024-10-24T08:02:18.029Z\",\n" + + " \"parent_kid\": null,\n" + + " \"public_key\": null\n" + + " },\n" + + " {\n" + + " \"kid\": \"kid-2\",\n" + + " \"type\": \"tenant-master-key\",\n" + + " \"state\": \"active\",\n" + + " \"created_at\": \"2024-10-24T06:47:23.749Z\",\n" + + " \"updated_at\": \"2024-10-24T06:47:23.749Z\",\n" + + " \"parent_kid\": \"pkid-1\",\n" + + " \"public_key\": null\n" + + " }\n" + + " ]\n" + + "}"; + + @Test + public void shouldDeserializeWithTotal() throws Exception { + EncryptionKeysPage page = fromJSON(jsonWithTotal, EncryptionKeysPage.class); + + assertThat(page, is(notNullValue())); + assertThat(page.getStart(), is(0)); + assertThat(page.getTotal(), is(20)); + assertThat(page.getLimit(), is(50)); + assertThat(page.getItems(), is(notNullValue())); + assertThat(page.getItems().size(), is(2)); + assertThat(page.getItems().get(0).getKid(), is("kid-1")); + assertThat(page.getItems().get(0).getType(), is("customer-provided-root-key")); + assertThat(page.getItems().get(0).getState(), is("pre-activation")); + assertThat(page.getItems().get(0).getCreatedAt(), is("2024-10-24T08:02:18.029Z")); + assertThat(page.getItems().get(0).getUpdatedAt(), is("2024-10-24T08:02:18.029Z")); + } + + @Test + public void shouldDeserializeWithoutTotal() throws Exception { + EncryptionKeysPage page = fromJSON(jsonWithoutTotal, EncryptionKeysPage.class); + + assertThat(page, is(notNullValue())); + assertThat(page.getStart(), is(0)); + assertThat(page.getLimit(), is(50)); + assertThat(page.getItems(), is(notNullValue())); + assertThat(page.getItems().size(), is(2)); + assertThat(page.getItems().get(0).getKid(), is("kid-1")); + assertThat(page.getItems().get(0).getType(), is("customer-provided-root-key")); + assertThat(page.getItems().get(0).getState(), is("pre-activation")); + assertThat(page.getItems().get(0).getCreatedAt(), is("2024-10-24T08:02:18.029Z")); + assertThat(page.getItems().get(0).getUpdatedAt(), is("2024-10-24T08:02:18.029Z")); + } +} diff --git a/src/test/java/com/auth0/json/mgmt/keys/EncryptionWrappingKeyResponseTest.java b/src/test/java/com/auth0/json/mgmt/keys/EncryptionWrappingKeyResponseTest.java new file mode 100644 index 00000000..c6762702 --- /dev/null +++ b/src/test/java/com/auth0/json/mgmt/keys/EncryptionWrappingKeyResponseTest.java @@ -0,0 +1,49 @@ +package com.auth0.json.mgmt.keys; + +import com.auth0.json.JsonMatcher; +import com.auth0.json.JsonTest; +import org.junit.jupiter.api.Test; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.notNullValue; + +public class EncryptionWrappingKeyResponseTest extends JsonTest { + private static final String json = "{\n" + + " \"public_key\": \"pkey\",\n" + + " \"algorithm\": \"alg\"\n" + + "}"; + + private static final String readOnlyJson = "{\n" + + " \"public_key\": \"pkey\"\n" + + "}"; + + @Test + public void shouldDeserialize() throws Exception { + EncryptionWrappingKeyResponse response = fromJSON(json, EncryptionWrappingKeyResponse.class); + + assertThat(response, is(notNullValue())); + assertThat(response.getPublicKey(), is("pkey")); + assertThat(response.getAlgorithm(), is("alg")); + } + + @Test + public void shouldSerialize() throws Exception { + EncryptionWrappingKeyResponse response = new EncryptionWrappingKeyResponse(); + response.setPublicKey("pkey"); + response.setAlgorithm("alg"); + + String serialized = toJSON(response); + assertThat(serialized, is(notNullValue())); + assertThat(serialized, JsonMatcher.hasEntry("public_key", "pkey")); + assertThat(serialized, JsonMatcher.hasEntry("algorithm", "alg")); + } + + @Test + public void shouldIncludeReadOnlyValuesOnDeserialize() throws Exception { + EncryptionWrappingKeyResponse response = fromJSON(readOnlyJson, EncryptionWrappingKeyResponse.class); + + assertThat(response, is(notNullValue())); + assertThat(response.getPublicKey(), is("pkey")); + } +} diff --git a/src/test/java/com/auth0/json/mgmt/KeyTest.java b/src/test/java/com/auth0/json/mgmt/keys/KeyTest.java similarity index 98% rename from src/test/java/com/auth0/json/mgmt/KeyTest.java rename to src/test/java/com/auth0/json/mgmt/keys/KeyTest.java index fce6a476..1f69edb0 100644 --- a/src/test/java/com/auth0/json/mgmt/KeyTest.java +++ b/src/test/java/com/auth0/json/mgmt/keys/KeyTest.java @@ -1,7 +1,6 @@ -package com.auth0.json.mgmt; +package com.auth0.json.mgmt.keys; import com.auth0.json.JsonTest; -import com.auth0.json.mgmt.keys.Key; import org.junit.jupiter.api.Test; import java.time.Instant; diff --git a/src/test/resources/mgmt/encryption_key.json b/src/test/resources/mgmt/encryption_key.json new file mode 100644 index 00000000..8c11c21e --- /dev/null +++ b/src/test/resources/mgmt/encryption_key.json @@ -0,0 +1,9 @@ +{ + "kid": "kid", + "type": "tenant-master-key", + "state": "active", + "created_at": "2024-10-16T10:50:44.107Z", + "updated_at": "2024-10-24T06:47:24.899Z", + "parent_kid": "pkid", + "public_key": "pkey" +} diff --git a/src/test/resources/mgmt/encryption_keys_list.json b/src/test/resources/mgmt/encryption_keys_list.json new file mode 100644 index 00000000..fe5fc2d2 --- /dev/null +++ b/src/test/resources/mgmt/encryption_keys_list.json @@ -0,0 +1,29 @@ +[ + { + "kid": "kid-1", + "type": "customer-provided-root-key", + "state": "pre-activation", + "created_at": "2024-10-24T08:02:18.029Z", + "updated_at": "2024-10-24T08:02:18.029Z", + "parent_kid": null, + "public_key": null + }, + { + "kid": "kid-2", + "type": "tenant-master-key", + "state": "active", + "created_at": "2024-10-24T06:47:23.749Z", + "updated_at": "2024-10-24T06:47:23.749Z", + "parent_kid": "pkid-1", + "public_key": null + }, + { + "kid": "kid-3", + "type": "tenant-master-key", + "state": "destroyed", + "created_at": "2024-10-16T10:50:44.107Z", + "updated_at": "2024-10-24T06:47:24.899Z", + "parent_kid": "pkid-2", + "public_key": null + } +] From bc505cafbd6e28cf4e4166debd66f8b407d5bc22 Mon Sep 17 00:00:00 2001 From: Tanya Sinha Date: Tue, 5 Nov 2024 10:47:09 +0530 Subject: [PATCH 21/32] Release 2.15.0 (#675) --- .version | 2 +- CHANGELOG.md | 6 ++++++ README.md | 4 ++-- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/.version b/.version index edcfe40d..68e69e40 100644 --- a/.version +++ b/.version @@ -1 +1 @@ -2.14.0 +2.15.0 diff --git a/CHANGELOG.md b/CHANGELOG.md index ff8707a7..59a0c057 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Change Log +## [2.15.0](https://github.com/auth0/auth0-java/tree/2.15.0) (2024-10-31) +[Full Changelog](https://github.com/auth0/auth0-java/compare/2.14.0...2.15.0) + +**Added** +- Added support for byok [\#673](https://github.com/auth0/auth0-java/pull/673) ([tanya732](https://github.com/tanya732)) + ## [2.14.0](https://github.com/auth0/auth0-java/tree/2.14.0) (2024-10-16) [Full Changelog](https://github.com/auth0/auth0-java/compare/2.13.0...2.14.0) diff --git a/README.md b/README.md index 9528b907..adecd2b9 100644 --- a/README.md +++ b/README.md @@ -34,14 +34,14 @@ Add the dependency via Maven: com.auth0 auth0 - 2.14.0 + 2.15.0 ``` or Gradle: ```gradle -implementation 'com.auth0:auth0:2.14.0' +implementation 'com.auth0:auth0:2.15.0' ``` ### Configure the SDK From a05e32bfb1afd3b8325edc1d2a5fc15246a9cade Mon Sep 17 00:00:00 2001 From: Tanya Sinha Date: Tue, 3 Dec 2024 09:23:01 +0530 Subject: [PATCH 22/32] Added is_signup_enabled field to OrganizationConnection (#677) --- .../mgmt/organizations/EnabledConnection.java | 17 +++++++++++++++++ .../EnabledConnectionsPageTest.java | 4 ++++ .../organizations/EnabledConnectionsTest.java | 3 +++ 3 files changed, 24 insertions(+) diff --git a/src/main/java/com/auth0/json/mgmt/organizations/EnabledConnection.java b/src/main/java/com/auth0/json/mgmt/organizations/EnabledConnection.java index af9d0588..ba144f46 100644 --- a/src/main/java/com/auth0/json/mgmt/organizations/EnabledConnection.java +++ b/src/main/java/com/auth0/json/mgmt/organizations/EnabledConnection.java @@ -20,6 +20,8 @@ public class EnabledConnection { private String connectionId; @JsonProperty("show_as_button") private Boolean showAsButton; + @JsonProperty("is_signup_enabled") + private Boolean isSignupEnabled; public EnabledConnection() {} @@ -95,4 +97,19 @@ public Boolean getShowAsButton() { public void setShowAsButton(Boolean showAsButton) { this.showAsButton = showAsButton; } + + /** + * @return whether signup is enabled for this connection. + */ + public Boolean getSignupEnabled() { + return isSignupEnabled; + } + + /** + * Sets whether signup is enabled for this connection. + * @param signupEnabled {@code true} to enable signup, {@code false} to disable it. + */ + public void setSignupEnabled(Boolean signupEnabled) { + isSignupEnabled = signupEnabled; + } } diff --git a/src/test/java/com/auth0/json/mgmt/organizations/EnabledConnectionsPageTest.java b/src/test/java/com/auth0/json/mgmt/organizations/EnabledConnectionsPageTest.java index d52e0112..8bfe7529 100644 --- a/src/test/java/com/auth0/json/mgmt/organizations/EnabledConnectionsPageTest.java +++ b/src/test/java/com/auth0/json/mgmt/organizations/EnabledConnectionsPageTest.java @@ -12,6 +12,7 @@ public class EnabledConnectionsPageTest extends JsonTest " {\n" + " \"connection_id\": \"con_1\",\n" + " \"assign_membership_on_login\": false,\n" + + " \"is_signup_enabled\": true,\n" + " \"connection\": {\n" + " \"name\": \"google-oauth2\",\n" + " \"strategy\": \"google-oauth2\"\n" + @@ -20,6 +21,7 @@ public class EnabledConnectionsPageTest extends JsonTest " {\n" + " \"connection_id\": \"con_2\",\n" + " \"assign_membership_on_login\": true,\n" + + " \"is_signup_enabled\": true,\n" + " \"connection\": {\n" + " \"name\": \"Username-Password-Authentication\",\n" + " \"strategy\": \"auth0\"\n" + @@ -32,6 +34,7 @@ public class EnabledConnectionsPageTest extends JsonTest " {\n" + " \"connection_id\": \"con_1\",\n" + " \"assign_membership_on_login\": false,\n" + + " \"is_signup_enabled\": true,\n" + " \"connection\": {\n" + " \"name\": \"google-oauth2\",\n" + " \"strategy\": \"google-oauth2\"\n" + @@ -40,6 +43,7 @@ public class EnabledConnectionsPageTest extends JsonTest " {\n" + " \"connection_id\": \"con_2\",\n" + " \"assign_membership_on_login\": true,\n" + + " \"is_signup_enabled\": true,\n" + " \"connection\": {\n" + " \"name\": \"Username-Password-Authentication\",\n" + " \"strategy\": \"auth0\"\n" + diff --git a/src/test/java/com/auth0/json/mgmt/organizations/EnabledConnectionsTest.java b/src/test/java/com/auth0/json/mgmt/organizations/EnabledConnectionsTest.java index b232c627..49017692 100644 --- a/src/test/java/com/auth0/json/mgmt/organizations/EnabledConnectionsTest.java +++ b/src/test/java/com/auth0/json/mgmt/organizations/EnabledConnectionsTest.java @@ -22,6 +22,7 @@ public void shouldSerialize() throws Exception { EnabledConnection enabledConnection = new EnabledConnection(); enabledConnection.setAssignMembershipOnLogin(true); enabledConnection.setConnection(connection); + enabledConnection.setSignupEnabled(true); String serialized = toJSON(enabledConnection); assertThat(serialized, is(notNullValue())); @@ -39,6 +40,7 @@ public void shouldDeserialize() throws Exception { String json = "{\n" + " \"connection_id\": \"con_id\",\n" + " \"assign_membership_on_login\": false,\n" + + " \"is_signup_enabled\": true,\n" + " \"connection\": {\n" + " \"name\": \"google-oauth2\",\n" + " \"strategy\": \"google-oauth2\"\n" + @@ -49,6 +51,7 @@ public void shouldDeserialize() throws Exception { assertThat(enabledConnection, is(notNullValue())); assertThat(enabledConnection.getConnectionId(), is("con_id")); assertThat(enabledConnection.isAssignMembershipOnLogin(), is(false)); + assertThat(enabledConnection.getSignupEnabled(), is(true)); assertThat(enabledConnection.getConnection(), is(notNullValue())); assertThat(enabledConnection.getConnection().getName(), is("google-oauth2")); assertThat(enabledConnection.getConnection().getStrategy(), is("google-oauth2")); From 9c484d33a6a29dc90271a46f6d02928308b9d7bf Mon Sep 17 00:00:00 2001 From: Tanya Sinha Date: Tue, 3 Dec 2024 09:28:04 +0530 Subject: [PATCH 23/32] Added phone number identifier in signup Auth API (#679) --- .../java/com/auth0/client/auth/AuthAPI.java | 36 +++++++++++++++++++ .../java/com/auth0/json/auth/CreatedUser.java | 6 ++++ .../com/auth0/client/auth/AuthAPITest.java | 35 ++++++++++++++++++ src/test/resources/auth/sign_up_username.json | 5 +-- 4 files changed, 80 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/auth0/client/auth/AuthAPI.java b/src/main/java/com/auth0/client/auth/AuthAPI.java index a9f7a9e9..ad353a32 100644 --- a/src/main/java/com/auth0/client/auth/AuthAPI.java +++ b/src/main/java/com/auth0/client/auth/AuthAPI.java @@ -68,6 +68,7 @@ public class AuthAPI { private static final String PATH_PASSWORDLESS = "passwordless"; private static final String PATH_START = "start"; private static final String KEY_ORGANIZATION = "organization"; + private static final String KEY_PHONE_NUMBER = "phone_number"; private final Auth0HttpClient client; private final String clientId; @@ -485,6 +486,41 @@ public Request resetPassword(String clientId, String email, String connect return request; } + /** + * Creates a sign up request with the given credentials, phone number and database connection. + * "Requires Username" option must be turned on in the Connection's configuration first. + * i.e.: + *

+     * {@code
+     * try {
+     *      Map fields = new HashMap();
+     *      fields.put("age", "25);
+     *      fields.put("city", "Buenos Aires");
+     *      authAPI.signUp("me@auth0.com", "myself", new char[]{'s','e','c','r','e','t'}, "db-connection", "1234567890")
+     *          .setCustomFields(fields)
+     *          .execute();
+     * } catch (Auth0Exception e) {
+     *      //Something happened
+     * }
+     * }
+     * 
+ * + * @see Signup API docs + * @param email the desired user's email. + * @param username the desired user's username. + * @param password the desired user's password. + * @param connection the database connection where the user is going to be created. + * @param phoneNumber the desired users's phone number. + * @return a Request to configure and execute. + */ + public SignUpRequest signUp(String email, String username, char[] password, String connection, String phoneNumber) { + Asserts.assertNotNull(phoneNumber, "phone number"); + + SignUpRequest request = this.signUp(email, username, password, connection); + request.addParameter(KEY_PHONE_NUMBER, phoneNumber); + return request; + } + /** * Creates a sign up request with the given credentials and database connection. * "Requires Username" option must be turned on in the Connection's configuration first. diff --git a/src/main/java/com/auth0/json/auth/CreatedUser.java b/src/main/java/com/auth0/json/auth/CreatedUser.java index 79d05378..c2d0b6ef 100644 --- a/src/main/java/com/auth0/json/auth/CreatedUser.java +++ b/src/main/java/com/auth0/json/auth/CreatedUser.java @@ -22,6 +22,8 @@ public class CreatedUser { private String username; @JsonProperty("email_verified") private Boolean emailVerified; + @JsonProperty("phone_number") + private String phoneNumber; @JsonProperty("_id") @JsonAlias({"_id", "id", "user_id"}) @@ -44,4 +46,8 @@ public Boolean isEmailVerified() { return emailVerified; } + @JsonProperty("phone_number") + public String getPhoneNumber() { + return phoneNumber; + } } diff --git a/src/test/java/com/auth0/client/auth/AuthAPITest.java b/src/test/java/com/auth0/client/auth/AuthAPITest.java index 6ae92f09..535fec03 100644 --- a/src/test/java/com/auth0/client/auth/AuthAPITest.java +++ b/src/test/java/com/auth0/client/auth/AuthAPITest.java @@ -400,6 +400,13 @@ public void shouldThrowOnUsernameSignUpWithNullConnection() { "'connection' cannot be null!"); } + @Test + public void shouldThrowOnUsernameAndPhoneNumberSignUpWithNullPhoneNumber() { + verifyThrows(IllegalArgumentException.class, + () -> api.signUp("me@auth0.com", "me", new char[]{'p','4','5','5','w','0','r','d'}, "my-connection", null), + "'phone number' cannot be null!"); + } + @Test public void shouldHaveNotStrongPasswordWithDetailedDescription() throws Exception { ObjectMapper mapper = new ObjectMapper(); @@ -424,6 +431,34 @@ public void shouldHaveNotStrongPasswordWithShortDetailedDescription() throws Exc assertThat(ex.getDescription(), is(expectedDescription)); } + @Test + public void shouldCreateSignUpRequestWithUsernameAndPhoneNumber() throws Exception { + SignUpRequest request = api.signUp("me@auth0.com", "me", new char[]{'p','4','5','5','w','0','r','d'}, "db-connection", "1234567890"); + assertThat(request, is(notNullValue())); + + server.jsonResponse(AUTH_SIGN_UP_USERNAME, 200); + CreatedUser response = request.execute().getBody(); + RecordedRequest recordedRequest = server.takeRequest(); + + assertThat(recordedRequest, hasMethodAndPath(HttpMethod.POST, "/dbconnections/signup")); + assertThat(recordedRequest, hasHeader("Content-Type", "application/json")); + + Map body = bodyFromRequest(recordedRequest); + assertThat(body, hasEntry("email", "me@auth0.com")); + assertThat(body, hasEntry("username", "me")); + assertThat(body, hasEntry("password", "p455w0rd")); + assertThat(body, hasEntry("connection", "db-connection")); + assertThat(body, hasEntry("client_id", CLIENT_ID)); + assertThat(body, hasEntry("phone_number", "1234567890")); + + assertThat(response, is(notNullValue())); + assertThat(response.getUserId(), is("58457fe6b27")); + assertThat(response.getEmail(), is("me@auth0.com")); + assertThat(response.isEmailVerified(), is(false)); + assertThat(response.getUsername(), is("me")); + assertThat(response.getPhoneNumber(), is("1234567890")); + } + @Test public void shouldCreateSignUpRequestWithUsername() throws Exception { @SuppressWarnings("deprecation") diff --git a/src/test/resources/auth/sign_up_username.json b/src/test/resources/auth/sign_up_username.json index 6baee703..83315e25 100644 --- a/src/test/resources/auth/sign_up_username.json +++ b/src/test/resources/auth/sign_up_username.json @@ -2,5 +2,6 @@ "_id": "58457fe6b27", "email_verified": false, "email": "me@auth0.com", - "username": "me" -} \ No newline at end of file + "username": "me", + "phone_number": "1234567890" +} From 4ad68f1c51155f256628ce792f35c8bce92f5472 Mon Sep 17 00:00:00 2001 From: Tanya Sinha Date: Tue, 3 Dec 2024 09:35:17 +0530 Subject: [PATCH 24/32] 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 +} From 13cded1592a2664a94b2b121c33de16ba1c5c980 Mon Sep 17 00:00:00 2001 From: tanya732 Date: Tue, 3 Dec 2024 15:15:18 +0530 Subject: [PATCH 25/32] Release 2.16.0 --- .version | 2 +- CHANGELOG.md | 8 ++++++++ README.md | 4 ++-- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/.version b/.version index 68e69e40..75249069 100644 --- a/.version +++ b/.version @@ -1 +1 @@ -2.15.0 +2.16.0 diff --git a/CHANGELOG.md b/CHANGELOG.md index 59a0c057..7c35b759 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Change Log +## [2.16.0](https://github.com/auth0/auth0-java/tree/2.16.0) (2024-12-03) +[Full Changelog](https://github.com/auth0/auth0-java/compare/2.15.0...2.16.0) + +**Added** +- Added support for custom prompts [\#680](https://github.com/auth0/auth0-java/pull/680) ([tanya732](https://github.com/tanya732)) +- Added phone number identifier in signup Auth API [\#679](https://github.com/auth0/auth0-java/pull/679) ([tanya732](https://github.com/tanya732)) +- Added is_signup_enabled field to OrganizationConnection [\#677](https://github.com/auth0/auth0-java/pull/677) ([tanya732](https://github.com/tanya732)) + ## [2.15.0](https://github.com/auth0/auth0-java/tree/2.15.0) (2024-10-31) [Full Changelog](https://github.com/auth0/auth0-java/compare/2.14.0...2.15.0) diff --git a/README.md b/README.md index adecd2b9..8c043f84 100644 --- a/README.md +++ b/README.md @@ -34,14 +34,14 @@ Add the dependency via Maven: com.auth0 auth0 - 2.15.0 + 2.16.0 ``` or Gradle: ```gradle -implementation 'com.auth0:auth0:2.15.0' +implementation 'com.auth0:auth0:2.16.0' ``` ### Configure the SDK From 95b7e43dc908b1ed0c9255cc728edbbac149ed7c Mon Sep 17 00:00:00 2001 From: Tanya Sinha Date: Thu, 2 Jan 2025 17:56:30 +0530 Subject: [PATCH 26/32] Added support for Back Channel Login (#682) --- .../java/com/auth0/client/auth/AuthAPI.java | 55 ++++++++ .../auth/BackChannelAuthorizeResponse.java | 45 +++++++ .../json/auth/BackChannelTokenResponse.java | 34 +++++ .../java/com/auth0/client/MockServer.java | 2 + .../com/auth0/client/auth/AuthAPITest.java | 121 ++++++++++++++++++ .../auth/back_channel_authorize_response.json | 5 + .../back_channel_login_status_response.json | 6 + 7 files changed, 268 insertions(+) create mode 100644 src/main/java/com/auth0/json/auth/BackChannelAuthorizeResponse.java create mode 100644 src/main/java/com/auth0/json/auth/BackChannelTokenResponse.java create mode 100644 src/test/resources/auth/back_channel_authorize_response.json create mode 100644 src/test/resources/auth/back_channel_login_status_response.json diff --git a/src/main/java/com/auth0/client/auth/AuthAPI.java b/src/main/java/com/auth0/client/auth/AuthAPI.java index ad353a32..4334223c 100644 --- a/src/main/java/com/auth0/client/auth/AuthAPI.java +++ b/src/main/java/com/auth0/client/auth/AuthAPI.java @@ -225,6 +225,61 @@ public AuthorizeUrlBuilder authorizeUrl(String redirectUri) { return AuthorizeUrlBuilder.newInstance(baseUrl, clientId, redirectUri); } + public Request authorizeBackChannel(String scope, String bindingMessage, Map loginHint) { + return authorizeBackChannel(scope, bindingMessage, loginHint, null, null); + } + + public Request authorizeBackChannel(String scope, String bindingMessage, Map loginHint, String audience, Integer requestExpiry) { + Asserts.assertNotNull(scope, "scope"); + Asserts.assertNotNull(bindingMessage, "binding message"); + Asserts.assertNotNull(loginHint, "login hint"); + + String url = baseUrl + .newBuilder() + .addPathSegment("bc-authorize") + .build() + .toString(); + + FormBodyRequest request = new FormBodyRequest<>(client, null, url, HttpMethod.POST, new TypeReference() {}); + + request.addParameter(KEY_CLIENT_ID, clientId); + addClientAuthentication(request, false); + request.addParameter("scope", scope); + request.addParameter("binding_message", bindingMessage); + + if(Objects.nonNull(audience)){ + request.addParameter(KEY_AUDIENCE, audience); + } + if(Objects.nonNull(requestExpiry)){ + request.addParameter("request_expiry", requestExpiry); + } + + try { + String loginHintJson = getMapper().writeValueAsString(loginHint); + request.addParameter("login_hint", loginHintJson); + } + catch (JsonProcessingException e) { + throw new IllegalArgumentException("'loginHint' must be a map that can be serialized to JSON", e); + } + return request; + } + + public Request getBackChannelLoginStatus(String authReqId, String grantType) { + Asserts.assertNotNull(authReqId, "auth req id"); + Asserts.assertNotNull(grantType, "grant type"); + + String url = getTokenUrl(); + + FormBodyRequest request = new FormBodyRequest<>(client, null, url, HttpMethod.POST, new TypeReference() {}); + + request.addParameter(KEY_CLIENT_ID, clientId); + addClientAuthentication(request, false); + request.addParameter("auth_req_id", authReqId); + request.addParameter(KEY_GRANT_TYPE, grantType); + + return request; + } + /** * Builds an authorization URL for Pushed Authorization Requests (PAR) * @param requestUri the {@code request_uri} parameter from a successful pushed authorization request. diff --git a/src/main/java/com/auth0/json/auth/BackChannelAuthorizeResponse.java b/src/main/java/com/auth0/json/auth/BackChannelAuthorizeResponse.java new file mode 100644 index 00000000..1765867d --- /dev/null +++ b/src/main/java/com/auth0/json/auth/BackChannelAuthorizeResponse.java @@ -0,0 +1,45 @@ +package com.auth0.json.auth; + +import com.fasterxml.jackson.annotation.*; + +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +public class BackChannelAuthorizeResponse { + @JsonProperty("auth_req_id") + private String authReqId; + @JsonProperty("expires_in") + private Long expiresIn; + @JsonProperty("interval") + private Integer interval; + + @JsonCreator + public BackChannelAuthorizeResponse(@JsonProperty("auth_req_id") String authReqId, @JsonProperty("expires_in") Long expiresIn, @JsonProperty("interval") Integer interval) { + this.authReqId = authReqId; + this.expiresIn = expiresIn; + this.interval = interval; + } + + /** + * Getter for the Auth Request ID. + * @return the Auth Request ID. + */ + public String getAuthReqId() { + return authReqId; + } + + /** + * Getter for the Expires In value. + * @return the Expires In value. + */ + public Long getExpiresIn() { + return expiresIn; + } + + /** + * Getter for the Interval value. + * @return the Interval value. + */ + public Integer getInterval() { + return interval; + } +} diff --git a/src/main/java/com/auth0/json/auth/BackChannelTokenResponse.java b/src/main/java/com/auth0/json/auth/BackChannelTokenResponse.java new file mode 100644 index 00000000..ab632f98 --- /dev/null +++ b/src/main/java/com/auth0/json/auth/BackChannelTokenResponse.java @@ -0,0 +1,34 @@ +package com.auth0.json.auth; + +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 BackChannelTokenResponse { + @JsonProperty("access_token") + private String accessToken; + @JsonProperty("id_token") + private String idToken; + @JsonProperty("expires_in") + private long expiresIn; + @JsonProperty("scope") + private String scope; + + public String getAccessToken() { + return accessToken; + } + + public String getIdToken() { + return idToken; + } + + public long getExpiresIn() { + return expiresIn; + } + + public String getScope() { + return scope; + } +} diff --git a/src/test/java/com/auth0/client/MockServer.java b/src/test/java/com/auth0/client/MockServer.java index cc65cab6..54bfc049 100644 --- a/src/test/java/com/auth0/client/MockServer.java +++ b/src/test/java/com/auth0/client/MockServer.java @@ -116,6 +116,8 @@ public class MockServer { public static final String PASSWORDLESS_EMAIL_RESPONSE = "src/test/resources/auth/passwordless_email.json"; public static final String PASSWORDLESS_SMS_RESPONSE = "src/test/resources/auth/passwordless_sms.json"; public static final String PUSHED_AUTHORIZATION_RESPONSE = "src/test/resources/auth/pushed_authorization_response.json"; + public static final String BACK_CHANNEL_AUTHORIZE_RESPONSE = "src/test/resources/auth/back_channel_authorize_response.json"; + public static final String BACK_CHANNEL_LOGIN_STATUS_RESPONSE = "src/test/resources/auth/back_channel_login_status_response.json"; public static final String AUTHENTICATOR_METHOD_BY_ID = "src/test/resources/mgmt/authenticator_method_by_id.json"; public static final String AUTHENTICATOR_METHOD_CREATE = "src/test/resources/mgmt/authenticator_method_create.json"; public static final String AUTHENTICATOR_METHOD_LIST = "src/test/resources/mgmt/authenticator_method_list.json"; diff --git a/src/test/java/com/auth0/client/auth/AuthAPITest.java b/src/test/java/com/auth0/client/auth/AuthAPITest.java index 535fec03..4e8366a4 100644 --- a/src/test/java/com/auth0/client/auth/AuthAPITest.java +++ b/src/test/java/com/auth0/client/auth/AuthAPITest.java @@ -2009,6 +2009,127 @@ public void shouldThrowWhenCreatePushedAuthorizationJarRequestWithInvalidAuthDet assertThat(e.getCause(), instanceOf(JsonProcessingException.class)); } + @Test + public void authorizeBackChannelWhenScopeIsNull() { + verifyThrows(IllegalArgumentException.class, + () -> api.authorizeBackChannel(null, "This is binding message", getLoginHint()), + "'scope' cannot be null!"); + } + + @Test + public void authorizeBackChannelWhenBindingMessageIsNull() { + verifyThrows(IllegalArgumentException.class, + () -> api.authorizeBackChannel("openid", null, getLoginHint()), + "'binding message' cannot be null!"); + } + + @Test + public void authorizeBackChannelWhenLoginHintIsNull() { + verifyThrows(IllegalArgumentException.class, + () -> api.authorizeBackChannel("openid", "This is binding message", null), + "'login hint' cannot be null!"); + } + + @Test + public void authorizeBackChannel() throws Exception { + Request request = api.authorizeBackChannel("openid", "This is binding message", getLoginHint()); + assertThat(request, is(notNullValue())); + + server.jsonResponse(BACK_CHANNEL_AUTHORIZE_RESPONSE, 200); + BackChannelAuthorizeResponse response = request.execute().getBody(); + RecordedRequest recordedRequest = server.takeRequest(); + + assertThat(recordedRequest, hasMethodAndPath(HttpMethod.POST, "/bc-authorize")); + assertThat(recordedRequest, hasHeader("Content-Type", "application/x-www-form-urlencoded")); + + String body = URLDecoder.decode(readFromRequest(recordedRequest), StandardCharsets.UTF_8.name()); + assertThat(body, containsString("scope=" + "openid")); + assertThat(body, containsString("client_id=" + CLIENT_ID)); + assertThat(body, containsString("client_secret=" + CLIENT_SECRET)); + assertThat(body, containsString("binding_message=This is binding message")); + assertThat(body, containsString("login_hint={\"sub\":\"auth0|user1\",\"format\":\"format1\",\"iss\":\"https://auth0.com\"}")); + + assertThat(response, is(notNullValue())); + assertThat(response.getAuthReqId(), not(emptyOrNullString())); + assertThat(response.getExpiresIn(), notNullValue()); + assertThat(response.getInterval(), notNullValue()); + } + + @Test + public void authorizeBackChannelWithAudienceAndRequestExpiry() throws Exception { + Request request = api.authorizeBackChannel("openid", "This is binding message", getLoginHint(), "https://api.example.com", 300); + assertThat(request, is(notNullValue())); + + server.jsonResponse(BACK_CHANNEL_AUTHORIZE_RESPONSE, 200); + BackChannelAuthorizeResponse response = request.execute().getBody(); + RecordedRequest recordedRequest = server.takeRequest(); + + assertThat(recordedRequest, hasMethodAndPath(HttpMethod.POST, "/bc-authorize")); + assertThat(recordedRequest, hasHeader("Content-Type", "application/x-www-form-urlencoded")); + + String body = URLDecoder.decode(readFromRequest(recordedRequest), StandardCharsets.UTF_8.name()); + assertThat(body, containsString("scope=" + "openid")); + assertThat(body, containsString("client_id=" + CLIENT_ID)); + assertThat(body, containsString("client_secret=" + CLIENT_SECRET)); + assertThat(body, containsString("binding_message=This is binding message")); + assertThat(body, containsString("login_hint={\"sub\":\"auth0|user1\",\"format\":\"format1\",\"iss\":\"https://auth0.com\"}")); + assertThat(body, containsString("request_expiry=" + 300)); + assertThat(body, containsString("audience=" + "https://api.example.com")); + + assertThat(response, is(notNullValue())); + assertThat(response.getAuthReqId(), not(emptyOrNullString())); + assertThat(response.getExpiresIn(), notNullValue()); + assertThat(response.getInterval(), notNullValue()); + } + + private Map getLoginHint() { + Map loginHint = new HashMap<>(); + loginHint.put("format", "format1"); + loginHint.put("iss", "https://auth0.com"); + loginHint.put("sub", "auth0|user1"); + return loginHint; + } + + @Test + public void getBackChannelLoginStatusWhenAuthReqIdIsNull() { + verifyThrows(IllegalArgumentException.class, + () -> api.getBackChannelLoginStatus(null, "ciba"), + "'auth req id' cannot be null!"); + } + + @Test + public void getBackChannelLoginStatusWhenGrantTypeIsNull() { + verifyThrows(IllegalArgumentException.class, + () -> api.getBackChannelLoginStatus("red_id_1", null), + "'grant type' cannot be null!"); + } + + @Test + public void getBackChannelLoginStatus() throws Exception { + Request request = api.getBackChannelLoginStatus("red_id_1", "ciba"); + assertThat(request, is(notNullValue())); + + server.jsonResponse(BACK_CHANNEL_LOGIN_STATUS_RESPONSE, 200); + BackChannelTokenResponse response = request.execute().getBody(); + RecordedRequest recordedRequest = server.takeRequest(); + + assertThat(recordedRequest, hasMethodAndPath(HttpMethod.POST, "/oauth/token")); + assertThat(recordedRequest, hasHeader("Content-Type", "application/x-www-form-urlencoded")); + + String body = URLDecoder.decode(readFromRequest(recordedRequest), StandardCharsets.UTF_8.name()); + assertThat(body, containsString("client_id=" + CLIENT_ID)); + assertThat(body, containsString("client_secret=" + CLIENT_SECRET)); + assertThat(body, containsString("auth_req_id=red_id_1")); + assertThat(body, containsString("grant_type=ciba")); + + assertThat(response, is(notNullValue())); + assertThat(response.getAccessToken(), not(emptyOrNullString())); + assertThat(response.getIdToken(), not(emptyOrNullString())); + assertThat(response.getExpiresIn(), notNullValue()); + assertThat(response.getScope(), not(emptyOrNullString())); + } + + private Map getQueryMap(String input) { String[] params = input.split("&"); diff --git a/src/test/resources/auth/back_channel_authorize_response.json b/src/test/resources/auth/back_channel_authorize_response.json new file mode 100644 index 00000000..bc0649f0 --- /dev/null +++ b/src/test/resources/auth/back_channel_authorize_response.json @@ -0,0 +1,5 @@ +{ + "auth_req_id": "red_id_1", + "expires_in": 300, + "interval": 5 +} diff --git a/src/test/resources/auth/back_channel_login_status_response.json b/src/test/resources/auth/back_channel_login_status_response.json new file mode 100644 index 00000000..bc1676e2 --- /dev/null +++ b/src/test/resources/auth/back_channel_login_status_response.json @@ -0,0 +1,6 @@ +{ + "access_token": "eyJhbGciOiJkaXIi.....", + "id_token": "eyJhbGciOiJSUzI1NiIs.....", + "expires_in": 86400, + "scope": "openid" +} From 15367e725a5fd22c6613839571dc92e3421e6ebe Mon Sep 17 00:00:00 2001 From: Tanya Sinha Date: Fri, 3 Jan 2025 13:33:42 +0530 Subject: [PATCH 27/32] Migrated bouncycastle to jdk18on (#684) --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 21a25440..9f9ad2ad 100644 --- a/build.gradle +++ b/build.gradle @@ -134,7 +134,7 @@ dependencies { implementation "com.auth0:java-jwt:4.4.0" implementation "net.jodah:failsafe:2.4.4" - testImplementation "org.bouncycastle:bcprov-jdk15on:1.70" + testImplementation "org.bouncycastle:bcprov-jdk18on:1.78" testImplementation "org.mockito:mockito-core:4.8.1" testImplementation "com.squareup.okhttp3:mockwebserver:${okhttpVersion}" testImplementation "org.hamcrest:hamcrest:${hamcrestVersion}" From 40f35f15d2e2136f79556d5d8725d24159eb237c Mon Sep 17 00:00:00 2001 From: Tanya Sinha Date: Wed, 8 Jan 2025 13:38:48 +0530 Subject: [PATCH 28/32] Added Support for Self-Service-Profile (#683) --- .../com/auth0/client/mgmt/ManagementAPI.java | 8 + .../mgmt/SelfServiceProfilesEntity.java | 239 +++++++++++++ .../filter/PageBasedPaginationFilter.java | 31 ++ .../mgmt/selfserviceprofiles/Branding.java | 46 +++ .../json/mgmt/selfserviceprofiles/Color.java | 43 +++ .../SelfServiceProfile.java | 103 ++++++ .../SelfServiceProfileResponse.java | 64 ++++ .../SelfServiceProfileResponsePage.java | 21 ++ ...erviceProfileResponsePageDeserializer.java | 23 ++ .../SsoAccessTicketResponse.java | 41 +++ .../selfserviceprofiles/UserAttribute.java | 83 +++++ .../java/com/auth0/client/MockServer.java | 4 + .../mgmt/SelfServiceProfilesEntityTest.java | 325 ++++++++++++++++++ .../filter/PageBasedPaginationFilterTest.java | 39 +++ .../SelfServiceProfileResponsePageTest.java | 173 ++++++++++ .../SelfServiceProfileResponseTest.java | 73 ++++ .../SelfServiceProfileTest.java | 62 ++++ .../SsoAccessTicketResponseTest.java | 31 ++ .../resources/mgmt/self_service_profile.json | 21 ++ .../self_service_profile_custom_text.json | 3 + .../mgmt/self_service_profile_response.json | 23 ++ .../mgmt/self_service_profile_sso_ticket.json | 3 + .../mgmt/self_service_profiles_list.json | 64 ++++ 23 files changed, 1523 insertions(+) create mode 100644 src/main/java/com/auth0/client/mgmt/SelfServiceProfilesEntity.java create mode 100644 src/main/java/com/auth0/client/mgmt/filter/PageBasedPaginationFilter.java create mode 100644 src/main/java/com/auth0/json/mgmt/selfserviceprofiles/Branding.java create mode 100644 src/main/java/com/auth0/json/mgmt/selfserviceprofiles/Color.java create mode 100644 src/main/java/com/auth0/json/mgmt/selfserviceprofiles/SelfServiceProfile.java create mode 100644 src/main/java/com/auth0/json/mgmt/selfserviceprofiles/SelfServiceProfileResponse.java create mode 100644 src/main/java/com/auth0/json/mgmt/selfserviceprofiles/SelfServiceProfileResponsePage.java create mode 100644 src/main/java/com/auth0/json/mgmt/selfserviceprofiles/SelfServiceProfileResponsePageDeserializer.java create mode 100644 src/main/java/com/auth0/json/mgmt/selfserviceprofiles/SsoAccessTicketResponse.java create mode 100644 src/main/java/com/auth0/json/mgmt/selfserviceprofiles/UserAttribute.java create mode 100644 src/test/java/com/auth0/client/mgmt/SelfServiceProfilesEntityTest.java create mode 100644 src/test/java/com/auth0/client/mgmt/filter/PageBasedPaginationFilterTest.java create mode 100644 src/test/java/com/auth0/json/mgmt/selfserviceprofiles/SelfServiceProfileResponsePageTest.java create mode 100644 src/test/java/com/auth0/json/mgmt/selfserviceprofiles/SelfServiceProfileResponseTest.java create mode 100644 src/test/java/com/auth0/json/mgmt/selfserviceprofiles/SelfServiceProfileTest.java create mode 100644 src/test/java/com/auth0/json/mgmt/selfserviceprofiles/SsoAccessTicketResponseTest.java create mode 100644 src/test/resources/mgmt/self_service_profile.json create mode 100644 src/test/resources/mgmt/self_service_profile_custom_text.json create mode 100644 src/test/resources/mgmt/self_service_profile_response.json create mode 100644 src/test/resources/mgmt/self_service_profile_sso_ticket.json create mode 100644 src/test/resources/mgmt/self_service_profiles_list.json diff --git a/src/main/java/com/auth0/client/mgmt/ManagementAPI.java b/src/main/java/com/auth0/client/mgmt/ManagementAPI.java index bc2a2d8f..6d4b03c2 100644 --- a/src/main/java/com/auth0/client/mgmt/ManagementAPI.java +++ b/src/main/java/com/auth0/client/mgmt/ManagementAPI.java @@ -388,6 +388,14 @@ public PromptsEntity prompts() { return new PromptsEntity(client, baseUrl, tokenProvider); } + /** + * Getter for the SelfServiceProfiles Entity + * @return the SelfServiceProfiles Entity + */ + public SelfServiceProfilesEntity selfServiceProfiles() { + return new SelfServiceProfilesEntity(client, baseUrl, tokenProvider); + } + /** * Builder for {@link ManagementAPI} API client instances. */ diff --git a/src/main/java/com/auth0/client/mgmt/SelfServiceProfilesEntity.java b/src/main/java/com/auth0/client/mgmt/SelfServiceProfilesEntity.java new file mode 100644 index 00000000..cf1cbdfe --- /dev/null +++ b/src/main/java/com/auth0/client/mgmt/SelfServiceProfilesEntity.java @@ -0,0 +1,239 @@ +package com.auth0.client.mgmt; + +import com.auth0.client.mgmt.filter.PageBasedPaginationFilter; +import com.auth0.json.mgmt.selfserviceprofiles.SelfServiceProfile; +import com.auth0.json.mgmt.selfserviceprofiles.SelfServiceProfileResponse; +import com.auth0.json.mgmt.selfserviceprofiles.SelfServiceProfileResponsePage; +import com.auth0.json.mgmt.selfserviceprofiles.SsoAccessTicketResponse; +import com.auth0.net.*; +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; + +import java.util.Map; + +public class SelfServiceProfilesEntity extends BaseManagementEntity { + + private final static String ORGS_PATH = "api/v2/self-service-profiles"; + + SelfServiceProfilesEntity(Auth0HttpClient client, HttpUrl baseUrl, TokenProvider tokenProvider) { + super(client, baseUrl, tokenProvider); + } + + /** + * Request the list of self-service profiles. + * A token with {@code read:self_service_profiles} scope is needed + * @see https://auth0.com/docs/api/management/v2#!/self-service-profiles/get-self-service-profiles + * @param pageFilter the pagination filter to apply. Can be null to use the default values. + * @return a Request to execute. + */ + public Request get(PageBasedPaginationFilter pageFilter) { + HttpUrl.Builder builder = baseUrl.newBuilder() + .addPathSegments(ORGS_PATH); + + if (pageFilter != null) { + for (Map.Entry e : pageFilter.getAsMap().entrySet()) { + builder.addQueryParameter(e.getKey(), String.valueOf(e.getValue())); + } + } + + String url = builder.build().toString(); + return new BaseRequest<>(this.client, tokenProvider, url, HttpMethod.GET, new TypeReference() { + }); + } + + /** + * Create a new self-service profile. + * A token with {@code create:self_service_profiles} scope is needed + * @see https://auth0.com/docs/api/management/v2#!/self-service-profiles/post-self-service-profiles + * @param selfServiceProfile the self-service profile to create. + * @return a Request to execute. + */ + public Request create(SelfServiceProfile selfServiceProfile) { + Asserts.assertNotNull(selfServiceProfile, "self service profile"); + Asserts.assertNotNull(selfServiceProfile.getName(), "name"); + + String url = baseUrl.newBuilder() + .addPathSegments(ORGS_PATH) + .build() + .toString(); + + BaseRequest request = new BaseRequest<>(this.client, tokenProvider, url, HttpMethod.POST, new TypeReference() { + }); + request.setBody(selfServiceProfile); + return request; + } + + /** + * Request the self-service profile with the given ID. + * A token with {@code read:self_service_profiles} scope is needed + * @see https://auth0.com/docs/api/management/v2#!/self-service-profiles/get-self-service-profiles-by-id + * @param id the self-service profile ID. + * @return a Request to execute. + */ + public Request getById(String id) { + Asserts.assertNotNull(id, "id"); + + String url = baseUrl.newBuilder() + .addPathSegments(ORGS_PATH) + .addPathSegment(id) + .build() + .toString(); + + return new BaseRequest<>(this.client, tokenProvider, url, HttpMethod.GET, new TypeReference() { + }); + } + + /** + * Delete the self-service profile with the given ID. + * A token with {@code delete:self_service_profiles} scope is needed + * @see https://auth0.com/docs/api/management/v2#!/self-service-profiles/delete-self-service-profiles-by-id + * @param id the self-service profile ID. + * @return a Request to execute. + */ + public Request delete(String id) { + Asserts.assertNotNull(id, "id"); + + String url = baseUrl.newBuilder() + .addPathSegments(ORGS_PATH) + .addPathSegment(id) + .build() + .toString(); + + return new VoidRequest(this.client, tokenProvider, url, HttpMethod.DELETE); + } + + /** + * Update the self-service profile with the given ID. + * A token with {@code update:self_service_profiles} scope is needed + * @see https://auth0.com/docs/api/management/v2#!/self-service-profiles/patch-self-service-profiles-by-id + * @param selfServiceProfile the self-service profile to update. + * @param id the self-service profile ID. + * @return a Request to execute. + */ + public Request update(SelfServiceProfile selfServiceProfile, String id) { + Asserts.assertNotNull(selfServiceProfile, "self service profile"); + Asserts.assertNotNull(id, "id"); + + String url = baseUrl.newBuilder() + .addPathSegments(ORGS_PATH) + .addPathSegment(id) + .build() + .toString(); + + BaseRequest request = new BaseRequest<>(this.client, tokenProvider, url, HttpMethod.PATCH, new TypeReference() { + }); + request.setBody(selfServiceProfile); + return request; + } + + /** + * Get the custom text for specific self-service profile and language. + * A token with {@code read:self_service_profile_custom_texts} scope is needed + * @see https://auth0.com/docs/api/management/v2#!/self-service-profiles/get-self-service-profile-custom-text + * @param id the self-service profile ID. + * @param language the language. + * @param page the page. + * @return a Request to execute. + */ + public Request getCustomText(String id, String language, String page) { + Asserts.assertNotNull(id, "id"); + Asserts.assertNotNull(language, "language"); + Asserts.assertNotNull(page, "page"); + + HttpUrl.Builder builder = baseUrl.newBuilder() + .addPathSegments(ORGS_PATH) + .addPathSegment(id) + .addPathSegment("custom-text") + .addPathSegment(language) + .addPathSegment(page); + + String url = builder.build().toString(); + + return new BaseRequest<>(this.client, tokenProvider, url, HttpMethod.GET, new TypeReference() { + }); + } + + /** + * Set the custom text for specific self-service profile and language. + * A token with {@code update:self_service_profile_custom_texts} scope is needed + * @see https://auth0.com/docs/api/management/v2#!/self-service-profiles/put-self-service-profile-custom-text + * @param id the self-service profile ID. + * @param language the language. + * @param page the page. + * @param customText the custom text. + * @return a Request to execute. + */ + public Request setCustomText(String id, String language, String page, Object customText) { + Asserts.assertNotNull(id, "id"); + Asserts.assertNotNull(language, "language"); + Asserts.assertNotNull(page, "page"); + Asserts.assertNotNull(customText, "custom text"); + + HttpUrl.Builder builder = baseUrl.newBuilder() + .addPathSegments(ORGS_PATH) + .addPathSegment(id) + .addPathSegment("custom-text") + .addPathSegment(language) + .addPathSegment(page); + + String url = builder.build().toString(); + + BaseRequest request = new BaseRequest<>(this.client, tokenProvider, url, HttpMethod.PUT, new TypeReference() { + }); + request.setBody(customText); + return request; + } + + /** + * Create a new SSO access ticket. + * A token with {@code create:sso_access_tickets} scope is needed + * @see https://auth0.com/docs/api/management/v2#!/self-service-profiles/post-sso-ticket + * @param id the self-service profile ID. + * @param payload the payload. + * @return a Request to execute. + */ + public Request createSsoAccessTicket(String id, Object payload) { + Asserts.assertNotNull(id, "id"); + Asserts.assertNotNull(payload, "payload"); + + HttpUrl.Builder builder = baseUrl.newBuilder() + .addPathSegments(ORGS_PATH) + .addPathSegment(id) + .addPathSegment("sso-ticket"); + + String url = builder.build().toString(); + + BaseRequest request = new BaseRequest<>(this.client, tokenProvider, url, HttpMethod.POST, new TypeReference() { + }); + request.setBody(payload); + return request; + } + + /** + * Revoke an SSO ticket. + * A token with {@code delete:sso_access_tickets} scope is needed + * @see https://auth0.com/docs/api/management/v2#!/self-service-profiles/post-revoke + * @param id the self-service profile ID. + * @param ticketId the ticket ID. + * @return a Request to execute. + */ + public Request revokeSsoTicket(String id, String ticketId) { + Asserts.assertNotNull(id, "id"); + Asserts.assertNotNull(ticketId, "ticket id"); + + HttpUrl.Builder builder = baseUrl.newBuilder() + .addPathSegments(ORGS_PATH) + .addPathSegment(id) + .addPathSegment("sso-ticket") + .addPathSegment(ticketId) + .addPathSegment("revoke"); + + String url = builder.build().toString(); + + return new EmptyBodyVoidRequest<>(this.client, tokenProvider, url, HttpMethod.POST, new TypeReference() { + }); + } +} diff --git a/src/main/java/com/auth0/client/mgmt/filter/PageBasedPaginationFilter.java b/src/main/java/com/auth0/client/mgmt/filter/PageBasedPaginationFilter.java new file mode 100644 index 00000000..a11b69b8 --- /dev/null +++ b/src/main/java/com/auth0/client/mgmt/filter/PageBasedPaginationFilter.java @@ -0,0 +1,31 @@ +package com.auth0.client.mgmt.filter; + +/** + * Class that represents a filter to be used when requesting a list of items with pagination. + */ +public class PageBasedPaginationFilter extends BaseFilter{ + + /** + * Filter by page + * + * @param pageNumber the page number to retrieve. + * @param amountPerPage the amount of items per page to retrieve. + * @return this filter instance + */ + public PageBasedPaginationFilter withPage(int pageNumber, int amountPerPage) { + parameters.put("page", pageNumber); + parameters.put("per_page", amountPerPage); + return this; + } + + /** + * Include the query summary + * + * @param includeTotals whether to include or not the query summary. + * @return this filter instance + */ + public PageBasedPaginationFilter withTotals(boolean includeTotals) { + parameters.put("include_totals", includeTotals); + return this; + } +} diff --git a/src/main/java/com/auth0/json/mgmt/selfserviceprofiles/Branding.java b/src/main/java/com/auth0/json/mgmt/selfserviceprofiles/Branding.java new file mode 100644 index 00000000..55433ba7 --- /dev/null +++ b/src/main/java/com/auth0/json/mgmt/selfserviceprofiles/Branding.java @@ -0,0 +1,46 @@ +package com.auth0.json.mgmt.selfserviceprofiles; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; + +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public class Branding { + @JsonProperty("logo_url") + private String logoUrl; + @JsonProperty("colors") + private Color colors; + + /** + * Getter for the logo URL. + * @return the logo URL. + */ + public String getLogoUrl() { + return logoUrl; + } + + /** + * Setter for the logo URL. + * @param logoUrl the logo URL to set. + */ + public void setLogoUrl(String logoUrl) { + this.logoUrl = logoUrl; + } + + /** + * Getter for the colors. + * @return the colors. + */ + public Color getColors() { + return colors; + } + + /** + * Setter for the colors. + * @param colors the colors to set. + */ + public void setColors(Color colors) { + this.colors = colors; + } +} diff --git a/src/main/java/com/auth0/json/mgmt/selfserviceprofiles/Color.java b/src/main/java/com/auth0/json/mgmt/selfserviceprofiles/Color.java new file mode 100644 index 00000000..87891fba --- /dev/null +++ b/src/main/java/com/auth0/json/mgmt/selfserviceprofiles/Color.java @@ -0,0 +1,43 @@ +package com.auth0.json.mgmt.selfserviceprofiles; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; + +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public class Color { + @JsonProperty("primary") + private String primary; + + /** + * Creates a new instance of the Color class. + */ + public Color() {} + + /** + * Creates a new instance of the Color class. + * @param primary the primary color. + */ + @JsonCreator + public Color(@JsonProperty("primary") String primary) { + this.primary = primary; + } + + /** + * Getter for the primary color. + * @return the primary color. + */ + public String getPrimary() { + return primary; + } + + /** + * Setter for the primary color. + * @param primary the primary color to set. + */ + public void setPrimary(String primary) { + this.primary = primary; + } +} diff --git a/src/main/java/com/auth0/json/mgmt/selfserviceprofiles/SelfServiceProfile.java b/src/main/java/com/auth0/json/mgmt/selfserviceprofiles/SelfServiceProfile.java new file mode 100644 index 00000000..1a81aa81 --- /dev/null +++ b/src/main/java/com/auth0/json/mgmt/selfserviceprofiles/SelfServiceProfile.java @@ -0,0 +1,103 @@ +package com.auth0.json.mgmt.selfserviceprofiles; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; + +import java.util.List; + +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public class SelfServiceProfile { + @JsonProperty("name") + private String name; + @JsonProperty("description") + private String description; + @JsonProperty("user_attributes") + private List userAttributes; + @JsonProperty("branding") + private Branding branding; + @JsonProperty("allowed_strategies") + private List allowedStrategies; + + /** + * Getter for the name of the self-service profile. + * @return the name of the self-service profile. + */ + public String getName() { + return name; + } + + /** + * Setter for the name of the self-service profile. + * @param name the name of the self-service profile to set. + */ + public void setName(String name) { + this.name = name; + } + + /** + * Getter for the description of the self-service profile. + * @return the description of the self-service profile. + */ + public String getDescription() { + return description; + } + + /** + * Setter for the description of the self-service profile. + * @param description the description of the self-service profile to set. + */ + public void setDescription(String description) { + this.description = description; + } + + /** + * Getter for the user attributes of the self-service profile. + * @return the user attributes of the self-service profile. + */ + public List getUserAttributes() { + return userAttributes; + } + + /** + * Setter for the user attributes of the self-service profile. + * @param userAttributes the user attributes of the self-service profile to set. + */ + public void setUserAttributes(List userAttributes) { + this.userAttributes = userAttributes; + } + + /** + * Getter for the branding of the self-service profile. + * @return the branding of the self-service profile. + */ + public Branding getBranding() { + return branding; + } + + /** + * Setter for the branding of the self-service profile. + * @param branding the branding of the self-service profile to set. + */ + public void setBranding(Branding branding) { + this.branding = branding; + } + + /** + * Getter for the allowed strategies of the self-service profile. + * @return the allowed strategies of the self-service profile. + */ + public List getAllowedStrategies() { + return allowedStrategies; + } + + /** + * Setter for the allowed strategies of the self-service profile. + * @param allowedStrategies the allowed strategies of the self-service profile to set. + */ + public void setAllowedStrategies(List allowedStrategies) { + this.allowedStrategies = allowedStrategies; + } +} diff --git a/src/main/java/com/auth0/json/mgmt/selfserviceprofiles/SelfServiceProfileResponse.java b/src/main/java/com/auth0/json/mgmt/selfserviceprofiles/SelfServiceProfileResponse.java new file mode 100644 index 00000000..838bb9da --- /dev/null +++ b/src/main/java/com/auth0/json/mgmt/selfserviceprofiles/SelfServiceProfileResponse.java @@ -0,0 +1,64 @@ +package com.auth0.json.mgmt.selfserviceprofiles; + +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 SelfServiceProfileResponse extends SelfServiceProfile { + @JsonProperty("id") + private String id; + @JsonProperty("created_at") + private String createdAt; + @JsonProperty("updated_at") + private String updatedAt; + + /** + * Getter for the id of the self-service profile. + * @return the id of the self-service profile. + */ + public String getId() { + return id; + } + + /** + * Setter for the id of the self-service profile. + * @param id the id of the self-service profile to set. + */ + public void setId(String id) { + this.id = id; + } + + /** + * Getter for the created at of the self-service profile. + * @return the created at of the self-service profile. + */ + public String getCreatedAt() { + return createdAt; + } + + /** + * Setter for the created at of the self-service profile. + * @param createdAt the created at of the self-service profile to set. + */ + public void setCreatedAt(String createdAt) { + this.createdAt = createdAt; + } + + /** + * Getter for the updated at of the self-service profile. + * @return the updated at of the self-service profile. + */ + public String getUpdatedAt() { + return updatedAt; + } + + /** + * Setter for the updated at of the self-service profile. + * @param updatedAt the updated at of the self-service profile to set. + */ + public void setUpdatedAt(String updatedAt) { + this.updatedAt = updatedAt; + } +} diff --git a/src/main/java/com/auth0/json/mgmt/selfserviceprofiles/SelfServiceProfileResponsePage.java b/src/main/java/com/auth0/json/mgmt/selfserviceprofiles/SelfServiceProfileResponsePage.java new file mode 100644 index 00000000..e28d4cf7 --- /dev/null +++ b/src/main/java/com/auth0/json/mgmt/selfserviceprofiles/SelfServiceProfileResponsePage.java @@ -0,0 +1,21 @@ +package com.auth0.json.mgmt.selfserviceprofiles; + +import com.auth0.json.mgmt.Page; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; + +import java.util.List; + +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonDeserialize(using = SelfServiceProfileResponsePageDeserializer.class) +public class SelfServiceProfileResponsePage extends Page { + public SelfServiceProfileResponsePage(List items) { + super(items); + } + + public SelfServiceProfileResponsePage(Integer start, Integer length, Integer total, Integer limit, List items) { + super(start, length, total, limit, items); + } +} diff --git a/src/main/java/com/auth0/json/mgmt/selfserviceprofiles/SelfServiceProfileResponsePageDeserializer.java b/src/main/java/com/auth0/json/mgmt/selfserviceprofiles/SelfServiceProfileResponsePageDeserializer.java new file mode 100644 index 00000000..bebdbade --- /dev/null +++ b/src/main/java/com/auth0/json/mgmt/selfserviceprofiles/SelfServiceProfileResponsePageDeserializer.java @@ -0,0 +1,23 @@ +package com.auth0.json.mgmt.selfserviceprofiles; + +import com.auth0.json.mgmt.PageDeserializer; + +import java.util.List; + + +public class SelfServiceProfileResponsePageDeserializer extends PageDeserializer { + + protected SelfServiceProfileResponsePageDeserializer() { + super(SelfServiceProfileResponse.class, "self_service_profiles"); + } + + @Override + protected SelfServiceProfileResponsePage createPage(List items) { + return new SelfServiceProfileResponsePage(items); + } + + @Override + protected SelfServiceProfileResponsePage createPage(Integer start, Integer length, Integer total, Integer limit, List items) { + return new SelfServiceProfileResponsePage(start, length, total, limit, items); + } +} diff --git a/src/main/java/com/auth0/json/mgmt/selfserviceprofiles/SsoAccessTicketResponse.java b/src/main/java/com/auth0/json/mgmt/selfserviceprofiles/SsoAccessTicketResponse.java new file mode 100644 index 00000000..ab4bf344 --- /dev/null +++ b/src/main/java/com/auth0/json/mgmt/selfserviceprofiles/SsoAccessTicketResponse.java @@ -0,0 +1,41 @@ +package com.auth0.json.mgmt.selfserviceprofiles; + +import com.fasterxml.jackson.annotation.*; + +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public class SsoAccessTicketResponse { + @JsonProperty("ticket") + private String ticket; + + /** + * Creates a new instance. + */ + public SsoAccessTicketResponse() { + } + + /** + * Creates a new instance with the given ticket. + * @param ticket the ticket. + */ + @JsonCreator + public SsoAccessTicketResponse(@JsonProperty("ticket") String ticket) { + this.ticket = ticket; + } + + /** + * Getter for the ticket. + * @return the ticket. + */ + public String getTicket() { + return ticket; + } + + /** + * Setter for the ticket. + * @param ticket the ticket to set. + */ + public void setTicket(String ticket) { + this.ticket = ticket; + } +} diff --git a/src/main/java/com/auth0/json/mgmt/selfserviceprofiles/UserAttribute.java b/src/main/java/com/auth0/json/mgmt/selfserviceprofiles/UserAttribute.java new file mode 100644 index 00000000..33db0ad6 --- /dev/null +++ b/src/main/java/com/auth0/json/mgmt/selfserviceprofiles/UserAttribute.java @@ -0,0 +1,83 @@ +package com.auth0.json.mgmt.selfserviceprofiles; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; + +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public class UserAttribute { + @JsonProperty("name") + private String name; + @JsonProperty("description") + private String description; + @JsonProperty("is_optional") + private boolean isOptional; + + /** + * Creates a new instance of the UserAttribute class. + */ + public UserAttribute() { } + + /** + * Creates a new instance of the UserAttribute class. + * @param name the name of the user attribute. + * @param description the description of the user attribute. + * @param isOptional the isOptional of the user attribute. + */ + @JsonCreator + public UserAttribute(@JsonProperty("name") String name, @JsonProperty("description") String description, @JsonProperty("is_optional") boolean isOptional) { + this.name = name; + this.description = description; + this.isOptional = isOptional; + } + + /** + * Getter for the name of the user attribute. + * @return the name of the user attribute. + */ + public String getName() { + return name; + } + + /** + * Setter for the name of the user attribute. + * @param name the name of the user attribute to set. + */ + public void setName(String name) { + this.name = name; + } + + /** + * Getter for the description of the user attribute. + * @return the description of the user attribute. + */ + public String getDescription() { + return description; + } + + /** + * Setter for the description of the user attribute. + * @param description the description of the user attribute to set. + */ + public void setDescription(String description) { + this.description = description; + } + + /** + * Getter for the isOptional of the user attribute. + * @return the isOptional of the user attribute. + */ + public boolean getIsOptional() { + return isOptional; + } + + /** + * Setter for the isOptional of the user attribute. + * @param isOptional the isOptional of the user attribute to set. + */ + public void setIsOptional(boolean isOptional) { + this.isOptional = isOptional; + } +} diff --git a/src/test/java/com/auth0/client/MockServer.java b/src/test/java/com/auth0/client/MockServer.java index 54bfc049..78899bad 100644 --- a/src/test/java/com/auth0/client/MockServer.java +++ b/src/test/java/com/auth0/client/MockServer.java @@ -159,6 +159,10 @@ public class MockServer { public static final String ENCRYPTION_KEY = "src/test/resources/mgmt/encryption_key.json"; public static final String ENCRYPTION_KEYS_LIST = "src/test/resources/mgmt/encryption_keys_list.json"; public static final String RATE_LIMIT_ERROR = "src/test/resources/mgmt/rate_limit_error.json"; + public static final String SELF_SERVICE_PROFILES_LIST = "src/test/resources/mgmt/self_service_profiles_list.json"; + public static final String SELF_SERVICE_PROFILE_RESPONSE = "src/test/resources/mgmt/self_service_profile_response.json"; + public static final String SELF_SERVICE_PROFILE_CUSTOM_TEXT = "src/test/resources/mgmt/self_service_profile_custom_text.json"; + public static final String SELF_SERVICE_PROFILE_SSO_TICKET = "src/test/resources/mgmt/self_service_profile_sso_ticket.json"; private final MockWebServer server; diff --git a/src/test/java/com/auth0/client/mgmt/SelfServiceProfilesEntityTest.java b/src/test/java/com/auth0/client/mgmt/SelfServiceProfilesEntityTest.java new file mode 100644 index 00000000..227bcfe0 --- /dev/null +++ b/src/test/java/com/auth0/client/mgmt/SelfServiceProfilesEntityTest.java @@ -0,0 +1,325 @@ +package com.auth0.client.mgmt; + +import com.auth0.client.mgmt.filter.PageBasedPaginationFilter; +import com.auth0.json.mgmt.selfserviceprofiles.SelfServiceProfile; +import com.auth0.json.mgmt.selfserviceprofiles.SelfServiceProfileResponse; +import com.auth0.json.mgmt.selfserviceprofiles.SelfServiceProfileResponsePage; +import com.auth0.json.mgmt.selfserviceprofiles.SsoAccessTicketResponse; +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.AssertsUtil.verifyThrows; +import static com.auth0.client.MockServer.*; +import static com.auth0.client.RecordedRequestMatcher.*; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.*; + +public class SelfServiceProfilesEntityTest extends BaseMgmtEntityTest { + + @Test + public void shouldGetSelfServiceProfilesWithoutFilter() throws Exception{ + Request request = api.selfServiceProfiles().get(null); + assertThat(request, is(notNullValue())); + + server.jsonResponse(SELF_SERVICE_PROFILES_LIST, 200); + SelfServiceProfileResponsePage response = request.execute().getBody(); + RecordedRequest recordedRequest = server.takeRequest(); + + assertThat(recordedRequest, hasMethodAndPath(HttpMethod.GET, "/api/v2/self-service-profiles")); + assertThat(recordedRequest, hasHeader("Content-Type", "application/json")); + assertThat(recordedRequest, hasHeader("Authorization", "Bearer apiToken")); + + assertThat(response, is(notNullValue())); + assertThat(response.getItems(), hasSize(3)); + } + + @Test + public void shouldGetSelfServiceProfilesWithPage() throws Exception { + PageBasedPaginationFilter filter = new PageBasedPaginationFilter().withPage(1, 5); + Request request = api.selfServiceProfiles().get(filter); + assertThat(request, is(notNullValue())); + + server.jsonResponse(SELF_SERVICE_PROFILES_LIST, 200); + SelfServiceProfileResponsePage response = request.execute().getBody(); + RecordedRequest recordedRequest = server.takeRequest(); + + assertThat(recordedRequest, hasMethodAndPath(HttpMethod.GET, "/api/v2/self-service-profiles")); + assertThat(recordedRequest, hasHeader("Content-Type", "application/json")); + assertThat(recordedRequest, hasHeader("Authorization", "Bearer apiToken")); + assertThat(recordedRequest, hasQueryParameter("page", "1")); + assertThat(recordedRequest, hasQueryParameter("per_page", "5")); + + assertThat(response, is(notNullValue())); + assertThat(response.getItems(), hasSize(3)); + } + + @Test + public void shouldGetSelfServiceProfilesWithTotals() throws Exception { + PageBasedPaginationFilter filter = new PageBasedPaginationFilter().withTotals(true); + Request request = api.selfServiceProfiles().get(filter); + assertThat(request, is(notNullValue())); + + server.jsonResponse(SELF_SERVICE_PROFILES_LIST, 200); + SelfServiceProfileResponsePage response = request.execute().getBody(); + RecordedRequest recordedRequest = server.takeRequest(); + + assertThat(recordedRequest, hasMethodAndPath(HttpMethod.GET, "/api/v2/self-service-profiles")); + assertThat(recordedRequest, hasHeader("Content-Type", "application/json")); + assertThat(recordedRequest, hasHeader("Authorization", "Bearer apiToken")); + assertThat(recordedRequest, hasQueryParameter("include_totals", "true")); + + assertThat(response, is(notNullValue())); + assertThat(response.getItems(), hasSize(3)); + } + + @Test + public void shouldThrowOnCreateWhenSelfServiceProfileIsNull() { + verifyThrows(IllegalArgumentException.class, + () -> api.selfServiceProfiles().create(null), "'self service profile' cannot be null!"); + } + + @Test + public void shouldThrowOnCreateWhenNameInSelfServiceProfileIsNull() { + verifyThrows(IllegalArgumentException.class, + () -> api.selfServiceProfiles().create(new SelfServiceProfile()), "'name' cannot be null!"); + } + + @Test + public void shouldCreateSelfServiceProfile() throws Exception { + SelfServiceProfile profile = new SelfServiceProfile(); + profile.setName("Test"); + profile.setDescription("This is for Test"); + Request request = api.selfServiceProfiles().create(profile); + assertThat(request, is(notNullValue())); + + server.jsonResponse(SELF_SERVICE_PROFILE_RESPONSE, 201); + SelfServiceProfileResponse response = request.execute().getBody(); + RecordedRequest recordedRequest = server.takeRequest(); + + assertThat(recordedRequest, hasMethodAndPath(HttpMethod.POST, "/api/v2/self-service-profiles")); + assertThat(recordedRequest, hasHeader("Content-Type", "application/json")); + assertThat(recordedRequest, hasHeader("Authorization", "Bearer apiToken")); + + Map body = bodyFromRequest(recordedRequest); + assertThat(body.size(), is(2)); + assertThat(body, hasEntry("name", "Test")); + assertThat(body, hasEntry("description", "This is for Test")); + + assertThat(response, is(notNullValue())); + } + + @Test + public void shouldThrowOnGetByIdWhenIdIsNull() { + verifyThrows(IllegalArgumentException.class, + () -> api.selfServiceProfiles().getById(null), "'id' cannot be null!"); + } + + @Test + public void shouldGetSelfServiceProfileById() throws Exception { + Request request = api.selfServiceProfiles().getById("id"); + assertThat(request, is(notNullValue())); + + server.jsonResponse(SELF_SERVICE_PROFILE_RESPONSE, 200); + SelfServiceProfileResponse response = request.execute().getBody(); + RecordedRequest recordedRequest = server.takeRequest(); + + assertThat(recordedRequest, hasMethodAndPath(HttpMethod.GET, "/api/v2/self-service-profiles/id")); + assertThat(recordedRequest, hasHeader("Content-Type", "application/json")); + assertThat(recordedRequest, hasHeader("Authorization", "Bearer apiToken")); + + assertThat(response, is(notNullValue())); + } + + @Test + public void shouldThrowOnDeleteWhenIdIsNull() { + verifyThrows(IllegalArgumentException.class, + () -> api.selfServiceProfiles().delete(null), "'id' cannot be null!"); + } + + @Test + public void shouldDeleteSelfServiceProfile() throws Exception { + Request request = api.selfServiceProfiles().delete("id"); + assertThat(request, is(notNullValue())); + + server.jsonResponse(SELF_SERVICE_PROFILE_RESPONSE, 200); + request.execute().getBody(); + RecordedRequest recordedRequest = server.takeRequest(); + + assertThat(recordedRequest, hasMethodAndPath(HttpMethod.DELETE, "/api/v2/self-service-profiles/id")); + assertThat(recordedRequest, hasHeader("Content-Type", "application/json")); + assertThat(recordedRequest, hasHeader("Authorization", "Bearer apiToken")); + } + + @Test + public void shouldThrowOnUpdateWhenIdIsNull() { + verifyThrows(IllegalArgumentException.class, + () -> api.selfServiceProfiles().update(new SelfServiceProfile(), null), "'id' cannot be null!"); + } + + @Test + public void shouldThrowOnUpdateWhenSelfServiceProfileIsNull() { + verifyThrows(IllegalArgumentException.class, + () -> api.selfServiceProfiles().update(null, "id"), "'self service profile' cannot be null!"); + } + + @Test + public void shouldUpdateSelfServiceProfile() throws Exception { + SelfServiceProfile profile = new SelfServiceProfile(); + profile.setDescription("This is Test is updated"); + Request request = api.selfServiceProfiles().update(profile, "id"); + assertThat(request, is(notNullValue())); + + server.jsonResponse(SELF_SERVICE_PROFILE_RESPONSE, 200); + SelfServiceProfileResponse response = request.execute().getBody(); + RecordedRequest recordedRequest = server.takeRequest(); + + assertThat(recordedRequest, hasMethodAndPath(HttpMethod.PATCH, "/api/v2/self-service-profiles/id")); + assertThat(recordedRequest, hasHeader("Content-Type", "application/json")); + assertThat(recordedRequest, hasHeader("Authorization", "Bearer apiToken")); + + Map body = bodyFromRequest(recordedRequest); + assertThat(body.size(), is(1)); + assertThat(body, hasEntry("description", "This is Test is updated")); + + assertThat(response, is(notNullValue())); + } + + @Test + public void shouldThrowOnGetCustomTextWhenIdIsNull() { + verifyThrows(IllegalArgumentException.class, + () -> api.selfServiceProfiles().getCustomText(null, "language", "page"), "'id' cannot be null!"); + } + + @Test + public void shouldThrowOnGetCustomTextWhenLanguageIsNull() { + verifyThrows(IllegalArgumentException.class, + () -> api.selfServiceProfiles().getCustomText("id", null, "page"), "'language' cannot be null!"); + } + + @Test + public void shouldThrowOnGetCustomTextWhenPageIsNull() { + verifyThrows(IllegalArgumentException.class, + () -> api.selfServiceProfiles().getCustomText("id", "language", null), "'page' cannot be null!"); + } + + @Test + public void shouldGetCustomText() throws Exception { + Request request = api.selfServiceProfiles().getCustomText("id", "language", "page"); + assertThat(request, is(notNullValue())); + + server.jsonResponse(SELF_SERVICE_PROFILE_CUSTOM_TEXT, 200); + Object response = request.execute().getBody(); + RecordedRequest recordedRequest = server.takeRequest(); + + assertThat(recordedRequest, hasMethodAndPath(HttpMethod.GET, "/api/v2/self-service-profiles/id/custom-text/language/page")); + assertThat(recordedRequest, hasHeader("Content-Type", "application/json")); + assertThat(recordedRequest, hasHeader("Authorization", "Bearer apiToken")); + + assertThat(response, is(notNullValue())); + } + + @Test + public void shouldThrowOnSetCustomTextWhenIdIsNull() { + verifyThrows(IllegalArgumentException.class, + () -> api.selfServiceProfiles().setCustomText(null, "language", "page", new Object()), "'id' cannot be null!"); + } + + @Test + public void shouldThrowOnSetCustomTextWhenLanguageIsNull() { + verifyThrows(IllegalArgumentException.class, + () -> api.selfServiceProfiles().setCustomText("id", null, "page", new Object()), "'language' cannot be null!"); + } + + @Test + public void shouldThrowOnSetCustomTextWhenPageIsNull() { + verifyThrows(IllegalArgumentException.class, + () -> api.selfServiceProfiles().setCustomText("id", "language", null, new Object()), "'page' cannot be null!"); + } + + @Test + public void shouldThrowOnSetCustomTextWhenCustomTextIsNull() { + verifyThrows(IllegalArgumentException.class, + () -> api.selfServiceProfiles().setCustomText("id", "language", "page", null), "'custom text' cannot be null!"); + } + + @Test + public void shouldSetCustomText() throws Exception { + Map customText = new HashMap<>(); + customText.put("introduction", "Welcome! With only a few steps"); + Request request = api.selfServiceProfiles().setCustomText("id", "language", "page", customText); + assertThat(request, is(notNullValue())); + + server.jsonResponse(SELF_SERVICE_PROFILE_CUSTOM_TEXT, 200); + Object response = request.execute().getBody(); + RecordedRequest recordedRequest = server.takeRequest(); + + assertThat(recordedRequest, hasMethodAndPath(HttpMethod.PUT, "/api/v2/self-service-profiles/id/custom-text/language/page")); + assertThat(recordedRequest, hasHeader("Content-Type", "application/json")); + assertThat(recordedRequest, hasHeader("Authorization", "Bearer apiToken")); + + assertThat(response, is(notNullValue())); + } + + @Test + public void shouldThrowOnCreateSsoAccessTicketWhenIdIsNull() { + verifyThrows(IllegalArgumentException.class, + () -> api.selfServiceProfiles().createSsoAccessTicket(null, new Object()), "'id' cannot be null!"); + } + + @Test + public void shouldThrowOnCreateSsoAccessTicketWhenPayloadIsNull() { + verifyThrows(IllegalArgumentException.class, + () -> api.selfServiceProfiles().createSsoAccessTicket("id", null), "'payload' cannot be null!"); + } + + @Test + public void shouldCreateSsoAccessTicket() throws Exception{ + Map payload = new HashMap<>(); + + payload.put("connection_id", "test-connection"); + + Request request = api.selfServiceProfiles().createSsoAccessTicket("id", payload); + assertThat(request, is(notNullValue())); + + server.jsonResponse(SELF_SERVICE_PROFILE_SSO_TICKET, 200); + SsoAccessTicketResponse response = request.execute().getBody(); + RecordedRequest recordedRequest = server.takeRequest(); + + assertThat(recordedRequest, hasMethodAndPath(HttpMethod.POST, "/api/v2/self-service-profiles/id/sso-ticket")); + assertThat(recordedRequest, hasHeader("Content-Type", "application/json")); + assertThat(recordedRequest, hasHeader("Authorization", "Bearer apiToken")); + + assertThat(response, is(notNullValue())); + } + + @Test + public void shouldThrowOnRevokeSsoTicketWhenIdIsNull() { + verifyThrows(IllegalArgumentException.class, + () -> api.selfServiceProfiles().revokeSsoTicket(null, "ticketId"), "'id' cannot be null!"); + } + + @Test + public void shouldThrowOnRevokeSsoTicketWhenTicketIdIsNull() { + verifyThrows(IllegalArgumentException.class, + () -> api.selfServiceProfiles().revokeSsoTicket("id", null), "'ticket id' cannot be null!"); + } + + @Test + public void shouldRevokeSsoTicket() throws Exception{ + Request request = api.selfServiceProfiles().revokeSsoTicket("id", "ticketId"); + assertThat(request, is(notNullValue())); + + server.noContentResponse(); + request.execute().getBody(); + RecordedRequest recordedRequest = server.takeRequest(); + + assertThat(recordedRequest, hasMethodAndPath(HttpMethod.POST, "/api/v2/self-service-profiles/id/sso-ticket/ticketId/revoke")); + assertThat(recordedRequest, hasHeader("Content-Type", "application/json")); + assertThat(recordedRequest, hasHeader("Authorization", "Bearer apiToken")); + } +} diff --git a/src/test/java/com/auth0/client/mgmt/filter/PageBasedPaginationFilterTest.java b/src/test/java/com/auth0/client/mgmt/filter/PageBasedPaginationFilterTest.java new file mode 100644 index 00000000..282cfc69 --- /dev/null +++ b/src/test/java/com/auth0/client/mgmt/filter/PageBasedPaginationFilterTest.java @@ -0,0 +1,39 @@ +package com.auth0.client.mgmt.filter; + +import org.hamcrest.Matchers; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.notNullValue; +import static org.hamcrest.MatcherAssert.assertThat; + +public class PageBasedPaginationFilterTest { + + private PageBasedPaginationFilter filter; + + @BeforeEach + public void setUp() { + filter = new PageBasedPaginationFilter(); + } + + @Test + public void shouldFilterByPage() { + PageBasedPaginationFilter instance = filter.withPage(5, 10); + + assertThat(filter, is(instance)); + assertThat(filter.getAsMap(), is(notNullValue())); + assertThat(filter.getAsMap(), Matchers.hasEntry("per_page", 10)); + assertThat(filter.getAsMap(), Matchers.hasEntry("page", 5)); + } + + @Test + public void shouldIncludeTotals() { + PageBasedPaginationFilter instance = filter.withTotals(true); + + assertThat(filter, is(instance)); + assertThat(filter.getAsMap(), is(notNullValue())); + assertThat(filter.getAsMap(), Matchers.hasEntry("include_totals", true)); + } + +} diff --git a/src/test/java/com/auth0/json/mgmt/selfserviceprofiles/SelfServiceProfileResponsePageTest.java b/src/test/java/com/auth0/json/mgmt/selfserviceprofiles/SelfServiceProfileResponsePageTest.java new file mode 100644 index 00000000..108e0312 --- /dev/null +++ b/src/test/java/com/auth0/json/mgmt/selfserviceprofiles/SelfServiceProfileResponsePageTest.java @@ -0,0 +1,173 @@ +package com.auth0.json.mgmt.selfserviceprofiles; + +import com.auth0.json.JsonTest; +import org.junit.jupiter.api.Test; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.*; + +public class SelfServiceProfileResponsePageTest extends JsonTest { + + private static final String jsonWithoutTotals = + "[\n" + + " {\n" + + " \"id\": \"id1\",\n" + + " \"name\": \"test1\",\n" + + " \"description\": \"This is for testing\",\n" + + " \"user_attributes\": [\n" + + " {\n" + + " \"name\": \"Phone\",\n" + + " \"description\": \"This is Phone Number\",\n" + + " \"is_optional\": true\n" + + " }\n" + + " ],\n" + + " \"allowed_strategies\": [\n" + + " \"google-apps\"\n" + + " ],\n" + + " \"created_at\": \"2024-12-16T15:26:39.015Z\",\n" + + " \"updated_at\": \"2024-12-16T15:28:04.933Z\"\n" + + " },\n" + + " {\n" + + " \"id\": \"id2\",\n" + + " \"name\": \"Test2\",\n" + + " \"description\": \"This is for Test2\",\n" + + " \"user_attributes\": [\n" + + " {\n" + + " \"name\": \"Phone\",\n" + + " \"description\": \"This is Phone Number\",\n" + + " \"is_optional\": true\n" + + " },\n" + + " {\n" + + " \"name\": \"UserName\",\n" + + " \"description\": \"This is User Name\",\n" + + " \"is_optional\": true\n" + + " }\n" + + " ],\n" + + " \"allowed_strategies\": [\n" + + " \"oidc\"\n" + + " ],\n" + + " \"created_at\": \"2024-12-16T15:29:06.119Z\",\n" + + " \"updated_at\": \"2024-12-16T15:29:06.119Z\"\n" + + " },\n" + + " {\n" + + " \"id\": \"id3\",\n" + + " \"name\": \"Test3\",\n" + + " \"description\": \"This is a Test3\",\n" + + " \"user_attributes\": [\n" + + " {\n" + + " \"name\": \"Name\",\n" + + " \"description\": \"Name Field\",\n" + + " \"is_optional\": true\n" + + " }\n" + + " ],\n" + + " \"allowed_strategies\": [\n" + + " \"oidc\"\n" + + " ],\n" + + " \"created_at\": \"2024-12-20T09:32:13.885Z\",\n" + + " \"updated_at\": \"2024-12-20T09:32:13.885Z\",\n" + + " \"branding\": {\n" + + " \"logo_url\": \"https://www.google.com\",\n" + + " \"colors\": {\n" + + " \"primary\": \"#ffffff\"\n" + + " }\n" + + " }\n" + + " }\n" + + "]\n"; + + private static final String jsonWithTotals = + "{\n" + + " \"self_service_profiles\": [\n" + + " {\n" + + " \"id\": \"id1\",\n" + + " \"name\": \"test1\",\n" + + " \"description\": \"This is for testing\",\n" + + " \"user_attributes\": [\n" + + " {\n" + + " \"name\": \"Phone\",\n" + + " \"description\": \"This is Phone Number\",\n" + + " \"is_optional\": true\n" + + " }\n" + + " ],\n" + + " \"allowed_strategies\": [\n" + + " \"google-apps\"\n" + + " ],\n" + + " \"created_at\": \"2024-12-16T15:26:39.015Z\",\n" + + " \"updated_at\": \"2024-12-16T15:28:04.933Z\"\n" + + " },\n" + + " {\n" + + " \"id\": \"id2\",\n" + + " \"name\": \"Test2\",\n" + + " \"description\": \"This is for Test2\",\n" + + " \"user_attributes\": [\n" + + " {\n" + + " \"name\": \"Phone\",\n" + + " \"description\": \"This is Phone Number\",\n" + + " \"is_optional\": true\n" + + " },\n" + + " {\n" + + " \"name\": \"UserName\",\n" + + " \"description\": \"This is User Name\",\n" + + " \"is_optional\": true\n" + + " }\n" + + " ],\n" + + " \"allowed_strategies\": [\n" + + " \"oidc\"\n" + + " ],\n" + + " \"created_at\": \"2024-12-16T15:29:06.119Z\",\n" + + " \"updated_at\": \"2024-12-16T15:29:06.119Z\"\n" + + " },\n" + + " {\n" + + " \"id\": \"id3\",\n" + + " \"name\": \"Test3\",\n" + + " \"description\": \"This is a Test3\",\n" + + " \"user_attributes\": [\n" + + " {\n" + + " \"name\": \"Name\",\n" + + " \"description\": \"Name Field\",\n" + + " \"is_optional\": true\n" + + " }\n" + + " ],\n" + + " \"allowed_strategies\": [\n" + + " \"oidc\"\n" + + " ],\n" + + " \"created_at\": \"2024-12-20T09:32:13.885Z\",\n" + + " \"updated_at\": \"2024-12-20T09:32:13.885Z\",\n" + + " \"branding\": {\n" + + " \"logo_url\": \"https://www.google.com\",\n" + + " \"colors\": {\n" + + " \"primary\": \"#ffffff\"\n" + + " }\n" + + " }\n" + + " }\n" + + " ],\n" + + " \"start\": 0,\n" + + " \"limit\": 10,\n" + + " \"total\": 3\n" + + "}"; + + @Test + public void shouldDeserializeWithoutTotals() throws Exception { + SelfServiceProfileResponsePage page = fromJSON(jsonWithoutTotals, SelfServiceProfileResponsePage.class); + + assertThat(page, is(notNullValue())); + assertThat(page.getStart(), is(nullValue())); + assertThat(page.getTotal(), is(nullValue())); + assertThat(page.getLimit(), is(nullValue())); + assertThat(page.getItems(), is(notNullValue())); + assertThat(page.getItems().size(), is(3)); + assertThat(page.getNext(), is(nullValue())); + } + + @Test + public void shouldDeserializeWithTotals() throws Exception { + SelfServiceProfileResponsePage page = fromJSON(jsonWithTotals, SelfServiceProfileResponsePage.class); + + assertThat(page, is(notNullValue())); + assertThat(page.getStart(), is(0)); + assertThat(page.getTotal(), is(3)); + assertThat(page.getLimit(), is(10)); + assertThat(page.getItems(), is(notNullValue())); + assertThat(page.getItems().size(), is(3)); + assertThat(page.getNext(), is(nullValue())); + } +} diff --git a/src/test/java/com/auth0/json/mgmt/selfserviceprofiles/SelfServiceProfileResponseTest.java b/src/test/java/com/auth0/json/mgmt/selfserviceprofiles/SelfServiceProfileResponseTest.java new file mode 100644 index 00000000..3a1173e9 --- /dev/null +++ b/src/test/java/com/auth0/json/mgmt/selfserviceprofiles/SelfServiceProfileResponseTest.java @@ -0,0 +1,73 @@ +package com.auth0.json.mgmt.selfserviceprofiles; + +import com.auth0.json.JsonTest; +import org.junit.jupiter.api.Test; + +import java.util.ArrayList; +import java.util.List; + +import static com.auth0.json.JsonMatcher.hasEntry; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.*; + +public class SelfServiceProfileResponseTest extends JsonTest { + + private final static String SELF_SERVICE_PROFILE_RESPONSE_JSON = "src/test/resources/mgmt/self_service_profile_response.json"; + + @Test + public void deserialize() throws Exception { + SelfServiceProfileResponse deserialized = fromJSON(readTextFile(SELF_SERVICE_PROFILE_RESPONSE_JSON), SelfServiceProfileResponse.class); + + assertThat(deserialized.getId(), is("id")); + assertThat(deserialized.getName(), is("Test")); + assertThat(deserialized.getDescription(), is("This is a Test")); + assertThat(deserialized.getUserAttributes().get(0).getName(), is("Phone")); + assertThat(deserialized.getUserAttributes().get(0).getDescription(), is("This is Phone Number")); + assertThat(deserialized.getUserAttributes().get(0).getIsOptional(), is(true)); + assertThat(deserialized.getBranding().getColors().getPrimary(), is("#ffffff")); + assertThat(deserialized.getBranding().getLogoUrl(), is("https://www.google.com")); + assertThat(deserialized.getAllowedStrategies().get(0), is("oidc")); + assertThat(deserialized.getCreatedAt(), is("2024-12-20T09:32:13.885Z")); + assertThat(deserialized.getCreatedAt(), is("2024-12-20T09:32:13.885Z")); + } + + @Test + public void serialize() throws Exception { + SelfServiceProfileResponse selfServiceProfileResponse = new SelfServiceProfileResponse(); + selfServiceProfileResponse.setId("id"); + selfServiceProfileResponse.setName("Test"); + selfServiceProfileResponse.setDescription("This is for Test"); + + UserAttribute userAttribute = new UserAttribute("Phone", "This is Phone Number", true); + List userAttributes = new ArrayList<>(); + userAttributes.add(userAttribute); + selfServiceProfileResponse.setUserAttributes(userAttributes); + + Branding branding = new Branding(); + branding.setColors(new Color("#ffffff")); + branding.setLogoUrl("https://www.google.com"); + selfServiceProfileResponse.setBranding(branding); + + List allowedStrategies = new ArrayList<>(); + allowedStrategies.add("oidc"); + selfServiceProfileResponse.setAllowedStrategies(allowedStrategies); + + selfServiceProfileResponse.setCreatedAt("2024-12-20T09:32:13.885Z"); + selfServiceProfileResponse.setUpdatedAt("2024-12-20T09:32:13.885Z"); + + String serialized = toJSON(selfServiceProfileResponse); + assertThat(serialized, is(notNullValue())); + + assertThat(serialized, hasEntry("id", "id")); + assertThat(serialized, hasEntry("name", "Test")); + assertThat(serialized, hasEntry("description", "This is for Test")); + assertThat(serialized, hasEntry("user_attributes", notNullValue())); + assertThat(serialized, containsString("\"user_attributes\":[{\"name\":\"Phone\",\"description\":\"This is Phone Number\",\"is_optional\":true}]")); + assertThat(serialized, hasEntry("branding", notNullValue())); + assertThat(serialized, containsString("\"branding\":{\"logo_url\":\"https://www.google.com\",\"colors\":{\"primary\":\"#ffffff\"}}")); + assertThat(serialized, hasEntry("allowed_strategies", notNullValue())); + assertThat(serialized, containsString("\"allowed_strategies\":[\"oidc\"]")); + assertThat(serialized, hasEntry("created_at", "2024-12-20T09:32:13.885Z")); + assertThat(serialized, hasEntry("updated_at", "2024-12-20T09:32:13.885Z")); + } +} diff --git a/src/test/java/com/auth0/json/mgmt/selfserviceprofiles/SelfServiceProfileTest.java b/src/test/java/com/auth0/json/mgmt/selfserviceprofiles/SelfServiceProfileTest.java new file mode 100644 index 00000000..2f7e1b8c --- /dev/null +++ b/src/test/java/com/auth0/json/mgmt/selfserviceprofiles/SelfServiceProfileTest.java @@ -0,0 +1,62 @@ +package com.auth0.json.mgmt.selfserviceprofiles; + +import com.auth0.json.JsonTest; +import org.junit.jupiter.api.Test; + +import java.util.ArrayList; +import java.util.List; + +import static com.auth0.json.JsonMatcher.hasEntry; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.*; + +public class SelfServiceProfileTest extends JsonTest { + private final static String SELF_SERVICE_PROFILE_JSON = "src/test/resources/mgmt/self_service_profile.json"; + + @Test + public void deserialize() throws Exception { + SelfServiceProfile deserialized = fromJSON(readTextFile(SELF_SERVICE_PROFILE_JSON), SelfServiceProfile.class); + + assertThat(deserialized.getName(), is("Test")); + assertThat(deserialized.getDescription(), is("This is for Test")); + assertThat(deserialized.getUserAttributes().get(0).getName(), is("Phone")); + assertThat(deserialized.getUserAttributes().get(0).getDescription(), is("This is Phone Number")); + assertThat(deserialized.getUserAttributes().get(0).getIsOptional(), is(true)); + assertThat(deserialized.getBranding().getColors().getPrimary(), is("#ffffff")); + assertThat(deserialized.getBranding().getLogoUrl(), is("https://www.google.com")); + assertThat(deserialized.getAllowedStrategies().get(0), is("oidc")); + } + + @Test + public void serialize() throws Exception { + SelfServiceProfile selfServiceProfile = new SelfServiceProfile(); + selfServiceProfile.setName("Test"); + selfServiceProfile.setDescription("This is for Test"); + + UserAttribute userAttribute = new UserAttribute("Phone", "This is Phone Number", true); + List userAttributes = new ArrayList<>(); + userAttributes.add(userAttribute); + selfServiceProfile.setUserAttributes(userAttributes); + + Branding branding = new Branding(); + branding.setColors(new Color("#ffffff")); + branding.setLogoUrl("https://www.google.com"); + selfServiceProfile.setBranding(branding); + + List allowedStrategies = new ArrayList<>(); + allowedStrategies.add("oidc"); + selfServiceProfile.setAllowedStrategies(allowedStrategies); + + String serialized = toJSON(selfServiceProfile); + assertThat(serialized, is(notNullValue())); + + assertThat(serialized, hasEntry("name", "Test")); + assertThat(serialized, hasEntry("description", "This is for Test")); + assertThat(serialized, hasEntry("user_attributes", notNullValue())); + assertThat(serialized, containsString("\"user_attributes\":[{\"name\":\"Phone\",\"description\":\"This is Phone Number\",\"is_optional\":true}]")); + assertThat(serialized, hasEntry("branding", notNullValue())); + assertThat(serialized, containsString("\"branding\":{\"logo_url\":\"https://www.google.com\",\"colors\":{\"primary\":\"#ffffff\"}}")); + assertThat(serialized, hasEntry("allowed_strategies", notNullValue())); + assertThat(serialized, containsString("\"allowed_strategies\":[\"oidc\"]")); + } +} diff --git a/src/test/java/com/auth0/json/mgmt/selfserviceprofiles/SsoAccessTicketResponseTest.java b/src/test/java/com/auth0/json/mgmt/selfserviceprofiles/SsoAccessTicketResponseTest.java new file mode 100644 index 00000000..3c1eb147 --- /dev/null +++ b/src/test/java/com/auth0/json/mgmt/selfserviceprofiles/SsoAccessTicketResponseTest.java @@ -0,0 +1,31 @@ +package com.auth0.json.mgmt.selfserviceprofiles; + +import com.auth0.json.JsonTest; +import org.junit.jupiter.api.Test; + +import static com.auth0.json.JsonMatcher.hasEntry; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.*; + +public class SsoAccessTicketResponseTest extends JsonTest { + + private final static String SELF_SERVICE_PROFILE_SSO_TICKET_JSON = "src/test/resources/mgmt/self_service_profile_sso_ticket.json"; + + @Test + public void deserialize() throws Exception { + SsoAccessTicketResponse deserialized = fromJSON(readTextFile(SELF_SERVICE_PROFILE_SSO_TICKET_JSON), SsoAccessTicketResponse.class); + + assertThat(deserialized.getTicket(), is("https://example.auth0.com/self-service/connections-flow?ticket=ticket-1234")); + } + + @Test + public void serialize() throws Exception { + SsoAccessTicketResponse ssoAccessTicketResponse = new SsoAccessTicketResponse(); + ssoAccessTicketResponse.setTicket("https://example.auth0.com/self-service/connections-flow?ticket=ticket-1234"); + + String serialized = toJSON(ssoAccessTicketResponse); + assertThat(serialized, is(notNullValue())); + + assertThat(serialized, hasEntry("ticket", "https://example.auth0.com/self-service/connections-flow?ticket=ticket-1234")); + } +} diff --git a/src/test/resources/mgmt/self_service_profile.json b/src/test/resources/mgmt/self_service_profile.json new file mode 100644 index 00000000..6c090caa --- /dev/null +++ b/src/test/resources/mgmt/self_service_profile.json @@ -0,0 +1,21 @@ +{ + "id": "id", + "name": "Test", + "description": "This is for Test", + "user_attributes": [ + { + "name": "Phone", + "description": "This is Phone Number", + "is_optional": true + } + ], + "branding": { + "logo_url": "https://www.google.com", + "colors": { + "primary": "#ffffff" + } + }, + "allowed_strategies": [ + "oidc" + ] +} diff --git a/src/test/resources/mgmt/self_service_profile_custom_text.json b/src/test/resources/mgmt/self_service_profile_custom_text.json new file mode 100644 index 00000000..ef8aac8d --- /dev/null +++ b/src/test/resources/mgmt/self_service_profile_custom_text.json @@ -0,0 +1,3 @@ +{ + "introduction": "Welcome! With only a few steps" +} diff --git a/src/test/resources/mgmt/self_service_profile_response.json b/src/test/resources/mgmt/self_service_profile_response.json new file mode 100644 index 00000000..46b5bcd8 --- /dev/null +++ b/src/test/resources/mgmt/self_service_profile_response.json @@ -0,0 +1,23 @@ +{ + "id": "id", + "name": "Test", + "description": "This is a Test", + "user_attributes": [ + { + "name": "Phone", + "description": "This is Phone Number", + "is_optional": true + } + ], + "allowed_strategies": [ + "oidc" + ], + "created_at": "2024-12-20T09:32:13.885Z", + "updated_at": "2024-12-20T09:32:13.885Z", + "branding": { + "logo_url": "https://www.google.com", + "colors": { + "primary": "#ffffff" + } + } +} diff --git a/src/test/resources/mgmt/self_service_profile_sso_ticket.json b/src/test/resources/mgmt/self_service_profile_sso_ticket.json new file mode 100644 index 00000000..8b8c3e83 --- /dev/null +++ b/src/test/resources/mgmt/self_service_profile_sso_ticket.json @@ -0,0 +1,3 @@ +{ + "ticket": "https://example.auth0.com/self-service/connections-flow?ticket=ticket-1234" +} diff --git a/src/test/resources/mgmt/self_service_profiles_list.json b/src/test/resources/mgmt/self_service_profiles_list.json new file mode 100644 index 00000000..53001be8 --- /dev/null +++ b/src/test/resources/mgmt/self_service_profiles_list.json @@ -0,0 +1,64 @@ +[ + { + "id": "id1", + "name": "test1", + "description": "This is for testing", + "user_attributes": [ + { + "name": "Phone", + "description": "This is Phone Number", + "is_optional": true + } + ], + "allowed_strategies": [ + "google-apps" + ], + "created_at": "2024-12-16T15:26:39.015Z", + "updated_at": "2024-12-16T15:28:04.933Z" + }, + { + "id": "id2", + "name": "Test2", + "description": "This is for Test2", + "user_attributes": [ + { + "name": "Phone", + "description": "This is Phone Number", + "is_optional": true + }, + { + "name": "UserName", + "description": "This is User Name", + "is_optional": true + } + ], + "allowed_strategies": [ + "oidc" + ], + "created_at": "2024-12-16T15:29:06.119Z", + "updated_at": "2024-12-16T15:29:06.119Z" + }, + { + "id": "id3", + "name": "Test3", + "description": "This is a Test3", + "user_attributes": [ + { + "name": "Name", + "description": "Name Field", + "is_optional": true + } + ], + "allowed_strategies": [ + "oidc" + ], + "created_at": "2024-12-20T09:32:13.885Z", + "updated_at": "2024-12-20T09:32:13.885Z", + "branding": { + "logo_url": "https://www.google.com", + "colors": { + "primary": "#ffffff" + } + } + } +] From 8d14654c70a7c3dcfb82c8de76ba55bcc2656737 Mon Sep 17 00:00:00 2001 From: Tanya Sinha Date: Wed, 8 Jan 2025 16:33:50 +0530 Subject: [PATCH 29/32] Release 2.17.0 (#686) --- .version | 2 +- CHANGELOG.md | 7 +++++++ README.md | 4 ++-- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/.version b/.version index 75249069..d76bd2ba 100644 --- a/.version +++ b/.version @@ -1 +1 @@ -2.16.0 +2.17.0 diff --git a/CHANGELOG.md b/CHANGELOG.md index 7c35b759..7007e1dd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Change Log +## [2.17.0](https://github.com/auth0/auth0-java/tree/2.17.0) (2025-01-08) +[Full Changelog](https://github.com/auth0/auth0-java/compare/2.16.0...2.17.0) + +**Added** +- Added Support for Self-Service-Profile [\#683](https://github.com/auth0/auth0-java/pull/683) ([tanya732](https://github.com/tanya732)) +- Added support for Back Channel Login [\#682](https://github.com/auth0/auth0-java/pull/682) ([tanya732](https://github.com/tanya732)) + ## [2.16.0](https://github.com/auth0/auth0-java/tree/2.16.0) (2024-12-03) [Full Changelog](https://github.com/auth0/auth0-java/compare/2.15.0...2.16.0) diff --git a/README.md b/README.md index 8c043f84..a40aefaf 100644 --- a/README.md +++ b/README.md @@ -34,14 +34,14 @@ Add the dependency via Maven: com.auth0 auth0 - 2.16.0 + 2.17.0 ``` or Gradle: ```gradle -implementation 'com.auth0:auth0:2.16.0' +implementation 'com.auth0:auth0:2.17.0' ``` ### Configure the SDK From e5b5c3dd900e7f936d9dc47d20c013b96bb2cd7e Mon Sep 17 00:00:00 2001 From: Tanya Sinha Date: Wed, 8 Jan 2025 17:30:58 +0530 Subject: [PATCH 30/32] Added groovy version compatible with java 8 (#687) --- build.gradle | 1 + 1 file changed, 1 insertion(+) diff --git a/build.gradle b/build.gradle index 9f9ad2ad..a14704a1 100644 --- a/build.gradle +++ b/build.gradle @@ -4,6 +4,7 @@ buildscript { } dependencies { + classpath 'org.codehaus.groovy:groovy-all:2.5.14' // Ensure Groovy version compatible with Java 8 // https://github.com/melix/japicmp-gradle-plugin/issues/36 classpath 'com.google.guava:guava:31.1-jre' } From 801b54c833a780addeae2eeb179ee0ada9767329 Mon Sep 17 00:00:00 2001 From: Tanya Sinha Date: Wed, 8 Jan 2025 18:42:10 +0530 Subject: [PATCH 31/32] Remove bounycastle test implementations (#688) --- build.gradle | 1 - .../utils/tokens/SignatureVerifierTest.java | 20 +++++++++++++------ 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/build.gradle b/build.gradle index a14704a1..a4c31b28 100644 --- a/build.gradle +++ b/build.gradle @@ -135,7 +135,6 @@ dependencies { implementation "com.auth0:java-jwt:4.4.0" implementation "net.jodah:failsafe:2.4.4" - testImplementation "org.bouncycastle:bcprov-jdk18on:1.78" testImplementation "org.mockito:mockito-core:4.8.1" testImplementation "com.squareup.okhttp3:mockwebserver:${okhttpVersion}" testImplementation "org.hamcrest:hamcrest:${hamcrestVersion}" diff --git a/src/test/java/com/auth0/utils/tokens/SignatureVerifierTest.java b/src/test/java/com/auth0/utils/tokens/SignatureVerifierTest.java index 151378ef..443a99dd 100644 --- a/src/test/java/com/auth0/utils/tokens/SignatureVerifierTest.java +++ b/src/test/java/com/auth0/utils/tokens/SignatureVerifierTest.java @@ -4,9 +4,9 @@ import com.auth0.exception.PublicKeyProviderException; import com.auth0.jwt.exceptions.AlgorithmMismatchException; import com.auth0.jwt.interfaces.DecodedJWT; -import org.bouncycastle.util.io.pem.PemReader; import org.junit.jupiter.api.Test; +import java.io.BufferedReader; import java.io.FileInputStream; import java.io.FileReader; import java.io.IOException; @@ -18,6 +18,7 @@ import java.security.interfaces.RSAPublicKey; import java.security.spec.EncodedKeySpec; import java.security.spec.X509EncodedKeySpec; +import java.util.Base64; import java.util.Scanner; import static com.auth0.AssertsUtil.verifyThrows; @@ -144,7 +145,7 @@ public RSAPublicKey getPublicKeyById(String keyId) throws PublicKeyProviderExcep private static RSAPublicKey readPublicKeyFromFile(final String path) throws IOException { Scanner scanner = null; - PemReader pemReader = null; + BufferedReader reader = null; try { scanner = new Scanner(Paths.get(path)); if (scanner.hasNextLine() && scanner.nextLine().startsWith("-----BEGIN CERTIFICATE-----")) { @@ -155,8 +156,15 @@ private static RSAPublicKey readPublicKeyFromFile(final String path) throws IOEx fs.close(); return (RSAPublicKey) key; } else { - pemReader = new PemReader(new FileReader(path)); - byte[] keyBytes = pemReader.readPemObject().getContent(); + reader = new BufferedReader(new FileReader(path)); + StringBuilder pemContent = new StringBuilder(); + String line; + while ((line = reader.readLine()) != null) { + if (!line.startsWith("-----BEGIN") && !line.startsWith("-----END")) { + pemContent.append(line); + } + } + byte[] keyBytes = Base64.getDecoder().decode(pemContent.toString()); KeyFactory kf = KeyFactory.getInstance("RSA"); EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes); return (RSAPublicKey) kf.generatePublic(keySpec); @@ -167,8 +175,8 @@ private static RSAPublicKey readPublicKeyFromFile(final String path) throws IOEx if (scanner != null) { scanner.close(); } - if (pemReader != null) { - pemReader.close(); + if (reader != null) { + reader.close(); } } } From e9dcbd21a318764dc21534c78c02c164159d4bc8 Mon Sep 17 00:00:00 2001 From: Tanya Sinha Date: Wed, 8 Jan 2025 18:53:21 +0530 Subject: [PATCH 32/32] Removed groovy from dependency (#689) --- build.gradle | 1 - 1 file changed, 1 deletion(-) diff --git a/build.gradle b/build.gradle index a4c31b28..27d72ca3 100644 --- a/build.gradle +++ b/build.gradle @@ -4,7 +4,6 @@ buildscript { } dependencies { - classpath 'org.codehaus.groovy:groovy-all:2.5.14' // Ensure Groovy version compatible with Java 8 // https://github.com/melix/japicmp-gradle-plugin/issues/36 classpath 'com.google.guava:guava:31.1-jre' }