keycloak-aplcache
Changes
adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/AdapterDeploymentContext.java 10(+10 -0)
adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/KeycloakDeploymentBuilder.java 1(+1 -0)
adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/rotation/JWKPublicKeyLocator.java 18(+13 -5)
adapters/oidc/adapter-core/src/test/java/org/keycloak/adapters/KeycloakDeploymentBuilderTest.java 2(+2 -0)
testsuite/integration-arquillian/servers/auth-server/undertow/src/main/java/org/keycloak/testsuite/arquillian/undertow/KeycloakOnUndertow.java 4(+2 -2)
testsuite/integration-arquillian/test-apps/servlets/src/main/java/org/keycloak/testsuite/adapter/filter/AdapterActionsFilter.java 25(+18 -7)
testsuite/integration-arquillian/test-apps/servlets/src/main/java/org/keycloak/testsuite/adapter/servlet/AbstractShowTokensServlet.java 1(+1 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/AbstractShowTokensPage.java 17(+16 -1)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/AbstractServletsAdapterTest.java 15(+9 -6)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/servlet/AbstractDemoFilterServletAdapterTest.java 6(+0 -6)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/servlet/AbstractDemoServletsAdapterTest.java 99(+1 -98)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/servlet/AbstractOIDCPublicKeyRotationAdapterTest.java 344(+344 -0)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/undertow/servlet/UndertowOIDCPublicKeyRotationAdapterTest.java 28(+28 -0)
testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/customer-db/WEB-INF/keycloak.json 4(+2 -2)
testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/customer-db/WEB-INF/web.xml 17(+17 -0)
testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/secure-portal/WEB-INF/keycloak.json 1(+0 -1)
testsuite/integration-arquillian/tests/other/adapters/jboss/as7/src/test/java/org/keycloak/testsuite/adapter/AS7OIDCPublicKeyRotationAdapterTest.java 28(+28 -0)
testsuite/integration-arquillian/tests/other/adapters/jboss/eap/src/test/java/org/keycloak/testsuite/adapter/EAPOIDCPublicKeyRotationAdapterTest.java 28(+28 -0)
testsuite/integration-arquillian/tests/other/adapters/jboss/eap6/src/test/java/org/keycloak/testsuite/adapter/EAP6OIDCPublicKeyRotationAdapterTest.java 28(+28 -0)
testsuite/integration-arquillian/tests/other/adapters/jboss/wildfly/src/test/java/org/keycloak/testsuite/adapter/WildflyOIDCPublicKeyRotationAdapterTest.java 28(+28 -0)
Details
diff --git a/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/AdapterDeploymentContext.java b/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/AdapterDeploymentContext.java
index 63ea79e..0b33294 100755
--- a/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/AdapterDeploymentContext.java
+++ b/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/AdapterDeploymentContext.java
@@ -446,6 +446,16 @@ public class AdapterDeploymentContext {
public int getMinTimeBetweenJwksRequests() {
return delegate.getMinTimeBetweenJwksRequests();
}
+
+ @Override
+ public int getPublicKeyCacheTtl() {
+ return delegate.getPublicKeyCacheTtl();
+ }
+
+ @Override
+ public void setPublicKeyCacheTtl(int publicKeyCacheTtl) {
+ delegate.setPublicKeyCacheTtl(publicKeyCacheTtl);
+ }
}
protected KeycloakUriBuilder getBaseBuilder(HttpFacade facade, String base) {
diff --git a/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/HttpAdapterUtils.java b/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/HttpAdapterUtils.java
index 3e0f36d..b787796 100644
--- a/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/HttpAdapterUtils.java
+++ b/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/HttpAdapterUtils.java
@@ -46,14 +46,7 @@ public class HttpAdapterUtils {
}
InputStream is = entity.getContent();
try {
- ByteArrayOutputStream os = new ByteArrayOutputStream();
- int c;
- while ((c = is.read()) != -1) {
- os.write(c);
- }
- byte[] bytes = os.toByteArray();
- String json = new String(bytes);
- return JsonSerialization.readValue(json, clazz);
+ return JsonSerialization.readValue(is, clazz);
} finally {
try {
is.close();
diff --git a/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/KeycloakDeployment.java b/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/KeycloakDeployment.java
index 1071b71..3f98a68 100755
--- a/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/KeycloakDeployment.java
+++ b/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/KeycloakDeployment.java
@@ -81,6 +81,7 @@ public class KeycloakDeployment {
protected volatile int notBefore;
protected int tokenMinimumTimeToLive;
protected int minTimeBetweenJwksRequests;
+ protected int publicKeyCacheTtl;
private PolicyEnforcer policyEnforcer;
public KeycloakDeployment() {
@@ -384,6 +385,14 @@ public class KeycloakDeployment {
this.minTimeBetweenJwksRequests = minTimeBetweenJwksRequests;
}
+ public int getPublicKeyCacheTtl() {
+ return publicKeyCacheTtl;
+ }
+
+ public void setPublicKeyCacheTtl(int publicKeyCacheTtl) {
+ this.publicKeyCacheTtl = publicKeyCacheTtl;
+ }
+
public void setPolicyEnforcer(PolicyEnforcer policyEnforcer) {
this.policyEnforcer = policyEnforcer;
}
diff --git a/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/KeycloakDeploymentBuilder.java b/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/KeycloakDeploymentBuilder.java
index f6c6f5e..85b19ca 100755
--- a/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/KeycloakDeploymentBuilder.java
+++ b/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/KeycloakDeploymentBuilder.java
@@ -105,6 +105,7 @@ public class KeycloakDeploymentBuilder {
deployment.setRegisterNodePeriod(adapterConfig.getRegisterNodePeriod());
deployment.setTokenMinimumTimeToLive(adapterConfig.getTokenMinimumTimeToLive());
deployment.setMinTimeBetweenJwksRequests(adapterConfig.getMinTimeBetweenJwksRequests());
+ deployment.setPublicKeyCacheTtl(adapterConfig.getPublicKeyCacheTtl());
if (realmKeyPem == null && adapterConfig.isBearerOnly() && adapterConfig.getAuthServerUrl() == null) {
throw new IllegalArgumentException("For bearer auth, you must set the realm-public-key or auth-server-url");
diff --git a/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/rotation/JWKPublicKeyLocator.java b/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/rotation/JWKPublicKeyLocator.java
index 9305f32..45f420c 100644
--- a/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/rotation/JWKPublicKeyLocator.java
+++ b/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/rotation/JWKPublicKeyLocator.java
@@ -25,7 +25,6 @@ import org.keycloak.adapters.KeycloakDeployment;
import org.keycloak.common.util.Time;
import org.keycloak.jose.jwk.JSONWebKeySet;
import org.keycloak.jose.jwk.JWK;
-import org.keycloak.jose.jws.JWSInput;
import org.keycloak.util.JWKSUtils;
import java.security.PublicKey;
@@ -48,15 +47,15 @@ public class JWKPublicKeyLocator implements PublicKeyLocator {
@Override
public PublicKey getPublicKey(String kid, KeycloakDeployment deployment) {
int minTimeBetweenRequests = deployment.getMinTimeBetweenJwksRequests();
+ int publicKeyCacheTtl = deployment.getPublicKeyCacheTtl();
+ int currentTime = Time.currentTime();
// Check if key is in cache.
- PublicKey publicKey = currentKeys.get(kid);
+ PublicKey publicKey = lookupCachedKey(publicKeyCacheTtl, currentTime, kid);
if (publicKey != null) {
return publicKey;
}
- int currentTime = Time.currentTime();
-
// Check if we are allowed to send request
if (currentTime > lastRequestTime + minTimeBetweenRequests) {
synchronized (this) {
@@ -70,11 +69,20 @@ public class JWKPublicKeyLocator implements PublicKeyLocator {
}
}
- return currentKeys.get(kid);
+ return lookupCachedKey(publicKeyCacheTtl, currentTime, kid);
}
+ private PublicKey lookupCachedKey(int publicKeyCacheTtl, int currentTime, String kid) {
+ if (lastRequestTime + publicKeyCacheTtl > currentTime) {
+ return currentKeys.get(kid);
+ } else {
+ return null;
+ }
+ }
+
+
private void sendRequest(KeycloakDeployment deployment) {
if (log.isTraceEnabled()) {
log.tracef("Going to send request to retrieve new set of realm public keys for client %s", deployment.getResourceName());
diff --git a/adapters/oidc/adapter-core/src/test/java/org/keycloak/adapters/KeycloakDeploymentBuilderTest.java b/adapters/oidc/adapter-core/src/test/java/org/keycloak/adapters/KeycloakDeploymentBuilderTest.java
index 77eb475..233c1ed 100644
--- a/adapters/oidc/adapter-core/src/test/java/org/keycloak/adapters/KeycloakDeploymentBuilderTest.java
+++ b/adapters/oidc/adapter-core/src/test/java/org/keycloak/adapters/KeycloakDeploymentBuilderTest.java
@@ -69,6 +69,7 @@ public class KeycloakDeploymentBuilderTest {
assertEquals("email", deployment.getPrincipalAttribute());
assertEquals(10, deployment.getTokenMinimumTimeToLive());
assertEquals(20, deployment.getMinTimeBetweenJwksRequests());
+ assertEquals(120, deployment.getPublicKeyCacheTtl());
}
@Test
@@ -78,6 +79,7 @@ public class KeycloakDeploymentBuilderTest {
assertTrue(deployment.getPublicKeyLocator() instanceof JWKPublicKeyLocator);
assertEquals(10, deployment.getMinTimeBetweenJwksRequests());
+ assertEquals(86400, deployment.getPublicKeyCacheTtl());
}
@Test
diff --git a/adapters/oidc/adapter-core/src/test/resources/keycloak.json b/adapters/oidc/adapter-core/src/test/resources/keycloak.json
index a8afd22..9f0a204 100644
--- a/adapters/oidc/adapter-core/src/test/resources/keycloak.json
+++ b/adapters/oidc/adapter-core/src/test/resources/keycloak.json
@@ -30,5 +30,6 @@
"token-store": "cookie",
"principal-attribute": "email",
"token-minimum-time-to-live": 10,
- "min-time-between-jwks-requests": 20
+ "min-time-between-jwks-requests": 20,
+ "public-key-cache-ttl": 120
}
\ No newline at end of file
diff --git a/core/src/main/java/org/keycloak/representations/adapters/config/AdapterConfig.java b/core/src/main/java/org/keycloak/representations/adapters/config/AdapterConfig.java
index 0ba327d..e4065bc 100755
--- a/core/src/main/java/org/keycloak/representations/adapters/config/AdapterConfig.java
+++ b/core/src/main/java/org/keycloak/representations/adapters/config/AdapterConfig.java
@@ -36,7 +36,8 @@ import com.fasterxml.jackson.annotation.JsonPropertyOrder;
"client-keystore", "client-keystore-password", "client-key-password",
"always-refresh-token",
"register-node-at-startup", "register-node-period", "token-store", "principal-attribute",
- "proxy-url", "turn-off-change-session-id-on-login", "token-minimum-time-to-live", "min-time-between-jwks-requests",
+ "proxy-url", "turn-off-change-session-id-on-login", "token-minimum-time-to-live",
+ "min-time-between-jwks-requests", "public-key-cache-ttl",
"policy-enforcer"
})
public class AdapterConfig extends BaseAdapterConfig implements AdapterHttpClientConfig {
@@ -73,6 +74,8 @@ public class AdapterConfig extends BaseAdapterConfig implements AdapterHttpClien
protected int tokenMinimumTimeToLive = 0;
@JsonProperty("min-time-between-jwks-requests")
protected int minTimeBetweenJwksRequests = 10;
+ @JsonProperty("public-key-cache-ttl")
+ protected int publicKeyCacheTtl = 86400; // 1 day
@JsonProperty("policy-enforcer")
protected PolicyEnforcerConfig policyEnforcerConfig;
@@ -233,4 +236,12 @@ public class AdapterConfig extends BaseAdapterConfig implements AdapterHttpClien
public void setMinTimeBetweenJwksRequests(int minTimeBetweenJwksRequests) {
this.minTimeBetweenJwksRequests = minTimeBetweenJwksRequests;
}
+
+ public int getPublicKeyCacheTtl() {
+ return publicKeyCacheTtl;
+ }
+
+ public void setPublicKeyCacheTtl(int publicKeyCacheTtl) {
+ this.publicKeyCacheTtl = publicKeyCacheTtl;
+ }
}
diff --git a/testsuite/integration-arquillian/servers/auth-server/undertow/src/main/java/org/keycloak/testsuite/arquillian/undertow/KeycloakOnUndertow.java b/testsuite/integration-arquillian/servers/auth-server/undertow/src/main/java/org/keycloak/testsuite/arquillian/undertow/KeycloakOnUndertow.java
index 9d29973..bdbd4d9 100644
--- a/testsuite/integration-arquillian/servers/auth-server/undertow/src/main/java/org/keycloak/testsuite/arquillian/undertow/KeycloakOnUndertow.java
+++ b/testsuite/integration-arquillian/servers/auth-server/undertow/src/main/java/org/keycloak/testsuite/arquillian/undertow/KeycloakOnUndertow.java
@@ -50,8 +50,8 @@ import javax.servlet.ServletException;
import java.lang.reflect.Field;
import java.util.Collection;
-import java.util.HashMap;
import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
public class KeycloakOnUndertow implements DeployableContainer<KeycloakOnUndertowConfiguration> {
@@ -61,7 +61,7 @@ public class KeycloakOnUndertow implements DeployableContainer<KeycloakOnUnderto
private KeycloakOnUndertowConfiguration configuration;
private KeycloakSessionFactory sessionFactory;
- Map<String, String> deployedArchivesToContextPath = new HashMap<>();
+ Map<String, String> deployedArchivesToContextPath = new ConcurrentHashMap<>();
private DeploymentInfo createAuthServerDeploymentInfo() {
ResteasyDeployment deployment = new ResteasyDeployment();
diff --git a/testsuite/integration-arquillian/test-apps/servlets/src/main/java/org/keycloak/testsuite/adapter/filter/AdapterActionsFilter.java b/testsuite/integration-arquillian/test-apps/servlets/src/main/java/org/keycloak/testsuite/adapter/filter/AdapterActionsFilter.java
index 1bfbb3e..3b3cc49 100644
--- a/testsuite/integration-arquillian/test-apps/servlets/src/main/java/org/keycloak/testsuite/adapter/filter/AdapterActionsFilter.java
+++ b/testsuite/integration-arquillian/test-apps/servlets/src/main/java/org/keycloak/testsuite/adapter/filter/AdapterActionsFilter.java
@@ -23,12 +23,14 @@ import org.keycloak.adapters.AdapterDeploymentContext;
import org.keycloak.adapters.KeycloakDeployment;
import org.keycloak.adapters.rotation.JWKPublicKeyLocator;
import org.keycloak.common.util.Time;
+import org.keycloak.common.util.reflections.Reflections;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
+import java.lang.reflect.Field;
/**
* Filter to handle "special" requests to perform actions on adapter side (for example setting time offset )
@@ -38,7 +40,7 @@ import java.io.PrintWriter;
public class AdapterActionsFilter implements Filter {
public static final String TIME_OFFSET_PARAM = "timeOffset";
- public static final String RESET_PUBLIC_KEY_PARAM = "resetPublicKey";
+ public static final String RESET_DEPLOYMENT_PARAM = "resetDeployment";
private static final Logger log = Logger.getLogger(AdapterActionsFilter.class);
@@ -54,19 +56,28 @@ public class AdapterActionsFilter implements Filter {
//Accept timeOffset as argument to enforce timeouts
String timeOffsetParam = request.getParameter(TIME_OFFSET_PARAM);
- String resetPublicKey = request.getParameter(RESET_PUBLIC_KEY_PARAM);
+ String resetDeploymentParam = request.getParameter(RESET_DEPLOYMENT_PARAM);
if (timeOffsetParam != null && !timeOffsetParam.isEmpty()) {
int timeOffset = Integer.parseInt(timeOffsetParam);
log.infof("Time offset updated to %d for application %s", timeOffset, servletReq.getRequestURI());
Time.setOffset(timeOffset);
writeResponse(servletResp, "Offset set successfully");
- } else if (resetPublicKey != null && !resetPublicKey.isEmpty()) {
+ } else if (resetDeploymentParam != null && !resetDeploymentParam.isEmpty()) {
AdapterDeploymentContext deploymentContext = (AdapterDeploymentContext) request.getServletContext().getAttribute(AdapterDeploymentContext.class.getName());
- KeycloakDeployment deployment = deploymentContext.resolveDeployment(null);
- deployment.setPublicKeyLocator(new JWKPublicKeyLocator());
- log.infof("Restarted publicKey locator for application %s", servletReq.getRequestURI());
- writeResponse(servletResp, "PublicKeyLocator restarted successfully");
+
+ Field field = Reflections.findDeclaredField(AdapterDeploymentContext.class, "deployment");
+ Reflections.setAccessible(field);
+ KeycloakDeployment deployment = (KeycloakDeployment) Reflections.getFieldValue(field, deploymentContext);
+
+ Time.setOffset(0);
+ deployment.setNotBefore(0);
+ if (deployment.getPublicKeyLocator() instanceof JWKPublicKeyLocator) {
+ deployment.setPublicKeyLocator(new JWKPublicKeyLocator());
+ }
+
+ log.infof("Restarted PublicKeyLocator, notBefore and timeOffset for application %s", servletReq.getRequestURI());
+ writeResponse(servletResp, "Restarted PublicKeyLocator, notBefore and timeOffset successfully");
} else {
// Continue request
chain.doFilter(request, response);
diff --git a/testsuite/integration-arquillian/test-apps/servlets/src/main/java/org/keycloak/testsuite/adapter/servlet/AbstractShowTokensServlet.java b/testsuite/integration-arquillian/test-apps/servlets/src/main/java/org/keycloak/testsuite/adapter/servlet/AbstractShowTokensServlet.java
index 3707172..6db5922 100644
--- a/testsuite/integration-arquillian/test-apps/servlets/src/main/java/org/keycloak/testsuite/adapter/servlet/AbstractShowTokensServlet.java
+++ b/testsuite/integration-arquillian/test-apps/servlets/src/main/java/org/keycloak/testsuite/adapter/servlet/AbstractShowTokensServlet.java
@@ -49,6 +49,7 @@ public abstract class AbstractShowTokensServlet extends HttpServlet {
return new StringBuilder("<span id=\"accessToken\">" + accessTokenPretty + "</span>")
.append("<span id=\"refreshToken\">" + refreshTokenPretty + "</span>")
+ .append("<span id=\"accessTokenString\">" + ctx.getTokenString() + "</span>")
.toString();
}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/AbstractShowTokensPage.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/AbstractShowTokensPage.java
index ea7ef6f..64d0de2 100644
--- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/AbstractShowTokensPage.java
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/AbstractShowTokensPage.java
@@ -38,6 +38,9 @@ public abstract class AbstractShowTokensPage extends AbstractPageWithInjectedUrl
@FindBy(id = "refreshToken")
private WebElement refreshToken;
+ @FindBy(id = "accessTokenString")
+ private WebElement accessTokenString;
+
public AccessToken getAccessToken() {
try {
@@ -51,13 +54,25 @@ public abstract class AbstractShowTokensPage extends AbstractPageWithInjectedUrl
return null;
}
+
public RefreshToken getRefreshToken() {
try {
return JsonSerialization.readValue(refreshToken.getText(), RefreshToken.class);
} catch (IOException e) {
e.printStackTrace();
} catch (NoSuchElementException nsee) {
- log.warn("No idToken element found on the page");
+ log.warn("No refreshToken element found on the page");
+ }
+
+ return null;
+ }
+
+
+ public String getAccessTokenString() {
+ try {
+ return accessTokenString.getText();
+ } catch (NoSuchElementException nsee) {
+ log.warn("No accessTokenString element found on the page");
}
return null;
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/AbstractServletsAdapterTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/AbstractServletsAdapterTest.java
index a40275f..cc018d2 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/AbstractServletsAdapterTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/AbstractServletsAdapterTest.java
@@ -111,14 +111,17 @@ public abstract class AbstractServletsAdapterTest extends AbstractAdapterTest {
testRealmPage.setAuthRealm(DEMO);
}
- protected void setAdapterAndServerTimeOffset(int timeOffset, String servletUri) {
+ protected void setAdapterAndServerTimeOffset(int timeOffset, String... servletUris) {
setTimeOffset(timeOffset);
- String timeOffsetUri = UriBuilder.fromUri(servletUri)
- .queryParam(AdapterActionsFilter.TIME_OFFSET_PARAM, timeOffset)
- .build().toString();
- driver.navigate().to(timeOffsetUri);
- WaitUtils.waitUntilElement(By.tagName("body")).is().visible();
+ for (String servletUri : servletUris) {
+ String timeOffsetUri = UriBuilder.fromUri(servletUri)
+ .queryParam(AdapterActionsFilter.TIME_OFFSET_PARAM, timeOffset)
+ .build().toString();
+
+ driver.navigate().to(timeOffsetUri);
+ WaitUtils.waitUntilElement(By.tagName("body")).is().visible();
+ }
}
}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/servlet/AbstractDemoFilterServletAdapterTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/servlet/AbstractDemoFilterServletAdapterTest.java
index 0ad81d5..a9ce39a 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/servlet/AbstractDemoFilterServletAdapterTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/servlet/AbstractDemoFilterServletAdapterTest.java
@@ -27,10 +27,4 @@ public abstract class AbstractDemoFilterServletAdapterTest extends AbstractDemoS
}
- @Test
- @Override
- @Ignore
- public void testClientWithJwksUri() {
-
- }
}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/servlet/AbstractDemoServletsAdapterTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/servlet/AbstractDemoServletsAdapterTest.java
index f57b858..fde26a1 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/servlet/AbstractDemoServletsAdapterTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/servlet/AbstractDemoServletsAdapterTest.java
@@ -27,17 +27,13 @@ import org.junit.Test;
import org.keycloak.OAuth2Constants;
import org.keycloak.admin.client.resource.ClientResource;
import org.keycloak.common.Version;
-import org.keycloak.common.util.MultivaluedHashMap;
import org.keycloak.common.util.Time;
import org.keycloak.constants.AdapterConstants;
-import org.keycloak.keys.KeyProvider;
-import org.keycloak.protocol.oidc.OIDCAdvancedConfigWrapper;
import org.keycloak.protocol.oidc.OIDCLoginProtocol;
import org.keycloak.protocol.oidc.OIDCLoginProtocolService;
import org.keycloak.representations.AccessToken;
import org.keycloak.representations.VersionRepresentation;
import org.keycloak.representations.idm.ClientRepresentation;
-import org.keycloak.representations.idm.ComponentRepresentation;
import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.representations.idm.UserRepresentation;
import org.keycloak.testsuite.adapter.AbstractServletsAdapterTest;
@@ -67,7 +63,6 @@ import javax.ws.rs.client.WebTarget;
import javax.ws.rs.core.Form;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.Response;
-import javax.ws.rs.core.UriBuilder;
import java.io.File;
import java.io.IOException;
import java.net.URI;
@@ -86,7 +81,6 @@ import static org.junit.Assert.assertTrue;
import org.keycloak.testsuite.adapter.page.CustomerPortalNoConf;
import static org.keycloak.testsuite.auth.page.AuthRealm.DEMO;
import static org.keycloak.testsuite.util.URLAssert.assertCurrentUrlEquals;
-import static org.keycloak.testsuite.util.URLAssert.assertCurrentUrlStartsWith;
import static org.keycloak.testsuite.util.URLAssert.assertCurrentUrlStartsWithLoginUrlOf;
import static org.keycloak.testsuite.util.WaitUtils.pause;
import static org.keycloak.testsuite.util.WaitUtils.waitUntilElement;
@@ -141,7 +135,7 @@ public abstract class AbstractDemoServletsAdapterTest extends AbstractServletsAd
@Deployment(name = CustomerDb.DEPLOYMENT_NAME)
protected static WebArchive customerDb() {
- return servletDeployment(CustomerDb.DEPLOYMENT_NAME, CustomerDatabaseServlet.class);
+ return servletDeployment(CustomerDb.DEPLOYMENT_NAME, AdapterActionsFilter.class, CustomerDatabaseServlet.class);
}
@Deployment(name = CustomerDbErrorPage.DEPLOYMENT_NAME)
@@ -218,97 +212,6 @@ public abstract class AbstractDemoServletsAdapterTest extends AbstractServletsAd
}
@Test
- public void testRealmKeyRotationWithNewKeyDownload() throws Exception {
- // Login success first
- tokenMinTTLPage.navigateTo();
- testRealmLoginPage.form().waitForUsernameInputPresent();
- assertCurrentUrlStartsWithLoginUrlOf(testRealmPage);
- testRealmLoginPage.form().login("bburke@redhat.com", "password");
- assertCurrentUrlEquals(tokenMinTTLPage);
-
- AccessToken token = tokenMinTTLPage.getAccessToken();
- Assert.assertEquals("bburke@redhat.com", token.getPreferredUsername());
-
- // Logout
- String logoutUri = OIDCLoginProtocolService.logoutUrl(authServerPage.createUriBuilder())
- .queryParam(OAuth2Constants.REDIRECT_URI, tokenMinTTLPage.toString())
- .build("demo").toString();
- driver.navigate().to(logoutUri);
-
- // Generate new realm key
- String realmId = adminClient.realm(DEMO).toRepresentation().getId();
- ComponentRepresentation keys = new ComponentRepresentation();
- keys.setName("generated");
- keys.setProviderType(KeyProvider.class.getName());
- keys.setProviderId("rsa-generated");
- keys.setParentId(realmId);
- keys.setConfig(new MultivaluedHashMap<>());
- keys.getConfig().putSingle("priority", "100");
- Response response = adminClient.realm(DEMO).components().add(keys);
- assertEquals(201, response.getStatus());
- response.close();
-
- String adapterActionsUrl = tokenMinTTLPage.toString() + "/unsecured/foo";
- setAdapterAndServerTimeOffset(300, adapterActionsUrl);
-
- // Try to login. Should work now due to realm key change
- tokenMinTTLPage.navigateTo();
- testRealmLoginPage.form().waitForUsernameInputPresent();
- assertCurrentUrlStartsWithLoginUrlOf(testRealmPage);
- testRealmLoginPage.form().login("bburke@redhat.com", "password");
- assertCurrentUrlEquals(tokenMinTTLPage);
- token = tokenMinTTLPage.getAccessToken();
- Assert.assertEquals("bburke@redhat.com", token.getPreferredUsername());
- driver.navigate().to(logoutUri);
-
- // Revert public keys change
- String timeOffsetUri = UriBuilder.fromUri(adapterActionsUrl)
- .queryParam(AdapterActionsFilter.RESET_PUBLIC_KEY_PARAM, "true")
- .build().toString();
- driver.navigate().to(timeOffsetUri);
- waitUntilElement(By.tagName("body")).is().visible();
-
- setAdapterAndServerTimeOffset(0, adapterActionsUrl);
- }
-
- @Test
- public void testClientWithJwksUri() throws Exception {
- // Set client to bad JWKS URI
- ClientResource clientResource = ApiUtil.findClientResourceByClientId(testRealmResource(), "secure-portal");
- ClientRepresentation client = clientResource.toRepresentation();
- OIDCAdvancedConfigWrapper wrapper = OIDCAdvancedConfigWrapper.fromClientRepresentation(client);
- wrapper.setUseJwksUrl(true);
- wrapper.setJwksUrl(securePortal + "/bad-jwks-url");
- clientResource.update(client);
-
- // Login should fail at the code-to-token
- securePortal.navigateTo();
- assertCurrentUrlStartsWithLoginUrlOf(testRealmPage);
- testRealmLoginPage.form().login("bburke@redhat.com", "password");
- String pageSource = driver.getPageSource();
- assertCurrentUrlStartsWith(securePortal);
- assertFalse(pageSource.contains("Bill Burke") && pageSource.contains("Stian Thorgersen"));
-
- // Set client to correct JWKS URI
- client = clientResource.toRepresentation();
- wrapper = OIDCAdvancedConfigWrapper.fromClientRepresentation(client);
- wrapper.setUseJwksUrl(true);
- wrapper.setJwksUrl(securePortal + "/" + AdapterConstants.K_JWKS);
- clientResource.update(client);
-
- // Login to secure-portal should be fine now. Client keys downloaded from JWKS URI
- securePortal.navigateTo();
- assertCurrentUrlEquals(securePortal);
- pageSource = driver.getPageSource();
- assertTrue(pageSource.contains("Bill Burke") && pageSource.contains("Stian Thorgersen"));
-
- // Logout
- String logoutUri = OIDCLoginProtocolService.logoutUrl(authServerPage.createUriBuilder())
- .queryParam(OAuth2Constants.REDIRECT_URI, securePortal.toString()).build("demo").toString();
- driver.navigate().to(logoutUri);
- }
-
- @Test
public void testLoginSSOAndLogout() {
// test login to customer-portal which does a bearer request to customer-db
customerPortal.navigateTo();
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/servlet/AbstractOIDCPublicKeyRotationAdapterTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/servlet/AbstractOIDCPublicKeyRotationAdapterTest.java
new file mode 100644
index 0000000..d9116ce
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/servlet/AbstractOIDCPublicKeyRotationAdapterTest.java
@@ -0,0 +1,344 @@
+/*
+ * Copyright 2016 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.servlet;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.concurrent.TimeUnit;
+
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriBuilder;
+
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpResponse;
+import org.apache.http.client.HttpClient;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.impl.client.DefaultHttpClient;
+import org.jboss.arquillian.container.test.api.Deployment;
+import org.jboss.arquillian.graphene.page.Page;
+import org.jboss.shrinkwrap.api.spec.WebArchive;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.keycloak.OAuth2Constants;
+import org.keycloak.admin.client.resource.ClientResource;
+import org.keycloak.common.util.MultivaluedHashMap;
+import org.keycloak.common.util.StreamUtil;
+import org.keycloak.common.util.Time;
+import org.keycloak.constants.AdapterConstants;
+import org.keycloak.keys.KeyProvider;
+import org.keycloak.protocol.oidc.OIDCAdvancedConfigWrapper;
+import org.keycloak.protocol.oidc.OIDCLoginProtocolService;
+import org.keycloak.representations.AccessToken;
+import org.keycloak.representations.adapters.action.GlobalRequestResult;
+import org.keycloak.representations.idm.ClientRepresentation;
+import org.keycloak.representations.idm.ComponentRepresentation;
+import org.keycloak.representations.idm.RealmRepresentation;
+import org.keycloak.testsuite.adapter.AbstractServletsAdapterTest;
+import org.keycloak.testsuite.adapter.filter.AdapterActionsFilter;
+import org.keycloak.testsuite.adapter.page.CustomerDb;
+import org.keycloak.testsuite.adapter.page.SecurePortal;
+import org.keycloak.testsuite.adapter.page.TokenMinTTLPage;
+import org.keycloak.testsuite.admin.ApiUtil;
+import org.keycloak.testsuite.util.URLAssert;
+import org.openqa.selenium.By;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.keycloak.testsuite.auth.page.AuthRealm.DEMO;
+import static org.keycloak.testsuite.util.URLAssert.assertCurrentUrlEquals;
+import static org.keycloak.testsuite.util.URLAssert.assertCurrentUrlStartsWith;
+import static org.keycloak.testsuite.util.URLAssert.assertCurrentUrlStartsWithLoginUrlOf;
+import static org.keycloak.testsuite.util.WaitUtils.waitUntilElement;
+
+/**
+ * Tests related to public key rotation for OIDC adapter
+ *
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class AbstractOIDCPublicKeyRotationAdapterTest extends AbstractServletsAdapterTest {
+
+ @Page
+ private SecurePortal securePortal;
+
+ @Page
+ private TokenMinTTLPage tokenMinTTLPage;
+
+ @Page
+ private CustomerDb customerDb;
+
+ @Deployment(name = SecurePortal.DEPLOYMENT_NAME)
+ protected static WebArchive securePortal() {
+ return servletDeployment(SecurePortal.DEPLOYMENT_NAME, CallAuthenticatedServlet.class);
+ }
+
+ @Deployment(name = TokenMinTTLPage.DEPLOYMENT_NAME)
+ protected static WebArchive tokenMinTTLPage() {
+ return servletDeployment(TokenMinTTLPage.DEPLOYMENT_NAME, AdapterActionsFilter.class, AbstractShowTokensServlet.class, TokenMinTTLServlet.class, ErrorServlet.class);
+ }
+
+ @Deployment(name = CustomerDb.DEPLOYMENT_NAME)
+ protected static WebArchive customerDb() {
+ return servletDeployment(CustomerDb.DEPLOYMENT_NAME, AdapterActionsFilter.class, CustomerDatabaseServlet.class);
+ }
+
+
+
+
+ @Before
+ public void beforeRotationAdapterTest() {
+ // Delete all cookies from token-min-ttl page to be sure we are logged out
+ tokenMinTTLPage.navigateTo();
+ driver.manage().deleteAllCookies();
+ }
+
+
+ @Test
+ public void testRealmKeyRotationWithNewKeyDownload() throws Exception {
+ // Login success first
+ loginToTokenMinTtlApp();
+
+ // Logout
+ String logoutUri = OIDCLoginProtocolService.logoutUrl(authServerPage.createUriBuilder())
+ .queryParam(OAuth2Constants.REDIRECT_URI, tokenMinTTLPage.toString())
+ .build("demo").toString();
+ driver.navigate().to(logoutUri);
+ assertCurrentUrlStartsWithLoginUrlOf(testRealmPage);
+
+ // Generate new realm key
+ generateNewRealmKey();
+
+ // Try to login again. It should fail now because not yet allowed to download new keys
+ tokenMinTTLPage.navigateTo();
+ testRealmLoginPage.form().waitForUsernameInputPresent();
+ assertCurrentUrlStartsWithLoginUrlOf(testRealmPage);
+ testRealmLoginPage.form().login("bburke@redhat.com", "password");
+ URLAssert.assertCurrentUrlStartsWith(driver, tokenMinTTLPage.getInjectedUrl().toString());
+ Assert.assertNull(tokenMinTTLPage.getAccessToken());
+
+ driver.navigate().to(logoutUri);
+ assertCurrentUrlStartsWithLoginUrlOf(testRealmPage);
+
+ setAdapterAndServerTimeOffset(300, tokenMinTTLPage.toString() + "/unsecured/foo");
+
+ // Try to login. Should work now due to realm key change
+ loginToTokenMinTtlApp();
+ driver.navigate().to(logoutUri);
+
+ // Revert public keys change
+ resetKeycloakDeploymentForAdapter(tokenMinTTLPage.toString() + "/unsecured/foo");
+ }
+
+
+ @Test
+ public void testClientWithJwksUri() throws Exception {
+ // Set client to bad JWKS URI
+ ClientResource clientResource = ApiUtil.findClientResourceByClientId(testRealmResource(), "secure-portal");
+ ClientRepresentation client = clientResource.toRepresentation();
+ OIDCAdvancedConfigWrapper wrapper = OIDCAdvancedConfigWrapper.fromClientRepresentation(client);
+ wrapper.setUseJwksUrl(true);
+ wrapper.setJwksUrl(securePortal + "/bad-jwks-url");
+ clientResource.update(client);
+
+ // Login should fail at the code-to-token
+ securePortal.navigateTo();
+ assertCurrentUrlStartsWithLoginUrlOf(testRealmPage);
+ testRealmLoginPage.form().login("bburke@redhat.com", "password");
+ String pageSource = driver.getPageSource();
+ assertCurrentUrlStartsWith(securePortal);
+ assertFalse(pageSource.contains("Bill Burke") && pageSource.contains("Stian Thorgersen"));
+
+ // Set client to correct JWKS URI
+ client = clientResource.toRepresentation();
+ wrapper = OIDCAdvancedConfigWrapper.fromClientRepresentation(client);
+ wrapper.setUseJwksUrl(true);
+ wrapper.setJwksUrl(securePortal + "/" + AdapterConstants.K_JWKS);
+ clientResource.update(client);
+
+ // Login to secure-portal should be fine now. Client keys downloaded from JWKS URI
+ securePortal.navigateTo();
+ assertCurrentUrlEquals(securePortal);
+ pageSource = driver.getPageSource();
+ assertTrue(pageSource.contains("Bill Burke") && pageSource.contains("Stian Thorgersen"));
+
+ // Logout
+ String logoutUri = OIDCLoginProtocolService.logoutUrl(authServerPage.createUriBuilder())
+ .queryParam(OAuth2Constants.REDIRECT_URI, securePortal.toString()).build("demo").toString();
+ driver.navigate().to(logoutUri);
+ }
+
+
+ // KEYCLOAK-3824: Test for public-key-cache-ttl
+ @Test
+ public void testPublicKeyCacheTtl() {
+ driver.manage().timeouts().pageLoadTimeout(1000, TimeUnit.SECONDS);
+
+ // increase accessTokenLifespan to 1200
+ RealmRepresentation demoRealm = adminClient.realm(DEMO).toRepresentation();
+ demoRealm.setAccessTokenLifespan(1200);
+ adminClient.realm(DEMO).update(demoRealm);
+
+ // authenticate in tokenMinTTL app
+ loginToTokenMinTtlApp();
+ String accessTokenString = tokenMinTTLPage.getAccessTokenString();
+
+ // Send REST request to customer-db app. I should be successfully authenticated
+ int status = invokeRESTEndpoint(accessTokenString);
+ Assert.assertEquals(200, status);
+
+ // Invalidate realm public key
+ generateNewRealmKey();
+
+ // Send REST request to the customer-db app. Should be still succcessfully authenticated as the JWKPublicKeyLocator cache is still valid
+ status = invokeRESTEndpoint(accessTokenString);
+ Assert.assertEquals(200, status);
+
+ // TimeOffset to 900 on the REST app side. Token is still valid (1200) but JWKPublicKeyLocator should try to download new key (public-key-cache-ttl=600)
+ setAdapterAndServerTimeOffset(900, customerDb.toString() + "/unsecured/foo");
+
+ // Send REST request. New request to the publicKey cache should be sent, and key is no longer returned as token contains the old kid
+ status = invokeRESTEndpoint(accessTokenString);
+ Assert.assertEquals(401, status);
+
+ // Revert public keys change and time offset
+ resetKeycloakDeploymentForAdapter(customerDb.toString() + "/unsecured/foo");
+ resetKeycloakDeploymentForAdapter(tokenMinTTLPage.toString() + "/unsecured/foo");
+ }
+
+
+ // KEYCLOAK-3823: Test that sending notBefore policy invalidates JWKPublicKeyLocator cache
+ @Test
+ public void testPublicKeyCacheInvalidatedWhenPushedNotBefore() {
+ // increase accessTokenLifespan to 1200
+ RealmRepresentation demoRealm = adminClient.realm(DEMO).toRepresentation();
+ demoRealm.setAccessTokenLifespan(1200);
+ adminClient.realm(DEMO).update(demoRealm);
+
+ // authenticate in tokenMinTTL app
+ loginToTokenMinTtlApp();
+ String accessTokenString = tokenMinTTLPage.getAccessTokenString();
+
+ // Send REST request to customer-db app. I should be successfully authenticated
+ int status = invokeRESTEndpoint(accessTokenString);
+ Assert.assertEquals(200, status);
+
+ // Invalidate realm public key
+ generateNewRealmKey();
+
+ // Set some offset to ensure pushing notBefore will pass
+ setAdapterAndServerTimeOffset(130, customerDb.toString() + "/unsecured/foo", tokenMinTTLPage.toString() + "/unsecured/foo");
+
+ // Send REST request to the REST app. Should be still succcessfully authenticated as the JWKPublicKeyLocator cache is still valid
+ status = invokeRESTEndpoint(accessTokenString);
+ Assert.assertEquals(200, status);
+
+ // Send notBefore policy from the realm
+ demoRealm.setNotBefore(Time.currentTime() - 1);
+ adminClient.realm(DEMO).update(demoRealm);
+ GlobalRequestResult result = adminClient.realm(DEMO).pushRevocation();
+ Assert.assertTrue(result.getSuccessRequests().contains(customerDb.toString()));
+
+ // Send REST request. New request to the publicKey cache should be sent, and key is no longer returned as token contains the old kid
+ status = invokeRESTEndpoint(accessTokenString);
+ Assert.assertEquals(401, status);
+
+ // Revert public keys change and time offset
+ resetKeycloakDeploymentForAdapter(customerDb.toString() + "/unsecured/foo");
+ resetKeycloakDeploymentForAdapter(tokenMinTTLPage.toString() + "/unsecured/foo");
+ }
+
+
+ // HELPER METHODS
+
+ private void loginToTokenMinTtlApp() {
+ tokenMinTTLPage.navigateTo();
+ testRealmLoginPage.form().waitForUsernameInputPresent();
+ assertCurrentUrlStartsWithLoginUrlOf(testRealmPage);
+ testRealmLoginPage.form().login("bburke@redhat.com", "password");
+ assertCurrentUrlEquals(tokenMinTTLPage);
+
+ AccessToken token = tokenMinTTLPage.getAccessToken();
+ Assert.assertEquals("bburke@redhat.com", token.getPreferredUsername());
+ }
+
+
+ private void generateNewRealmKey() {
+ String realmId = adminClient.realm(DEMO).toRepresentation().getId();
+
+ String oldKeyId = adminClient.realm(DEMO).components().query(realmId, KeyProvider.class.getName())
+ .get(0).getId();
+
+ ComponentRepresentation keys = new ComponentRepresentation();
+ keys.setName("generated");
+ keys.setProviderType(KeyProvider.class.getName());
+ keys.setProviderId("rsa-generated");
+ keys.setParentId(realmId);
+ keys.setConfig(new MultivaluedHashMap<>());
+ keys.getConfig().putSingle("priority", "150");
+ Response response = adminClient.realm(DEMO).components().add(keys);
+ assertEquals(201, response.getStatus());
+ response.close();
+
+ // Remove original key
+ adminClient.realm(DEMO).components().component(oldKeyId).remove();
+ }
+
+
+ private int invokeRESTEndpoint(String accessTokenString) {
+
+ HttpClient client = new DefaultHttpClient();
+ try {
+ String restUrl = customerDb.toString();
+ HttpGet get = new HttpGet(restUrl);
+ get.addHeader("Authorization", "Bearer " + accessTokenString);
+ try {
+ HttpResponse response = client.execute(get);
+ int status = response.getStatusLine().getStatusCode();
+ if (status != 200) {
+ return status;
+ }
+
+ HttpEntity entity = response.getEntity();
+ InputStream is = entity.getContent();
+ try {
+ String body = StreamUtil.readString(is);
+ Assert.assertTrue(body.contains("Stian Thorgersen") && body.contains("Bill Burke"));
+ return status;
+ } finally {
+ is.close();
+ }
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ } finally {
+ client.getConnectionManager().shutdown();
+ }
+ }
+
+
+ private void resetKeycloakDeploymentForAdapter(String adapterActionsUrl) {
+ String timeOffsetUri = UriBuilder.fromUri(adapterActionsUrl)
+ .queryParam(AdapterActionsFilter.RESET_DEPLOYMENT_PARAM, "true")
+ .build().toString();
+ driver.navigate().to(timeOffsetUri);
+ waitUntilElement(By.tagName("body")).is().visible();
+ }
+
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/undertow/servlet/UndertowOIDCPublicKeyRotationAdapterTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/undertow/servlet/UndertowOIDCPublicKeyRotationAdapterTest.java
new file mode 100644
index 0000000..0dfd99c
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/undertow/servlet/UndertowOIDCPublicKeyRotationAdapterTest.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2016 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.undertow.servlet;
+
+import org.keycloak.testsuite.adapter.servlet.AbstractOIDCPublicKeyRotationAdapterTest;
+import org.keycloak.testsuite.arquillian.annotation.AppServerContainer;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+@AppServerContainer("auth-server-undertow")
+public class UndertowOIDCPublicKeyRotationAdapterTest extends AbstractOIDCPublicKeyRotationAdapterTest {
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/customer-db/WEB-INF/keycloak.json b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/customer-db/WEB-INF/keycloak.json
index 3620170..400fac3 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/customer-db/WEB-INF/keycloak.json
+++ b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/customer-db/WEB-INF/keycloak.json
@@ -1,10 +1,10 @@
{
"realm" : "demo",
"resource" : "customer-db",
- "realm-public-key" : "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
"auth-server-url": "http://localhost:8180/auth",
"ssl-required" : "external",
"bearer-only" : true,
- "enable-cors" : true
+ "enable-cors" : true,
+ "public-key-cache-ttl": 600
}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/customer-db/WEB-INF/web.xml b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/customer-db/WEB-INF/web.xml
index cebfe6f..56ed0e7 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/customer-db/WEB-INF/web.xml
+++ b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/customer-db/WEB-INF/web.xml
@@ -23,11 +23,22 @@
<module-name>customer-db</module-name>
+
+ <filter>
+ <filter-name>AdapterActionsFilter</filter-name>
+ <filter-class>org.keycloak.testsuite.adapter.filter.AdapterActionsFilter</filter-class>
+ </filter>
+
<servlet>
<servlet-name>Servlet</servlet-name>
<servlet-class>org.keycloak.testsuite.adapter.servlet.CustomerDatabaseServlet</servlet-class>
</servlet>
+ <filter-mapping>
+ <filter-name>AdapterActionsFilter</filter-name>
+ <url-pattern>/*</url-pattern>
+ </filter-mapping>
+
<servlet-mapping>
<servlet-name>Servlet</servlet-name>
<url-pattern>/*</url-pattern>
@@ -42,6 +53,12 @@
<role-name>user</role-name>
</auth-constraint>
</security-constraint>
+ <security-constraint>
+ <web-resource-collection>
+ <web-resource-name>Unsecured</web-resource-name>
+ <url-pattern>/unsecured/*</url-pattern>
+ </web-resource-collection>
+ </security-constraint>
<login-config>
<auth-method>KEYCLOAK</auth-method>
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/demorealm.json b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/demorealm.json
index d65fa94..b1f70e2 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/demorealm.json
+++ b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/demorealm.json
@@ -118,6 +118,13 @@
],
"clients": [
{
+ "clientId": "customer-db",
+ "enabled": true,
+ "adminUrl": "/customer-db",
+ "baseUrl": "/customer-db",
+ "bearerOnly": true
+ },
+ {
"clientId": "customer-portal",
"enabled": true,
"adminUrl": "/customer-portal",
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/secure-portal/WEB-INF/keycloak.json b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/secure-portal/WEB-INF/keycloak.json
index de290de..f3fa1a5 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/secure-portal/WEB-INF/keycloak.json
+++ b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/secure-portal/WEB-INF/keycloak.json
@@ -1,6 +1,5 @@
{
"realm": "demo",
- "realm-public-key": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
"auth-server-url": "http://localhost:8180/auth",
"ssl-required": "external",
"resource": "secure-portal",
diff --git a/testsuite/integration-arquillian/tests/other/adapters/jboss/as7/src/test/java/org/keycloak/testsuite/adapter/AS7OIDCPublicKeyRotationAdapterTest.java b/testsuite/integration-arquillian/tests/other/adapters/jboss/as7/src/test/java/org/keycloak/testsuite/adapter/AS7OIDCPublicKeyRotationAdapterTest.java
new file mode 100644
index 0000000..50cc0e9
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/other/adapters/jboss/as7/src/test/java/org/keycloak/testsuite/adapter/AS7OIDCPublicKeyRotationAdapterTest.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2016 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;
+
+import org.keycloak.testsuite.adapter.servlet.AbstractOIDCPublicKeyRotationAdapterTest;
+import org.keycloak.testsuite.arquillian.annotation.AppServerContainer;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+@AppServerContainer("app-server-as7")
+public class AS7OIDCPublicKeyRotationAdapterTest extends AbstractOIDCPublicKeyRotationAdapterTest {
+}
diff --git a/testsuite/integration-arquillian/tests/other/adapters/jboss/eap/src/test/java/org/keycloak/testsuite/adapter/EAPOIDCPublicKeyRotationAdapterTest.java b/testsuite/integration-arquillian/tests/other/adapters/jboss/eap/src/test/java/org/keycloak/testsuite/adapter/EAPOIDCPublicKeyRotationAdapterTest.java
new file mode 100644
index 0000000..df936d8
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/other/adapters/jboss/eap/src/test/java/org/keycloak/testsuite/adapter/EAPOIDCPublicKeyRotationAdapterTest.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2016 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;
+
+import org.keycloak.testsuite.adapter.servlet.AbstractOIDCPublicKeyRotationAdapterTest;
+import org.keycloak.testsuite.arquillian.annotation.AppServerContainer;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+@AppServerContainer("app-server-eap")
+public class EAPOIDCPublicKeyRotationAdapterTest extends AbstractOIDCPublicKeyRotationAdapterTest {
+}
diff --git a/testsuite/integration-arquillian/tests/other/adapters/jboss/eap6/src/test/java/org/keycloak/testsuite/adapter/EAP6OIDCPublicKeyRotationAdapterTest.java b/testsuite/integration-arquillian/tests/other/adapters/jboss/eap6/src/test/java/org/keycloak/testsuite/adapter/EAP6OIDCPublicKeyRotationAdapterTest.java
new file mode 100644
index 0000000..607ead8
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/other/adapters/jboss/eap6/src/test/java/org/keycloak/testsuite/adapter/EAP6OIDCPublicKeyRotationAdapterTest.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2016 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;
+
+import org.keycloak.testsuite.adapter.servlet.AbstractOIDCPublicKeyRotationAdapterTest;
+import org.keycloak.testsuite.arquillian.annotation.AppServerContainer;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+@AppServerContainer("app-server-eap6")
+public class EAP6OIDCPublicKeyRotationAdapterTest extends AbstractOIDCPublicKeyRotationAdapterTest {
+}
diff --git a/testsuite/integration-arquillian/tests/other/adapters/jboss/wildfly/src/test/java/org/keycloak/testsuite/adapter/WildflyOIDCPublicKeyRotationAdapterTest.java b/testsuite/integration-arquillian/tests/other/adapters/jboss/wildfly/src/test/java/org/keycloak/testsuite/adapter/WildflyOIDCPublicKeyRotationAdapterTest.java
new file mode 100644
index 0000000..d54889b
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/other/adapters/jboss/wildfly/src/test/java/org/keycloak/testsuite/adapter/WildflyOIDCPublicKeyRotationAdapterTest.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2016 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;
+
+import org.keycloak.testsuite.adapter.servlet.AbstractOIDCPublicKeyRotationAdapterTest;
+import org.keycloak.testsuite.arquillian.annotation.AppServerContainer;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+@AppServerContainer("app-server-wildfly")
+public class WildflyOIDCPublicKeyRotationAdapterTest extends AbstractOIDCPublicKeyRotationAdapterTest {
+}
diff --git a/testsuite/integration-arquillian/tests/other/adapters/jboss/wildfly8/src/test/java/org/keycloak/testsuite/adapter/Wildfly8OIDCPublicKeyRotationAdapterTest.java b/testsuite/integration-arquillian/tests/other/adapters/jboss/wildfly8/src/test/java/org/keycloak/testsuite/adapter/Wildfly8OIDCPublicKeyRotationAdapterTest.java
new file mode 100644
index 0000000..0cad5fc
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/other/adapters/jboss/wildfly8/src/test/java/org/keycloak/testsuite/adapter/Wildfly8OIDCPublicKeyRotationAdapterTest.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2016 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;
+
+import org.keycloak.testsuite.adapter.servlet.AbstractOIDCPublicKeyRotationAdapterTest;
+import org.keycloak.testsuite.arquillian.annotation.AppServerContainer;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+@AppServerContainer("app-server-wildfly8")
+public class Wildfly8OIDCPublicKeyRotationAdapterTest extends AbstractOIDCPublicKeyRotationAdapterTest {
+}
diff --git a/testsuite/integration-arquillian/tests/other/adapters/jboss/wildfly9/src/test/java/org/keycloak/testsuite/adapter/Wildfly9OIDCPublicKeyRotationAdapterTest.java b/testsuite/integration-arquillian/tests/other/adapters/jboss/wildfly9/src/test/java/org/keycloak/testsuite/adapter/Wildfly9OIDCPublicKeyRotationAdapterTest.java
new file mode 100644
index 0000000..a1b8118
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/other/adapters/jboss/wildfly9/src/test/java/org/keycloak/testsuite/adapter/Wildfly9OIDCPublicKeyRotationAdapterTest.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2016 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;
+
+import org.keycloak.testsuite.adapter.servlet.AbstractOIDCPublicKeyRotationAdapterTest;
+import org.keycloak.testsuite.arquillian.annotation.AppServerContainer;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+@AppServerContainer("app-server-wildfly9")
+public class Wildfly9OIDCPublicKeyRotationAdapterTest extends AbstractOIDCPublicKeyRotationAdapterTest {
+}