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 63ea79e65b..0b33294ff5 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 3e0f36dee7..b7877964a0 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 1071b710fc..3f98a68411 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 f6c6f5ea12..85b19ca538 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 9305f32a49..45f420c1f7 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 77eb475bf6..233c1ed2f0 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 a8afd22cf2..9f0a204826 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 0ba327d733..e4065bcd05 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 9d299734b0..bdbd4d92ce 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 { @@ -61,7 +61,7 @@ public class KeycloakOnUndertow implements DeployableContainer deployedArchivesToContextPath = new HashMap<>(); + Map 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 1bfbb3e0ce..3b3cc4997f 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 370717210c..6db5922cc1 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("" + accessTokenPretty + "") .append("" + refreshTokenPretty + "") + .append("" + ctx.getTokenString() + "") .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 ea7ef6fe48..64d0de2eb7 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 a40275f727..cc018d2267 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 0ad81d501b..a9ce39a16d 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 f57b858bdf..fde26a1514 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) @@ -217,97 +211,6 @@ public abstract class AbstractDemoServletsAdapterTest extends AbstractServletsAd client.close(); } - @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 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 0000000000..d9116ce4f4 --- /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 Marek Posolda + */ +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 0000000000..0dfd99c996 --- /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 Marek Posolda + */ +@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 362017077b..400fac3871 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 cebfe6f5e5..56ed0e725a 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 @@ customer-db + + + AdapterActionsFilter + org.keycloak.testsuite.adapter.filter.AdapterActionsFilter + + Servlet org.keycloak.testsuite.adapter.servlet.CustomerDatabaseServlet + + AdapterActionsFilter + /* + + Servlet /* @@ -42,6 +53,12 @@ user + + + Unsecured + /unsecured/* + + KEYCLOAK 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 d65fa94847..b1f70e2738 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 @@ -117,6 +117,13 @@ ], "clients": [ + { + "clientId": "customer-db", + "enabled": true, + "adminUrl": "/customer-db", + "baseUrl": "/customer-db", + "bearerOnly": true + }, { "clientId": "customer-portal", "enabled": true, 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 de290de301..f3fa1a59f0 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 0000000000..50cc0e9046 --- /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 Marek Posolda + */ +@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 0000000000..df936d8cce --- /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 Marek Posolda + */ +@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 0000000000..607ead848a --- /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 Marek Posolda + */ +@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 0000000000..d54889be07 --- /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 Marek Posolda + */ +@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 0000000000..0cad5fcfda --- /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 Marek Posolda + */ +@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 0000000000..a1b8118ef5 --- /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 Marek Posolda + */ +@AppServerContainer("app-server-wildfly9") +public class Wildfly9OIDCPublicKeyRotationAdapterTest extends AbstractOIDCPublicKeyRotationAdapterTest { +}