authz/client: Fix getPermissions returning wrong type

Due to an issue with runtime type erasure, getPermissions returned a
List<LinkedHashSet> instead of List<Permission>.
Fixed and added test to catch this

Closes #16520

Signed-off-by: Clemens Zagler <c.zagler@noi.bz.it>
This commit is contained in:
Clemens Zagler 2024-03-12 13:25:21 +01:00 committed by Pedro Igor
parent c86620963d
commit b44252fde9
4 changed files with 16 additions and 15 deletions

View file

@ -71,7 +71,7 @@ public class AuthorizationResource {
* @throws AuthorizationDeniedException in case the request was denied by the server * @throws AuthorizationDeniedException in case the request was denied by the server
*/ */
public AuthorizationResponse authorize(final AuthorizationRequest request) throws AuthorizationDeniedException { public AuthorizationResponse authorize(final AuthorizationRequest request) throws AuthorizationDeniedException {
return invoke(request); return invoke(request, new TypeReference<AuthorizationResponse>(){});
} }
/** /**
@ -93,10 +93,10 @@ public class AuthorizationResource {
metadata.setResponseMode("permissions"); metadata.setResponseMode("permissions");
return invoke(request); return (List<Permission>) invoke(request, new TypeReference<List<Permission>>(){});
} }
private <T> T invoke(AuthorizationRequest request) { private <T> T invoke(AuthorizationRequest request, TypeReference<T> responseType) {
if (request == null) { if (request == null) {
throw new IllegalArgumentException("Authorization request must not be null"); throw new IllegalArgumentException("Authorization request must not be null");
} }
@ -117,13 +117,8 @@ public class AuthorizationResource {
HttpMethodResponse<T> response = method HttpMethodResponse<T> response = method
.authentication() .authentication()
.uma(request) .uma(request)
.response(); .response()
.json(responseType);
if (request.getMetadata() != null && "permissions".equals(request.getMetadata().getResponseMode())) {
response = response.json(new TypeReference<T>(){});
} else {
response = response.json((Class<T>) AuthorizationResponse.class);
}
return response.execute(); return response.execute();
} }

View file

@ -26,3 +26,11 @@ Keycloak supports a new password policy that allows you to deny user passwords w
= Searching by user attribute no longer case insensitive = Searching by user attribute no longer case insensitive
When searching for users by user attribute, {project_name} no longer searches for user attribute names forcing lower case comparisons. The goal of this change was to speed up searches by using {project_name}'s native index on the user attribute table. If your database collation is case-insensitive, your search results will stay the same. If your database collation is case-sensitive, you might see less search results than before. When searching for users by user attribute, {project_name} no longer searches for user attribute names forcing lower case comparisons. The goal of this change was to speed up searches by using {project_name}'s native index on the user attribute table. If your database collation is case-insensitive, your search results will stay the same. If your database collation is case-sensitive, you might see less search results than before.
= Breaking fix in authorization client library
For users of the `keycloak-authz-client` library, calling `AuthorizationResource.getPermissions(...)` now correctly returns a `List<Permission>`.
Previously, it would return a `List<Map>` at runtime, even though the method declaration advertised `List<Permission>`.
This fix will break code that relied on casting the List or its contents to `List<Map>`. If you have used this method in any capacity, you are likely to have done this and be affected.

View file

@ -204,6 +204,7 @@ public class AuthorizationAPITest extends AbstractAuthzTest {
List<Permission> permissions = authzClient.authorization("marta", "password").getPermissions(request); List<Permission> permissions = authzClient.authorization("marta", "password").getPermissions(request);
assertFalse(permissions.isEmpty()); assertFalse(permissions.isEmpty());
assertTrue(permissions.get(0) instanceof Permission);
} }
public void testResourceServerAsAudience(String clientId, String resourceServerClientId, String authzConfigFile) throws Exception { public void testResourceServerAsAudience(String clientId, String resourceServerClientId, String authzConfigFile) throws Exception {

View file

@ -290,11 +290,8 @@ private void createRegexPolicyExtended(String name, String targetClaim, String p
theRequest.setMetadata(metadata); theRequest.setMetadata(metadata);
List<Permission> permissions = authzClient.authorization("admin", "password").getPermissions(theRequest); List<Permission> permissions = authzClient.authorization("admin", "password").getPermissions(theRequest);
assertNotNull(permissions); assertNotNull(permissions);
Assert.assertTrue(((Map)permissions.get(0)).get("rsname").equals("service")); Assert.assertTrue(permissions.get(0).getResourceName().equals("service"));
Assert.assertTrue(((List)(((Map)permissions.get(0)).get("scopes"))).get(0).equals("read")); Assert.assertTrue(permissions.get(0).getScopes().contains("read"));
} }