keycloak-aplcache
Changes
adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/AuthenticatedActionsHandler.java 8(+6 -2)
adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/authorization/AbstractPolicyEnforcer.java 77(+49 -28)
Details
diff --git a/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/AuthenticatedActionsHandler.java b/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/AuthenticatedActionsHandler.java
index 121adf1..472afb7 100755
--- a/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/AuthenticatedActionsHandler.java
+++ b/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/AuthenticatedActionsHandler.java
@@ -142,9 +142,13 @@ public class AuthenticatedActionsHandler {
AuthorizationContext authorizationContext = policyEnforcer.enforce(facade);
RefreshableKeycloakSecurityContext session = (RefreshableKeycloakSecurityContext) facade.getSecurityContext();
- session.setAuthorizationContext(authorizationContext);
+ if (session != null) {
+ session.setAuthorizationContext(authorizationContext);
- return authorizationContext.isGranted();
+ return authorizationContext.isGranted();
+ }
+
+ return true;
} catch (Exception e) {
throw new RuntimeException("Failed to enforce policy decisions.", e);
}
diff --git a/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/authorization/AbstractPolicyEnforcer.java b/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/authorization/AbstractPolicyEnforcer.java
index 9377b0b..0186e18 100644
--- a/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/authorization/AbstractPolicyEnforcer.java
+++ b/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/authorization/AbstractPolicyEnforcer.java
@@ -19,6 +19,7 @@ package org.keycloak.adapters.authorization;
import org.jboss.logging.Logger;
import org.keycloak.AuthorizationContext;
+import org.keycloak.KeycloakSecurityContext;
import org.keycloak.adapters.OIDCHttpFacade;
import org.keycloak.adapters.spi.HttpFacade.Request;
import org.keycloak.adapters.spi.HttpFacade.Response;
@@ -66,40 +67,51 @@ public abstract class AbstractPolicyEnforcer {
return createEmptyAuthorizationContext(true);
}
- AccessToken accessToken = httpFacade.getSecurityContext().getToken();
- Request request = httpFacade.getRequest();
- Response response = httpFacade.getResponse();
- String pathInfo = URI.create(request.getURI()).getPath().substring(1);
- String path = pathInfo.substring(pathInfo.indexOf('/'), pathInfo.length());
- PathConfig pathConfig = this.pathMatcher.matches(path, this.paths);
+ KeycloakSecurityContext securityContext = httpFacade.getSecurityContext();
- LOGGER.debugf("Checking permissions for path [%s] with config [%s].", request.getURI(), pathConfig);
+ if (securityContext != null) {
+ AccessToken accessToken = securityContext.getToken();
- if (pathConfig == null) {
- if (EnforcementMode.PERMISSIVE.equals(enforcementMode)) {
- return createAuthorizationContext(accessToken);
- }
+ if (accessToken != null) {
+ Request request = httpFacade.getRequest();
+ Response response = httpFacade.getResponse();
+ String pathInfo = URI.create(request.getURI()).getPath().substring(1);
+ String path = pathInfo.substring(pathInfo.indexOf('/'), pathInfo.length());
+ PathConfig pathConfig = this.pathMatcher.matches(path, this.paths);
- LOGGER.debugf("Could not find a configuration for path [%s]", path);
- response.sendError(403, "Could not find a configuration for path [" + path + "].");
+ LOGGER.debugf("Checking permissions for path [%s] with config [%s].", request.getURI(), pathConfig);
- return createEmptyAuthorizationContext(false);
- }
+ if (pathConfig == null) {
+ if (EnforcementMode.PERMISSIVE.equals(enforcementMode)) {
+ return createAuthorizationContext(accessToken);
+ }
- PathConfig actualPathConfig = resolvePathConfig(pathConfig, request);
- Set<String> requiredScopes = getRequiredScopes(actualPathConfig, request);
+ LOGGER.debugf("Could not find a configuration for path [%s]", path);
+ response.sendError(403, "Could not find a configuration for path [" + path + "].");
- if (isAuthorized(actualPathConfig, requiredScopes, accessToken, httpFacade)) {
- try {
- return createAuthorizationContext(accessToken);
- } catch (Exception e) {
- throw new RuntimeException("Error processing path [" + actualPathConfig.getPath() + "].", e);
- }
- }
+ return createEmptyAuthorizationContext(false);
+ }
+
+ if (EnforcementMode.DISABLED.equals(pathConfig.getEnforcementMode())) {
+ return createEmptyAuthorizationContext(true);
+ }
+
+ PathConfig actualPathConfig = resolvePathConfig(pathConfig, request);
+ Set<String> requiredScopes = getRequiredScopes(actualPathConfig, request);
- if (!challenge(actualPathConfig, requiredScopes, httpFacade)) {
- LOGGER.debugf("Sending challenge to the client. Path [%s]", pathConfig);
- response.sendError(403, "Authorization failed.");
+ if (isAuthorized(actualPathConfig, requiredScopes, accessToken, httpFacade)) {
+ try {
+ return createAuthorizationContext(accessToken);
+ } catch (Exception e) {
+ throw new RuntimeException("Error processing path [" + actualPathConfig.getPath() + "].", e);
+ }
+ }
+
+ if (!challenge(actualPathConfig, requiredScopes, httpFacade)) {
+ LOGGER.debugf("Sending challenge to the client. Path [%s]", pathConfig);
+ response.sendError(403, "Authorization failed.");
+ }
+ }
}
return createEmptyAuthorizationContext(false);
@@ -125,14 +137,17 @@ public abstract class AbstractPolicyEnforcer {
}
List<Permission> permissions = authorization.getPermissions();
+ boolean hasPermission = false;
for (Permission permission : permissions) {
if (permission.getResourceSetId() != null) {
if (isResourcePermission(actualPathConfig, permission)) {
+ hasPermission = true;
+
if (actualPathConfig.isInstance() && !matchResourcePermission(actualPathConfig, permission)) {
continue;
-
}
+
if (hasResourceScopePermission(requiredScopes, permission, actualPathConfig)) {
LOGGER.debugf("Authorization GRANTED for path [%s]. Permissions [%s].", actualPathConfig, permissions);
if (request.getMethod().equalsIgnoreCase("DELETE") && actualPathConfig.isInstance()) {
@@ -143,11 +158,16 @@ public abstract class AbstractPolicyEnforcer {
}
} else {
if (hasResourceScopePermission(requiredScopes, permission, actualPathConfig)) {
+ hasPermission = true;
return true;
}
}
}
+ if (!hasPermission && EnforcementMode.PERMISSIVE.equals(actualPathConfig.getEnforcementMode())) {
+ return true;
+ }
+
LOGGER.debugf("Authorization FAILED for path [%s]. No enough permissions [%s].", actualPathConfig, permissions);
return false;
@@ -218,6 +238,7 @@ public abstract class AbstractPolicyEnforcer {
config.setScopes(originalConfig.getScopes());
config.setMethods(originalConfig.getMethods());
config.setParentConfig(originalConfig);
+ config.setEnforcementMode(originalConfig.getEnforcementMode());
this.paths.add(config);
diff --git a/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/authorization/PolicyEnforcer.java b/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/authorization/PolicyEnforcer.java
index ff694bf..37b8f3d 100644
--- a/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/authorization/PolicyEnforcer.java
+++ b/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/authorization/PolicyEnforcer.java
@@ -105,7 +105,16 @@ public class PolicyEnforcer {
}
private List<PathConfig> configurePaths(ProtectedResource protectedResource, PolicyEnforcerConfig enforcerConfig) {
- if (enforcerConfig.getPaths().isEmpty()) {
+ boolean loadPathsFromServer = true;
+
+ for (PathConfig pathConfig : enforcerConfig.getPaths()) {
+ if (!PolicyEnforcerConfig.EnforcementMode.DISABLED.equals(pathConfig.getEnforcementMode())) {
+ loadPathsFromServer = false;
+ break;
+ }
+ }
+
+ if (loadPathsFromServer) {
LOGGER.info("No path provided in configuration.");
return configureAllPathsForResourceServer(protectedResource);
} else {
diff --git a/core/src/main/java/org/keycloak/AuthorizationContext.java b/core/src/main/java/org/keycloak/AuthorizationContext.java
index 05bb97d..a14594b 100644
--- a/core/src/main/java/org/keycloak/AuthorizationContext.java
+++ b/core/src/main/java/org/keycloak/AuthorizationContext.java
@@ -18,9 +18,11 @@
package org.keycloak;
import org.keycloak.representations.AccessToken;
+import org.keycloak.representations.AccessToken.Authorization;
import org.keycloak.representations.adapters.config.PolicyEnforcerConfig.PathConfig;
import org.keycloak.representations.idm.authorization.Permission;
+import java.util.Collections;
import java.util.List;
/**
@@ -44,7 +46,17 @@ public class AuthorizationContext {
}
public boolean hasPermission(String resourceName, String scopeName) {
- for (Permission permission : authzToken.getAuthorization().getPermissions()) {
+ if (this.authzToken == null) {
+ return false;
+ }
+
+ Authorization authorization = this.authzToken.getAuthorization();
+
+ if (authorization == null) {
+ return false;
+ }
+
+ for (Permission permission : authorization.getPermissions()) {
for (PathConfig pathHolder : this.paths) {
if (pathHolder.getName().equals(resourceName)) {
if (pathHolder.getId().equals(permission.getResourceSetId())) {
@@ -60,7 +72,17 @@ public class AuthorizationContext {
}
public boolean hasResourcePermission(String resourceName) {
- for (Permission permission : authzToken.getAuthorization().getPermissions()) {
+ if (this.authzToken == null) {
+ return false;
+ }
+
+ Authorization authorization = this.authzToken.getAuthorization();
+
+ if (authorization == null) {
+ return false;
+ }
+
+ for (Permission permission : authorization.getPermissions()) {
for (PathConfig pathHolder : this.paths) {
if (pathHolder.getName().equals(resourceName)) {
if (pathHolder.getId().equals(permission.getResourceSetId())) {
@@ -74,7 +96,17 @@ public class AuthorizationContext {
}
public boolean hasScopePermission(String scopeName) {
- for (Permission permission : authzToken.getAuthorization().getPermissions()) {
+ if (this.authzToken == null) {
+ return false;
+ }
+
+ Authorization authorization = this.authzToken.getAuthorization();
+
+ if (authorization == null) {
+ return false;
+ }
+
+ for (Permission permission : authorization.getPermissions()) {
if (permission.getScopes().contains(scopeName)) {
return true;
}
@@ -84,7 +116,17 @@ public class AuthorizationContext {
}
public List<Permission> getPermissions() {
- return this.authzToken.getAuthorization().getPermissions();
+ if (this.authzToken == null) {
+ return Collections.emptyList();
+ }
+
+ Authorization authorization = this.authzToken.getAuthorization();
+
+ if (authorization == null) {
+ return Collections.emptyList();
+ }
+
+ return Collections.unmodifiableList(authorization.getPermissions());
}
public boolean isGranted() {
diff --git a/core/src/main/java/org/keycloak/representations/adapters/config/PolicyEnforcerConfig.java b/core/src/main/java/org/keycloak/representations/adapters/config/PolicyEnforcerConfig.java
index 0c3faf8..db874c0 100644
--- a/core/src/main/java/org/keycloak/representations/adapters/config/PolicyEnforcerConfig.java
+++ b/core/src/main/java/org/keycloak/representations/adapters/config/PolicyEnforcerConfig.java
@@ -122,6 +122,9 @@ public class PolicyEnforcerConfig {
private List<String> scopes = Collections.emptyList();
private String id;
+ @JsonProperty("enforcement-mode")
+ private EnforcementMode enforcementMode = EnforcementMode.ENFORCING;
+
@JsonIgnore
private PathConfig parentConfig;
@@ -173,6 +176,14 @@ public class PolicyEnforcerConfig {
return id;
}
+ public EnforcementMode getEnforcementMode() {
+ return enforcementMode;
+ }
+
+ public void setEnforcementMode(EnforcementMode enforcementMode) {
+ this.enforcementMode = enforcementMode;
+ }
+
@Override
public String toString() {
return "PathConfig{" +
@@ -181,6 +192,7 @@ public class PolicyEnforcerConfig {
", path='" + path + '\'' +
", scopes=" + scopes +
", id='" + id + '\'' +
+ ", enforcerMode='" + enforcementMode + '\'' +
'}';
}