keycloak-uncached
Changes
adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/authorization/AbstractPolicyEnforcer.java 4(+2 -2)
adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/authorization/PathCache.java 6(+6 -0)
adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/authorization/PolicyEnforcer.java 120(+70 -50)
authz/client/src/main/java/org/keycloak/authorization/client/ClientAuthorizationContext.java 4(+2 -2)
core/src/main/java/org/keycloak/representations/adapters/config/PolicyEnforcerConfig.java 35(+35 -0)
core/src/main/java/org/keycloak/representations/idm/authorization/AbstractPolicyRepresentation.java 6(+6 -0)
testsuite/integration-arquillian/test-apps/servlet-authz/keycloak-cache-disabled-authz-service.json 26(+26 -0)
testsuite/integration-arquillian/test-apps/servlet-authz/keycloak-cache-lifespan-authz-service.json 26(+26 -0)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/example/authorization/AbstractServletCacheDisabledAdapterTest.java 86(+86 -0)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/example/authorization/AbstractServletCacheLifespanAdapterTest.java 81(+81 -0)
Details
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 c600e1a..402ed48 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
@@ -159,7 +159,7 @@ public abstract class AbstractPolicyEnforcer {
LOGGER.debugf("Authorization GRANTED for path [%s]. Permissions [%s].", actualPathConfig, grantedPermissions);
}
if (HTTP_METHOD_DELETE.equalsIgnoreCase(request.getMethod()) && actualPathConfig.isInstance()) {
- policyEnforcer.getPaths().remove(actualPathConfig);
+ policyEnforcer.getPathMatcher().removeFromCache(getPath(request));
}
return true;
}
@@ -281,7 +281,7 @@ public abstract class AbstractPolicyEnforcer {
}
private AuthorizationContext createAuthorizationContext(AccessToken accessToken, PathConfig pathConfig) {
- return new ClientAuthorizationContext(accessToken, pathConfig, policyEnforcer.getPaths(), getAuthzClient());
+ return new ClientAuthorizationContext(accessToken, pathConfig, getAuthzClient());
}
private boolean isResourcePermission(PathConfig actualPathConfig, Permission permission) {
diff --git a/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/authorization/PathCache.java b/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/authorization/PathCache.java
index cf8815c..dfeb48e 100644
--- a/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/authorization/PathCache.java
+++ b/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/authorization/PathCache.java
@@ -40,6 +40,7 @@ public class PathCache {
private final AtomicBoolean writing = new AtomicBoolean(false);
private final long maxAge;
+ private final boolean enabled;
/**
* Creates a new instance.
@@ -55,9 +56,14 @@ public class PathCache {
}
};
this.maxAge = maxAge;
+ this.enabled = maxAge > 0;
}
public void put(String uri, PathConfig newValue) {
+ if (!enabled) {
+ return;
+ }
+
try {
if (parkForWriteAndCheckInterrupt()) {
return;
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 275315e..2ccdf28 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
@@ -38,6 +38,7 @@ import org.keycloak.authorization.client.resource.ProtectedResource;
import org.keycloak.common.util.PathMatcher;
import org.keycloak.representations.adapters.config.AdapterConfig;
import org.keycloak.representations.adapters.config.PolicyEnforcerConfig;
+import org.keycloak.representations.adapters.config.PolicyEnforcerConfig.PathCacheConfig;
import org.keycloak.representations.adapters.config.PolicyEnforcerConfig.PathConfig;
import org.keycloak.representations.idm.authorization.Permission;
import org.keycloak.representations.idm.authorization.ResourceRepresentation;
@@ -52,8 +53,8 @@ public class PolicyEnforcer {
private final KeycloakDeployment deployment;
private final AuthzClient authzClient;
private final PolicyEnforcerConfig enforcerConfig;
+ private final PathConfigMatcher pathMatcher;
private final Map<String, PathConfig> paths;
- private final PathMatcher pathMatcher;
public PolicyEnforcer(KeycloakDeployment deployment, AdapterConfig adapterConfig) {
this.deployment = deployment;
@@ -70,8 +71,8 @@ public class PolicyEnforcer {
}
});
- this.paths = configurePaths(this.authzClient.protection().resource(), this.enforcerConfig);
- this.pathMatcher = createPathMatcher(authzClient);
+ paths = configurePaths(this.authzClient.protection().resource(), this.enforcerConfig);
+ pathMatcher = new PathConfigMatcher(paths, enforcerConfig, authzClient);
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Initialization complete. Path configurations:");
@@ -117,7 +118,7 @@ public class PolicyEnforcer {
return paths;
}
- public PathMatcher<PathConfig> getPathMatcher() {
+ public PathConfigMatcher getPathMatcher() {
return pathMatcher;
}
@@ -216,71 +217,90 @@ public class PolicyEnforcer {
return paths;
}
- private PathMatcher<PathConfig> createPathMatcher(final AuthzClient authzClient) {
- final PathCache pathCache = new PathCache(100, 30000);
+ public class PathConfigMatcher extends PathMatcher<PathConfig> {
- return new PathMatcher<PathConfig>() {
- @Override
- public PathConfig matches(String targetUri) {
- PathConfig pathConfig = pathCache.get(targetUri);
+ private final Map<String, PathConfig> paths;
+ private final PathCache pathCache;
+ private final AuthzClient authzClient;
+ private final PolicyEnforcerConfig enforcerConfig;
- if (pathCache.containsKey(targetUri) || pathConfig != null) {
- return pathConfig;
- }
+ public PathConfigMatcher(Map<String, PathConfig> paths, PolicyEnforcerConfig enforcerConfig, AuthzClient authzClient) {
+ this.paths = paths;
+ this.enforcerConfig = enforcerConfig;
+ PathCacheConfig cacheConfig = enforcerConfig.getPathCacheConfig();
+
+ if (cacheConfig == null) {
+ cacheConfig = new PathCacheConfig();
+ }
+
+ pathCache = new PathCache(cacheConfig.getMaxEntries(), cacheConfig.getLifespan());
+ this.authzClient = authzClient;
+ }
+
+ @Override
+ public PathConfig matches(String targetUri) {
+ PathConfig pathConfig = pathCache.get(targetUri);
+
+ if (pathCache.containsKey(targetUri) || pathConfig != null) {
+ return pathConfig;
+ }
- pathConfig = super.matches(targetUri);
+ pathConfig = super.matches(targetUri);
- if (enforcerConfig.getLazyLoadPaths() && (pathConfig == null || pathConfig.getPath().contains("*"))) {
+ if (enforcerConfig.getLazyLoadPaths() || enforcerConfig.getPathCacheConfig() != null) {
+ if ((pathConfig == null || (pathConfig.getPath().contains("*")))) {
try {
List<ResourceRepresentation> matchingResources = authzClient.protection().resource().findByMatchingUri(targetUri);
if (!matchingResources.isEmpty()) {
pathConfig = PathConfig.createPathConfig(matchingResources.get(0));
- paths.put(pathConfig.getPath(), pathConfig);
}
} catch (Exception cause) {
- LOGGER.errorf(cause, "Could not lazy load paths from server");
+ LOGGER.errorf(cause, "Could not lazy load resource with path [" + targetUri + "] from server");
return null;
}
}
+ }
- pathCache.put(targetUri, pathConfig);
+ pathCache.put(targetUri, pathConfig);
- return pathConfig;
- }
+ return pathConfig;
+ }
- @Override
- protected String getPath(PathConfig entry) {
- return entry.getPath();
- }
+ @Override
+ protected String getPath(PathConfig entry) {
+ return entry.getPath();
+ }
- @Override
- protected Collection<PathConfig> getPaths() {
- return paths.values();
- }
+ @Override
+ protected Collection<PathConfig> getPaths() {
+ return paths.values();
+ }
- @Override
- protected PathConfig resolvePathConfig(PathConfig originalConfig, String path) {
- if (originalConfig.hasPattern()) {
- ProtectedResource resource = authzClient.protection().resource();
- List<ResourceRepresentation> search = resource.findByUri(path);
-
- if (!search.isEmpty()) {
- // resource does exist on the server, cache it
- ResourceRepresentation targetResource = search.get(0);
- PathConfig config = PathConfig.createPathConfig(targetResource);
-
- config.setScopes(originalConfig.getScopes());
- config.setMethods(originalConfig.getMethods());
- config.setParentConfig(originalConfig);
- config.setEnforcementMode(originalConfig.getEnforcementMode());
-
- return config;
- }
- }
+ @Override
+ protected PathConfig resolvePathConfig(PathConfig originalConfig, String path) {
+ if (originalConfig.hasPattern()) {
+ ProtectedResource resource = authzClient.protection().resource();
+ List<ResourceRepresentation> search = resource.findByUri(path);
+
+ if (!search.isEmpty()) {
+ ResourceRepresentation targetResource = search.get(0);
+ PathConfig config = PathConfig.createPathConfig(targetResource);
- return null;
+ config.setScopes(originalConfig.getScopes());
+ config.setMethods(originalConfig.getMethods());
+ config.setParentConfig(originalConfig);
+ config.setEnforcementMode(originalConfig.getEnforcementMode());
+
+ return config;
+ }
}
- };
- }
+
+ return null;
+ }
+
+ public void removeFromCache(String pathConfig) {
+ pathCache.remove(pathConfig);
+ }
+ };
}
diff --git a/authz/client/src/main/java/org/keycloak/authorization/client/ClientAuthorizationContext.java b/authz/client/src/main/java/org/keycloak/authorization/client/ClientAuthorizationContext.java
index a46e511..d848b25 100644
--- a/authz/client/src/main/java/org/keycloak/authorization/client/ClientAuthorizationContext.java
+++ b/authz/client/src/main/java/org/keycloak/authorization/client/ClientAuthorizationContext.java
@@ -30,8 +30,8 @@ public class ClientAuthorizationContext extends AuthorizationContext {
private final AuthzClient client;
- public ClientAuthorizationContext(AccessToken authzToken, PolicyEnforcerConfig.PathConfig current, Map<String, PolicyEnforcerConfig.PathConfig> paths, AuthzClient client) {
- super(authzToken, current, paths);
+ public ClientAuthorizationContext(AccessToken authzToken, PolicyEnforcerConfig.PathConfig current, AuthzClient client) {
+ super(authzToken, current);
this.client = client;
}
diff --git a/core/src/main/java/org/keycloak/AuthorizationContext.java b/core/src/main/java/org/keycloak/AuthorizationContext.java
index 538a70f..0bc7b44 100644
--- a/core/src/main/java/org/keycloak/AuthorizationContext.java
+++ b/core/src/main/java/org/keycloak/AuthorizationContext.java
@@ -33,18 +33,16 @@ public class AuthorizationContext {
private final AccessToken authzToken;
private final PathConfig current;
- private final Map<String, PathConfig> paths;
private boolean granted;
- public AuthorizationContext(AccessToken authzToken, PathConfig current, Map<String, PathConfig> paths) {
+ public AuthorizationContext(AccessToken authzToken, PathConfig current) {
this.authzToken = authzToken;
this.current = current;
- this.paths = paths;
this.granted = true;
}
public AuthorizationContext() {
- this(null, null, null);
+ this(null, null);
this.granted = false;
}
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 71b44a4..d01d7c5 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
@@ -38,6 +38,10 @@ public class PolicyEnforcerConfig {
@JsonInclude(JsonInclude.Include.NON_EMPTY)
private List<PathConfig> paths = new ArrayList<>();
+ @JsonProperty("path-cache")
+ @JsonInclude(JsonInclude.Include.NON_EMPTY)
+ private PathCacheConfig pathCacheConfig;
+
@JsonProperty("lazy-load-paths")
private Boolean lazyLoadPaths = Boolean.FALSE;
@@ -53,6 +57,10 @@ public class PolicyEnforcerConfig {
return this.paths;
}
+ public PathCacheConfig getPathCacheConfig() {
+ return pathCacheConfig;
+ }
+
public Boolean getLazyLoadPaths() {
return lazyLoadPaths;
}
@@ -77,6 +85,10 @@ public class PolicyEnforcerConfig {
this.paths = paths;
}
+ public void setPathCacheConfig(PathCacheConfig pathCacheConfig) {
+ this.pathCacheConfig = pathCacheConfig;
+ }
+
public String getOnDenyRedirectTo() {
return onDenyRedirectTo;
}
@@ -250,6 +262,29 @@ public class PolicyEnforcerConfig {
}
}
+ public static class PathCacheConfig {
+
+ @JsonProperty("max-entries")
+ int maxEntries = 1000;
+ long lifespan = 30000;
+
+ public int getMaxEntries() {
+ return maxEntries;
+ }
+
+ public void setMaxEntries(int maxEntries) {
+ this.maxEntries = maxEntries;
+ }
+
+ public long getLifespan() {
+ return lifespan;
+ }
+
+ public void setLifespan(long lifespan) {
+ this.lifespan = lifespan;
+ }
+ }
+
public enum EnforcementMode {
PERMISSIVE,
ENFORCING,
diff --git a/core/src/main/java/org/keycloak/representations/idm/authorization/AbstractPolicyRepresentation.java b/core/src/main/java/org/keycloak/representations/idm/authorization/AbstractPolicyRepresentation.java
index ddac66d..ada763c 100644
--- a/core/src/main/java/org/keycloak/representations/idm/authorization/AbstractPolicyRepresentation.java
+++ b/core/src/main/java/org/keycloak/representations/idm/authorization/AbstractPolicyRepresentation.java
@@ -99,6 +99,12 @@ public class AbstractPolicyRepresentation {
this.policies.addAll(Arrays.asList(id));
}
+ public void removePolicy(String policy) {
+ if (policies != null) {
+ policies.remove(policy);
+ }
+ }
+
public Set<String> getResources() {
return resources;
}
diff --git a/testsuite/integration-arquillian/test-apps/servlet-authz/keycloak-cache-disabled-authz-service.json b/testsuite/integration-arquillian/test-apps/servlet-authz/keycloak-cache-disabled-authz-service.json
new file mode 100644
index 0000000..29979d8
--- /dev/null
+++ b/testsuite/integration-arquillian/test-apps/servlet-authz/keycloak-cache-disabled-authz-service.json
@@ -0,0 +1,26 @@
+{
+ "realm": "servlet-authz",
+ "realm-public-key" : "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
+ "auth-server-url" : "http://localhost:8180/auth",
+ "ssl-required" : "external",
+ "resource" : "servlet-authz-app",
+ "public-client" : false,
+ "credentials": {
+ "secret": "secret"
+ },
+ "policy-enforcer": {
+ "on-deny-redirect-to" : "/servlet-authz-app/accessDenied.jsp",
+ "path-cache": {
+ "lifespan": 0,
+ "max-entries": 1000
+ },
+ "paths": [
+ {
+ "name": "Premium Resource",
+ "path": "/protected/premium/pep-disabled.jsp",
+ "enforcement-mode": "DISABLED"
+ }
+ ]
+
+ }
+}
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/test-apps/servlet-authz/keycloak-cache-lifespan-authz-service.json b/testsuite/integration-arquillian/test-apps/servlet-authz/keycloak-cache-lifespan-authz-service.json
new file mode 100644
index 0000000..d4b4af7
--- /dev/null
+++ b/testsuite/integration-arquillian/test-apps/servlet-authz/keycloak-cache-lifespan-authz-service.json
@@ -0,0 +1,26 @@
+{
+ "realm": "servlet-authz",
+ "realm-public-key" : "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
+ "auth-server-url" : "http://localhost:8180/auth",
+ "ssl-required" : "external",
+ "resource" : "servlet-authz-app",
+ "public-client" : false,
+ "credentials": {
+ "secret": "secret"
+ },
+ "policy-enforcer": {
+ "on-deny-redirect-to" : "/servlet-authz-app/accessDenied.jsp",
+ "path-cache": {
+ "lifespan": 5000,
+ "max-entries": 1000
+ },
+ "paths": [
+ {
+ "name": "Premium Resource",
+ "path": "/protected/premium/pep-disabled.jsp",
+ "enforcement-mode": "DISABLED"
+ }
+ ]
+
+ }
+}
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/example/authorization/AbstractServletCacheDisabledAdapterTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/example/authorization/AbstractServletCacheDisabledAdapterTest.java
new file mode 100644
index 0000000..8bc641a
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/example/authorization/AbstractServletCacheDisabledAdapterTest.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright 2018 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.testsuite.adapter.example.authorization;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.io.File;
+import java.io.IOException;
+
+import org.jboss.arquillian.container.test.api.Deployment;
+import org.jboss.shrinkwrap.api.spec.WebArchive;
+import org.junit.Test;
+import org.keycloak.representations.idm.authorization.ResourcePermissionRepresentation;
+import org.keycloak.representations.idm.authorization.ResourceRepresentation;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public abstract class AbstractServletCacheDisabledAdapterTest extends AbstractServletAuthzFunctionalAdapterTest {
+
+ @Deployment(name = RESOURCE_SERVER_ID, managed = false)
+ public static WebArchive deployment() throws IOException {
+ return exampleDeployment(RESOURCE_SERVER_ID)
+ .addAsWebInfResource(new File(TEST_APPS_HOME_DIR + "/servlet-authz-app/keycloak-cache-disabled-authz-service.json"), "keycloak.json");
+ }
+
+ @Test
+ public void testCreateNewResource() {
+ performTests(() -> {
+ login("alice", "alice");
+ assertFalse(wasDenied());
+
+ this.driver.navigate().to(getResourceServerUrl() + "/new-resource");
+ assertFalse(wasDenied());
+
+ ResourceRepresentation resource = new ResourceRepresentation();
+
+ resource.setName("New Resource");
+ resource.setUri("/new-resource");
+
+ getAuthorizationResource().resources().create(resource);
+
+ ResourcePermissionRepresentation permission = new ResourcePermissionRepresentation();
+
+ permission.setName(resource.getName() + " Permission");
+ permission.addResource(resource.getName());
+ permission.addPolicy("Deny Policy");
+
+ permission = getAuthorizationResource().permissions().resource().create(permission).readEntity(ResourcePermissionRepresentation.class);
+
+ login("alice", "alice");
+ assertFalse(wasDenied());
+
+ this.driver.navigate().to(getResourceServerUrl() + "/new-resource");
+ assertTrue(wasDenied());
+
+ permission = getAuthorizationResource().permissions().resource().findById(permission.getId()).toRepresentation();
+
+ permission.removePolicy("Deny Policy");
+ permission.addPolicy("Any User Policy");
+
+ getAuthorizationResource().permissions().resource().findById(permission.getId()).update(permission);
+
+ login("alice", "alice");
+ assertFalse(wasDenied());
+
+ this.driver.navigate().to(getResourceServerUrl() + "/new-resource");
+ assertFalse(wasDenied());
+ });
+ }
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/example/authorization/AbstractServletCacheLifespanAdapterTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/example/authorization/AbstractServletCacheLifespanAdapterTest.java
new file mode 100644
index 0000000..6477cd4
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/example/authorization/AbstractServletCacheLifespanAdapterTest.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2018 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.testsuite.adapter.example.authorization;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.io.File;
+import java.io.IOException;
+
+import org.jboss.arquillian.container.test.api.Deployment;
+import org.jboss.shrinkwrap.api.spec.WebArchive;
+import org.junit.Test;
+import org.keycloak.representations.idm.authorization.ResourcePermissionRepresentation;
+import org.keycloak.representations.idm.authorization.ResourceRepresentation;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public abstract class AbstractServletCacheLifespanAdapterTest extends AbstractServletAuthzFunctionalAdapterTest {
+
+ @Deployment(name = RESOURCE_SERVER_ID, managed = false)
+ public static WebArchive deployment() throws IOException {
+ return exampleDeployment(RESOURCE_SERVER_ID)
+ .addAsWebInfResource(new File(TEST_APPS_HOME_DIR + "/servlet-authz-app/keycloak-cache-lifespan-authz-service.json"), "keycloak.json");
+ }
+
+ @Test
+ public void testCreateNewResourceWaitExpiration() {
+ performTests(() -> {
+ login("alice", "alice");
+ assertFalse(wasDenied());
+
+ this.driver.navigate().to(getResourceServerUrl() + "/new-resource");
+ assertFalse(wasDenied());
+
+ ResourceRepresentation resource = new ResourceRepresentation();
+
+ resource.setName("New Resource");
+ resource.setUri("/new-resource");
+
+ getAuthorizationResource().resources().create(resource);
+
+ ResourcePermissionRepresentation permission = new ResourcePermissionRepresentation();
+
+ permission.setName(resource.getName() + " Permission");
+ permission.addResource(resource.getName());
+ permission.addPolicy("Deny Policy");
+
+ permission = getAuthorizationResource().permissions().resource().create(permission).readEntity(ResourcePermissionRepresentation.class);
+
+ login("alice", "alice");
+ assertFalse(wasDenied());
+
+ this.driver.navigate().to(getResourceServerUrl() + "/new-resource");
+ assertFalse(wasDenied());
+
+ Thread.sleep(5000);
+
+ login("alice", "alice");
+ assertFalse(wasDenied());
+
+ this.driver.navigate().to(getResourceServerUrl() + "/new-resource");
+ assertTrue(wasDenied());
+ });
+ }
+}
diff --git a/testsuite/integration-arquillian/tests/other/adapters/jboss/wildfly/src/test/java/org/keycloak/testsuite/adapter/example/authorization/WildflyServletCacheDisabledAdapterTest.java b/testsuite/integration-arquillian/tests/other/adapters/jboss/wildfly/src/test/java/org/keycloak/testsuite/adapter/example/authorization/WildflyServletCacheDisabledAdapterTest.java
new file mode 100644
index 0000000..c4aec94
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/other/adapters/jboss/wildfly/src/test/java/org/keycloak/testsuite/adapter/example/authorization/WildflyServletCacheDisabledAdapterTest.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2018 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.testsuite.adapter.example.authorization;
+
+import org.jboss.arquillian.container.test.api.RunAsClient;
+import org.keycloak.testsuite.arquillian.annotation.AppServerContainer;
+
+/**
+ *
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+@RunAsClient
+@AppServerContainer("app-server-wildfly")
+//@AdapterLibsLocationProperty("adapter.libs.wildfly")
+public class WildflyServletCacheDisabledAdapterTest extends AbstractServletCacheDisabledAdapterTest {
+
+}
diff --git a/testsuite/integration-arquillian/tests/other/adapters/jboss/wildfly/src/test/java/org/keycloak/testsuite/adapter/example/authorization/WildflyServletCacheLifespanAdapterTest.java b/testsuite/integration-arquillian/tests/other/adapters/jboss/wildfly/src/test/java/org/keycloak/testsuite/adapter/example/authorization/WildflyServletCacheLifespanAdapterTest.java
new file mode 100644
index 0000000..c3e75ef
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/other/adapters/jboss/wildfly/src/test/java/org/keycloak/testsuite/adapter/example/authorization/WildflyServletCacheLifespanAdapterTest.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2018 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.testsuite.adapter.example.authorization;
+
+import org.jboss.arquillian.container.test.api.RunAsClient;
+import org.keycloak.testsuite.arquillian.annotation.AppServerContainer;
+
+/**
+ *
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+@RunAsClient
+@AppServerContainer("app-server-wildfly")
+//@AdapterLibsLocationProperty("adapter.libs.wildfly")
+public class WildflyServletCacheLifespanAdapterTest extends AbstractServletCacheLifespanAdapterTest {
+
+}