Allow setting response mode (#14104)

Closes #14083
This commit is contained in:
Pedro Igor
2022-09-09 09:28:47 -03:00
committed by GitHub
parent 0fcf5d3936
commit a0079b516b
3 changed files with 70 additions and 7 deletions

View File

@@ -18,6 +18,7 @@
package org.keycloak.authorization.client.resource;
import java.util.List;
import java.util.concurrent.Callable;
import org.keycloak.authorization.client.AuthorizationDeniedException;
@@ -25,10 +26,13 @@ import org.keycloak.authorization.client.Configuration;
import org.keycloak.authorization.client.representation.ServerConfiguration;
import org.keycloak.authorization.client.util.Http;
import org.keycloak.authorization.client.util.HttpMethod;
import org.keycloak.authorization.client.util.HttpMethodResponse;
import org.keycloak.authorization.client.util.Throwables;
import org.keycloak.authorization.client.util.TokenCallable;
import org.keycloak.representations.idm.authorization.AuthorizationRequest;
import org.keycloak.representations.idm.authorization.AuthorizationResponse;
import org.keycloak.representations.idm.authorization.Permission;
import com.fasterxml.jackson.core.type.TypeReference;
/**
* An entry point for obtaining permissions from the server.
@@ -67,29 +71,60 @@ public class AuthorizationResource {
* @throws AuthorizationDeniedException in case the request was denied by the server
*/
public AuthorizationResponse authorize(final AuthorizationRequest request) throws AuthorizationDeniedException {
return invoke(request);
}
/**
* Query the server for a list of permissions given an {@link AuthorizationRequest}.
*
* @param request an {@link AuthorizationRequest} (not {@code null})
* @return a list of permissions granted by the server
* @throws AuthorizationDeniedException in case the request was denied by the server
*/
public List<Permission> getPermissions(final AuthorizationRequest request) throws AuthorizationDeniedException {
AuthorizationRequest.Metadata metadata;
if (request.getMetadata() == null) {
metadata = new AuthorizationRequest.Metadata();
} else {
metadata = request.getMetadata();
}
metadata.setResponseMode("permissions");
return invoke(request);
}
private <T> T invoke(AuthorizationRequest request) {
if (request == null) {
throw new IllegalArgumentException("Authorization request must not be null");
}
Callable<AuthorizationResponse> callable = new Callable<AuthorizationResponse>() {
Callable<T> callable = new Callable<T>() {
@Override
public AuthorizationResponse call() throws Exception {
public T call() throws Exception {
if (request.getAudience() == null) {
request.setAudience(configuration.getResource());
}
HttpMethod<AuthorizationResponse> method = http.<AuthorizationResponse>post(serverConfiguration.getTokenEndpoint());
HttpMethod<T> method = http.post(serverConfiguration.getTokenEndpoint());
if (token != null) {
method = method.authorizationBearer(token.call());
}
return method
HttpMethodResponse<T> response = method
.authentication()
.uma(request)
.response()
.json(AuthorizationResponse.class)
.execute();
.response();
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();
}
};
try {

View File

@@ -125,6 +125,10 @@ public class HttpMethodAuthenticator<R> {
if (metadata.getLimit() != null) {
method.param("response_permissions_limit", metadata.getLimit().toString());
}
if (metadata.getResponseMode() != null) {
method.param("response_mode", metadata.getResponseMode());
}
}
return method;

View File

@@ -17,7 +17,10 @@
package org.keycloak.testsuite.authz;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import java.io.IOException;
import java.util.Collections;
@@ -39,6 +42,7 @@ import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.representations.idm.authorization.AuthorizationRequest;
import org.keycloak.representations.idm.authorization.AuthorizationResponse;
import org.keycloak.representations.idm.authorization.JSPolicyRepresentation;
import org.keycloak.representations.idm.authorization.Permission;
import org.keycloak.representations.idm.authorization.PermissionRequest;
import org.keycloak.representations.idm.authorization.ResourcePermissionRepresentation;
import org.keycloak.representations.idm.authorization.ResourceRepresentation;
@@ -185,6 +189,26 @@ public class AuthorizationAPITest extends AbstractAuthzTest {
PAIRWISE_AUTHZ_CLIENT_CONFIG);
}
@Test
public void testResponseMode() {
AuthzClient authzClient = getAuthzClient(AUTHZ_CLIENT_CONFIG);
PermissionRequest permission = new PermissionRequest("Resource A");
String ticket = authzClient.protection().permission().create(permission).getTicket();
AuthorizationRequest request = new AuthorizationRequest(ticket);
AuthorizationResponse response = authzClient.authorization("marta", "password").authorize(request);
assertNotNull(response.getToken());
request.setMetadata(new AuthorizationRequest.Metadata());
request.getMetadata().setResponseMode("decision");
response = authzClient.authorization("marta", "password").authorize(request);
assertNull(response.getToken());
assertTrue((Boolean) response.getOtherClaims().getOrDefault("result", "false"));
List<Permission> permissions = authzClient.authorization("marta", "password").getPermissions(request);
assertFalse(permissions.isEmpty());
}
public void testResourceServerAsAudience(String clientId, String resourceServerClientId, String authzConfigFile) throws Exception {
AuthzClient authzClient = getAuthzClient(authzConfigFile);
PermissionRequest request = new PermissionRequest();