[KEYCLOAK-3156] - Missing CORS when responding with denies
This commit is contained in:
parent
333bdb62dd
commit
f48288865b
5 changed files with 44 additions and 8 deletions
|
@ -129,7 +129,7 @@ public abstract class AbstractPolicyEnforcer {
|
|||
Set<String> allowedScopes = permission.getScopes();
|
||||
|
||||
if (permission.getResourceSetId() != null) {
|
||||
if (permission.getResourceSetId().equals(actualPathConfig.getId())) {
|
||||
if (isResourcePermission(actualPathConfig, permission)) {
|
||||
if (((allowedScopes == null || allowedScopes.isEmpty()) && requiredScopes.isEmpty()) || allowedScopes.containsAll(requiredScopes)) {
|
||||
LOGGER.debugf("Authorization GRANTED for path [%s]. Permissions [%s].", actualPathConfig, permissions);
|
||||
if (request.getMethod().equalsIgnoreCase("DELETE") && actualPathConfig.isInstance()) {
|
||||
|
@ -211,6 +211,7 @@ public abstract class AbstractPolicyEnforcer {
|
|||
config.setScopes(originalConfig.getScopes());
|
||||
config.setMethods(originalConfig.getMethods());
|
||||
config.setInstance(true);
|
||||
config.setParentConfig(originalConfig);
|
||||
|
||||
this.paths.add(config);
|
||||
|
||||
|
@ -240,4 +241,16 @@ public abstract class AbstractPolicyEnforcer {
|
|||
private AuthorizationContext createAuthorizationContext(AccessToken accessToken) {
|
||||
return new AuthorizationContext(accessToken, this.paths);
|
||||
}
|
||||
|
||||
private boolean isResourcePermission(PathConfig actualPathConfig, Permission permission) {
|
||||
// first we try a match using resource id
|
||||
boolean resourceMatch = permission.getResourceSetId().equals(actualPathConfig.getId());
|
||||
|
||||
// as a fallback, check if the current path is an instance and if so, check if parent's id matches the permission
|
||||
if (!resourceMatch && actualPathConfig.isInstance()) {
|
||||
resourceMatch = permission.getResourceSetId().equals(actualPathConfig.getParentConfig().getId());
|
||||
}
|
||||
|
||||
return resourceMatch;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
*/
|
||||
package org.keycloak.representations.adapters.config;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
@ -99,6 +100,9 @@ public class PolicyEnforcerConfig {
|
|||
private String id;
|
||||
private boolean instance;
|
||||
|
||||
@JsonIgnore
|
||||
private PathConfig parentConfig;
|
||||
|
||||
public String getPath() {
|
||||
return this.path;
|
||||
}
|
||||
|
@ -169,6 +173,14 @@ public class PolicyEnforcerConfig {
|
|||
public void setInstance(boolean instance) {
|
||||
this.instance = instance;
|
||||
}
|
||||
|
||||
public void setParentConfig(PathConfig parentConfig) {
|
||||
this.parentConfig = parentConfig;
|
||||
}
|
||||
|
||||
public PathConfig getParentConfig() {
|
||||
return parentConfig;
|
||||
}
|
||||
}
|
||||
|
||||
public static class MethodConfig {
|
||||
|
|
|
@ -106,7 +106,10 @@ public class AuthorizationTokenService {
|
|||
List<Permission> entitlements = Permissions.allPermits(results);
|
||||
|
||||
if (entitlements.isEmpty()) {
|
||||
asyncResponse.resume(new ErrorResponseException("not_authorized", "Authorization denied.", Status.FORBIDDEN));
|
||||
asyncResponse.resume(Cors.add(httpRequest, Response.status(Status.FORBIDDEN)
|
||||
.entity(new ErrorResponseException("not_authorized", "Authorization denied.", Status.FORBIDDEN)))
|
||||
.allowedOrigins(identity.getAccessToken())
|
||||
.exposedHeaders(Cors.ACCESS_CONTROL_ALLOW_METHODS).build());
|
||||
} else {
|
||||
AuthorizationResponse response = new AuthorizationResponse(createRequestingPartyToken(entitlements, identity.getAccessToken()));
|
||||
asyncResponse.resume(Cors.add(httpRequest, Response.status(Status.CREATED).entity(response)).allowedOrigins(identity.getAccessToken())
|
||||
|
@ -217,12 +220,14 @@ public class AuthorizationTokenService {
|
|||
}
|
||||
|
||||
private PermissionTicket verifyPermissionTicket(AuthorizationRequest request) {
|
||||
if (!Tokens.verifySignature(request.getTicket(), getRealm().getPublicKey())) {
|
||||
String ticketString = request.getTicket();
|
||||
|
||||
if (ticketString == null || !Tokens.verifySignature(ticketString, getRealm().getPublicKey())) {
|
||||
throw new ErrorResponseException("invalid_ticket", "Ticket verification failed", Status.FORBIDDEN);
|
||||
}
|
||||
|
||||
try {
|
||||
PermissionTicket ticket = new JWSInput(request.getTicket()).readJsonContent(PermissionTicket.class);
|
||||
PermissionTicket ticket = new JWSInput(ticketString).readJsonContent(PermissionTicket.class);
|
||||
|
||||
if (!ticket.isActive()) {
|
||||
throw new ErrorResponseException("invalid_ticket", "Invalid permission ticket.", Status.FORBIDDEN);
|
||||
|
|
|
@ -80,8 +80,9 @@ public class EntitlementService {
|
|||
this.authorization = authorization;
|
||||
}
|
||||
|
||||
@Path("{resource_server_id}")
|
||||
@OPTIONS
|
||||
public Response authorizePreFlight() {
|
||||
public Response authorizePreFlight(@PathParam("resource_server_id") String resourceServerId) {
|
||||
return Cors.add(this.request, Response.ok()).auth().preflight().build();
|
||||
}
|
||||
|
||||
|
@ -118,7 +119,10 @@ public class EntitlementService {
|
|||
List<Permission> entitlements = Permissions.allPermits(results);
|
||||
|
||||
if (entitlements.isEmpty()) {
|
||||
asyncResponse.resume(new ErrorResponseException("not_authorized", "Authorization denied.", Status.FORBIDDEN));
|
||||
asyncResponse.resume(Cors.add(request, Response.status(Status.FORBIDDEN)
|
||||
.entity(new ErrorResponseException("not_authorized", "Authorization denied.", Status.FORBIDDEN)))
|
||||
.allowedOrigins(identity.getAccessToken())
|
||||
.exposedHeaders(Cors.ACCESS_CONTROL_ALLOW_METHODS).build());
|
||||
} else {
|
||||
asyncResponse.resume(Cors.add(request, Response.ok().entity(new EntitlementResponse(createRequestingPartyToken(entitlements)))).allowedOrigins(identity.getAccessToken()).allowedMethods("GET").exposedHeaders(Cors.ACCESS_CONTROL_ALLOW_METHODS).build());
|
||||
}
|
||||
|
|
|
@ -26,6 +26,7 @@ import org.keycloak.authorization.model.ResourceServer;
|
|||
import org.keycloak.authorization.model.Scope;
|
||||
import org.keycloak.authorization.permission.ResourcePermission;
|
||||
import org.keycloak.authorization.policy.evaluation.Result;
|
||||
import org.keycloak.authorization.store.ResourceStore;
|
||||
import org.keycloak.authorization.store.StoreFactory;
|
||||
import org.keycloak.representations.authorization.Permission;
|
||||
|
||||
|
@ -58,9 +59,10 @@ public final class Permissions {
|
|||
public static List<ResourcePermission> all(ResourceServer resourceServer, Identity identity, AuthorizationProvider authorization) {
|
||||
List<ResourcePermission> permissions = new ArrayList<>();
|
||||
StoreFactory storeFactory = authorization.getStoreFactory();
|
||||
ResourceStore resourceStore = storeFactory.getResourceStore();
|
||||
|
||||
storeFactory.getResourceStore().findByOwner(resourceServer.getClientId()).stream().forEach(resource -> permissions.addAll(createResourcePermissions(resource)));
|
||||
storeFactory.getResourceStore().findByOwner(identity.getId()).stream().forEach(resource -> permissions.addAll(createResourcePermissions(resource)));
|
||||
resourceStore.findByOwner(resourceServer.getClientId()).stream().forEach(resource -> permissions.addAll(createResourcePermissions(resource)));
|
||||
resourceStore.findByOwner(identity.getId()).stream().forEach(resource -> permissions.addAll(createResourcePermissions(resource)));
|
||||
|
||||
return permissions;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue