[KEYCLOAK-5726] - Support define enforcement mode for scopes on the adapter configuration
This commit is contained in:
parent
a4ec32ba66
commit
a6e1413d58
8 changed files with 128 additions and 34 deletions
|
@ -33,6 +33,7 @@ import org.keycloak.authorization.client.ClientAuthorizationContext;
|
||||||
import org.keycloak.representations.AccessToken;
|
import org.keycloak.representations.AccessToken;
|
||||||
import org.keycloak.representations.adapters.config.PolicyEnforcerConfig;
|
import org.keycloak.representations.adapters.config.PolicyEnforcerConfig;
|
||||||
import org.keycloak.representations.adapters.config.PolicyEnforcerConfig.EnforcementMode;
|
import org.keycloak.representations.adapters.config.PolicyEnforcerConfig.EnforcementMode;
|
||||||
|
import org.keycloak.representations.adapters.config.PolicyEnforcerConfig.MethodConfig;
|
||||||
import org.keycloak.representations.adapters.config.PolicyEnforcerConfig.PathConfig;
|
import org.keycloak.representations.adapters.config.PolicyEnforcerConfig.PathConfig;
|
||||||
import org.keycloak.representations.idm.authorization.Permission;
|
import org.keycloak.representations.idm.authorization.Permission;
|
||||||
|
|
||||||
|
@ -96,9 +97,9 @@ public abstract class AbstractPolicyEnforcer {
|
||||||
return createEmptyAuthorizationContext(true);
|
return createEmptyAuthorizationContext(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
Set<String> requiredScopes = getRequiredScopes(pathConfig, request);
|
MethodConfig methodConfig = getRequiredScopes(pathConfig, request);
|
||||||
|
|
||||||
if (isAuthorized(pathConfig, requiredScopes, accessToken, httpFacade)) {
|
if (isAuthorized(pathConfig, methodConfig, accessToken, httpFacade)) {
|
||||||
try {
|
try {
|
||||||
return createAuthorizationContext(accessToken, pathConfig);
|
return createAuthorizationContext(accessToken, pathConfig);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
@ -108,7 +109,7 @@ public abstract class AbstractPolicyEnforcer {
|
||||||
|
|
||||||
LOGGER.debugf("Sending challenge to the client. Path [%s]", pathConfig);
|
LOGGER.debugf("Sending challenge to the client. Path [%s]", pathConfig);
|
||||||
|
|
||||||
if (!challenge(pathConfig, requiredScopes, httpFacade)) {
|
if (!challenge(pathConfig, methodConfig, httpFacade)) {
|
||||||
LOGGER.debugf("Challenge not sent, sending default forbidden response. Path [%s]", pathConfig);
|
LOGGER.debugf("Challenge not sent, sending default forbidden response. Path [%s]", pathConfig);
|
||||||
handleAccessDenied(httpFacade);
|
handleAccessDenied(httpFacade);
|
||||||
}
|
}
|
||||||
|
@ -118,9 +119,9 @@ public abstract class AbstractPolicyEnforcer {
|
||||||
return createEmptyAuthorizationContext(false);
|
return createEmptyAuthorizationContext(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract boolean challenge(PathConfig pathConfig, Set<String> requiredScopes, OIDCHttpFacade facade);
|
protected abstract boolean challenge(PathConfig pathConfig, MethodConfig methodConfig, OIDCHttpFacade facade);
|
||||||
|
|
||||||
protected boolean isAuthorized(PathConfig actualPathConfig, Set<String> requiredScopes, AccessToken accessToken, OIDCHttpFacade httpFacade) {
|
protected boolean isAuthorized(PathConfig actualPathConfig, MethodConfig methodConfig, AccessToken accessToken, OIDCHttpFacade httpFacade) {
|
||||||
Request request = httpFacade.getRequest();
|
Request request = httpFacade.getRequest();
|
||||||
PolicyEnforcerConfig enforcerConfig = getEnforcerConfig();
|
PolicyEnforcerConfig enforcerConfig = getEnforcerConfig();
|
||||||
|
|
||||||
|
@ -146,7 +147,7 @@ public abstract class AbstractPolicyEnforcer {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hasResourceScopePermission(requiredScopes, permission, actualPathConfig)) {
|
if (hasResourceScopePermission(methodConfig, permission)) {
|
||||||
LOGGER.debugf("Authorization GRANTED for path [%s]. Permissions [%s].", actualPathConfig, permissions);
|
LOGGER.debugf("Authorization GRANTED for path [%s]. Permissions [%s].", actualPathConfig, permissions);
|
||||||
if (request.getMethod().equalsIgnoreCase("DELETE") && actualPathConfig.isInstance()) {
|
if (request.getMethod().equalsIgnoreCase("DELETE") && actualPathConfig.isInstance()) {
|
||||||
this.paths.remove(actualPathConfig);
|
this.paths.remove(actualPathConfig);
|
||||||
|
@ -155,7 +156,7 @@ public abstract class AbstractPolicyEnforcer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (hasResourceScopePermission(requiredScopes, permission, actualPathConfig)) {
|
if (hasResourceScopePermission(methodConfig, permission)) {
|
||||||
hasPermission = true;
|
hasPermission = true;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -166,7 +167,7 @@ public abstract class AbstractPolicyEnforcer {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
LOGGER.debugf("Authorization FAILED for path [%s]. No enough permissions [%s].", actualPathConfig, permissions);
|
LOGGER.debugf("Authorization FAILED for path [%s]. Not enough permissions [%s].", actualPathConfig, permissions);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -186,9 +187,28 @@ public abstract class AbstractPolicyEnforcer {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean hasResourceScopePermission(Set<String> requiredScopes, Permission permission, PathConfig actualPathConfig) {
|
private boolean hasResourceScopePermission(MethodConfig methodConfig, Permission permission) {
|
||||||
Set<String> allowedScopes = permission.getScopes();
|
Set<String> allowedScopes = permission.getScopes();
|
||||||
return (allowedScopes.containsAll(requiredScopes) || allowedScopes.isEmpty());
|
|
||||||
|
if (allowedScopes.isEmpty()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
PolicyEnforcerConfig.ScopeEnforcementMode enforcementMode = methodConfig.getScopesEnforcementMode();
|
||||||
|
|
||||||
|
if (PolicyEnforcerConfig.ScopeEnforcementMode.ALL.equals(enforcementMode)) {
|
||||||
|
return allowedScopes.containsAll(methodConfig.getScopes());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (PolicyEnforcerConfig.ScopeEnforcementMode.ANY.equals(enforcementMode)) {
|
||||||
|
for (String requiredScope : methodConfig.getScopes()) {
|
||||||
|
if (allowedScopes.contains(requiredScope)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected AuthzClient getAuthzClient() {
|
protected AuthzClient getAuthzClient() {
|
||||||
|
@ -236,20 +256,22 @@ public abstract class AbstractPolicyEnforcer {
|
||||||
return request.getRelativePath();
|
return request.getRelativePath();
|
||||||
}
|
}
|
||||||
|
|
||||||
private Set<String> getRequiredScopes(PathConfig pathConfig, Request request) {
|
private MethodConfig getRequiredScopes(PathConfig pathConfig, Request request) {
|
||||||
Set<String> requiredScopes = new HashSet<>();
|
|
||||||
|
|
||||||
requiredScopes.addAll(pathConfig.getScopes());
|
|
||||||
|
|
||||||
String method = request.getMethod();
|
String method = request.getMethod();
|
||||||
|
|
||||||
for (PolicyEnforcerConfig.MethodConfig methodConfig : pathConfig.getMethods()) {
|
for (MethodConfig methodConfig : pathConfig.getMethods()) {
|
||||||
if (methodConfig.getMethod().equals(method)) {
|
if (methodConfig.getMethod().equals(method)) {
|
||||||
requiredScopes.addAll(methodConfig.getScopes());
|
return methodConfig;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return requiredScopes;
|
MethodConfig methodConfig = new MethodConfig();
|
||||||
|
|
||||||
|
methodConfig.setMethod(request.getMethod());
|
||||||
|
methodConfig.setScopes(pathConfig.getScopes());
|
||||||
|
methodConfig.setScopesEnforcementMode(PolicyEnforcerConfig.ScopeEnforcementMode.ANY);
|
||||||
|
|
||||||
|
return methodConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
private AuthorizationContext createAuthorizationContext(AccessToken accessToken, PathConfig pathConfig) {
|
private AuthorizationContext createAuthorizationContext(AccessToken accessToken, PathConfig pathConfig) {
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
*/
|
*/
|
||||||
package org.keycloak.adapters.authorization;
|
package org.keycloak.adapters.authorization;
|
||||||
|
|
||||||
import java.util.Set;
|
import java.util.HashSet;
|
||||||
|
|
||||||
import org.jboss.logging.Logger;
|
import org.jboss.logging.Logger;
|
||||||
import org.keycloak.adapters.OIDCHttpFacade;
|
import org.keycloak.adapters.OIDCHttpFacade;
|
||||||
|
@ -26,6 +26,7 @@ import org.keycloak.authorization.client.AuthzClient;
|
||||||
import org.keycloak.authorization.client.representation.PermissionRequest;
|
import org.keycloak.authorization.client.representation.PermissionRequest;
|
||||||
import org.keycloak.authorization.client.resource.PermissionResource;
|
import org.keycloak.authorization.client.resource.PermissionResource;
|
||||||
import org.keycloak.authorization.client.resource.ProtectionResource;
|
import org.keycloak.authorization.client.resource.ProtectionResource;
|
||||||
|
import org.keycloak.representations.adapters.config.PolicyEnforcerConfig;
|
||||||
import org.keycloak.representations.adapters.config.PolicyEnforcerConfig.PathConfig;
|
import org.keycloak.representations.adapters.config.PolicyEnforcerConfig.PathConfig;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -40,9 +41,9 @@ public class BearerTokenPolicyEnforcer extends AbstractPolicyEnforcer {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean challenge(PathConfig pathConfig, Set<String> requiredScopes, OIDCHttpFacade facade) {
|
protected boolean challenge(PathConfig pathConfig, PolicyEnforcerConfig.MethodConfig methodConfig, OIDCHttpFacade facade) {
|
||||||
if (getEnforcerConfig().getUserManagedAccess() != null) {
|
if (getEnforcerConfig().getUserManagedAccess() != null) {
|
||||||
challengeUmaAuthentication(pathConfig, requiredScopes, facade);
|
challengeUmaAuthentication(pathConfig, methodConfig, facade);
|
||||||
} else {
|
} else {
|
||||||
challengeEntitlementAuthentication(facade);
|
challengeEntitlementAuthentication(facade);
|
||||||
}
|
}
|
||||||
|
@ -61,10 +62,10 @@ public class BearerTokenPolicyEnforcer extends AbstractPolicyEnforcer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void challengeUmaAuthentication(PathConfig pathConfig, Set<String> requiredScopes, OIDCHttpFacade facade) {
|
private void challengeUmaAuthentication(PathConfig pathConfig, PolicyEnforcerConfig.MethodConfig methodConfig, OIDCHttpFacade facade) {
|
||||||
HttpFacade.Response response = facade.getResponse();
|
HttpFacade.Response response = facade.getResponse();
|
||||||
AuthzClient authzClient = getAuthzClient();
|
AuthzClient authzClient = getAuthzClient();
|
||||||
String ticket = getPermissionTicket(pathConfig, requiredScopes, authzClient);
|
String ticket = getPermissionTicket(pathConfig, methodConfig, authzClient);
|
||||||
String clientId = authzClient.getConfiguration().getResource();
|
String clientId = authzClient.getConfiguration().getResource();
|
||||||
String authorizationServerUri = authzClient.getServerConfiguration().getIssuer().toString() + "/authz/authorize";
|
String authorizationServerUri = authzClient.getServerConfiguration().getIssuer().toString() + "/authz/authorize";
|
||||||
response.setStatus(401);
|
response.setStatus(401);
|
||||||
|
@ -74,12 +75,12 @@ public class BearerTokenPolicyEnforcer extends AbstractPolicyEnforcer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getPermissionTicket(PathConfig pathConfig, Set<String> requiredScopes, AuthzClient authzClient) {
|
private String getPermissionTicket(PathConfig pathConfig, PolicyEnforcerConfig.MethodConfig methodConfig, AuthzClient authzClient) {
|
||||||
ProtectionResource protection = authzClient.protection();
|
ProtectionResource protection = authzClient.protection();
|
||||||
PermissionResource permission = protection.permission();
|
PermissionResource permission = protection.permission();
|
||||||
PermissionRequest permissionRequest = new PermissionRequest();
|
PermissionRequest permissionRequest = new PermissionRequest();
|
||||||
permissionRequest.setResourceSetId(pathConfig.getId());
|
permissionRequest.setResourceSetId(pathConfig.getId());
|
||||||
permissionRequest.setScopes(requiredScopes);
|
permissionRequest.setScopes(new HashSet<>(methodConfig.getScopes()));
|
||||||
return permission.forResource(permissionRequest).getTicket();
|
return permission.forResource(permissionRequest).getTicket();
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -35,6 +35,7 @@ import org.keycloak.authorization.client.representation.EntitlementResponse;
|
||||||
import org.keycloak.authorization.client.representation.PermissionRequest;
|
import org.keycloak.authorization.client.representation.PermissionRequest;
|
||||||
import org.keycloak.authorization.client.representation.PermissionResponse;
|
import org.keycloak.authorization.client.representation.PermissionResponse;
|
||||||
import org.keycloak.representations.AccessToken;
|
import org.keycloak.representations.AccessToken;
|
||||||
|
import org.keycloak.representations.adapters.config.PolicyEnforcerConfig;
|
||||||
import org.keycloak.representations.adapters.config.PolicyEnforcerConfig.PathConfig;
|
import org.keycloak.representations.adapters.config.PolicyEnforcerConfig.PathConfig;
|
||||||
import org.keycloak.representations.idm.authorization.Permission;
|
import org.keycloak.representations.idm.authorization.Permission;
|
||||||
|
|
||||||
|
@ -50,14 +51,14 @@ public class KeycloakAdapterPolicyEnforcer extends AbstractPolicyEnforcer {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean isAuthorized(PathConfig pathConfig, Set<String> requiredScopes, AccessToken accessToken, OIDCHttpFacade httpFacade) {
|
protected boolean isAuthorized(PathConfig pathConfig, PolicyEnforcerConfig.MethodConfig methodConfig, AccessToken accessToken, OIDCHttpFacade httpFacade) {
|
||||||
AccessToken original = accessToken;
|
AccessToken original = accessToken;
|
||||||
|
|
||||||
if (super.isAuthorized(pathConfig, requiredScopes, accessToken, httpFacade)) {
|
if (super.isAuthorized(pathConfig, methodConfig, accessToken, httpFacade)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
accessToken = requestAuthorizationToken(pathConfig, requiredScopes, httpFacade);
|
accessToken = requestAuthorizationToken(pathConfig, methodConfig, httpFacade);
|
||||||
|
|
||||||
if (accessToken == null) {
|
if (accessToken == null) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -78,11 +79,11 @@ public class KeycloakAdapterPolicyEnforcer extends AbstractPolicyEnforcer {
|
||||||
|
|
||||||
original.setAuthorization(authorization);
|
original.setAuthorization(authorization);
|
||||||
|
|
||||||
return super.isAuthorized(pathConfig, requiredScopes, accessToken, httpFacade);
|
return super.isAuthorized(pathConfig, methodConfig, accessToken, httpFacade);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean challenge(PathConfig pathConfig, Set<String> requiredScopes, OIDCHttpFacade facade) {
|
protected boolean challenge(PathConfig pathConfig, PolicyEnforcerConfig.MethodConfig methodConfig, OIDCHttpFacade facade) {
|
||||||
handleAccessDenied(facade);
|
handleAccessDenied(facade);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -100,7 +101,7 @@ public class KeycloakAdapterPolicyEnforcer extends AbstractPolicyEnforcer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private AccessToken requestAuthorizationToken(PathConfig pathConfig, Set<String> requiredScopes, OIDCHttpFacade httpFacade) {
|
private AccessToken requestAuthorizationToken(PathConfig pathConfig, PolicyEnforcerConfig.MethodConfig methodConfig, OIDCHttpFacade httpFacade) {
|
||||||
try {
|
try {
|
||||||
String accessToken = httpFacade.getSecurityContext().getTokenString();
|
String accessToken = httpFacade.getSecurityContext().getTokenString();
|
||||||
AuthzClient authzClient = getAuthzClient();
|
AuthzClient authzClient = getAuthzClient();
|
||||||
|
@ -111,7 +112,7 @@ public class KeycloakAdapterPolicyEnforcer extends AbstractPolicyEnforcer {
|
||||||
PermissionRequest permissionRequest = new PermissionRequest();
|
PermissionRequest permissionRequest = new PermissionRequest();
|
||||||
|
|
||||||
permissionRequest.setResourceSetId(pathConfig.getId());
|
permissionRequest.setResourceSetId(pathConfig.getId());
|
||||||
permissionRequest.setScopes(requiredScopes);
|
permissionRequest.setScopes(new HashSet<>(methodConfig.getScopes()));
|
||||||
|
|
||||||
PermissionResponse permissionResponse = authzClient.protection().permission().forResource(permissionRequest);
|
PermissionResponse permissionResponse = authzClient.protection().permission().forResource(permissionRequest);
|
||||||
AuthorizationRequest authzRequest = new AuthorizationRequest(permissionResponse.getTicket());
|
AuthorizationRequest authzRequest = new AuthorizationRequest(permissionResponse.getTicket());
|
||||||
|
|
|
@ -220,6 +220,9 @@ public class PolicyEnforcerConfig {
|
||||||
private String method;
|
private String method;
|
||||||
private List<String> scopes = Collections.emptyList();
|
private List<String> scopes = Collections.emptyList();
|
||||||
|
|
||||||
|
@JsonProperty("scopes-enforcement-mode")
|
||||||
|
private ScopeEnforcementMode scopesEnforcementMode = ScopeEnforcementMode.ALL;
|
||||||
|
|
||||||
public String getMethod() {
|
public String getMethod() {
|
||||||
return method;
|
return method;
|
||||||
}
|
}
|
||||||
|
@ -235,6 +238,14 @@ public class PolicyEnforcerConfig {
|
||||||
public void setScopes(List<String> scopes) {
|
public void setScopes(List<String> scopes) {
|
||||||
this.scopes = scopes;
|
this.scopes = scopes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setScopesEnforcementMode(ScopeEnforcementMode scopesEnforcementMode) {
|
||||||
|
this.scopesEnforcementMode = scopesEnforcementMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ScopeEnforcementMode getScopesEnforcementMode() {
|
||||||
|
return scopesEnforcementMode;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum EnforcementMode {
|
public enum EnforcementMode {
|
||||||
|
@ -243,6 +254,11 @@ public class PolicyEnforcerConfig {
|
||||||
DISABLED
|
DISABLED
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public enum ScopeEnforcementMode {
|
||||||
|
ALL,
|
||||||
|
ANY
|
||||||
|
}
|
||||||
|
|
||||||
public static class UmaProtocolConfig {
|
public static class UmaProtocolConfig {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -108,7 +108,7 @@
|
||||||
"redirectUris": [
|
"redirectUris": [
|
||||||
"/photoz-html5-client/*"
|
"/photoz-html5-client/*"
|
||||||
],
|
],
|
||||||
"webOrigins": ["*"]
|
"webOrigins": ["http://localhost:8280"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"clientId": "photoz-restful-api",
|
"clientId": "photoz-restful-api",
|
||||||
|
@ -118,7 +118,7 @@
|
||||||
"redirectUris": [
|
"redirectUris": [
|
||||||
"/photoz-restful-api/*"
|
"/photoz-restful-api/*"
|
||||||
],
|
],
|
||||||
"webOrigins" : ["*"],
|
"webOrigins" : ["http://localhost:8280"],
|
||||||
"clientAuthenticatorType": "client-jwt",
|
"clientAuthenticatorType": "client-jwt",
|
||||||
"attributes" : {
|
"attributes" : {
|
||||||
"jwt.credential.certificate" : "MIICqTCCAZECBgFT0Ngs/DANBgkqhkiG9w0BAQsFADAYMRYwFAYDVQQDDA1zZWN1cmUtcG9ydGFsMB4XDTE2MDQwMTA4MDA0MVoXDTI2MDQwMTA4MDIyMVowGDEWMBQGA1UEAwwNc2VjdXJlLXBvcnRhbDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJa4GixpmzP511AmI0eLPLORyJwXS8908MUvdG3hmh8jMOIhe28XjIFeZSY09vFxh22F2SUMjxU/B2Hw4PDJUkebuNR7rXhOIYCJAo6eEZzjSBY/wngFtfm74zJ/eLCobBtDvIld7jobdHTfE1Oz9+GzvtG0k7cm7ubrLT0J4I1UsFZj3b//3wa+O0vNaTwHC1Jz/m59VbtXqyO4xEzIdl416cnGCmEmk5qd5h1de2UoLi/CTad8HftIJhzN1qhlySzW/9Ha70aYlDH2hiibDsXDTrNaMdaaLik7I8Rv/nIbggysG863PKZo8wknDe62QctH5VYSSktiy4gjSJkGh7ECAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAZnnx+AHQ8txugGcFK8gWjildDgk+v31fBHBDvmLQaSzsUaIOJaK4wnlwUI+VfR46HmBXhjlDCobFLUptd+kz0G7xapcIn3b5jLrySUUD7L+LAp1vNOQU4mKhTGS3IEvNB73D3GH9rQ+M3KEcoN3f99fNKqKsUdxbmZqGf4VOQ57PUfLBw4PJJGlROPosBc7ivPRyeYnKekhoCTynq30BAD1FA1BA8ppcY4ZVGADPTAgMJxpglpFY9LiqCwdLAGW1ttnsyIJ7DpT+kybhhk7c+MU7gyQdv8xPnMR0bSCB9hndowgBn5oZ393aMscwMNCzwJ0aWBs1sUyn3X0RIsu9Jg=="
|
"jwt.credential.certificate" : "MIICqTCCAZECBgFT0Ngs/DANBgkqhkiG9w0BAQsFADAYMRYwFAYDVQQDDA1zZWN1cmUtcG9ydGFsMB4XDTE2MDQwMTA4MDA0MVoXDTI2MDQwMTA4MDIyMVowGDEWMBQGA1UEAwwNc2VjdXJlLXBvcnRhbDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJa4GixpmzP511AmI0eLPLORyJwXS8908MUvdG3hmh8jMOIhe28XjIFeZSY09vFxh22F2SUMjxU/B2Hw4PDJUkebuNR7rXhOIYCJAo6eEZzjSBY/wngFtfm74zJ/eLCobBtDvIld7jobdHTfE1Oz9+GzvtG0k7cm7ubrLT0J4I1UsFZj3b//3wa+O0vNaTwHC1Jz/m59VbtXqyO4xEzIdl416cnGCmEmk5qd5h1de2UoLi/CTad8HftIJhzN1qhlySzW/9Ha70aYlDH2hiibDsXDTrNaMdaaLik7I8Rv/nIbggysG863PKZo8wknDe62QctH5VYSSktiy4gjSJkGh7ECAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAZnnx+AHQ8txugGcFK8gWjildDgk+v31fBHBDvmLQaSzsUaIOJaK4wnlwUI+VfR46HmBXhjlDCobFLUptd+kz0G7xapcIn3b5jLrySUUD7L+LAp1vNOQU4mKhTGS3IEvNB73D3GH9rQ+M3KEcoN3f99fNKqKsUdxbmZqGf4VOQ57PUfLBw4PJJGlROPosBc7ivPRyeYnKekhoCTynq30BAD1FA1BA8ppcY4ZVGADPTAgMJxpglpFY9LiqCwdLAGW1ttnsyIJ7DpT+kybhhk7c+MU7gyQdv8xPnMR0bSCB9hndowgBn5oZ393aMscwMNCzwJ0aWBs1sUyn3X0RIsu9Jg=="
|
||||||
|
|
|
@ -46,6 +46,18 @@
|
||||||
"name": "urn:servlet-authz:page:main:actionForPremiumUser"
|
"name": "urn:servlet-authz:page:main:actionForPremiumUser"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Resource A",
|
||||||
|
"uri": "/protected/scopes.jsp",
|
||||||
|
"scopes": [
|
||||||
|
{
|
||||||
|
"name": "read"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "write"
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"policies": [
|
"policies": [
|
||||||
|
@ -142,6 +154,37 @@
|
||||||
"scopes": "[\"urn:servlet-authz:page:main:actionForPremiumUser\"]",
|
"scopes": "[\"urn:servlet-authz:page:main:actionForPremiumUser\"]",
|
||||||
"applyPolicies": "[\"Only Premium User Policy\"]"
|
"applyPolicies": "[\"Only Premium User Policy\"]"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Deny Policy",
|
||||||
|
"type": "js",
|
||||||
|
"logic": "POSITIVE",
|
||||||
|
"decisionStrategy": "UNANIMOUS",
|
||||||
|
"config": {
|
||||||
|
"code": "// by default, grants any permission associated with this policy\n$evaluation.deny();"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Resource A Read Permission",
|
||||||
|
"type": "scope",
|
||||||
|
"logic": "POSITIVE",
|
||||||
|
"decisionStrategy": "UNANIMOUS",
|
||||||
|
"config": {
|
||||||
|
"resources": "[\"Resource A\"]",
|
||||||
|
"scopes": "[\"read\"]",
|
||||||
|
"applyPolicies": "[\"Any User Policy\"]"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Resource A Write Permission",
|
||||||
|
"type": "scope",
|
||||||
|
"logic": "POSITIVE",
|
||||||
|
"decisionStrategy": "UNANIMOUS",
|
||||||
|
"config": {
|
||||||
|
"resources": "[\"Resource A\"]",
|
||||||
|
"scopes": "[\"write\"]",
|
||||||
|
"applyPolicies": "[\"Deny Policy\"]"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
|
@ -0,0 +1 @@
|
||||||
|
Granted
|
|
@ -307,4 +307,14 @@ public abstract class AbstractServletAuthzFunctionalAdapterTest extends Abstract
|
||||||
assertFalse(wasDenied());
|
assertFalse(wasDenied());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAccessResourceWithAnyScope() throws Exception {
|
||||||
|
performTests(() -> {
|
||||||
|
login("jdoe", "jdoe");
|
||||||
|
driver.navigate().to(getResourceServerUrl() + "/protected/scopes.jsp");
|
||||||
|
WaitUtils.waitForPageToLoad();
|
||||||
|
assertTrue(hasText("Granted"));
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue