Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.descope.exception;

import lombok.Getter;

@Getter
public class RateLimitExceededException extends DescopeException {
private long retryAfterSeconds;

public RateLimitExceededException(String message, String code, long retryAfterSeconds) {
super(message);
setCode(code);
this.retryAfterSeconds = retryAfterSeconds;
}

}
42 changes: 22 additions & 20 deletions src/main/java/com/descope/literals/Routes.java
Original file line number Diff line number Diff line change
Expand Up @@ -63,25 +63,27 @@ public static class ManagementEndPoints {
// User
public static final String CREATE_USER_LINK = "/v1/mgmt/user/create";
public static final String UPDATE_USER_LINK = "/v1/mgmt/user/update";
public static final String DELETE_USER_LINK = "/v1//mgmt/user/delete";
public static final String DELETE_ALL_TEST_USERS_LINK = "/mgmt/user/test/delete/all";
public static final String LOAD_USER_LINK = "/v1//mgmt/user";
public static final String USER_SEARCH_ALL_LINK = "/mgmt/user/search";
public static final String USER_UPDATE_STATUS_LINK = "/mgmt/user/update/status";
public static final String USER_UPDATE_EMAIL_LINK = "/mgmt/user/update/email";
public static final String USER_UPDATE_PHONE_LINK = "/mgmt/user/update/phone";
public static final String UPDATE_USER_NAME_LINK = "/mgmt/user/update/name";
public static final String UPDATE_PICTURE_LINK = "/mgmt/user/update/picture";
public static final String UPDATE_CUSTOM_ATTRIBUTE_LINK = "/mgmt/user/update/customAttribute";
public static final String USER_ADD_ROLES_LINK = "/mgmt/user/update/role/add";
public static final String USER_REMOVE_ROLES_LINK = "/mgmt/user/update/role/remove";
public static final String USER_ADD_TENANT_LINK = "/mgmt/user/update/tenant/add";
public static final String USER_REMOVE_TENANT_LINK = "/mgmt/user/update/tenant/remove";
public static final String COMPOSE_OTP_FOR_TEST_LINK = "/mgmt/tests/generate/otp";
public static final String MAGIC_LINK_FOR_TEST_LINK = "/mgmt/tests/generate/magiclink";
public static final String ENCHANTED_LINK_FOR_TEST_LINK = "/mgmt/tests/generate/enchantedlink";
public static final String USER_SET_PASSWORD_LINK = "/mgmt/user/password/set";
public static final String USER_EXPIRE_PASSWORD_LINK = "/mgmt/user/password/expire";
public static final String DELETE_USER_LINK = "/v1/mgmt/user/delete";
public static final String DELETE_ALL_TEST_USERS_LINK = "/v1/mgmt/user/test/delete/all";
public static final String LOAD_USER_LINK = "/v1/mgmt/user";
public static final String USER_SEARCH_ALL_LINK = "/v1/mgmt/user/search";
public static final String USER_UPDATE_STATUS_LINK = "/v1/mgmt/user/update/status";
public static final String USER_UPDATE_EMAIL_LINK = "/v1/mgmt/user/update/email";
public static final String USER_UPDATE_PHONE_LINK = "/v1/mgmt/user/update/phone";
public static final String UPDATE_USER_NAME_LINK = "/v1/mgmt/user/update/name";
public static final String UPDATE_PICTURE_LINK = "/v1/mgmt/user/update/picture";
public static final String UPDATE_CUSTOM_ATTRIBUTE_LINK =
"/v1/mgmt/user/update/customAttribute";
public static final String USER_ADD_ROLES_LINK = "/v1/mgmt/user/update/role/add";
public static final String USER_REMOVE_ROLES_LINK = "/v1/mgmt/user/update/role/remove";
public static final String USER_ADD_TENANT_LINK = "/v1/mgmt/user/update/tenant/add";
public static final String USER_REMOVE_TENANT_LINK = "/v1/mgmt/user/update/tenant/remove";
public static final String COMPOSE_OTP_FOR_TEST_LINK = "/v1/mgmt/tests/generate/otp";
public static final String MAGIC_LINK_FOR_TEST_LINK = "/v1/mgmt/tests/generate/magiclink";
public static final String ENCHANTED_LINK_FOR_TEST_LINK =
"/v1/mgmt/tests/generate/enchantedlink";
public static final String USER_SET_PASSWORD_LINK = "/v1/mgmt/user/password/set";
public static final String USER_EXPIRE_PASSWORD_LINK = "/v1/mgmt/user/password/expire";

// Tenant
public static final String CREATE_TENANT_LINK = "/v1/mgmt/tenant/create";
Expand All @@ -108,7 +110,7 @@ public static class ManagementEndPoints {
public static final String THEME_IMPORT_LINK = "/v1/mgmt/theme/import";

// JWT
public static final String UPDATE_JWT_LINK = "/mgmt/jwt/update";
public static final String UPDATE_JWT_LINK = "/v1/mgmt/jwt/update";

// Access key
public static final String MANAGEMENT_ACCESS_KEY_CREATE_LINK = "/v1/mgmt/accesskey/create";
Expand Down
2 changes: 2 additions & 0 deletions src/main/java/com/descope/model/user/request/UserRequest.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@
public class UserRequest {
String loginId;
String email;
Boolean verifiedEmail;
String phone;
Boolean verifiedPhone;
String displayName;
List<String> roleNames;
List<AssociatedTenant> tenants;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,11 @@
public class UserSearchRequest {
List<String> tenantIds;
List<String> roles;
Integer limit;
Integer page;
Boolean withTestUsers;
@Builder.Default
Integer limit = 0;
@Builder.Default
Integer page = 0;
Boolean withTestUser;
Boolean testUsersOnly;
Map<String, Object> customAttributes;
}
10 changes: 10 additions & 0 deletions src/main/java/com/descope/model/user/response/UserResponse.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import com.descope.model.auth.AssociatedTenant;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import java.util.List;
import java.util.Map;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
Expand All @@ -11,14 +12,23 @@
@NoArgsConstructor
@AllArgsConstructor
@JsonIgnoreProperties(ignoreUnknown = true)
@SuppressWarnings("checkstyle:MemberName")
public class UserResponse {
String userId;
List<String> loginIds;
String email;
Boolean verifiedEmail;
String phone;
Boolean verifiedPhone;
String name;
List<String> roleNames;
List<AssociatedTenant> userTenants;
String status;
String picture;
Boolean test;
Long createdTime;
Map<String, Object> customAttributes;
Boolean TOTP;
Boolean SAML;
Map<String, Boolean> oAuth;
}
11 changes: 11 additions & 0 deletions src/main/java/com/descope/proxy/impl/AbstractProxyImpl.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.descope.proxy.impl;

import com.descope.exception.ErrorCode;
import com.descope.exception.RateLimitExceededException;
import com.descope.exception.ServerCommonException;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.IOException;
Expand Down Expand Up @@ -82,6 +84,9 @@ protected <B, R> R delete(URI uri, B body, Class<R> returnClz) {

private static class JsonBodyHandler<R> implements HttpResponse.BodyHandler<Supplier<R>> {

private static final String RETRY_AFTER_HEADER = "Retry-After";
private static final long DEFAULT_RETRY = 60;

private final Class<R> returnClz;

public JsonBodyHandler(Class<R> returnClz) {
Expand All @@ -105,6 +110,12 @@ private static <R> Supplier<R> toSupplierOfType(
if (responseInfo.statusCode() < 200 || responseInfo.statusCode() > 299) {
var errorDetails = objectMapper.readValue(stream, JsonBodyHandler.ErrorDetails.class);
log.error(errorDetails.getActualMessage());
if (ErrorCode.RATE_LIMIT_EXCEEDED.equals(errorDetails.errorCode)) {
throw new RateLimitExceededException(
errorDetails.getActualMessage(),
errorDetails.getErrorCode(),
responseInfo.headers().firstValueAsLong(RETRY_AFTER_HEADER).orElse(DEFAULT_RETRY));
}
throw ServerCommonException.genericServerError(
errorDetails.getActualMessage(), errorDetails.getErrorCode());
}
Expand Down
4 changes: 2 additions & 2 deletions src/main/java/com/descope/sdk/mgmt/UserService.java
Original file line number Diff line number Diff line change
Expand Up @@ -118,11 +118,11 @@ public interface UserService {
*
* @param request The options optional parameter allows to fine-tune the search filters and
* results. Using nil will result in a filter-less query with a set amount of results.
* @return {@link List} of {@link UserResponseDetails}
* @return {@link AllUsersResponseDetails}
* @throws DescopeException If there occurs any exception, a subtype of this exception will be
* thrown.
*/
List<AllUsersResponseDetails> searchAll(UserSearchRequest request) throws DescopeException;
AllUsersResponseDetails searchAll(UserSearchRequest request) throws DescopeException;

/**
* Activate an existing user.
Expand Down
6 changes: 3 additions & 3 deletions src/main/java/com/descope/sdk/mgmt/impl/UserServiceImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ public void delete(String loginId) throws DescopeException {
public void deleteAllTestUsers() throws DescopeException {
URI deleteAllTestUsersUri = composeDeleteAllTestUsersUri();
var apiProxy = getApiProxy();
apiProxy.post(deleteAllTestUsersUri, null, Void.class);
apiProxy.delete(deleteAllTestUsersUri, null, Void.class);
}

@Override
Expand All @@ -143,7 +143,7 @@ public UserResponseDetails loadByUserId(String userId) throws DescopeException {

@Override
@SuppressWarnings("unchecked")
public List<AllUsersResponseDetails> searchAll(UserSearchRequest request)
public AllUsersResponseDetails searchAll(UserSearchRequest request)
throws DescopeException {
if (Objects.isNull(request)) {
request = UserSearchRequest.builder().limit(0).page(0).build();
Expand All @@ -157,7 +157,7 @@ public List<AllUsersResponseDetails> searchAll(UserSearchRequest request)

URI composeSearchAllUri = composeSearchAllUri();
var apiProxy = getApiProxy();
return (List<AllUsersResponseDetails>) apiProxy.post(composeSearchAllUri, request, List.class);
return apiProxy.post(composeSearchAllUri, request, AllUsersResponseDetails.class);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,13 +48,21 @@ public class EnchantedLinkServiceImplTest {
new UserResponse(
"someUserId",
List.of(MOCK_EMAIL),
"someEmail@descope.com",
true,
"+1-555-555-5555",
false,
"someName",
Collections.emptyList(),
Collections.emptyList(),
"enabled",
"",
false);
false,
0L,
Collections.emptyMap(),
false,
false,
Collections.emptyMap());
public static final JWTResponse MOCK_JWT_RESPONSE =
new JWTResponse(
"someSessionJwt",
Expand All @@ -72,6 +80,7 @@ public class EnchantedLinkServiceImplTest {
.jwt("someJwtToken")
.claims(Map.of("someClaim", 1))
.build();
@SuppressWarnings("checkstyle:LineLength")
public static final SigningKey MOCK_SIGNING_KEY =
SigningKey.builder()
.e("AQAB")
Expand Down
11 changes: 10 additions & 1 deletion src/test/java/com/descope/sdk/impl/JwtServiceImplTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -39,13 +39,21 @@ public class JwtServiceImplTest {
new UserResponse(
"someUserId",
List.of(MOCK_EMAIL),
"someEmail@descope.com",
true,
"+1-555-555-5555",
false,
"someName",
Collections.emptyList(),
Collections.emptyList(),
"enabled",
"",
false);
false,
0L,
Collections.emptyMap(),
false,
false,
Collections.emptyMap());
public static final JWTResponse MOCK_JWT_RESPONSE =
new JWTResponse(
"someSessionJwt",
Expand All @@ -56,6 +64,7 @@ public class JwtServiceImplTest {
1234567890,
MOCK_USER_RESPONSE,
true);
@SuppressWarnings("checkstyle:LineLength")
public static final SigningKey MOCK_SIGNING_KEY =
SigningKey.builder()
.e("AQAB")
Expand Down
11 changes: 10 additions & 1 deletion src/test/java/com/descope/sdk/impl/MagicLinkServiceImplTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -60,13 +60,21 @@ class MagicLinkServiceImplTest {
new UserResponse(
"someUserId",
List.of(MOCK_EMAIL),
"someEmail@descope.com",
true,
"+1-555-555-5555",
false,
"someName",
Collections.emptyList(),
Collections.emptyList(),
"enabled",
"",
false);
false,
0L,
Collections.emptyMap(),
false,
false,
Collections.emptyMap());
public static final JWTResponse MOCK_JWT_RESPONSE =
new JWTResponse(
"someSessionJwt",
Expand All @@ -84,6 +92,7 @@ class MagicLinkServiceImplTest {
.jwt("someJwtToken")
.claims(Map.of("someClaim", 1))
.build();
@SuppressWarnings("checkstyle:LineLength")
public static final SigningKey MOCK_SIGNING_KEY =
SigningKey.builder()
.e("AQAB")
Expand Down
10 changes: 9 additions & 1 deletion src/test/java/com/descope/sdk/impl/OAuthServiceImplTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -41,13 +41,21 @@ public class OAuthServiceImplTest {
new UserResponse(
"someUserId",
List.of(MOCK_EMAIL),
"someEmail@descope.com",
true,
"+1-555-555-5555",
false,
"someName",
Collections.emptyList(),
Collections.emptyList(),
"enabled",
"",
false);
false,
0L,
Collections.emptyMap(),
false,
false,
Collections.emptyMap());
public static final JWTResponse MOCK_JWT_RESPONSE =
new JWTResponse(
"someSessionJwt",
Expand Down
11 changes: 10 additions & 1 deletion src/test/java/com/descope/sdk/impl/OTPServiceImplTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -51,13 +51,21 @@ public class OTPServiceImplTest {
new UserResponse(
"someUserId",
List.of(MOCK_EMAIL),
"someEmail@descope.com",
true,
"+1-555-555-5555",
false,
"someName",
Collections.emptyList(),
Collections.emptyList(),
"enabled",
"",
false);
false,
0L,
Collections.emptyMap(),
false,
false,
Collections.emptyMap());
public static final JWTResponse MOCK_JWT_RESPONSE =
new JWTResponse(
"someSessionJwt",
Expand All @@ -75,6 +83,7 @@ public class OTPServiceImplTest {
.jwt("someJwtToken")
.claims(Map.of("someClaim", 1))
.build();
@SuppressWarnings("checkstyle:LineLength")
public static final SigningKey MOCK_SIGNING_KEY =
SigningKey.builder()
.e("AQAB")
Expand Down
11 changes: 10 additions & 1 deletion src/test/java/com/descope/sdk/impl/PasswordServiceImplTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -47,13 +47,21 @@ public class PasswordServiceImplTest {
new UserResponse(
"someUserId",
List.of(MOCK_EMAIL),
"someEmail@descope.com",
true,
"+1-555-555-5555",
false,
"someName",
Collections.emptyList(),
Collections.emptyList(),
"enabled",
"",
false);
false,
0L,
Collections.emptyMap(),
false,
false,
Collections.emptyMap());
public static final JWTResponse MOCK_JWT_RESPONSE =
new JWTResponse(
"someSessionJwt",
Expand All @@ -71,6 +79,7 @@ public class PasswordServiceImplTest {
.jwt("someJwtToken")
.claims(Map.of("someClaim", 1))
.build();
@SuppressWarnings("checkstyle:LineLength")
public static final SigningKey MOCK_SIGNING_KEY =
SigningKey.builder()
.e("AQAB")
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
package com.descope.sdk.impl;

import static com.descope.sdk.impl.PasswordServiceImplTest.MOCK_PROJECT_ID;
import static org.junit.jupiter.api.Assertions.*;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.*;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.mockStatic;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;

import com.descope.exception.ServerCommonException;
import com.descope.model.client.Client;
Expand Down
Loading