From 811c6cadeb77e4f8e60b9ed30efd57dd7255e876 Mon Sep 17 00:00:00 2001 From: Asaf Shen Date: Wed, 20 Dec 2023 18:33:35 +0200 Subject: [PATCH] Get matched roles and permissions (#87) --- README.md | 8 +++ .../sdk/auth/AuthenticationService.java | 51 ++++++++++++++++++- .../auth/impl/AuthenticationServiceImpl.java | 36 ++++++++++++- .../impl/AuthenticationServiceImplTest.java | 17 +++++++ 4 files changed, 109 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index c5030fa0..91e98263 100644 --- a/README.md +++ b/README.md @@ -515,6 +515,10 @@ try { // Handle the error } +// Or get the matched roles/permissions +List matchedPermissions = as.getMatchedPermissions(sessionToken, "my-tenant-ID", Arrays.asList("Permission1", "Permission2")); + +List matchedRoles = as.getMatchedRoles(sessionToken, "my-tenant-ID", Arrays.asList("Role1", "Role2")); ``` When not using tenants use: @@ -539,6 +543,10 @@ try { // Handle the error } +// Or get the matched roles/permissions +List matchedPermissions = as.getMatchedPermissions(sessionToken, Arrays.asList("Permission1", "Permission2")); + +List matchedRoles = as.getMatchedRoles(sessionToken, Arrays.asList("Role1", "Role2")); ``` ### Logging Out diff --git a/src/main/java/com/descope/sdk/auth/AuthenticationService.java b/src/main/java/com/descope/sdk/auth/AuthenticationService.java index d550cb1f..24ce7eea 100644 --- a/src/main/java/com/descope/sdk/auth/AuthenticationService.java +++ b/src/main/java/com/descope/sdk/auth/AuthenticationService.java @@ -50,7 +50,7 @@ Token validateAndRefreshSessionWithTokens(String sessionToken, String refreshTok /** * Use to ensure that a validated session token has been granted the specified permissions. This - * is a shortcut for ValidateTenantPermissions(token, "", permissions) + * is a shortcut for validatePermissions(token, "", permissions) * * @param token - {@link Token Token} * @param permissions - List of permissions. @@ -72,9 +72,33 @@ Token validateAndRefreshSessionWithTokens(String sessionToken, String refreshTok boolean validatePermissions(Token token, String tenant, List permissions) throws DescopeException; + /** + * Use to retrieves the permissions from top level token's claims that match the specified permissions list. This + * is a shortcut for getMatchedPermissions(token, "", permissions) + * + * @param token - {@link Token Token} + * @param permissions - List of permissions. + * @return is valid permissions. + * @throws DescopeException if there is an error + */ + List getMatchedPermissions(Token token, List permissions) throws DescopeException; + + /** + * Use to retrieves the permissions from token's claims of a specific tenant + * that match the specified permissions list. + * This is a shortcut for getMatchedPermissions(token, "", permissions) + * + * @param token - {@link Token Token} + * @param tenant - Tenant ID. + * @param permissions - List of permissions. + * @return is valid permissions. + * @throws DescopeException if there is an error + */ + List getMatchedPermissions(Token token, String tenant, List permissions) throws DescopeException; + /** * Use to ensure that a validated session token has been granted the specified roles. This is a - * shortcut for ValidateTenantRoles(token, "", roles) + * shortcut for validateRoles(token, "", roles) * * @param token - {@link Token Token} * @param roles - List of roles. @@ -95,6 +119,29 @@ boolean validatePermissions(Token token, String tenant, List permissions */ boolean validateRoles(Token token, String tenant, List roles) throws DescopeException; + /** + * Use to retrieves the roles from top level token's claims that match the specified roles list. This + * is a shortcut for getMatchedRoles(token, "", roles) + * + * @param token - {@link Token Token} + * @param roles - List of roles. + * @return is valid roles. + * @throws DescopeException if there is an error + */ + List getMatchedRoles(Token token, List roles) throws DescopeException; + + /** + * Use to retrieves the roles from token's claims of a specific tenant + * that match the specified roles list. + * + * @param token - {@link Token Token} + * @param tenant - Tenant ID. + * @param roles - List of roles. + * @return is valid permissions. + * @throws DescopeException if there is an error + */ + List getMatchedRoles(Token token, String tenant, List roles) throws DescopeException; + /** * Return the list of roles granted to the validated session token in the given tenant. * diff --git a/src/main/java/com/descope/sdk/auth/impl/AuthenticationServiceImpl.java b/src/main/java/com/descope/sdk/auth/impl/AuthenticationServiceImpl.java index 346698c1..b3704db1 100644 --- a/src/main/java/com/descope/sdk/auth/impl/AuthenticationServiceImpl.java +++ b/src/main/java/com/descope/sdk/auth/impl/AuthenticationServiceImpl.java @@ -16,6 +16,9 @@ import com.descope.model.jwt.response.JWTResponse; import com.descope.proxy.ApiProxy; import java.net.URI; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; import java.util.List; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.StringUtils; @@ -89,6 +92,22 @@ public boolean validatePermissions(Token token, String tenant, List perm return CollectionUtils.isSubCollection(permissions, grantedPermissions); } + @Override + public List getMatchedPermissions(Token token, List permissions) throws DescopeException { + return getMatchedPermissions(token, "", permissions); + } + + @Override + public List getMatchedPermissions(Token token, String tenant, List permissions) + throws DescopeException { + if (CollectionUtils.isEmpty(permissions) || StringUtils.isNotBlank(tenant) && !isTenantAssociated(token, tenant)) { + return Collections.emptyList(); + } + List grantedPermissions = getPermissions(token, tenant); + Collection intersection = CollectionUtils.intersection(permissions, grantedPermissions); + return new ArrayList<>(intersection); + } + @Override public boolean validateRoles(Token token, List roles) throws DescopeException { return validateRoles(token, "", roles); @@ -104,6 +123,21 @@ public boolean validateRoles(Token token, String tenant, List roles) return CollectionUtils.isSubCollection(roles, grantedRoles); } + @Override + public List getMatchedRoles(Token token, List roles) throws DescopeException { + return getMatchedRoles(token, "", roles); + } + + @Override + public List getMatchedRoles(Token token, String tenant, List roles) throws DescopeException { + if (CollectionUtils.isEmpty(roles) || StringUtils.isNotBlank(tenant) && !isTenantAssociated(token, tenant)) { + return Collections.emptyList(); + } + List grantedRoles = getRoles(token, tenant); + Collection intersection = CollectionUtils.intersection(roles, grantedRoles); + return new ArrayList<>(intersection); + } + @Override public List getRoles(Token token, String tenant) throws DescopeException { return getAuthorizationClaimItems(token, tenant, ROLES_CLAIM_KEY); @@ -130,7 +164,7 @@ public void logout(String refreshToken) throws DescopeException { throw ServerCommonException.missingArguments("Request doesn't contain refresh token"); } ApiProxy apiProxy = getApiProxy(refreshToken); - URI logOutURL = composeLogOutLinkURL(); + URI logOutURL = composeLogOutLinkURL(); apiProxy.post(logOutURL, null, JWTResponse.class); } diff --git a/src/test/java/com/descope/sdk/auth/impl/AuthenticationServiceImplTest.java b/src/test/java/com/descope/sdk/auth/impl/AuthenticationServiceImplTest.java index 378535e7..b381604c 100644 --- a/src/test/java/com/descope/sdk/auth/impl/AuthenticationServiceImplTest.java +++ b/src/test/java/com/descope/sdk/auth/impl/AuthenticationServiceImplTest.java @@ -2,6 +2,7 @@ import static com.descope.sdk.TestUtils.MOCK_TOKEN; import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -63,6 +64,22 @@ void testPermissionsAndRoles() { assertFalse(authenticationService.validateRoles(MOCK_TOKEN, Arrays.asList("r2", "r3"))); } + @Test + void textGetMatchedPermissionsAndRoles() { + assertEquals(Arrays.asList("tp1", "tp2"), + authenticationService.getMatchedPermissions(MOCK_TOKEN, "someTenant", Arrays.asList("tp1", "tp2"))); + assertEquals(Arrays.asList(), + authenticationService.getMatchedPermissions(MOCK_TOKEN, "someTenant", null)); + assertEquals(Arrays.asList("tp1", "tp2"), + authenticationService.getMatchedPermissions(MOCK_TOKEN, "someTenant", Arrays.asList("tp1", "tp2", "tp3"))); + assertEquals(Arrays.asList("p1", "p2"), + authenticationService.getMatchedPermissions(MOCK_TOKEN, Arrays.asList("p1", "p2"))); + assertEquals(Arrays.asList(), + authenticationService.getMatchedPermissions(MOCK_TOKEN, null)); + assertEquals(Arrays.asList("p1", "p2"), + authenticationService.getMatchedPermissions(MOCK_TOKEN, Arrays.asList("p1", "p2", "p3"))); + } + @RetryingTest(value = 3, suspendForMs = 30000, onExceptions = RateLimitExceededException.class) void testFunctionalPermissions() { String roleName = TestUtils.getRandomName("r-").substring(0, 20);