diff --git a/.gitignore b/.gitignore
index bf5d094f0c..443e12ad50 100644
--- a/.gitignore
+++ b/.gitignore
@@ -52,4 +52,6 @@ target
# nodejs #
##########
-node_modules
\ No newline at end of file
+# KEYCLOAK-5391: We will re-exclude node_modules when node_modules handling is worked out.
+# For now, we keep our js libraries checked into GitHub, so we don't ignore.
+#node_modules
\ No newline at end of file
diff --git a/README.md b/README.md
index c2efec51d5..3fafffc670 100755
--- a/README.md
+++ b/README.md
@@ -38,7 +38,7 @@ Starting Keycloak
To start Keycloak during development first build as specified above, then run:
- mvn -f testsuite/integration/pom.xml exec:java -Pkeycloak-server
+ mvn -f testsuite/utils/pom.xml exec:java -Pkeycloak-server
To start Keycloak from the server distribution first build the distribution it as specified above, then run:
diff --git a/adapters/oidc/adapter-core/pom.xml b/adapters/oidc/adapter-core/pom.xml
index a2f5b5bcff..431032105d 100755
--- a/adapters/oidc/adapter-core/pom.xml
+++ b/adapters/oidc/adapter-core/pom.xml
@@ -21,7 +21,7 @@
keycloak-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
../../../pom.xml
4.0.0
diff --git a/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/BearerTokenRequestAuthenticator.java b/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/BearerTokenRequestAuthenticator.java
index 5eed432920..fd4544f637 100755
--- a/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/BearerTokenRequestAuthenticator.java
+++ b/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/BearerTokenRequestAuthenticator.java
@@ -164,7 +164,12 @@ public class BearerTokenRequestAuthenticator {
OIDCAuthenticationError error = new OIDCAuthenticationError(reason, description);
facade.getRequest().setError(error);
facade.getResponse().addHeader("WWW-Authenticate", challenge);
- facade.getResponse().sendError(401);
+ if(deployment.isDelegateBearerErrorResponseSending()){
+ facade.getResponse().setStatus(401);
+ }
+ else {
+ facade.getResponse().sendError(401);
+ }
return true;
}
};
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 d5761bcf1a..707b882220 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
@@ -94,6 +94,8 @@ public class KeycloakDeployment {
protected Map redirectRewriteRules;
+ protected boolean delegateBearerErrorResponseSending = false;
+
public KeycloakDeployment() {
}
@@ -456,6 +458,12 @@ public class KeycloakDeployment {
public void setRewriteRedirectRules(Map redirectRewriteRules) {
this.redirectRewriteRules = redirectRewriteRules;
}
-
-
+
+ public boolean isDelegateBearerErrorResponseSending() {
+ return delegateBearerErrorResponseSending;
+ }
+
+ public void setDelegateBearerErrorResponseSending(boolean delegateBearerErrorResponseSending) {
+ this.delegateBearerErrorResponseSending = delegateBearerErrorResponseSending;
+ }
}
diff --git a/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/OAuthRequestAuthenticator.java b/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/OAuthRequestAuthenticator.java
index ee3f214e24..8d875ee4eb 100755
--- a/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/OAuthRequestAuthenticator.java
+++ b/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/OAuthRequestAuthenticator.java
@@ -331,7 +331,7 @@ public class OAuthRequestAuthenticator {
} catch (ServerRequest.HttpFailure failure) {
log.error("failed to turn code into token");
log.error("status from server: " + failure.getStatus());
- if (failure.getStatus() == 400 && failure.getError() != null) {
+ if (failure.getError() != null) {
log.error(" " + failure.getError());
}
return challenge(403, OIDCAuthenticationError.Reason.CODE_TO_TOKEN_FAILURE, null);
diff --git a/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/authorization/PathMatcher.java b/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/authorization/PathMatcher.java
index 9efa614573..c8bce94592 100644
--- a/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/authorization/PathMatcher.java
+++ b/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/authorization/PathMatcher.java
@@ -89,7 +89,7 @@ class PathMatcher {
pathString = "/";
}
- if (matchingUri.equals(targetUri)) {
+ if (matchingUri.equals(targetUri) || pathString.equals(targetUri)) {
cache.put(targetUri, entry);
return entry;
}
diff --git a/adapters/oidc/as7-eap6/as7-adapter-spi/pom.xml b/adapters/oidc/as7-eap6/as7-adapter-spi/pom.xml
index 89faf8b97b..9e5887acc0 100755
--- a/adapters/oidc/as7-eap6/as7-adapter-spi/pom.xml
+++ b/adapters/oidc/as7-eap6/as7-adapter-spi/pom.xml
@@ -21,7 +21,7 @@
keycloak-as7-integration-pom
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
../pom.xml
4.0.0
diff --git a/adapters/oidc/as7-eap6/as7-adapter/pom.xml b/adapters/oidc/as7-eap6/as7-adapter/pom.xml
index 47e344f914..d187857cdf 100755
--- a/adapters/oidc/as7-eap6/as7-adapter/pom.xml
+++ b/adapters/oidc/as7-eap6/as7-adapter/pom.xml
@@ -21,7 +21,7 @@
keycloak-as7-integration-pom
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
../pom.xml
4.0.0
diff --git a/adapters/oidc/as7-eap6/as7-adapter/src/main/java/org/keycloak/adapters/jbossweb/AuthenticatedActionsValve.java b/adapters/oidc/as7-eap6/as7-adapter/src/main/java/org/keycloak/adapters/jbossweb/AuthenticatedActionsValve.java
new file mode 100644
index 0000000000..a8b800f38b
--- /dev/null
+++ b/adapters/oidc/as7-eap6/as7-adapter/src/main/java/org/keycloak/adapters/jbossweb/AuthenticatedActionsValve.java
@@ -0,0 +1,13 @@
+package org.keycloak.adapters.jbossweb;
+
+import org.apache.catalina.Container;
+import org.apache.catalina.Valve;
+import org.keycloak.adapters.AdapterDeploymentContext;
+import org.keycloak.adapters.tomcat.AbstractAuthenticatedActionsValve;
+
+public class AuthenticatedActionsValve extends AbstractAuthenticatedActionsValve {
+
+ public AuthenticatedActionsValve(AdapterDeploymentContext deploymentContext, Valve next, Container container) {
+ super(deploymentContext, next, container);
+ }
+}
diff --git a/adapters/oidc/as7-eap6/as7-adapter/src/main/java/org/keycloak/adapters/jbossweb/KeycloakAuthenticatorValve.java b/adapters/oidc/as7-eap6/as7-adapter/src/main/java/org/keycloak/adapters/jbossweb/KeycloakAuthenticatorValve.java
index 72088b3b7d..6a79f0b45c 100755
--- a/adapters/oidc/as7-eap6/as7-adapter/src/main/java/org/keycloak/adapters/jbossweb/KeycloakAuthenticatorValve.java
+++ b/adapters/oidc/as7-eap6/as7-adapter/src/main/java/org/keycloak/adapters/jbossweb/KeycloakAuthenticatorValve.java
@@ -17,11 +17,15 @@
package org.keycloak.adapters.jbossweb;
+import org.apache.catalina.Container;
import org.apache.catalina.LifecycleException;
+import org.apache.catalina.Valve;
import org.apache.catalina.connector.Request;
import org.apache.catalina.connector.Response;
import org.apache.catalina.core.StandardContext;
import org.apache.catalina.deploy.LoginConfig;
+import org.keycloak.adapters.AdapterDeploymentContext;
+import org.keycloak.adapters.tomcat.AbstractAuthenticatedActionsValve;
import org.keycloak.adapters.tomcat.AbstractKeycloakAuthenticatorValve;
import org.keycloak.adapters.tomcat.GenericPrincipalFactory;
@@ -56,7 +60,6 @@ public class KeycloakAuthenticatorValve extends AbstractKeycloakAuthenticatorVal
super.start();
}
-
public void logout(Request request) {
logoutInternal(request);
}
@@ -65,4 +68,9 @@ public class KeycloakAuthenticatorValve extends AbstractKeycloakAuthenticatorVal
protected GenericPrincipalFactory createPrincipalFactory() {
return new JBossWebPrincipalFactory();
}
+
+ @Override
+ protected AbstractAuthenticatedActionsValve createAuthenticatedActionsValve(AdapterDeploymentContext deploymentContext, Valve next, Container container) {
+ return new AuthenticatedActionsValve(deploymentContext, next, container);
+ }
}
diff --git a/adapters/oidc/as7-eap6/as7-subsystem/pom.xml b/adapters/oidc/as7-eap6/as7-subsystem/pom.xml
index 5a2d24e3e9..2bdce7028d 100755
--- a/adapters/oidc/as7-eap6/as7-subsystem/pom.xml
+++ b/adapters/oidc/as7-eap6/as7-subsystem/pom.xml
@@ -21,7 +21,7 @@
org.keycloak
keycloak-as7-integration-pom
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
../pom.xml
diff --git a/adapters/oidc/as7-eap6/pom.xml b/adapters/oidc/as7-eap6/pom.xml
index 4b5a4272ec..72cada7a54 100755
--- a/adapters/oidc/as7-eap6/pom.xml
+++ b/adapters/oidc/as7-eap6/pom.xml
@@ -20,7 +20,7 @@
keycloak-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
../../../pom.xml
Keycloak AS7 / JBoss EAP 6 Integration
diff --git a/adapters/oidc/cli-sso/pom.xml b/adapters/oidc/cli-sso/pom.xml
index 216c3b794e..79b7f341c1 100755
--- a/adapters/oidc/cli-sso/pom.xml
+++ b/adapters/oidc/cli-sso/pom.xml
@@ -21,7 +21,7 @@
keycloak-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
../../../pom.xml
4.0.0
diff --git a/adapters/oidc/installed/pom.xml b/adapters/oidc/installed/pom.xml
index 3c14afa2de..d64b950209 100755
--- a/adapters/oidc/installed/pom.xml
+++ b/adapters/oidc/installed/pom.xml
@@ -21,7 +21,7 @@
keycloak-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
../../../pom.xml
4.0.0
diff --git a/adapters/oidc/jaxrs-oauth-client/pom.xml b/adapters/oidc/jaxrs-oauth-client/pom.xml
index 6f46e7c9cc..44cd9e686f 100755
--- a/adapters/oidc/jaxrs-oauth-client/pom.xml
+++ b/adapters/oidc/jaxrs-oauth-client/pom.xml
@@ -21,7 +21,7 @@
keycloak-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
../../../pom.xml
4.0.0
diff --git a/adapters/oidc/jetty/jetty-core/pom.xml b/adapters/oidc/jetty/jetty-core/pom.xml
index 3ee1c5e155..1a771e40b7 100755
--- a/adapters/oidc/jetty/jetty-core/pom.xml
+++ b/adapters/oidc/jetty/jetty-core/pom.xml
@@ -21,7 +21,7 @@
keycloak-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
../../../../pom.xml
4.0.0
diff --git a/adapters/oidc/jetty/jetty8.1/pom.xml b/adapters/oidc/jetty/jetty8.1/pom.xml
index 312475509b..74f86af7f9 100755
--- a/adapters/oidc/jetty/jetty8.1/pom.xml
+++ b/adapters/oidc/jetty/jetty8.1/pom.xml
@@ -21,7 +21,7 @@
keycloak-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
../../../../pom.xml
4.0.0
diff --git a/adapters/oidc/jetty/jetty9.1/pom.xml b/adapters/oidc/jetty/jetty9.1/pom.xml
index c5a4784711..e8957b17e8 100755
--- a/adapters/oidc/jetty/jetty9.1/pom.xml
+++ b/adapters/oidc/jetty/jetty9.1/pom.xml
@@ -21,7 +21,7 @@
keycloak-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
../../../../pom.xml
4.0.0
diff --git a/adapters/oidc/jetty/jetty9.2/pom.xml b/adapters/oidc/jetty/jetty9.2/pom.xml
index f8b6335404..b2e4796dd9 100755
--- a/adapters/oidc/jetty/jetty9.2/pom.xml
+++ b/adapters/oidc/jetty/jetty9.2/pom.xml
@@ -21,7 +21,7 @@
keycloak-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
../../../../pom.xml
4.0.0
diff --git a/adapters/oidc/jetty/jetty9.3/pom.xml b/adapters/oidc/jetty/jetty9.3/pom.xml
index c4cb37489a..04c9ae11a1 100644
--- a/adapters/oidc/jetty/jetty9.3/pom.xml
+++ b/adapters/oidc/jetty/jetty9.3/pom.xml
@@ -21,7 +21,7 @@
keycloak-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
../../../../pom.xml
4.0.0
diff --git a/adapters/oidc/jetty/jetty9.4/pom.xml b/adapters/oidc/jetty/jetty9.4/pom.xml
index acb36c6bcc..13fc4cdc08 100644
--- a/adapters/oidc/jetty/jetty9.4/pom.xml
+++ b/adapters/oidc/jetty/jetty9.4/pom.xml
@@ -21,7 +21,7 @@
keycloak-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
../../../../pom.xml
4.0.0
diff --git a/adapters/oidc/jetty/pom.xml b/adapters/oidc/jetty/pom.xml
index 5ec0c168b1..8556e6bc2c 100755
--- a/adapters/oidc/jetty/pom.xml
+++ b/adapters/oidc/jetty/pom.xml
@@ -20,7 +20,7 @@
keycloak-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
../../../pom.xml
Keycloak Jetty Integration
diff --git a/adapters/oidc/js/pom.xml b/adapters/oidc/js/pom.xml
index 8b4cc6789c..e4d866f801 100755
--- a/adapters/oidc/js/pom.xml
+++ b/adapters/oidc/js/pom.xml
@@ -21,7 +21,7 @@
keycloak-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
../../../pom.xml
4.0.0
@@ -38,6 +38,11 @@
com.samaxes.maven
minify-maven-plugin
+
+ CLOSURE
+ ECMASCRIPT5
+ true
+
min-js
diff --git a/adapters/oidc/js/src/main/resources/keycloak.js b/adapters/oidc/js/src/main/resources/keycloak.js
index a784936c78..ab6f78826a 100755
--- a/adapters/oidc/js/src/main/resources/keycloak.js
+++ b/adapters/oidc/js/src/main/resources/keycloak.js
@@ -221,7 +221,7 @@
var callbackState = {
state: state,
nonce: nonce,
- redirectUri: encodeURIComponent(redirectUri),
+ redirectUri: encodeURIComponent(redirectUri)
}
if (options && options.prompt) {
@@ -843,6 +843,7 @@
}
iframe.setAttribute('src', src );
+ iframe.setAttribute('title', 'keycloak-session-iframe' );
iframe.style.display = 'none';
document.body.appendChild(iframe);
diff --git a/adapters/oidc/osgi-adapter/pom.xml b/adapters/oidc/osgi-adapter/pom.xml
index 26a90ec487..537bcb2b44 100755
--- a/adapters/oidc/osgi-adapter/pom.xml
+++ b/adapters/oidc/osgi-adapter/pom.xml
@@ -21,7 +21,7 @@
keycloak-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
../../../pom.xml
4.0.0
diff --git a/adapters/oidc/pom.xml b/adapters/oidc/pom.xml
index 9207401a1c..28f243b704 100755
--- a/adapters/oidc/pom.xml
+++ b/adapters/oidc/pom.xml
@@ -20,7 +20,7 @@
keycloak-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
../../pom.xml
Keycloak OIDC Client Adapter Modules
diff --git a/adapters/oidc/servlet-filter/pom.xml b/adapters/oidc/servlet-filter/pom.xml
index 3d81dc7322..7e5bdcdee7 100755
--- a/adapters/oidc/servlet-filter/pom.xml
+++ b/adapters/oidc/servlet-filter/pom.xml
@@ -21,7 +21,7 @@
keycloak-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
../../../pom.xml
4.0.0
diff --git a/adapters/oidc/servlet-oauth-client/pom.xml b/adapters/oidc/servlet-oauth-client/pom.xml
index bb709f1dc2..a5b25f08ac 100755
--- a/adapters/oidc/servlet-oauth-client/pom.xml
+++ b/adapters/oidc/servlet-oauth-client/pom.xml
@@ -21,7 +21,7 @@
keycloak-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
../../../pom.xml
4.0.0
diff --git a/adapters/oidc/spring-boot-container-bundle/pom.xml b/adapters/oidc/spring-boot-container-bundle/pom.xml
index 49cab4ebe0..0b3d3c5e01 100644
--- a/adapters/oidc/spring-boot-container-bundle/pom.xml
+++ b/adapters/oidc/spring-boot-container-bundle/pom.xml
@@ -4,7 +4,7 @@
keycloak-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
../../../pom.xml
spring-boot-container-bundle
diff --git a/adapters/oidc/spring-boot/pom.xml b/adapters/oidc/spring-boot/pom.xml
index 6a720f65a5..c29a8d3f59 100755
--- a/adapters/oidc/spring-boot/pom.xml
+++ b/adapters/oidc/spring-boot/pom.xml
@@ -21,7 +21,7 @@
keycloak-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
../../../pom.xml
4.0.0
@@ -31,7 +31,9 @@
- 1.3.0.RELEASE
+ 1.4.0.RELEASE
+ 4.1.6.RELEASE
+ 1.9.5
@@ -98,7 +100,19 @@
junit
test
-
+
+ org.springframework
+ spring-test
+ ${spring.version}
+ test
+
+
+ org.mockito
+ mockito-all
+ ${mockito.version}
+ test
+
+
org.springframework.boot
spring-boot-configuration-processor
true
diff --git a/adapters/oidc/spring-boot/src/main/java/org/keycloak/adapters/springboot/client/KeycloakRestTemplateCustomizer.java b/adapters/oidc/spring-boot/src/main/java/org/keycloak/adapters/springboot/client/KeycloakRestTemplateCustomizer.java
new file mode 100644
index 0000000000..ae4836c713
--- /dev/null
+++ b/adapters/oidc/spring-boot/src/main/java/org/keycloak/adapters/springboot/client/KeycloakRestTemplateCustomizer.java
@@ -0,0 +1,24 @@
+package org.keycloak.adapters.springboot.client;
+
+import org.springframework.boot.web.client.RestTemplateCustomizer;
+import org.springframework.web.client.RestTemplate;
+
+public class KeycloakRestTemplateCustomizer implements RestTemplateCustomizer {
+
+ private final KeycloakSecurityContextClientRequestInterceptor keycloakInterceptor;
+
+ public KeycloakRestTemplateCustomizer() {
+ this(new KeycloakSecurityContextClientRequestInterceptor());
+ }
+
+ protected KeycloakRestTemplateCustomizer(
+ KeycloakSecurityContextClientRequestInterceptor keycloakInterceptor
+ ) {
+ this.keycloakInterceptor = keycloakInterceptor;
+ }
+
+ @Override
+ public void customize(RestTemplate restTemplate) {
+ restTemplate.getInterceptors().add(keycloakInterceptor);
+ }
+}
diff --git a/adapters/oidc/spring-boot/src/main/java/org/keycloak/adapters/springboot/client/KeycloakSecurityContextClientRequestInterceptor.java b/adapters/oidc/spring-boot/src/main/java/org/keycloak/adapters/springboot/client/KeycloakSecurityContextClientRequestInterceptor.java
new file mode 100644
index 0000000000..200a9035f1
--- /dev/null
+++ b/adapters/oidc/spring-boot/src/main/java/org/keycloak/adapters/springboot/client/KeycloakSecurityContextClientRequestInterceptor.java
@@ -0,0 +1,55 @@
+package org.keycloak.adapters.springboot.client;
+
+import org.keycloak.KeycloakPrincipal;
+import org.keycloak.KeycloakSecurityContext;
+import org.springframework.http.HttpRequest;
+import org.springframework.http.client.ClientHttpRequestExecution;
+import org.springframework.http.client.ClientHttpRequestInterceptor;
+import org.springframework.http.client.ClientHttpResponse;
+import org.springframework.web.context.request.RequestContextHolder;
+import org.springframework.web.context.request.ServletRequestAttributes;
+
+import java.io.IOException;
+import java.security.Principal;
+
+/**
+ * Interceptor for {@link ClientHttpRequestExecution} objects created for server to server secured
+ * communication using OAuth2 bearer tokens issued by Keycloak.
+ *
+ * @author James McShane
+ * @version $Revision: 1 $
+ */
+public class KeycloakSecurityContextClientRequestInterceptor implements ClientHttpRequestInterceptor {
+
+ private static final String AUTHORIZATION_HEADER = "Authorization";
+
+ /**
+ * Returns the {@link KeycloakSecurityContext} from the Spring {@link ServletRequestAttributes}'s {@link Principal}.
+ *
+ * The principal must support retrieval of the KeycloakSecurityContext, so at this point, only {@link KeycloakPrincipal}
+ * values are supported
+ *
+ * @return the current KeycloakSecurityContext
+ */
+ protected KeycloakSecurityContext getKeycloakSecurityContext() {
+ ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
+ Principal principal = attributes.getRequest().getUserPrincipal();
+ if (principal == null) {
+ throw new IllegalStateException("Cannot set authorization header because there is no authenticated principal");
+ }
+ if (!(principal instanceof KeycloakPrincipal)) {
+ throw new IllegalStateException(
+ String.format(
+ "Cannot set authorization header because the principal type %s does not provide the KeycloakSecurityContext",
+ principal.getClass()));
+ }
+ return ((KeycloakPrincipal) principal).getKeycloakSecurityContext();
+ }
+
+ @Override
+ public ClientHttpResponse intercept(HttpRequest httpRequest, byte[] bytes, ClientHttpRequestExecution clientHttpRequestExecution) throws IOException {
+ KeycloakSecurityContext context = this.getKeycloakSecurityContext();
+ httpRequest.getHeaders().set(AUTHORIZATION_HEADER, "Bearer " + context.getTokenString());
+ return clientHttpRequestExecution.execute(httpRequest, bytes);
+ }
+}
diff --git a/adapters/oidc/spring-boot/src/test/java/org/keycloak/adapters/springboot/client/KeycloakRestTemplateCustomizerTest.java b/adapters/oidc/spring-boot/src/test/java/org/keycloak/adapters/springboot/client/KeycloakRestTemplateCustomizerTest.java
new file mode 100644
index 0000000000..e8e599e40d
--- /dev/null
+++ b/adapters/oidc/spring-boot/src/test/java/org/keycloak/adapters/springboot/client/KeycloakRestTemplateCustomizerTest.java
@@ -0,0 +1,28 @@
+package org.keycloak.adapters.springboot.client;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.springframework.web.client.RestTemplate;
+
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+
+public class KeycloakRestTemplateCustomizerTest {
+
+ private KeycloakRestTemplateCustomizer customizer;
+ private KeycloakSecurityContextClientRequestInterceptor interceptor =
+ mock(KeycloakSecurityContextClientRequestInterceptor.class);
+
+ @Before
+ public void setup() {
+ customizer = new KeycloakRestTemplateCustomizer(interceptor);
+ }
+
+ @Test
+ public void interceptorIsAddedToRequest() {
+ RestTemplate restTemplate = new RestTemplate();
+ customizer.customize(restTemplate);
+ assertTrue(restTemplate.getInterceptors().contains(interceptor));
+ }
+
+}
diff --git a/adapters/oidc/spring-boot/src/test/java/org/keycloak/adapters/springboot/client/KeycloakSecurityContextClientRequestInterceptorTest.java b/adapters/oidc/spring-boot/src/test/java/org/keycloak/adapters/springboot/client/KeycloakSecurityContextClientRequestInterceptorTest.java
new file mode 100644
index 0000000000..689cc65274
--- /dev/null
+++ b/adapters/oidc/spring-boot/src/test/java/org/keycloak/adapters/springboot/client/KeycloakSecurityContextClientRequestInterceptorTest.java
@@ -0,0 +1,87 @@
+/*
+ * 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.adapters.springboot.client;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.keycloak.KeycloakPrincipal;
+import org.keycloak.KeycloakSecurityContext;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.mockito.Spy;
+import org.springframework.mock.web.MockHttpServletRequest;
+import org.springframework.web.context.request.RequestContextHolder;
+import org.springframework.web.context.request.ServletRequestAttributes;
+
+import java.security.Principal;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.mockito.Mockito.when;
+
+/**
+ * Keycloak spring boot client request factory tests.
+ */
+public class KeycloakSecurityContextClientRequestInterceptorTest {
+
+ @Spy
+ private KeycloakSecurityContextClientRequestInterceptor factory;
+
+ private MockHttpServletRequest servletRequest;
+
+ @Mock
+ private KeycloakSecurityContext keycloakSecurityContext;
+
+ @Mock
+ private KeycloakPrincipal keycloakPrincipal;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ servletRequest = new MockHttpServletRequest();
+ RequestContextHolder.setRequestAttributes(new ServletRequestAttributes(servletRequest));
+ servletRequest.setUserPrincipal(keycloakPrincipal);
+ when(keycloakPrincipal.getKeycloakSecurityContext()).thenReturn(keycloakSecurityContext);
+ }
+
+ @Test
+ public void testGetKeycloakSecurityContext() throws Exception {
+ KeycloakSecurityContext context = factory.getKeycloakSecurityContext();
+ assertNotNull(context);
+ assertEquals(keycloakSecurityContext, context);
+ }
+
+ @Test(expected = IllegalStateException.class)
+ public void testGetKeycloakSecurityContextInvalidPrincipal() throws Exception {
+ servletRequest.setUserPrincipal(new MarkerPrincipal());
+ factory.getKeycloakSecurityContext();
+ }
+
+ @Test(expected = IllegalStateException.class)
+ public void testGetKeycloakSecurityContextNullAuthentication() throws Exception {
+ servletRequest.setUserPrincipal(null);
+ factory.getKeycloakSecurityContext();
+ }
+
+ private static class MarkerPrincipal implements Principal {
+ @Override
+ public String getName() {
+ return null;
+ }
+ }
+}
diff --git a/adapters/oidc/spring-security/pom.xml b/adapters/oidc/spring-security/pom.xml
index b304cd5b0d..008f38899b 100755
--- a/adapters/oidc/spring-security/pom.xml
+++ b/adapters/oidc/spring-security/pom.xml
@@ -21,7 +21,7 @@
keycloak-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
../../../pom.xml
4.0.0
diff --git a/adapters/oidc/spring-security/src/main/java/org/keycloak/adapters/springsecurity/filter/KeycloakAuthenticationProcessingFilter.java b/adapters/oidc/spring-security/src/main/java/org/keycloak/adapters/springsecurity/filter/KeycloakAuthenticationProcessingFilter.java
index 7e235ae520..2e9ef40f6d 100644
--- a/adapters/oidc/spring-security/src/main/java/org/keycloak/adapters/springsecurity/filter/KeycloakAuthenticationProcessingFilter.java
+++ b/adapters/oidc/spring-security/src/main/java/org/keycloak/adapters/springsecurity/filter/KeycloakAuthenticationProcessingFilter.java
@@ -134,6 +134,10 @@ public class KeycloakAuthenticationProcessingFilter extends AbstractAuthenticati
HttpFacade facade = new SimpleHttpFacade(request, response);
KeycloakDeployment deployment = adapterDeploymentContext.resolveDeployment(facade);
+
+ // using Spring authenticationFailureHandler
+ deployment.setDelegateBearerErrorResponseSending(true);
+
AdapterTokenStore tokenStore = adapterTokenStoreFactory.createAdapterTokenStore(deployment, request);
RequestAuthenticator authenticator
= new SpringSecurityRequestAuthenticator(facade, request, deployment, tokenStore, -1);
diff --git a/adapters/oidc/tomcat/pom.xml b/adapters/oidc/tomcat/pom.xml
index d733dbd699..4c33882cdb 100755
--- a/adapters/oidc/tomcat/pom.xml
+++ b/adapters/oidc/tomcat/pom.xml
@@ -20,7 +20,7 @@
keycloak-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
../../../pom.xml
Keycloak Tomcat Integration
diff --git a/adapters/oidc/tomcat/tomcat-core/pom.xml b/adapters/oidc/tomcat/tomcat-core/pom.xml
index c47cc4dde9..154bed1ca6 100755
--- a/adapters/oidc/tomcat/tomcat-core/pom.xml
+++ b/adapters/oidc/tomcat/tomcat-core/pom.xml
@@ -21,7 +21,7 @@
keycloak-tomcat-integration-pom
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
../pom.xml
4.0.0
diff --git a/adapters/oidc/tomcat/tomcat-core/src/main/java/org/keycloak/adapters/tomcat/AuthenticatedActionsValve.java b/adapters/oidc/tomcat/tomcat-core/src/main/java/org/keycloak/adapters/tomcat/AbstractAuthenticatedActionsValve.java
old mode 100755
new mode 100644
similarity index 86%
rename from adapters/oidc/tomcat/tomcat-core/src/main/java/org/keycloak/adapters/tomcat/AuthenticatedActionsValve.java
rename to adapters/oidc/tomcat/tomcat-core/src/main/java/org/keycloak/adapters/tomcat/AbstractAuthenticatedActionsValve.java
index 69e993c80e..123c2ec0aa
--- a/adapters/oidc/tomcat/tomcat-core/src/main/java/org/keycloak/adapters/tomcat/AuthenticatedActionsValve.java
+++ b/adapters/oidc/tomcat/tomcat-core/src/main/java/org/keycloak/adapters/tomcat/AbstractAuthenticatedActionsValve.java
@@ -31,7 +31,7 @@ import javax.servlet.ServletException;
import java.io.IOException;
/**
- * Pre-installed actions that must be authenticated
+ * Abstract base for pre-installed actions that must be authenticated
*
* Actions include:
*
@@ -41,18 +41,17 @@ import java.io.IOException;
* @author Bill Burke
* @version $Revision: 1 $
*/
-public class AuthenticatedActionsValve extends ValveBase {
- private static final Logger log = Logger.getLogger(AuthenticatedActionsValve.class);
+public abstract class AbstractAuthenticatedActionsValve extends ValveBase {
+ private static final Logger log = Logger.getLogger(AbstractAuthenticatedActionsValve.class);
protected AdapterDeploymentContext deploymentContext;
- public AuthenticatedActionsValve(AdapterDeploymentContext deploymentContext, Valve next, Container container) {
+ public AbstractAuthenticatedActionsValve(AdapterDeploymentContext deploymentContext, Valve next, Container container) {
this.deploymentContext = deploymentContext;
if (next == null) throw new RuntimeException("Next valve is null!!!");
setNext(next);
setContainer(container);
}
-
@Override
public void invoke(Request request, Response response) throws IOException, ServletException {
log.debugv("AuthenticatedActionsValve.invoke {0}", request.getRequestURI());
diff --git a/adapters/oidc/tomcat/tomcat-core/src/main/java/org/keycloak/adapters/tomcat/AbstractKeycloakAuthenticatorValve.java b/adapters/oidc/tomcat/tomcat-core/src/main/java/org/keycloak/adapters/tomcat/AbstractKeycloakAuthenticatorValve.java
index 703709371c..7356fe5de1 100755
--- a/adapters/oidc/tomcat/tomcat-core/src/main/java/org/keycloak/adapters/tomcat/AbstractKeycloakAuthenticatorValve.java
+++ b/adapters/oidc/tomcat/tomcat-core/src/main/java/org/keycloak/adapters/tomcat/AbstractKeycloakAuthenticatorValve.java
@@ -17,11 +17,7 @@
package org.keycloak.adapters.tomcat;
-import org.apache.catalina.Context;
-import org.apache.catalina.Lifecycle;
-import org.apache.catalina.LifecycleEvent;
-import org.apache.catalina.LifecycleListener;
-import org.apache.catalina.Manager;
+import org.apache.catalina.*;
import org.apache.catalina.authenticator.FormAuthenticator;
import org.apache.catalina.connector.Request;
import org.apache.catalina.connector.Response;
@@ -136,7 +132,7 @@ public abstract class AbstractKeycloakAuthenticatorValve extends FormAuthenticat
}
context.getServletContext().setAttribute(AdapterDeploymentContext.class.getName(), deploymentContext);
- AuthenticatedActionsValve actions = new AuthenticatedActionsValve(deploymentContext, getNext(), getContainer());
+ AbstractAuthenticatedActionsValve actions = createAuthenticatedActionsValve(deploymentContext, getNext(), getContainer());
setNext(actions);
nodesRegistrationManagement = new NodesRegistrationManagement();
@@ -189,6 +185,7 @@ public abstract class AbstractKeycloakAuthenticatorValve extends FormAuthenticat
protected abstract GenericPrincipalFactory createPrincipalFactory();
protected abstract boolean forwardToErrorPageInternal(Request request, HttpServletResponse response, Object loginConfig) throws IOException;
+ protected abstract AbstractAuthenticatedActionsValve createAuthenticatedActionsValve(AdapterDeploymentContext deploymentContext, Valve next, Container container);
protected boolean authenticateInternal(Request request, HttpServletResponse response, Object loginConfig) throws IOException {
CatalinaHttpFacade facade = new OIDCCatalinaHttpFacade(request, response);
diff --git a/adapters/oidc/tomcat/tomcat6/pom.xml b/adapters/oidc/tomcat/tomcat6/pom.xml
index d0b7059351..087d0839c6 100755
--- a/adapters/oidc/tomcat/tomcat6/pom.xml
+++ b/adapters/oidc/tomcat/tomcat6/pom.xml
@@ -21,7 +21,7 @@
keycloak-tomcat-integration-pom
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
../pom.xml
4.0.0
diff --git a/adapters/oidc/tomcat/tomcat6/src/main/java/org/keycloak/adapters/tomcat/AuthenticatedActionsValve.java b/adapters/oidc/tomcat/tomcat6/src/main/java/org/keycloak/adapters/tomcat/AuthenticatedActionsValve.java
new file mode 100644
index 0000000000..496eed3e68
--- /dev/null
+++ b/adapters/oidc/tomcat/tomcat6/src/main/java/org/keycloak/adapters/tomcat/AuthenticatedActionsValve.java
@@ -0,0 +1,12 @@
+package org.keycloak.adapters.tomcat;
+
+import org.apache.catalina.Container;
+import org.apache.catalina.Valve;
+import org.keycloak.adapters.AdapterDeploymentContext;
+
+public class AuthenticatedActionsValve extends AbstractAuthenticatedActionsValve {
+
+ public AuthenticatedActionsValve(AdapterDeploymentContext deploymentContext, Valve next, Container container) {
+ super(deploymentContext, next, container);
+ }
+}
diff --git a/adapters/oidc/tomcat/tomcat6/src/main/java/org/keycloak/adapters/tomcat/KeycloakAuthenticatorValve.java b/adapters/oidc/tomcat/tomcat6/src/main/java/org/keycloak/adapters/tomcat/KeycloakAuthenticatorValve.java
index b9f4ab8323..8e0732487e 100755
--- a/adapters/oidc/tomcat/tomcat6/src/main/java/org/keycloak/adapters/tomcat/KeycloakAuthenticatorValve.java
+++ b/adapters/oidc/tomcat/tomcat6/src/main/java/org/keycloak/adapters/tomcat/KeycloakAuthenticatorValve.java
@@ -17,12 +17,15 @@
package org.keycloak.adapters.tomcat;
+import org.apache.catalina.Container;
import org.apache.catalina.LifecycleException;
+import org.apache.catalina.Valve;
import org.apache.catalina.connector.Request;
import org.apache.catalina.connector.Response;
import org.apache.catalina.core.StandardContext;
import org.apache.catalina.deploy.LoginConfig;
import org.apache.catalina.realm.GenericPrincipal;
+import org.keycloak.adapters.AdapterDeploymentContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletResponse;
@@ -51,6 +54,10 @@ public class KeycloakAuthenticatorValve extends AbstractKeycloakAuthenticatorVal
return true;
}
+ @Override
+ protected AbstractAuthenticatedActionsValve createAuthenticatedActionsValve(AdapterDeploymentContext deploymentContext, Valve next, Container container) {
+ return new AuthenticatedActionsValve(deploymentContext, next, container);
+ }
@Override
public void start() throws LifecycleException {
diff --git a/adapters/oidc/tomcat/tomcat7/pom.xml b/adapters/oidc/tomcat/tomcat7/pom.xml
index d42530557a..c09555126f 100755
--- a/adapters/oidc/tomcat/tomcat7/pom.xml
+++ b/adapters/oidc/tomcat/tomcat7/pom.xml
@@ -21,7 +21,7 @@
keycloak-tomcat-integration-pom
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
../pom.xml
4.0.0
diff --git a/adapters/oidc/tomcat/tomcat7/src/main/java/org/keycloak/adapters/tomcat/AuthenticatedActionsValve.java b/adapters/oidc/tomcat/tomcat7/src/main/java/org/keycloak/adapters/tomcat/AuthenticatedActionsValve.java
new file mode 100644
index 0000000000..82796d66ab
--- /dev/null
+++ b/adapters/oidc/tomcat/tomcat7/src/main/java/org/keycloak/adapters/tomcat/AuthenticatedActionsValve.java
@@ -0,0 +1,17 @@
+package org.keycloak.adapters.tomcat;
+
+import org.apache.catalina.Container;
+import org.apache.catalina.Valve;
+import org.keycloak.adapters.AdapterDeploymentContext;
+
+public class AuthenticatedActionsValve extends AbstractAuthenticatedActionsValve {
+
+ public AuthenticatedActionsValve(AdapterDeploymentContext deploymentContext, Valve next, Container container) {
+ super(deploymentContext, next, container);
+ }
+
+ @Override
+ public boolean isAsyncSupported() {
+ return true;
+ }
+}
diff --git a/adapters/oidc/tomcat/tomcat7/src/main/java/org/keycloak/adapters/tomcat/KeycloakAuthenticatorValve.java b/adapters/oidc/tomcat/tomcat7/src/main/java/org/keycloak/adapters/tomcat/KeycloakAuthenticatorValve.java
index 18195e354a..49854ff81d 100755
--- a/adapters/oidc/tomcat/tomcat7/src/main/java/org/keycloak/adapters/tomcat/KeycloakAuthenticatorValve.java
+++ b/adapters/oidc/tomcat/tomcat7/src/main/java/org/keycloak/adapters/tomcat/KeycloakAuthenticatorValve.java
@@ -17,11 +17,14 @@
package org.keycloak.adapters.tomcat;
+import org.apache.catalina.Container;
+import org.apache.catalina.Valve;
import org.apache.catalina.connector.Request;
import org.apache.catalina.connector.Response;
import org.apache.catalina.core.StandardContext;
import org.apache.catalina.deploy.LoginConfig;
import org.apache.catalina.realm.GenericPrincipal;
+import org.keycloak.adapters.AdapterDeploymentContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletResponse;
@@ -69,4 +72,9 @@ public class KeycloakAuthenticatorValve extends AbstractKeycloakAuthenticatorVal
};
}
+ @Override
+ protected AbstractAuthenticatedActionsValve createAuthenticatedActionsValve(AdapterDeploymentContext deploymentContext, Valve next, Container container) {
+ return new AuthenticatedActionsValve(deploymentContext, next, container);
+ }
+
}
diff --git a/adapters/oidc/tomcat/tomcat8/pom.xml b/adapters/oidc/tomcat/tomcat8/pom.xml
index 8bf86063b0..b6ad8322a1 100755
--- a/adapters/oidc/tomcat/tomcat8/pom.xml
+++ b/adapters/oidc/tomcat/tomcat8/pom.xml
@@ -21,7 +21,7 @@
keycloak-tomcat-integration-pom
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
../pom.xml
4.0.0
diff --git a/adapters/oidc/tomcat/tomcat8/src/main/java/org/keycloak/adapters/tomcat/AuthenticatedActionsValve.java b/adapters/oidc/tomcat/tomcat8/src/main/java/org/keycloak/adapters/tomcat/AuthenticatedActionsValve.java
new file mode 100644
index 0000000000..82796d66ab
--- /dev/null
+++ b/adapters/oidc/tomcat/tomcat8/src/main/java/org/keycloak/adapters/tomcat/AuthenticatedActionsValve.java
@@ -0,0 +1,17 @@
+package org.keycloak.adapters.tomcat;
+
+import org.apache.catalina.Container;
+import org.apache.catalina.Valve;
+import org.keycloak.adapters.AdapterDeploymentContext;
+
+public class AuthenticatedActionsValve extends AbstractAuthenticatedActionsValve {
+
+ public AuthenticatedActionsValve(AdapterDeploymentContext deploymentContext, Valve next, Container container) {
+ super(deploymentContext, next, container);
+ }
+
+ @Override
+ public boolean isAsyncSupported() {
+ return true;
+ }
+}
diff --git a/adapters/oidc/tomcat/tomcat8/src/main/java/org/keycloak/adapters/tomcat/KeycloakAuthenticatorValve.java b/adapters/oidc/tomcat/tomcat8/src/main/java/org/keycloak/adapters/tomcat/KeycloakAuthenticatorValve.java
index d227353ec7..9da6964405 100755
--- a/adapters/oidc/tomcat/tomcat8/src/main/java/org/keycloak/adapters/tomcat/KeycloakAuthenticatorValve.java
+++ b/adapters/oidc/tomcat/tomcat8/src/main/java/org/keycloak/adapters/tomcat/KeycloakAuthenticatorValve.java
@@ -17,11 +17,14 @@
package org.keycloak.adapters.tomcat;
+import org.apache.catalina.Container;
+import org.apache.catalina.Valve;
import org.apache.catalina.authenticator.FormAuthenticator;
import org.apache.catalina.connector.Request;
import org.apache.catalina.core.StandardContext;
import org.apache.catalina.realm.GenericPrincipal;
import org.apache.tomcat.util.descriptor.web.LoginConfig;
+import org.keycloak.adapters.AdapterDeploymentContext;
import org.keycloak.adapters.AdapterTokenStore;
import org.keycloak.adapters.KeycloakDeployment;
import org.keycloak.adapters.spi.HttpFacade;
@@ -102,4 +105,9 @@ public class KeycloakAuthenticatorValve extends AbstractKeycloakAuthenticatorVal
protected AdapterTokenStore getTokenStore(Request request, HttpFacade facade, KeycloakDeployment resolvedDeployment) {
return super.getTokenStore(request, facade, resolvedDeployment);
}
+
+ @Override
+ protected AbstractAuthenticatedActionsValve createAuthenticatedActionsValve(AdapterDeploymentContext deploymentContext, Valve next, Container container) {
+ return new AuthenticatedActionsValve(deploymentContext, next, container);
+ }
}
diff --git a/adapters/oidc/undertow/pom.xml b/adapters/oidc/undertow/pom.xml
index ccdc34e60e..32b5b8ee80 100755
--- a/adapters/oidc/undertow/pom.xml
+++ b/adapters/oidc/undertow/pom.xml
@@ -21,7 +21,7 @@
keycloak-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
../../../pom.xml
4.0.0
diff --git a/adapters/oidc/wildfly-elytron/pom.xml b/adapters/oidc/wildfly-elytron/pom.xml
index 71d5681818..811ffcf92f 100755
--- a/adapters/oidc/wildfly-elytron/pom.xml
+++ b/adapters/oidc/wildfly-elytron/pom.xml
@@ -22,7 +22,7 @@
keycloak-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
../../../pom.xml
4.0.0
diff --git a/adapters/oidc/wildfly-elytron/src/main/java/org/keycloak/adapters/elytron/ElytronHttpFacade.java b/adapters/oidc/wildfly-elytron/src/main/java/org/keycloak/adapters/elytron/ElytronHttpFacade.java
index 4472af75f9..4941275f1e 100644
--- a/adapters/oidc/wildfly-elytron/src/main/java/org/keycloak/adapters/elytron/ElytronHttpFacade.java
+++ b/adapters/oidc/wildfly-elytron/src/main/java/org/keycloak/adapters/elytron/ElytronHttpFacade.java
@@ -50,7 +50,9 @@ import java.net.InetSocketAddress;
import java.net.URI;
import java.net.URLDecoder;
import java.util.Collection;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
import java.util.function.Consumer;
/**
@@ -66,6 +68,7 @@ class ElytronHttpFacade implements OIDCHttpFacade {
private ElytronAccount account;
private SecurityIdentity securityIdentity;
private boolean restored;
+ private final Map headers = new HashMap<>();
public ElytronHttpFacade(HttpServerRequest request, AdapterDeploymentContext deploymentContext, CallbackHandler handler) {
this.request = request;
@@ -261,6 +264,7 @@ class ElytronHttpFacade implements OIDCHttpFacade {
@Override
public Response getResponse() {
return new Response() {
+
@Override
public void setStatus(final int status) {
responseConsumer = responseConsumer.andThen(response -> response.setStatusCode(status));
@@ -268,7 +272,17 @@ class ElytronHttpFacade implements OIDCHttpFacade {
@Override
public void addHeader(final String name, final String value) {
- responseConsumer = responseConsumer.andThen(response -> response.addResponseHeader(name, value));
+ headers.put(name, value);
+ responseConsumer = responseConsumer.andThen(new Consumer() {
+ @Override
+ public void accept(HttpServerResponse response) {
+ String latestValue = headers.get(name);
+
+ if (latestValue.equals(value)) {
+ response.addResponseHeader(name, latestValue);
+ }
+ }
+ });
}
@Override
diff --git a/adapters/oidc/wildfly-elytron/src/main/java/org/keycloak/adapters/elytron/KeycloakSecurityRealm.java b/adapters/oidc/wildfly-elytron/src/main/java/org/keycloak/adapters/elytron/KeycloakSecurityRealm.java
index 6042ec82d1..eef2b26942 100644
--- a/adapters/oidc/wildfly-elytron/src/main/java/org/keycloak/adapters/elytron/KeycloakSecurityRealm.java
+++ b/adapters/oidc/wildfly-elytron/src/main/java/org/keycloak/adapters/elytron/KeycloakSecurityRealm.java
@@ -17,6 +17,7 @@
package org.keycloak.adapters.elytron;
import java.security.Principal;
+import java.security.spec.AlgorithmParameterSpec;
import java.util.Set;
import org.keycloak.KeycloakPrincipal;
@@ -54,7 +55,7 @@ public class KeycloakSecurityRealm implements SecurityRealm {
}
@Override
- public SupportLevel getCredentialAcquireSupport(Class extends Credential> credentialType, String algorithmName) throws RealmUnavailableException {
+ public SupportLevel getCredentialAcquireSupport(Class extends Credential> credentialType, String algorithmName, AlgorithmParameterSpec parameterSpec) throws RealmUnavailableException {
return SupportLevel.UNSUPPORTED;
}
@@ -92,7 +93,7 @@ public class KeycloakSecurityRealm implements SecurityRealm {
}
@Override
- public SupportLevel getCredentialAcquireSupport(Class extends Credential> credentialType, String algorithmName) throws RealmUnavailableException {
+ public SupportLevel getCredentialAcquireSupport(Class extends Credential> credentialType, String algorithmName, AlgorithmParameterSpec parameterSpec) throws RealmUnavailableException {
return SupportLevel.UNSUPPORTED;
}
diff --git a/adapters/oidc/wildfly/pom.xml b/adapters/oidc/wildfly/pom.xml
index e93be16c2b..b6a1db9b03 100755
--- a/adapters/oidc/wildfly/pom.xml
+++ b/adapters/oidc/wildfly/pom.xml
@@ -20,7 +20,7 @@
keycloak-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
../../../pom.xml
Keycloak WildFly Integration
diff --git a/adapters/oidc/wildfly/wf8-subsystem/pom.xml b/adapters/oidc/wildfly/wf8-subsystem/pom.xml
index 2afcf14cdf..d04b8d1af6 100755
--- a/adapters/oidc/wildfly/wf8-subsystem/pom.xml
+++ b/adapters/oidc/wildfly/wf8-subsystem/pom.xml
@@ -21,7 +21,7 @@
org.keycloak
keycloak-parent
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
../../../../pom.xml
diff --git a/adapters/oidc/wildfly/wildfly-adapter/pom.xml b/adapters/oidc/wildfly/wildfly-adapter/pom.xml
index 686661d8cf..6fa127d4b6 100644
--- a/adapters/oidc/wildfly/wildfly-adapter/pom.xml
+++ b/adapters/oidc/wildfly/wildfly-adapter/pom.xml
@@ -21,7 +21,7 @@
keycloak-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
../../../../pom.xml
4.0.0
diff --git a/adapters/oidc/wildfly/wildfly-subsystem/pom.xml b/adapters/oidc/wildfly/wildfly-subsystem/pom.xml
index 1d8e6cf916..b73daf1070 100755
--- a/adapters/oidc/wildfly/wildfly-subsystem/pom.xml
+++ b/adapters/oidc/wildfly/wildfly-subsystem/pom.xml
@@ -21,7 +21,7 @@
org.keycloak
keycloak-parent
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
../../../../pom.xml
@@ -68,6 +68,10 @@
wildfly-web-common
provided
+
+ org.wildfly.security
+ wildfly-elytron
+
org.jboss.logging
jboss-logging-annotations
@@ -101,5 +105,9 @@
keycloak-wildfly-adapter
${project.version}
+
+ org.keycloak
+ keycloak-wildfly-elytron-oidc-adapter
+
diff --git a/adapters/oidc/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/extension/SecureDeploymentAddHandler.java b/adapters/oidc/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/extension/AbstractAdapterConfigurationAddHandler.java
similarity index 58%
rename from adapters/oidc/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/extension/SecureDeploymentAddHandler.java
rename to adapters/oidc/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/extension/AbstractAdapterConfigurationAddHandler.java
index 110d385a75..55c83ca96b 100755
--- a/adapters/oidc/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/extension/SecureDeploymentAddHandler.java
+++ b/adapters/oidc/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/extension/AbstractAdapterConfigurationAddHandler.java
@@ -17,41 +17,32 @@
package org.keycloak.subsystem.adapter.extension;
+import java.util.List;
+
import org.jboss.as.controller.AbstractAddStepHandler;
-import org.jboss.as.controller.AttributeDefinition;
import org.jboss.as.controller.OperationContext;
import org.jboss.as.controller.OperationFailedException;
+import org.jboss.as.controller.SimpleAttributeDefinition;
+import org.jboss.as.controller.capability.RuntimeCapability;
import org.jboss.dmr.ModelNode;
-import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.ADD;
-import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.OP;
-
/**
* Add a deployment to a realm.
*
* @author Stan Silvert ssilvert@redhat.com (C) 2013 Red Hat Inc.
*/
-public final class SecureDeploymentAddHandler extends AbstractAddStepHandler {
+abstract class AbstractAdapterConfigurationAddHandler extends AbstractAddStepHandler {
- public static SecureDeploymentAddHandler INSTANCE = new SecureDeploymentAddHandler();
+ private final boolean elytronEnabled;
- private SecureDeploymentAddHandler() {}
-
- @Override
- protected void populateModel(ModelNode operation, ModelNode model) throws OperationFailedException {
- // TODO: localize exception. get id number
- if (!operation.get(OP).asString().equals(ADD)) {
- throw new OperationFailedException("Unexpected operation for add secure deployment. operation=" + operation.toString());
- }
-
- for (AttributeDefinition attr : SecureDeploymentDefinition.ALL_ATTRIBUTES) {
- attr.validateAndSet(operation, model);
- }
+ AbstractAdapterConfigurationAddHandler(RuntimeCapability runtimeCapability, List attributes) {
+ super(runtimeCapability, attributes);
+ elytronEnabled = runtimeCapability != null;
}
@Override
protected void performRuntime(OperationContext context, ModelNode operation, ModelNode model) throws OperationFailedException {
KeycloakAdapterConfigService ckService = KeycloakAdapterConfigService.getInstance();
- ckService.addSecureDeployment(operation, context.resolveExpressions(model));
+ ckService.addSecureDeployment(operation, context.resolveExpressions(model), elytronEnabled);
}
}
diff --git a/adapters/oidc/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/extension/AbstractAdapterConfigurationDefinition.java b/adapters/oidc/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/extension/AbstractAdapterConfigurationDefinition.java
new file mode 100755
index 0000000000..613c946f4f
--- /dev/null
+++ b/adapters/oidc/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/extension/AbstractAdapterConfigurationDefinition.java
@@ -0,0 +1,164 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2016 Red Hat, Inc., and individual 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.subsystem.adapter.extension;
+
+import org.jboss.as.controller.AttributeDefinition;
+import org.jboss.as.controller.PathElement;
+import org.jboss.as.controller.SimpleAttributeDefinition;
+import org.jboss.as.controller.SimpleAttributeDefinitionBuilder;
+import org.jboss.as.controller.SimpleResourceDefinition;
+import org.jboss.as.controller.operations.common.GenericSubsystemDescribeHandler;
+import org.jboss.as.controller.operations.validation.IntRangeValidator;
+import org.jboss.as.controller.operations.validation.StringLengthValidator;
+import org.jboss.as.controller.registry.ManagementResourceRegistration;
+import org.jboss.dmr.ModelNode;
+import org.jboss.dmr.ModelType;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Defines attributes and operations for a secure-deployment.
+ *
+ * @author Stan Silvert ssilvert@redhat.com (C) 2013 Red Hat Inc.
+ */
+abstract class AbstractAdapterConfigurationDefinition extends SimpleResourceDefinition {
+
+ protected static final SimpleAttributeDefinition REALM =
+ new SimpleAttributeDefinitionBuilder("realm", ModelType.STRING, true)
+ .setXmlName("realm")
+ .setAllowExpression(true)
+ .setValidator(new StringLengthValidator(1, Integer.MAX_VALUE, true, true))
+ .build();
+ protected static final SimpleAttributeDefinition RESOURCE =
+ new SimpleAttributeDefinitionBuilder("resource", ModelType.STRING, true)
+ .setXmlName("resource")
+ .setAllowExpression(true)
+ .setValidator(new StringLengthValidator(1, Integer.MAX_VALUE, true, true))
+ .build();
+ protected static final SimpleAttributeDefinition USE_RESOURCE_ROLE_MAPPINGS =
+ new SimpleAttributeDefinitionBuilder("use-resource-role-mappings", ModelType.BOOLEAN, true)
+ .setXmlName("use-resource-role-mappings")
+ .setAllowExpression(true)
+ .setDefaultValue(new ModelNode(false))
+ .build();
+ protected static final SimpleAttributeDefinition BEARER_ONLY =
+ new SimpleAttributeDefinitionBuilder("bearer-only", ModelType.BOOLEAN, true)
+ .setXmlName("bearer-only")
+ .setAllowExpression(true)
+ .setDefaultValue(new ModelNode(false))
+ .build();
+ protected static final SimpleAttributeDefinition ENABLE_BASIC_AUTH =
+ new SimpleAttributeDefinitionBuilder("enable-basic-auth", ModelType.BOOLEAN, true)
+ .setXmlName("enable-basic-auth")
+ .setAllowExpression(true)
+ .setDefaultValue(new ModelNode(false))
+ .build();
+ protected static final SimpleAttributeDefinition PUBLIC_CLIENT =
+ new SimpleAttributeDefinitionBuilder("public-client", ModelType.BOOLEAN, true)
+ .setXmlName("public-client")
+ .setAllowExpression(true)
+ .setDefaultValue(new ModelNode(false))
+ .build();
+ protected static final SimpleAttributeDefinition TURN_OFF_CHANGE_SESSION =
+ new SimpleAttributeDefinitionBuilder("turn-off-change-session-id-on-login", ModelType.BOOLEAN, true)
+ .setXmlName("turn-off-change-session-id-on-login")
+ .setAllowExpression(true)
+ .setDefaultValue(new ModelNode(false))
+ .build();
+ protected static final SimpleAttributeDefinition TOKEN_MINIMUM_TIME_TO_LIVE =
+ new SimpleAttributeDefinitionBuilder("token-minimum-time-to-live", ModelType.INT, true)
+ .setXmlName("token-minimum-time-to-live")
+ .setValidator(new IntRangeValidator(-1, true))
+ .setAllowExpression(true)
+ .build();
+ protected static final SimpleAttributeDefinition MIN_TIME_BETWEEN_JWKS_REQUESTS =
+ new SimpleAttributeDefinitionBuilder("min-time-between-jwks-requests", ModelType.INT, true)
+ .setXmlName("min-time-between-jwks-requests")
+ .setValidator(new IntRangeValidator(-1, true))
+ .setAllowExpression(true)
+ .build();
+
+ static final List DEPLOYMENT_ONLY_ATTRIBUTES = new ArrayList();
+
+ static {
+ DEPLOYMENT_ONLY_ATTRIBUTES.add(REALM);
+ DEPLOYMENT_ONLY_ATTRIBUTES.add(RESOURCE);
+ DEPLOYMENT_ONLY_ATTRIBUTES.add(USE_RESOURCE_ROLE_MAPPINGS);
+ DEPLOYMENT_ONLY_ATTRIBUTES.add(BEARER_ONLY);
+ DEPLOYMENT_ONLY_ATTRIBUTES.add(ENABLE_BASIC_AUTH);
+ DEPLOYMENT_ONLY_ATTRIBUTES.add(PUBLIC_CLIENT);
+ DEPLOYMENT_ONLY_ATTRIBUTES.add(TURN_OFF_CHANGE_SESSION);
+ DEPLOYMENT_ONLY_ATTRIBUTES.add(TOKEN_MINIMUM_TIME_TO_LIVE);
+ DEPLOYMENT_ONLY_ATTRIBUTES.add(MIN_TIME_BETWEEN_JWKS_REQUESTS);
+ }
+
+ static final List ALL_ATTRIBUTES = new ArrayList();
+
+ static {
+ ALL_ATTRIBUTES.addAll(DEPLOYMENT_ONLY_ATTRIBUTES);
+ ALL_ATTRIBUTES.addAll(SharedAttributeDefinitons.ATTRIBUTES);
+ }
+
+ static final Map XML_ATTRIBUTES = new HashMap();
+
+ static {
+ for (SimpleAttributeDefinition def : ALL_ATTRIBUTES) {
+ XML_ATTRIBUTES.put(def.getXmlName(), def);
+ }
+ }
+
+ private static final Map DEFINITION_LOOKUP = new HashMap();
+ static {
+ for (SimpleAttributeDefinition def : ALL_ATTRIBUTES) {
+ DEFINITION_LOOKUP.put(def.getXmlName(), def);
+ }
+ }
+
+ private final AbstractAdapterConfigurationWriteAttributeHandler attrWriteHandler;
+ private final List attributes;
+
+ protected AbstractAdapterConfigurationDefinition(String name, List attributes, AbstractAdapterConfigurationAddHandler addHandler, AbstractAdapterConfigurationRemoveHandler removeHandler, AbstractAdapterConfigurationWriteAttributeHandler attrWriteHandler) {
+ super(PathElement.pathElement(name),
+ KeycloakExtension.getResourceDescriptionResolver(name),
+ addHandler,
+ removeHandler);
+ this.attributes = attributes;
+ this.attrWriteHandler = attrWriteHandler;
+ }
+
+ @Override
+ public void registerOperations(ManagementResourceRegistration resourceRegistration) {
+ super.registerOperations(resourceRegistration);
+ resourceRegistration.registerOperationHandler(GenericSubsystemDescribeHandler.DEFINITION, GenericSubsystemDescribeHandler.INSTANCE);
+ }
+
+ @Override
+ public void registerAttributes(ManagementResourceRegistration resourceRegistration) {
+ super.registerAttributes(resourceRegistration);
+ for (AttributeDefinition attrDef : this.attributes) {
+ resourceRegistration.registerReadWriteAttribute(attrDef, null, this.attrWriteHandler);
+ }
+ }
+
+ public static SimpleAttributeDefinition lookup(String name) {
+ return DEFINITION_LOOKUP.get(name);
+ }
+}
diff --git a/adapters/oidc/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/extension/SecureDeploymentRemoveHandler.java b/adapters/oidc/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/extension/AbstractAdapterConfigurationRemoveHandler.java
similarity index 85%
rename from adapters/oidc/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/extension/SecureDeploymentRemoveHandler.java
rename to adapters/oidc/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/extension/AbstractAdapterConfigurationRemoveHandler.java
index 7088ec0cf9..2066aed3f4 100644
--- a/adapters/oidc/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/extension/SecureDeploymentRemoveHandler.java
+++ b/adapters/oidc/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/extension/AbstractAdapterConfigurationRemoveHandler.java
@@ -27,11 +27,7 @@ import org.jboss.dmr.ModelNode;
*
* @author Stan Silvert ssilvert@redhat.com (C) 2013 Red Hat Inc.
*/
-public final class SecureDeploymentRemoveHandler extends AbstractRemoveStepHandler {
-
- public static SecureDeploymentRemoveHandler INSTANCE = new SecureDeploymentRemoveHandler();
-
- private SecureDeploymentRemoveHandler() {}
+abstract class AbstractAdapterConfigurationRemoveHandler extends AbstractRemoveStepHandler {
@Override
protected void performRuntime(OperationContext context, ModelNode operation, ModelNode model) throws OperationFailedException {
diff --git a/adapters/oidc/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/extension/SecureDeploymentWriteAttributeHandler.java b/adapters/oidc/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/extension/AbstractAdapterConfigurationWriteAttributeHandler.java
similarity index 83%
rename from adapters/oidc/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/extension/SecureDeploymentWriteAttributeHandler.java
rename to adapters/oidc/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/extension/AbstractAdapterConfigurationWriteAttributeHandler.java
index 908526c828..127ea538f1 100755
--- a/adapters/oidc/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/extension/SecureDeploymentWriteAttributeHandler.java
+++ b/adapters/oidc/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/extension/AbstractAdapterConfigurationWriteAttributeHandler.java
@@ -31,14 +31,10 @@ import java.util.List;
*
* @author Stan Silvert ssilvert@redhat.com (C) 2013 Red Hat Inc.
*/
-public class SecureDeploymentWriteAttributeHandler extends AbstractWriteAttributeHandler {
+abstract class AbstractAdapterConfigurationWriteAttributeHandler extends AbstractWriteAttributeHandler {
- public SecureDeploymentWriteAttributeHandler(List definitions) {
- this(definitions.toArray(new AttributeDefinition[definitions.size()]));
- }
-
- public SecureDeploymentWriteAttributeHandler(AttributeDefinition... definitions) {
- super(definitions);
+ AbstractAdapterConfigurationWriteAttributeHandler(List definitions) {
+ super(definitions.toArray(new AttributeDefinition[definitions.size()]));
}
@Override
diff --git a/adapters/oidc/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/extension/KeycloakAdapterConfigDeploymentProcessor.java b/adapters/oidc/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/extension/KeycloakAdapterConfigDeploymentProcessor.java
index 24e9ac0b74..1500808e32 100755
--- a/adapters/oidc/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/extension/KeycloakAdapterConfigDeploymentProcessor.java
+++ b/adapters/oidc/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/extension/KeycloakAdapterConfigDeploymentProcessor.java
@@ -25,7 +25,9 @@ import org.jboss.as.web.common.WarMetaData;
import org.jboss.logging.Logger;
import org.jboss.metadata.javaee.spec.ParamValueMetaData;
import org.jboss.metadata.web.jboss.JBossWebMetaData;
+import org.jboss.metadata.web.spec.ListenerMetaData;
import org.jboss.metadata.web.spec.LoginConfigMetaData;
+import org.keycloak.adapters.elytron.KeycloakConfigurationServletListener;
import org.keycloak.subsystem.adapter.logging.KeycloakLogger;
import java.util.ArrayList;
@@ -69,6 +71,9 @@ public class KeycloakAdapterConfigDeploymentProcessor implements DeploymentUnitP
KeycloakAdapterConfigService service = KeycloakAdapterConfigService.getInstance();
if (service.isSecureDeployment(deploymentUnit) && service.isDeploymentConfigured(deploymentUnit)) {
addKeycloakAuthData(phaseContext, service);
+ } else if (service.isElytronEnabled(deploymentUnit)) {
+ WarMetaData warMetaData = deploymentUnit.getAttachment(WarMetaData.ATTACHMENT_KEY);
+ addConfigurationListener(warMetaData);
}
// FYI, Undertow Extension will find deployments that have auth-method set to KEYCLOAK
@@ -99,6 +104,10 @@ public class KeycloakAdapterConfigDeploymentProcessor implements DeploymentUnitP
loginConfig.setAuthMethod("KEYCLOAK");
loginConfig.setRealmName(service.getRealmName(deploymentUnit));
KeycloakLogger.ROOT_LOGGER.deploymentSecured(deploymentUnit.getName());
+
+ if (service.isElytronEnabled(deploymentUnit)) {
+ addConfigurationListener(warMetaData);
+ }
}
private void addJSONData(String json, WarMetaData warMetaData) {
@@ -121,6 +130,31 @@ public class KeycloakAdapterConfigDeploymentProcessor implements DeploymentUnitP
webMetaData.setContextParams(contextParams);
}
+ private void addConfigurationListener(WarMetaData warMetaData) {
+ if (warMetaData == null) {
+ return;
+ }
+
+ JBossWebMetaData webMetaData = warMetaData.getMergedJBossWebMetaData();
+ if (webMetaData == null) {
+ webMetaData = new JBossWebMetaData();
+ warMetaData.setMergedJBossWebMetaData(webMetaData);
+ }
+
+ LoginConfigMetaData loginConfig = webMetaData.getLoginConfig();
+ if (loginConfig == null) {
+ return;
+ }
+ if (!loginConfig.getAuthMethod().equals("KEYCLOAK")) {
+ return;
+ }
+ ListenerMetaData listenerMetaData = new ListenerMetaData();
+
+ listenerMetaData.setListenerClass(KeycloakConfigurationServletListener.class.getName());
+
+ webMetaData.getListeners().add(listenerMetaData);
+ }
+
@Override
public void undeploy(DeploymentUnit du) {
diff --git a/adapters/oidc/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/extension/KeycloakAdapterConfigService.java b/adapters/oidc/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/extension/KeycloakAdapterConfigService.java
index 5a71e615a8..496c311982 100755
--- a/adapters/oidc/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/extension/KeycloakAdapterConfigService.java
+++ b/adapters/oidc/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/extension/KeycloakAdapterConfigService.java
@@ -23,8 +23,11 @@ import org.jboss.dmr.ModelNode;
import org.jboss.dmr.Property;
import org.jboss.metadata.web.jboss.JBossWebMetaData;
+import java.util.ArrayList;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.Map;
+import java.util.Set;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.ADDRESS;
@@ -50,6 +53,7 @@ public final class KeycloakAdapterConfigService {
// keycloak-secured deployments
private final Map secureDeployments = new HashMap();
+ private final Set elytronEnabledDeployments = new HashSet<>();
private KeycloakAdapterConfigService() {
@@ -68,9 +72,13 @@ public final class KeycloakAdapterConfigService {
this.realms.remove(realmNameFromOp(operation));
}
- public void addSecureDeployment(ModelNode operation, ModelNode model) {
+ public void addSecureDeployment(ModelNode operation, ModelNode model, boolean elytronEnabled) {
ModelNode deployment = model.clone();
- this.secureDeployments.put(deploymentNameFromOp(operation), deployment);
+ String name = deploymentNameFromOp(operation);
+ this.secureDeployments.put(name, deployment);
+ if (elytronEnabled) {
+ elytronEnabledDeployments.add(name);
+ }
}
public void updateSecureDeployment(ModelNode operation, String attrName, ModelNode resolvedValue) {
@@ -79,7 +87,9 @@ public final class KeycloakAdapterConfigService {
}
public void removeSecureDeployment(ModelNode operation) {
- this.secureDeployments.remove(deploymentNameFromOp(operation));
+ String name = deploymentNameFromOp(operation);
+ this.secureDeployments.remove(name);
+ elytronEnabledDeployments.remove(name);
}
public void addCredential(ModelNode operation, ModelNode model) {
@@ -187,7 +197,19 @@ public final class KeycloakAdapterConfigService {
}
private String deploymentNameFromOp(ModelNode operation) {
- return valueFromOpAddress(SecureDeploymentDefinition.TAG_NAME, operation);
+ String deploymentName = valueFromOpAddress(SecureDeploymentDefinition.TAG_NAME, operation);
+
+ if (deploymentName == null) {
+ deploymentName = valueFromOpAddress(KeycloakHttpServerAuthenticationMechanismFactoryDefinition.TAG_NAME, operation);
+ }
+
+ if (deploymentName == null) {
+ deploymentName = valueFromOpAddress(SecureServerDefinition.TAG_NAME, operation);
+ }
+
+ if (deploymentName == null) throw new RuntimeException("Can't find deployment name in address " + operation);
+
+ return deploymentName;
}
private String credentialNameFromOp(ModelNode operation) {
@@ -199,9 +221,7 @@ public final class KeycloakAdapterConfigService {
}
private String valueFromOpAddress(String addrElement, ModelNode operation) {
- String deploymentName = getValueOfAddrElement(operation.get(ADDRESS), addrElement);
- if (deploymentName == null) throw new RuntimeException("Can't find '" + addrElement + "' in address " + operation.toString());
- return deploymentName;
+ return getValueOfAddrElement(operation.get(ADDRESS), addrElement);
}
private String getValueOfAddrElement(ModelNode address, String elementName) {
@@ -241,8 +261,22 @@ public final class KeycloakAdapterConfigService {
return json.toJSONString(true);
}
+ public String getJSON(String deploymentName) {
+ ModelNode deployment = this.secureDeployments.get(deploymentName);
+ String realmName = deployment.get(RealmDefinition.TAG_NAME).asString();
+ ModelNode realm = this.realms.get(realmName);
+
+ ModelNode json = new ModelNode();
+ json.get(RealmDefinition.TAG_NAME).set(realmName);
+
+ // Realm values set first. Some can be overridden by deployment values.
+ if (realm != null) setJSONValues(json, realm);
+ setJSONValues(json, deployment);
+ return json.toJSONString(true);
+ }
+
private void setJSONValues(ModelNode json, ModelNode values) {
- for (Property prop : values.asPropertyList()) {
+ for (Property prop : new ArrayList<>(values.asPropertyList())) {
String name = prop.getName();
ModelNode value = prop.getValue();
if (value.isDefined()) {
@@ -258,6 +292,10 @@ public final class KeycloakAdapterConfigService {
return this.secureDeployments.containsKey(deploymentName);
}
+ public boolean isElytronEnabled(DeploymentUnit deploymentUnit) {
+ return elytronEnabledDeployments.contains(preferredDeploymentName(deploymentUnit));
+ }
+
private ModelNode getSecureDeployment(DeploymentUnit deploymentUnit) {
String deploymentName = preferredDeploymentName(deploymentUnit);
return this.secureDeployments.containsKey(deploymentName)
diff --git a/adapters/oidc/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/extension/KeycloakDependencyProcessorWildFly.java b/adapters/oidc/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/extension/KeycloakDependencyProcessorWildFly.java
index e306a7f630..61d670c8cd 100755
--- a/adapters/oidc/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/extension/KeycloakDependencyProcessorWildFly.java
+++ b/adapters/oidc/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/extension/KeycloakDependencyProcessorWildFly.java
@@ -29,13 +29,14 @@ import org.jboss.modules.ModuleLoader;
*/
public class KeycloakDependencyProcessorWildFly extends KeycloakDependencyProcessor {
+ private static final ModuleIdentifier KEYCLOAK_ELYTRON_ADAPTER = ModuleIdentifier.create("org.keycloak.keycloak-wildfly-elytron-oidc-adapter");
private static final ModuleIdentifier KEYCLOAK_WILDFLY_ADAPTER = ModuleIdentifier.create("org.keycloak.keycloak-wildfly-adapter");
private static final ModuleIdentifier KEYCLOAK_UNDERTOW_ADAPTER = ModuleIdentifier.create("org.keycloak.keycloak-undertow-adapter");
@Override
protected void addPlatformSpecificModules(ModuleSpecification moduleSpecification, ModuleLoader moduleLoader) {
- // ModuleDependency(ModuleLoader moduleLoader, ModuleIdentifier identifier, boolean optional, boolean export, boolean importServices, boolean userSpecified)
moduleSpecification.addSystemDependency(new ModuleDependency(moduleLoader, KEYCLOAK_WILDFLY_ADAPTER, false, false, true, false));
moduleSpecification.addSystemDependency(new ModuleDependency(moduleLoader, KEYCLOAK_UNDERTOW_ADAPTER, false, false, false, false));
+ moduleSpecification.addSystemDependency(new ModuleDependency(moduleLoader, KEYCLOAK_ELYTRON_ADAPTER, true, false, false, false));
}
}
diff --git a/adapters/oidc/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/extension/KeycloakExtension.java b/adapters/oidc/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/extension/KeycloakExtension.java
index d04e72d403..52113c0825 100755
--- a/adapters/oidc/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/extension/KeycloakExtension.java
+++ b/adapters/oidc/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/extension/KeycloakExtension.java
@@ -47,8 +47,9 @@ public class KeycloakExtension implements Extension {
private static final ResourceDefinition KEYCLOAK_SUBSYSTEM_RESOURCE = new KeycloakSubsystemDefinition();
static final RealmDefinition REALM_DEFINITION = new RealmDefinition();
static final SecureDeploymentDefinition SECURE_DEPLOYMENT_DEFINITION = new SecureDeploymentDefinition();
+ static final SecureServerDefinition SECURE_SERVER_DEFINITION = new SecureServerDefinition();
static final CredentialDefinition CREDENTIAL_DEFINITION = new CredentialDefinition();
- static final RedirecRewritetRuleDefinition REDIRECT_RULE_DEFINITON = new RedirecRewritetRuleDefinition();
+ static final RedirecRewritetRuleDefinition REDIRECT_RULE_DEFINITON = new RedirecRewritetRuleDefinition();
public static StandardResourceDescriptionResolver getResourceDescriptionResolver(final String... keyPrefix) {
StringBuilder prefix = new StringBuilder(SUBSYSTEM_NAME);
@@ -80,6 +81,10 @@ public class KeycloakExtension implements Extension {
secureDeploymentRegistration.registerSubModel(CREDENTIAL_DEFINITION);
secureDeploymentRegistration.registerSubModel(REDIRECT_RULE_DEFINITON);
+ ManagementResourceRegistration secureServerRegistration = registration.registerSubModel(SECURE_SERVER_DEFINITION);
+ secureServerRegistration.registerSubModel(CREDENTIAL_DEFINITION);
+ secureServerRegistration.registerSubModel(REDIRECT_RULE_DEFINITON);
+
subsystem.registerXMLElementWriter(PARSER);
}
}
diff --git a/adapters/oidc/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/extension/KeycloakHttpAuthenticationFactoryService.java b/adapters/oidc/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/extension/KeycloakHttpAuthenticationFactoryService.java
new file mode 100644
index 0000000000..94fb8e566d
--- /dev/null
+++ b/adapters/oidc/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/extension/KeycloakHttpAuthenticationFactoryService.java
@@ -0,0 +1,67 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2016 Red Hat, Inc., and individual 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.subsystem.adapter.extension;
+
+import org.jboss.msc.service.Service;
+import org.jboss.msc.service.StartContext;
+import org.jboss.msc.service.StartException;
+import org.jboss.msc.service.StopContext;
+import org.jboss.msc.value.InjectedValue;
+import org.keycloak.adapters.AdapterDeploymentContext;
+import org.keycloak.adapters.KeycloakDeploymentBuilder;
+import org.keycloak.adapters.elytron.KeycloakHttpServerAuthenticationMechanismFactory;
+import org.wildfly.security.auth.server.SecurityDomain;
+import org.wildfly.security.http.HttpServerAuthenticationMechanismFactory;
+import org.wildfly.security.http.util.SetMechanismInformationMechanismFactory;
+
+import java.io.ByteArrayInputStream;
+
+/**
+ * @author Pedro Igor
+ */
+public class KeycloakHttpAuthenticationFactoryService implements Service {
+
+ private final String factoryName;
+ private HttpServerAuthenticationMechanismFactory httpAuthenticationFactory;
+
+ public KeycloakHttpAuthenticationFactoryService(String factoryName) {
+ this.factoryName = factoryName;
+ }
+
+ @Override
+ public void start(StartContext context) throws StartException {
+ KeycloakAdapterConfigService adapterConfigService = KeycloakAdapterConfigService.getInstance();
+ String config = adapterConfigService.getJSON(this.factoryName);
+ this.httpAuthenticationFactory = new KeycloakHttpServerAuthenticationMechanismFactory(createDeploymentContext(config.getBytes()));
+ }
+
+ @Override
+ public void stop(StopContext context) {
+ this.httpAuthenticationFactory = null;
+ }
+
+ @Override
+ public HttpServerAuthenticationMechanismFactory getValue() throws IllegalStateException, IllegalArgumentException {
+ return new SetMechanismInformationMechanismFactory(this.httpAuthenticationFactory);
+ }
+
+ private AdapterDeploymentContext createDeploymentContext(byte[] config) {
+ return new AdapterDeploymentContext(KeycloakDeploymentBuilder.build(new ByteArrayInputStream(config)));
+ }
+}
diff --git a/adapters/oidc/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/extension/KeycloakHttpServerAuthenticationMechanismFactoryDefinition.java b/adapters/oidc/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/extension/KeycloakHttpServerAuthenticationMechanismFactoryDefinition.java
new file mode 100644
index 0000000000..1e177a49f4
--- /dev/null
+++ b/adapters/oidc/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/extension/KeycloakHttpServerAuthenticationMechanismFactoryDefinition.java
@@ -0,0 +1,117 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2016 Red Hat, Inc., and individual 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.subsystem.adapter.extension;
+
+import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.OP_ADDR;
+import static org.keycloak.subsystem.adapter.extension.KeycloakHttpServerAuthenticationMechanismFactoryDefinition.KeycloakHttpServerAuthenticationMechanismFactoryAddHandler.HTTP_SERVER_AUTHENTICATION_CAPABILITY;
+
+import org.jboss.as.controller.OperationContext;
+import org.jboss.as.controller.OperationFailedException;
+import org.jboss.as.controller.PathAddress;
+import org.jboss.as.controller.SimpleResourceDefinition;
+import org.jboss.as.controller.capability.RuntimeCapability;
+import org.jboss.dmr.ModelNode;
+import org.jboss.msc.service.ServiceController;
+import org.jboss.msc.service.ServiceName;
+import org.wildfly.security.http.HttpServerAuthenticationMechanismFactory;
+
+/**
+ * A {@link SimpleResourceDefinition} that can be used to configure a {@link org.keycloak.adapters.elytron.KeycloakHttpServerAuthenticationMechanismFactory}
+ * and expose it as a capability for other subsystems.
+ *
+ * @author Pedro Igor
+ */
+class KeycloakHttpServerAuthenticationMechanismFactoryDefinition extends AbstractAdapterConfigurationDefinition {
+
+ static final String TAG_NAME = "http-server-mechanism-factory";
+
+ KeycloakHttpServerAuthenticationMechanismFactoryDefinition() {
+ this(TAG_NAME);
+ }
+
+ KeycloakHttpServerAuthenticationMechanismFactoryDefinition(String tagName) {
+ super(tagName, ALL_ATTRIBUTES, new KeycloakHttpServerAuthenticationMechanismFactoryAddHandler(), new KeycloakHttpServerAuthenticationMechanismFactoryRemoveHandler(), new KeycloakHttpServerAuthenticationMechanismFactoryWriteHandler());
+ }
+
+ /**
+ * A {@link AbstractAdapterConfigurationAddHandler} that exposes a {@link KeycloakHttpServerAuthenticationMechanismFactoryDefinition}
+ * as a capability through the installation of a {@link KeycloakHttpAuthenticationFactoryService}.
+ *
+ * @author Pedro Igor
+ */
+ static final class KeycloakHttpServerAuthenticationMechanismFactoryAddHandler extends AbstractAdapterConfigurationAddHandler {
+
+ static final String HTTP_SERVER_AUTHENTICATION_CAPABILITY = "org.wildfly.security.http-server-mechanism-factory";
+ static final RuntimeCapability HTTP_SERVER_AUTHENTICATION_RUNTIME_CAPABILITY = RuntimeCapability
+ .Builder.of(HTTP_SERVER_AUTHENTICATION_CAPABILITY, true, HttpServerAuthenticationMechanismFactory.class)
+ .build();
+
+ KeycloakHttpServerAuthenticationMechanismFactoryAddHandler() {
+ super(HTTP_SERVER_AUTHENTICATION_RUNTIME_CAPABILITY, ALL_ATTRIBUTES);
+ }
+
+ @Override
+ protected void performRuntime(OperationContext context, ModelNode operation, ModelNode model) throws OperationFailedException {
+ super.performRuntime(context, operation, model);
+ installCapability(context, operation);
+ }
+
+ static void installCapability(OperationContext context, ModelNode operation) {
+ PathAddress pathAddress = PathAddress.pathAddress(operation.get(OP_ADDR));
+ String factoryName = pathAddress.getLastElement().getValue();
+ ServiceName serviceName = context.getCapabilityServiceName(HTTP_SERVER_AUTHENTICATION_CAPABILITY, factoryName, HttpServerAuthenticationMechanismFactory.class);
+ KeycloakHttpAuthenticationFactoryService service = new KeycloakHttpAuthenticationFactoryService(factoryName);
+ context.getServiceTarget().addService(serviceName, service).setInitialMode(ServiceController.Mode.ACTIVE).install();
+ }
+ }
+
+ /**
+ * A {@link AbstractAdapterConfigurationRemoveHandler} that handles the removal of {@link KeycloakHttpServerAuthenticationMechanismFactoryDefinition}.
+ *
+ * @author Pedro Igor
+ */
+ static final class KeycloakHttpServerAuthenticationMechanismFactoryRemoveHandler extends AbstractAdapterConfigurationRemoveHandler {
+ @Override
+ protected void performRuntime(OperationContext context, ModelNode operation, ModelNode model) throws OperationFailedException {
+ super.performRuntime(context, operation, model);
+ PathAddress pathAddress = PathAddress.pathAddress(operation.get(OP_ADDR));
+ String factoryName = pathAddress.getLastElement().getValue();
+ ServiceName serviceName = context.getCapabilityServiceName(HTTP_SERVER_AUTHENTICATION_CAPABILITY, factoryName, HttpServerAuthenticationMechanismFactory.class);
+
+ context.removeService(serviceName);
+ }
+
+ @Override
+ protected void recoverServices(OperationContext context, ModelNode operation, ModelNode model) throws OperationFailedException {
+ super.recoverServices(context, operation, model);
+ KeycloakHttpServerAuthenticationMechanismFactoryAddHandler.installCapability(context, operation);
+ }
+ }
+
+ /**
+ * A {@link AbstractAdapterConfigurationWriteAttributeHandler} that updates attributes on a {@link KeycloakHttpServerAuthenticationMechanismFactoryDefinition}.
+ *
+ * @author Pedro Igor
+ */
+ static final class KeycloakHttpServerAuthenticationMechanismFactoryWriteHandler extends AbstractAdapterConfigurationWriteAttributeHandler {
+ KeycloakHttpServerAuthenticationMechanismFactoryWriteHandler() {
+ super(ALL_ATTRIBUTES);
+ }
+ }
+}
diff --git a/adapters/oidc/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/extension/KeycloakSubsystemParser.java b/adapters/oidc/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/extension/KeycloakSubsystemParser.java
index 79555e3b7b..a8d50aeb3d 100755
--- a/adapters/oidc/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/extension/KeycloakSubsystemParser.java
+++ b/adapters/oidc/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/extension/KeycloakSubsystemParser.java
@@ -62,6 +62,9 @@ class KeycloakSubsystemParser implements XMLStreamConstants, XMLElementReader resourcesToAdd) throws XMLStreamException {
+ readSecureResource(KeycloakExtension.SECURE_DEPLOYMENT_DEFINITION.TAG_NAME, KeycloakExtension.SECURE_DEPLOYMENT_DEFINITION, reader, resourcesToAdd);
+ }
+
+ private void readSecureServer(XMLExtendedStreamReader reader, List resourcesToAdd) throws XMLStreamException {
+ readSecureResource(KeycloakExtension.SECURE_SERVER_DEFINITION.TAG_NAME, KeycloakExtension.SECURE_SERVER_DEFINITION, reader, resourcesToAdd);
+ }
+
+ private void readSecureResource(String tagName, AbstractAdapterConfigurationDefinition resource, XMLExtendedStreamReader reader, List resourcesToAdd) throws XMLStreamException {
String name = readNameAttribute(reader);
ModelNode addSecureDeployment = new ModelNode();
addSecureDeployment.get(ModelDescriptionConstants.OP).set(ModelDescriptionConstants.ADD);
PathAddress addr = PathAddress.pathAddress(PathElement.pathElement(ModelDescriptionConstants.SUBSYSTEM, KeycloakExtension.SUBSYSTEM_NAME),
- PathElement.pathElement(SecureDeploymentDefinition.TAG_NAME, name));
+ PathElement.pathElement(tagName, name));
addSecureDeployment.get(ModelDescriptionConstants.OP_ADDR).set(addr.toModelNode());
List credentialsToAdd = new ArrayList();
List redirectRulesToAdd = new ArrayList();
while (reader.hasNext() && nextTag(reader) != END_ELEMENT) {
- String tagName = reader.getLocalName();
- if (tagName.equals(CredentialDefinition.TAG_NAME)) {
+ String localName = reader.getLocalName();
+ if (localName.equals(CredentialDefinition.TAG_NAME)) {
readCredential(reader, addr, credentialsToAdd);
continue;
}
- if (tagName.equals(RedirecRewritetRuleDefinition.TAG_NAME)) {
+ if (localName.equals(RedirecRewritetRuleDefinition.TAG_NAME)) {
readRewriteRule(reader, addr, redirectRulesToAdd);
continue;
}
- SimpleAttributeDefinition def = SecureDeploymentDefinition.lookup(tagName);
- if (def == null) throw new XMLStreamException("Unknown secure-deployment tag " + tagName);
+ SimpleAttributeDefinition def = resource.lookup(localName);
+ if (def == null) throw new XMLStreamException("Unknown secure-deployment tag " + localName);
def.parseAndSetParameter(reader.getElementText(), addSecureDeployment, reader);
}
@@ -236,6 +247,7 @@ class KeycloakSubsystemParser implements XMLStreamConstants, XMLElementReader attributes, XMLExtendedStreamWriter writer, SubsystemMarshallingContext context) throws XMLStreamException {
+ if (!context.getModelNode().get(tagName).isDefined()) {
return;
}
- for (Property deployment : context.getModelNode().get(SecureDeploymentDefinition.TAG_NAME).asPropertyList()) {
- writer.writeStartElement(SecureDeploymentDefinition.TAG_NAME);
+ for (Property deployment : context.getModelNode().get(tagName).asPropertyList()) {
+ writer.writeStartElement(tagName);
writer.writeAttribute("name", deployment.getName());
ModelNode deploymentElements = deployment.getValue();
- for (AttributeDefinition element : SecureDeploymentDefinition.ALL_ATTRIBUTES) {
+ for (AttributeDefinition element : attributes) {
element.marshallAsElement(deploymentElements, writer);
}
@@ -271,7 +291,7 @@ class KeycloakSubsystemParser implements XMLStreamConstants, XMLElementReader DEPLOYMENT_ONLY_ATTRIBUTES = new ArrayList();
- static {
- DEPLOYMENT_ONLY_ATTRIBUTES.add(REALM);
- DEPLOYMENT_ONLY_ATTRIBUTES.add(RESOURCE);
- DEPLOYMENT_ONLY_ATTRIBUTES.add(USE_RESOURCE_ROLE_MAPPINGS);
- DEPLOYMENT_ONLY_ATTRIBUTES.add(BEARER_ONLY);
- DEPLOYMENT_ONLY_ATTRIBUTES.add(ENABLE_BASIC_AUTH);
- DEPLOYMENT_ONLY_ATTRIBUTES.add(PUBLIC_CLIENT);
- DEPLOYMENT_ONLY_ATTRIBUTES.add(TURN_OFF_CHANGE_SESSION);
- DEPLOYMENT_ONLY_ATTRIBUTES.add(TOKEN_MINIMUM_TIME_TO_LIVE);
- DEPLOYMENT_ONLY_ATTRIBUTES.add(MIN_TIME_BETWEEN_JWKS_REQUESTS);
- }
-
- protected static final List ALL_ATTRIBUTES = new ArrayList();
- static {
- ALL_ATTRIBUTES.addAll(DEPLOYMENT_ONLY_ATTRIBUTES);
- ALL_ATTRIBUTES.addAll(SharedAttributeDefinitons.ATTRIBUTES);
- }
-
- private static final Map DEFINITION_LOOKUP = new HashMap();
- static {
- for (SimpleAttributeDefinition def : ALL_ATTRIBUTES) {
- DEFINITION_LOOKUP.put(def.getXmlName(), def);
- }
- }
-
- private static SecureDeploymentWriteAttributeHandler attrHandler = new SecureDeploymentWriteAttributeHandler(ALL_ATTRIBUTES);
+ static final String TAG_NAME = "secure-deployment";
public SecureDeploymentDefinition() {
- super(PathElement.pathElement(TAG_NAME),
- KeycloakExtension.getResourceDescriptionResolver(TAG_NAME),
- SecureDeploymentAddHandler.INSTANCE,
- SecureDeploymentRemoveHandler.INSTANCE);
+ super(TAG_NAME, ALL_ATTRIBUTES, new SecureDeploymentAddHandler(), new SecureDeploymentRemoveHandler(), new SecureDeploymentWriteAttributeHandler());
}
- @Override
- public void registerOperations(ManagementResourceRegistration resourceRegistration) {
- super.registerOperations(resourceRegistration);
- resourceRegistration.registerOperationHandler(GenericSubsystemDescribeHandler.DEFINITION, GenericSubsystemDescribeHandler.INSTANCE);
- }
+ /**
+ * Add a deployment to a realm.
+ *
+ * @author Stan Silvert ssilvert@redhat.com (C) 2013 Red Hat Inc.
+ */
+ static final class SecureDeploymentAddHandler extends AbstractAdapterConfigurationAddHandler {
- @Override
- public void registerAttributes(ManagementResourceRegistration resourceRegistration) {
- super.registerAttributes(resourceRegistration);
- for (AttributeDefinition attrDef : ALL_ATTRIBUTES) {
- resourceRegistration.registerReadWriteAttribute(attrDef, null, attrHandler);
+ static final String HTTP_SERVER_AUTHENTICATION_CAPABILITY = "org.wildfly.security.http-server-mechanism-factory";
+ static RuntimeCapability HTTP_SERVER_AUTHENTICATION_RUNTIME_CAPABILITY;
+
+ static {
+ try {
+ HTTP_SERVER_AUTHENTICATION_RUNTIME_CAPABILITY = RuntimeCapability
+ .Builder.of(HTTP_SERVER_AUTHENTICATION_CAPABILITY, true, HttpServerAuthenticationMechanismFactory.class)
+ .build();
+ } catch (NoClassDefFoundError ncfe) {
+ // ignore, Elytron not present thus no capability will be published by this resource definition
+ }
+ }
+
+ SecureDeploymentAddHandler() {
+ super(HTTP_SERVER_AUTHENTICATION_RUNTIME_CAPABILITY, ALL_ATTRIBUTES);
+ }
+
+ @Override
+ protected void performRuntime(OperationContext context, ModelNode operation, ModelNode model) throws OperationFailedException {
+ super.performRuntime(context, operation, model);
+ if (HTTP_SERVER_AUTHENTICATION_RUNTIME_CAPABILITY != null) {
+ installCapability(context, operation);
+ }
+ }
+
+ static void installCapability(OperationContext context, ModelNode operation) {
+ PathAddress pathAddress = PathAddress.pathAddress(operation.get(OP_ADDR));
+ String factoryName = pathAddress.getLastElement().getValue();
+ ServiceName serviceName = context.getCapabilityServiceName(HTTP_SERVER_AUTHENTICATION_CAPABILITY, factoryName, HttpServerAuthenticationMechanismFactory.class);
+ KeycloakHttpAuthenticationFactoryService service = new KeycloakHttpAuthenticationFactoryService(factoryName);
+ ServiceTarget serviceTarget = context.getServiceTarget();
+ serviceTarget.addService(serviceName, service).setInitialMode(ServiceController.Mode.ACTIVE).install();
}
}
- public static SimpleAttributeDefinition lookup(String name) {
- return DEFINITION_LOOKUP.get(name);
+ /**
+ * Remove a secure-deployment from a realm.
+ *
+ * @author Stan Silvert ssilvert@redhat.com (C) 2013 Red Hat Inc.
+ */
+ static final class SecureDeploymentRemoveHandler extends AbstractAdapterConfigurationRemoveHandler {}
+
+ /**
+ * Update an attribute on a secure-deployment.
+ *
+ * @author Stan Silvert ssilvert@redhat.com (C) 2013 Red Hat Inc.
+ */
+ static final class SecureDeploymentWriteAttributeHandler extends AbstractAdapterConfigurationWriteAttributeHandler {
+ SecureDeploymentWriteAttributeHandler() {
+ super(ALL_ATTRIBUTES);
+ }
}
}
diff --git a/adapters/oidc/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/extension/SecureServerDefinition.java b/adapters/oidc/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/extension/SecureServerDefinition.java
new file mode 100755
index 0000000000..7d8fd05dfd
--- /dev/null
+++ b/adapters/oidc/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/extension/SecureServerDefinition.java
@@ -0,0 +1,258 @@
+/*
+ * 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.subsystem.adapter.extension;
+
+import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.OP_ADDR;
+import static org.keycloak.subsystem.adapter.extension.KeycloakHttpServerAuthenticationMechanismFactoryDefinition.KeycloakHttpServerAuthenticationMechanismFactoryAddHandler.HTTP_SERVER_AUTHENTICATION_CAPABILITY;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URL;
+import java.nio.file.Path;
+import java.util.Collections;
+import java.util.Date;
+import java.util.List;
+
+import io.undertow.io.IoCallback;
+import io.undertow.io.Sender;
+import io.undertow.server.HttpServerExchange;
+import io.undertow.server.handlers.resource.Resource;
+import io.undertow.server.handlers.resource.ResourceChangeListener;
+import io.undertow.server.handlers.resource.ResourceManager;
+import io.undertow.util.ETag;
+import io.undertow.util.MimeMappings;
+import org.jboss.as.controller.OperationContext;
+import org.jboss.as.controller.OperationFailedException;
+import org.jboss.as.controller.PathAddress;
+import org.jboss.as.controller.capability.RuntimeCapability;
+import org.jboss.as.server.mgmt.domain.ExtensibleHttpManagement;
+import org.jboss.dmr.ModelNode;
+import org.jboss.msc.service.Service;
+import org.jboss.msc.service.ServiceController.Mode;
+import org.jboss.msc.service.ServiceName;
+import org.jboss.msc.service.ServiceTarget;
+import org.jboss.msc.service.StartContext;
+import org.jboss.msc.service.StartException;
+import org.jboss.msc.service.StopContext;
+import org.jboss.msc.value.InjectedValue;
+import org.wildfly.security.http.HttpServerAuthenticationMechanismFactory;
+
+/**
+ * Defines attributes and operations for a secure-deployment.
+ *
+ * @author Stan Silvert ssilvert@redhat.com (C) 2013 Red Hat Inc.
+ */
+final class SecureServerDefinition extends AbstractAdapterConfigurationDefinition {
+
+ public static final String TAG_NAME = "secure-server";
+
+ SecureServerDefinition() {
+ super(TAG_NAME, ALL_ATTRIBUTES, new SecureServerAddHandler(), new SecureServerRemoveHandler(), new SecureServerWriteHandler());
+ }
+
+ /**
+ * A {@link AbstractAdapterConfigurationAddHandler} that exposes a {@link SecureServerDefinition}
+ * as a capability through the installation of a {@link KeycloakHttpAuthenticationFactoryService}.
+ *
+ * @author Pedro Igor
+ */
+ static final class SecureServerAddHandler extends AbstractAdapterConfigurationAddHandler {
+
+ static final String HTTP_SERVER_AUTHENTICATION_CAPABILITY = "org.wildfly.security.http-server-mechanism-factory";
+ static final String HTTP_MANAGEMENT_HTTP_EXTENSIBLE_CAPABILITY = "org.wildfly.management.http.extensible";
+ static RuntimeCapability HTTP_SERVER_AUTHENTICATION_RUNTIME_CAPABILITY;
+
+ static {
+ try {
+ HTTP_SERVER_AUTHENTICATION_RUNTIME_CAPABILITY = RuntimeCapability
+ .Builder.of(HTTP_SERVER_AUTHENTICATION_CAPABILITY, true, HttpServerAuthenticationMechanismFactory.class)
+ .build();
+ } catch (NoClassDefFoundError ncfe) {
+ // ignore, Elytron not present thus no capability will be published by this resource definition
+ }
+ }
+
+ SecureServerAddHandler() {
+ super(HTTP_SERVER_AUTHENTICATION_RUNTIME_CAPABILITY, ALL_ATTRIBUTES);
+ }
+
+ @Override
+ protected void performRuntime(OperationContext context, ModelNode operation, ModelNode model) throws OperationFailedException {
+ super.performRuntime(context, operation, model);
+ if (HTTP_SERVER_AUTHENTICATION_RUNTIME_CAPABILITY != null) {
+ installCapability(context, operation);
+ }
+ }
+
+ static void installCapability(OperationContext context, ModelNode operation) throws OperationFailedException {
+ PathAddress pathAddress = PathAddress.pathAddress(operation.get(OP_ADDR));
+ String factoryName = pathAddress.getLastElement().getValue();
+ ServiceName serviceName = context.getCapabilityServiceName(HTTP_SERVER_AUTHENTICATION_CAPABILITY, factoryName, HttpServerAuthenticationMechanismFactory.class);
+ boolean publicClient = SecureServerDefinition.PUBLIC_CLIENT.resolveModelAttribute(context, operation).asBoolean(false);
+
+ if (!publicClient) {
+ throw new OperationFailedException("Only public clients are allowed to have their configuration exposed through the management interface");
+ }
+
+ KeycloakHttpAuthenticationFactoryService service = new KeycloakHttpAuthenticationFactoryService(factoryName);
+ ServiceTarget serviceTarget = context.getServiceTarget();
+ InjectedValue injectedValue = new InjectedValue<>();
+ serviceTarget.addService(serviceName.append("http-management-context"), createHttpManagementConfigContextService(factoryName, injectedValue))
+ .addDependency(context.getCapabilityServiceName(HTTP_MANAGEMENT_HTTP_EXTENSIBLE_CAPABILITY, ExtensibleHttpManagement.class), ExtensibleHttpManagement.class, injectedValue).setInitialMode(Mode.ACTIVE).install();
+ serviceTarget.addService(serviceName, service).setInitialMode(Mode.ACTIVE).install();
+ }
+ }
+
+ /**
+ * A {@link AbstractAdapterConfigurationRemoveHandler} that handles the removal of {@link SecureServerDefinition}.
+ *
+ * @author Pedro Igor
+ */
+ static final class SecureServerRemoveHandler extends AbstractAdapterConfigurationRemoveHandler {
+ @Override
+ protected void performRuntime(OperationContext context, ModelNode operation, ModelNode model) throws OperationFailedException {
+ super.performRuntime(context, operation, model);
+ PathAddress pathAddress = PathAddress.pathAddress(operation.get(OP_ADDR));
+ String factoryName = pathAddress.getLastElement().getValue();
+ ServiceName serviceName = context.getCapabilityServiceName(HTTP_SERVER_AUTHENTICATION_CAPABILITY, factoryName, HttpServerAuthenticationMechanismFactory.class);
+ context.removeService(serviceName);
+ }
+
+ @Override
+ protected void recoverServices(OperationContext context, ModelNode operation, ModelNode model) throws OperationFailedException {
+ super.recoverServices(context, operation, model);
+ SecureServerDefinition.SecureServerAddHandler.installCapability(context, operation);
+ }
+ }
+
+ /**
+ * A {@link AbstractAdapterConfigurationWriteAttributeHandler} that updates attributes on a {@link SecureServerDefinition}.
+ *
+ * @author Pedro Igor
+ */
+ static final class SecureServerWriteHandler extends AbstractAdapterConfigurationWriteAttributeHandler {
+ SecureServerWriteHandler() {
+ super(ALL_ATTRIBUTES);
+ }
+ }
+
+ private static Service createHttpManagementConfigContextService(final String factoryName, final InjectedValue httpConfigContext) {
+ final String contextName = "/keycloak/adapter/" + factoryName + "/";
+ return new Service() {
+ public void start(StartContext startContext) throws StartException {
+ ExtensibleHttpManagement extensibleHttpManagement = (ExtensibleHttpManagement)httpConfigContext.getValue();
+ extensibleHttpManagement.addStaticContext(contextName, new ResourceManager() {
+ public Resource getResource(final String path) throws IOException {
+ KeycloakAdapterConfigService adapterConfigService = KeycloakAdapterConfigService.getInstance();
+ final String config = adapterConfigService.getJSON(factoryName);
+
+ if (config == null) {
+ return null;
+ }
+
+ return new Resource() {
+ public String getPath() {
+ return null;
+ }
+
+ public Date getLastModified() {
+ return null;
+ }
+
+ public String getLastModifiedString() {
+ return null;
+ }
+
+ public ETag getETag() {
+ return null;
+ }
+
+ public String getName() {
+ return null;
+ }
+
+ public boolean isDirectory() {
+ return false;
+ }
+
+ public List list() {
+ return Collections.emptyList();
+ }
+
+ public String getContentType(MimeMappings mimeMappings) {
+ return "application/json";
+ }
+
+ public void serve(Sender sender, HttpServerExchange exchange, IoCallback completionCallback) {
+ sender.send(config);
+ }
+
+ public Long getContentLength() {
+ return Long.valueOf((long)config.length());
+ }
+
+ public String getCacheKey() {
+ return null;
+ }
+
+ public File getFile() {
+ return null;
+ }
+
+ public Path getFilePath() {
+ return null;
+ }
+
+ public File getResourceManagerRoot() {
+ return null;
+ }
+
+ public Path getResourceManagerRootPath() {
+ return null;
+ }
+
+ public URL getUrl() {
+ return null;
+ }
+ };
+ }
+
+ public boolean isResourceChangeListenerSupported() {
+ return false;
+ }
+
+ public void registerResourceChangeListener(ResourceChangeListener listener) {
+ }
+
+ public void removeResourceChangeListener(ResourceChangeListener listener) {
+ }
+
+ public void close() throws IOException {
+ }
+ });
+ }
+
+ public void stop(StopContext stopContext) {
+ ((ExtensibleHttpManagement)httpConfigContext.getValue()).removeContext(contextName);
+ }
+
+ public Void getValue() throws IllegalStateException, IllegalArgumentException {
+ return null;
+ }
+ };
+ }
+}
diff --git a/adapters/oidc/wildfly/wildfly-subsystem/src/main/resources/org/keycloak/subsystem/adapter/extension/LocalDescriptions.properties b/adapters/oidc/wildfly/wildfly-subsystem/src/main/resources/org/keycloak/subsystem/adapter/extension/LocalDescriptions.properties
index c9cea77787..f6097ae5cf 100755
--- a/adapters/oidc/wildfly/wildfly-subsystem/src/main/resources/org/keycloak/subsystem/adapter/extension/LocalDescriptions.properties
+++ b/adapters/oidc/wildfly/wildfly-subsystem/src/main/resources/org/keycloak/subsystem/adapter/extension/LocalDescriptions.properties
@@ -20,6 +20,8 @@ keycloak.subsystem.add=Operation Adds Keycloak adapter subsystem
keycloak.subsystem.remove=Operation removes Keycloak adapter subsystem
keycloak.subsystem.realm=A Keycloak realm.
keycloak.subsystem.secure-deployment=A deployment secured by Keycloak.
+keycloak.subsystem.secure-server=A configuration exposed to the server.
+keycloak.subsystem.http-server-mechanism-factory=A http-server-mechanism-factory exposed to the server.
keycloak.realm=A Keycloak realm.
keycloak.realm.add=Add a realm definition to the subsystem.
@@ -90,7 +92,48 @@ keycloak.secure-deployment.token-minimum-time-to-live=The adapter will refresh t
keycloak.secure-deployment.min-time-between-jwks-requests=If adapter recognize token signed by unknown public key, it will try to download new public key from keycloak server. However it won't try to download if already tried it in less than 'min-time-between-jwks-requests' seconds
keycloak.secure-deployment.ignore-oauth-query-parameter=disable query parameter parsing for access_token
+keycloak.secure-server=A deployment secured by Keycloak
+keycloak.secure-server.add=Add a deployment to be secured by Keycloak
+keycloak.secure-server.realm=Keycloak realm
+keycloak.secure-server.remove=Remove a deployment to be secured by Keycloak
+keycloak.secure-server.realm-public-key=Public key of the realm
+keycloak.secure-server.auth-server-url=Base URL of the Realm Auth Server
+keycloak.secure-server.disable-trust-manager=Adapter will not use a trust manager when making adapter HTTPS requests
+keycloak.secure-server.ssl-required=Specify if SSL is required (valid values are all, external and none)
+keycloak.secure-server.allow-any-hostname=SSL Setting
+keycloak.secure-server.truststore=Truststore used for adapter client HTTPS requests
+keycloak.secure-server.truststore-password=Password of the Truststore
+keycloak.secure-server.connection-pool-size=Connection pool size for the client used by the adapter
+keycloak.secure-server.resource=Application name
+keycloak.secure-server.use-resource-role-mappings=Use resource level permissions from token
+keycloak.secure-server.credentials=Adapter credentials
+keycloak.secure-server.redirect-rewrite-rule=Apply a rewrite rule for the redirect URI
+keycloak.secure-server.bearer-only=Bearer Token Auth only
+keycloak.secure-server.enable-basic-auth=Enable Basic Authentication
+keycloak.secure-server.public-client=Public client
+keycloak.secure-server.enable-cors=Enable Keycloak CORS support
+keycloak.secure-server.autodetect-bearer-only=autodetect bearer-only requests
+keycloak.secure-server.client-keystore=n/a
+keycloak.secure-server.client-keystore-password=n/a
+keycloak.secure-server.client-key-password=n/a
+keycloak.secure-server.cors-max-age=CORS max-age header
+keycloak.secure-server.cors-allowed-headers=CORS allowed headers
+keycloak.secure-server.cors-allowed-methods=CORS allowed methods
+keycloak.secure-server.cors-exposed-headers=CORS exposed headers
+keycloak.secure-server.expose-token=Enable secure URL that exposes access token
+keycloak.secure-server.auth-server-url-for-backend-requests=URL to use to make background calls to auth server
+keycloak.secure-server.always-refresh-token=Refresh token on every single web request
+keycloak.secure-server.register-node-at-startup=Cluster setting
+keycloak.secure-server.register-node-period=how often to re-register node
+keycloak.secure-server.token-store=cookie or session storage for auth session data
+keycloak.secure-server.principal-attribute=token attribute to use to set Principal name
+keycloak.secure-server.turn-off-change-session-id-on-login=The session id is changed by default on a successful login. Change this to true if you want to turn this off
+keycloak.secure-server.token-minimum-time-to-live=The adapter will refresh the token if the current token is expired OR will expire in 'token-minimum-time-to-live' seconds or less
+keycloak.secure-server.min-time-between-jwks-requests=If adapter recognize token signed by unknown public key, it will try to download new public key from keycloak server. However it won't try to download if already tried it in less than 'min-time-between-jwks-requests' seconds
+keycloak.secure-server.ignore-oauth-query-parameter=disable query parameter parsing for access_token
+
keycloak.secure-deployment.credential=Credential value
+keycloak.secure-server.credential=Credential value
keycloak.credential=Credential
keycloak.credential.value=Credential value
diff --git a/adapters/oidc/wildfly/wildfly-subsystem/src/main/resources/schema/wildfly-keycloak_1_1.xsd b/adapters/oidc/wildfly/wildfly-subsystem/src/main/resources/schema/wildfly-keycloak_1_1.xsd
index d8f5bc3d74..caa147d821 100755
--- a/adapters/oidc/wildfly/wildfly-subsystem/src/main/resources/schema/wildfly-keycloak_1_1.xsd
+++ b/adapters/oidc/wildfly/wildfly-subsystem/src/main/resources/schema/wildfly-keycloak_1_1.xsd
@@ -38,6 +38,7 @@
+
@@ -84,7 +85,7 @@
-
+
@@ -99,9 +100,9 @@
-
-
-
+
+
+
diff --git a/adapters/oidc/wildfly/wildfly-subsystem/src/test/java/org/keycloak/subsystem/adapter/extension/SubsystemParsingTestCase.java b/adapters/oidc/wildfly/wildfly-subsystem/src/test/java/org/keycloak/subsystem/adapter/extension/SubsystemParsingTestCase.java
index 9d5f87ab39..4adad9f21a 100755
--- a/adapters/oidc/wildfly/wildfly-subsystem/src/test/java/org/keycloak/subsystem/adapter/extension/SubsystemParsingTestCase.java
+++ b/adapters/oidc/wildfly/wildfly-subsystem/src/test/java/org/keycloak/subsystem/adapter/extension/SubsystemParsingTestCase.java
@@ -73,7 +73,7 @@ public class SubsystemParsingTestCase extends AbstractSubsystemBaseTest {
ModelNode deployment = new ModelNode();
deployment.get("realm").set("demo");
deployment.get("resource").set("customer-portal");
- service.addSecureDeployment(deploymentOp, deployment);
+ service.addSecureDeployment(deploymentOp, deployment, false);
addCredential(addr, service, "secret", "secret1");
addCredential(addr, service, "jwt.client-keystore-file", "/tmp/foo.jks");
diff --git a/adapters/oidc/wildfly/wildfly-subsystem/src/test/resources/org/keycloak/subsystem/adapter/extension/keycloak-1.1.xml b/adapters/oidc/wildfly/wildfly-subsystem/src/test/resources/org/keycloak/subsystem/adapter/extension/keycloak-1.1.xml
index 246d76855f..fce5c41dae 100755
--- a/adapters/oidc/wildfly/wildfly-subsystem/src/test/resources/org/keycloak/subsystem/adapter/extension/keycloak-1.1.xml
+++ b/adapters/oidc/wildfly/wildfly-subsystem/src/test/resources/org/keycloak/subsystem/adapter/extension/keycloak-1.1.xml
@@ -40,6 +40,10 @@
session
sub
+
+ MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqKoq+a9MgXepmsPJDmo45qswuChW9pWjanX68oIBuI4hGvhQxFHryCow230A+sr7tFdMQMt8f1l/ysmV/fYAuW29WaoY4kI4Ou1yYPuwywKSsxT6PooTs83hKyZ1h4LZMj5DkLGDDDyVRHob2WmPaYg9RGVRw3iGGsD/p+Yb+L/gnBYQnZZ7lYqmN7h36p5CkzzlgXQA1Ha8sQxL+rJNH8+sZm0vBrKsoII3Of7TqHGsm1RwFV3XCuGJ7S61AbjJMXL5DQgJl9Z5scvxGAyoRLKC294UgMnQdzyBTMPw2GybxkRKmiK2KjQKmcopmrJp/Bt6fBR6ZkGSs9qUlxGHgwIDAQAB
+ http://localhost:8180/auth
+
master
web-console
@@ -69,4 +73,16 @@
/api/$1/
+
+ jboss-infra
+ wildfly-management
+ true
+ EXTERNAL
+ preferred_username
+
+
+ jboss-infra
+ wildfly-console
+ true
+
\ No newline at end of file
diff --git a/adapters/pom.xml b/adapters/pom.xml
index 21e23b987a..96c56d5300 100755
--- a/adapters/pom.xml
+++ b/adapters/pom.xml
@@ -20,7 +20,7 @@
keycloak-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
../pom.xml
Keycloak Adapters
diff --git a/adapters/saml/as7-eap6/adapter/pom.xml b/adapters/saml/as7-eap6/adapter/pom.xml
index dd8aff5317..2fdd3ee728 100755
--- a/adapters/saml/as7-eap6/adapter/pom.xml
+++ b/adapters/saml/as7-eap6/adapter/pom.xml
@@ -21,7 +21,7 @@
keycloak-saml-eap-integration-pom
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
../pom.xml
4.0.0
@@ -78,6 +78,18 @@
7.1.2.Final
provided
+
+ org.infinispan
+ infinispan-core
+ provided
+ 5.2.20.Final
+
+
+ org.infinispan
+ infinispan-cachestore-remote
+ provided
+ 5.2.20.Final
+
org.keycloak
keycloak-saml-tomcat-adapter-core
diff --git a/adapters/saml/as7-eap6/adapter/src/main/java/org/keycloak/adapters/saml/jbossweb/infinispan/InfinispanSessionCacheIdMapperUpdater.java b/adapters/saml/as7-eap6/adapter/src/main/java/org/keycloak/adapters/saml/jbossweb/infinispan/InfinispanSessionCacheIdMapperUpdater.java
index b6f4c23f09..dd19a7b7e6 100644
--- a/adapters/saml/as7-eap6/adapter/src/main/java/org/keycloak/adapters/saml/jbossweb/infinispan/InfinispanSessionCacheIdMapperUpdater.java
+++ b/adapters/saml/as7-eap6/adapter/src/main/java/org/keycloak/adapters/saml/jbossweb/infinispan/InfinispanSessionCacheIdMapperUpdater.java
@@ -16,9 +16,11 @@
*/
package org.keycloak.adapters.saml.jbossweb.infinispan;
+import org.keycloak.adapters.saml.AdapterConstants;
import org.keycloak.adapters.spi.SessionIdMapper;
import org.keycloak.adapters.spi.SessionIdMapperUpdater;
+import java.util.List;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.servlet.ServletContext;
@@ -26,6 +28,8 @@ import org.apache.catalina.Context;
import org.infinispan.Cache;
import org.infinispan.configuration.cache.CacheMode;
import org.infinispan.configuration.cache.Configuration;
+import org.infinispan.loaders.CacheLoaderManager;
+import org.infinispan.loaders.remote.RemoteCacheStore;
import org.infinispan.manager.EmbeddedCacheManager;
import org.jboss.logging.Logger;
@@ -37,24 +41,12 @@ public class InfinispanSessionCacheIdMapperUpdater {
private static final Logger LOG = Logger.getLogger(InfinispanSessionCacheIdMapperUpdater.class);
- public static final String DEFAULT_CACHE_CONTAINER_JNDI_NAME = "java:jboss/infinispan/container/web";
-
- private static final String DEPLOYMENT_CACHE_CONTAINER_JNDI_NAME_PARAM_NAME = "keycloak.sessionIdMapperUpdater.infinispan.cacheContainerJndi";
- private static final String DEPLOYMENT_CACHE_NAME_PARAM_NAME = "keycloak.sessionIdMapperUpdater.infinispan.deploymentCacheName";
- private static final String SSO_CACHE_NAME_PARAM_NAME = "keycloak.sessionIdMapperUpdater.infinispan.cacheName";
+ public static final String DEFAULT_CACHE_CONTAINER_JNDI_NAME = "java:jboss/infinispan/container";
public static SessionIdMapperUpdater addTokenStoreUpdaters(Context context, SessionIdMapper mapper, SessionIdMapperUpdater previousIdMapperUpdater) {
- boolean distributable = context.getDistributable();
-
- if (! distributable) {
- LOG.warnv("Deployment {0} does not use supported distributed session cache mechanism", context.getName());
- return previousIdMapperUpdater;
- }
-
ServletContext servletContext = context.getServletContext();
- String cacheContainerLookup = (servletContext != null && servletContext.getInitParameter(DEPLOYMENT_CACHE_CONTAINER_JNDI_NAME_PARAM_NAME) != null)
- ? servletContext.getInitParameter(DEPLOYMENT_CACHE_CONTAINER_JNDI_NAME_PARAM_NAME)
- : DEFAULT_CACHE_CONTAINER_JNDI_NAME;
+ String containerName = servletContext == null ? null : servletContext.getInitParameter(AdapterConstants.REPLICATION_CONFIG_CONTAINER_PARAM_NAME);
+ String cacheName = servletContext == null ? null : servletContext.getInitParameter(AdapterConstants.REPLICATION_CONFIG_SSO_CACHE_PARAM_NAME);
// the following is based on https://github.com/jbossas/jboss-as/blob/7.2.0.Final/clustering/web-infinispan/src/main/java/org/jboss/as/clustering/web/infinispan/DistributedCacheManagerFactory.java#L116-L122
String host = context.getParent() == null ? "" : context.getParent().getName();
@@ -62,43 +54,48 @@ public class InfinispanSessionCacheIdMapperUpdater {
if ("/".equals(contextPath)) {
contextPath = "/ROOT";
}
+ String deploymentSessionCacheName = host + contextPath;
- boolean deploymentSessionCacheNamePreset = servletContext != null && servletContext.getInitParameter(DEPLOYMENT_CACHE_NAME_PARAM_NAME) != null;
- String deploymentSessionCacheName = deploymentSessionCacheNamePreset
- ? servletContext.getInitParameter(DEPLOYMENT_CACHE_NAME_PARAM_NAME)
- : host + contextPath;
- boolean ssoCacheNamePreset = servletContext != null && servletContext.getInitParameter(SSO_CACHE_NAME_PARAM_NAME) != null;
- String ssoCacheName = ssoCacheNamePreset
- ? servletContext.getInitParameter(SSO_CACHE_NAME_PARAM_NAME)
- : deploymentSessionCacheName + ".ssoCache";
+ if (containerName == null || cacheName == null || deploymentSessionCacheName == null) {
+ LOG.warnv("Cannot determine parameters of SSO cache for deployment {0}.", host + contextPath);
+
+ return previousIdMapperUpdater;
+ }
+
+ String cacheContainerLookup = DEFAULT_CACHE_CONTAINER_JNDI_NAME + "/" + containerName;
try {
EmbeddedCacheManager cacheManager = (EmbeddedCacheManager) new InitialContext().lookup(cacheContainerLookup);
- Configuration ssoCacheConfiguration = cacheManager.getCacheConfiguration(ssoCacheName);
+ Configuration ssoCacheConfiguration = cacheManager.getCacheConfiguration(cacheName);
if (ssoCacheConfiguration == null) {
Configuration cacheConfiguration = cacheManager.getCacheConfiguration(deploymentSessionCacheName);
if (cacheConfiguration == null) {
- LOG.debugv("Using default cache container configuration for SSO cache. lookup={0}, looked up configuration of cache={1}", cacheContainerLookup, deploymentSessionCacheName);
+ LOG.debugv("Using default configuration for SSO cache {0}.{1}.", containerName, cacheName);
ssoCacheConfiguration = cacheManager.getDefaultCacheConfiguration();
} else {
- LOG.debugv("Using distributed HTTP session cache configuration for SSO cache. lookup={0}, configuration taken from cache={1}", cacheContainerLookup, deploymentSessionCacheName);
+ LOG.debugv("Using distributed HTTP session cache configuration for SSO cache {0}.{1}, configuration taken from cache {2}",
+ containerName, cacheName, deploymentSessionCacheName);
ssoCacheConfiguration = cacheConfiguration;
- cacheManager.defineConfiguration(ssoCacheName, ssoCacheConfiguration);
+ cacheManager.defineConfiguration(cacheName, ssoCacheConfiguration);
}
} else {
- LOG.debugv("Using custom configuration for SSO cache. lookup={0}, cache name={1}", cacheContainerLookup, ssoCacheName);
+ LOG.debugv("Using custom configuration of SSO cache {0}.{1}.", containerName, cacheName);
}
CacheMode ssoCacheMode = ssoCacheConfiguration.clustering().cacheMode();
if (ssoCacheMode != CacheMode.REPL_ASYNC && ssoCacheMode != CacheMode.REPL_SYNC) {
- LOG.warnv("SSO cache mode is {0}, it is recommended to use replicated mode instead", ssoCacheConfiguration.clustering().cacheModeString());
+ LOG.warnv("SSO cache mode is {0}, it is recommended to use replicated mode instead.", ssoCacheConfiguration.clustering().cacheModeString());
}
- Cache ssoCache = cacheManager.getCache(ssoCacheName, true);
- ssoCache.addListener(new SsoSessionCacheListener(mapper));
+ Cache ssoCache = cacheManager.getCache(cacheName, true);
+ final SsoSessionCacheListener listener = new SsoSessionCacheListener(ssoCache, mapper);
+ ssoCache.addListener(listener);
- LOG.debugv("Added distributed SSO session cache, lookup={0}, cache name={1}", cacheContainerLookup, deploymentSessionCacheName);
+ // Not possible to add listener for cross-DC support because of too old Infinispan in AS 7
+ warnIfRemoteStoreIsUsed(ssoCache);
+
+ LOG.debugv("Added distributed SSO session cache, lookup={0}, cache name={1}", cacheContainerLookup, cacheName);
SsoCacheSessionIdMapperUpdater updater = new SsoCacheSessionIdMapperUpdater(ssoCache, previousIdMapperUpdater);
@@ -108,4 +105,17 @@ public class InfinispanSessionCacheIdMapperUpdater {
return previousIdMapperUpdater;
}
}
+
+ private static void warnIfRemoteStoreIsUsed(Cache ssoCache) {
+ final List stores = getRemoteStores(ssoCache);
+ if (stores == null || stores.isEmpty()) {
+ return;
+ }
+
+ LOG.warnv("Unable to listen for events on remote stores configured for cache {0} (unsupported in this Infinispan limitations), logouts will not be propagated.", ssoCache.getName());
+ }
+
+ public static List getRemoteStores(Cache ssoCache) {
+ return ssoCache.getAdvancedCache().getComponentRegistry().getComponent(CacheLoaderManager.class).getCacheLoaders(RemoteCacheStore.class);
+ }
}
diff --git a/adapters/saml/as7-eap6/adapter/src/main/java/org/keycloak/adapters/saml/jbossweb/infinispan/SsoSessionCacheListener.java b/adapters/saml/as7-eap6/adapter/src/main/java/org/keycloak/adapters/saml/jbossweb/infinispan/SsoSessionCacheListener.java
index ee100ad317..aded4a38e9 100644
--- a/adapters/saml/as7-eap6/adapter/src/main/java/org/keycloak/adapters/saml/jbossweb/infinispan/SsoSessionCacheListener.java
+++ b/adapters/saml/as7-eap6/adapter/src/main/java/org/keycloak/adapters/saml/jbossweb/infinispan/SsoSessionCacheListener.java
@@ -20,6 +20,7 @@ import org.keycloak.adapters.spi.SessionIdMapper;
import java.util.*;
import java.util.concurrent.*;
+import org.infinispan.Cache;
import org.infinispan.notifications.Listener;
import org.infinispan.notifications.cachelistener.annotation.*;
import org.infinispan.notifications.cachelistener.event.*;
@@ -43,9 +44,12 @@ public class SsoSessionCacheListener {
private final SessionIdMapper idMapper;
+ private final Cache ssoCache;
+
private ExecutorService executor = Executors.newSingleThreadExecutor();
- public SsoSessionCacheListener(SessionIdMapper idMapper) {
+ public SsoSessionCacheListener(Cache ssoCache, SessionIdMapper idMapper) {
+ this.ssoCache = ssoCache;
this.idMapper = idMapper;
}
@@ -68,8 +72,10 @@ public class SsoSessionCacheListener {
@CacheEntryRemoved
@CacheEntryModified
public void addEvent(TransactionalEvent event) {
- if (event.isPre() == false) {
+ if (event.getGlobalTransaction() != null) {
map.get(event.getGlobalTransaction()).add(event);
+ } else {
+ processEvent(event);
}
}
@@ -87,40 +93,53 @@ public class SsoSessionCacheListener {
}
for (final Event e : events) {
- switch (e.getType()) {
- case CACHE_ENTRY_CREATED:
- this.executor.submit(new Runnable() {
- @Override public void run() {
- cacheEntryCreated((CacheEntryCreatedEvent) e);
- }
- });
- break;
+ processEvent(e);
+ }
+ }
- case CACHE_ENTRY_MODIFIED:
- this.executor.submit(new Runnable() {
- @Override public void run() {
- cacheEntryModified((CacheEntryModifiedEvent) e);
- }
- });
- break;
+ private void processEvent(final Event e) {
+ switch (e.getType()) {
+ case CACHE_ENTRY_CREATED:
+ this.executor.submit(new Runnable() {
+ @Override public void run() {
+ cacheEntryCreated((CacheEntryCreatedEvent) e);
+ }
+ });
+ break;
+
+ case CACHE_ENTRY_MODIFIED:
+ this.executor.submit(new Runnable() {
+ @Override public void run() {
+ cacheEntryModified((CacheEntryModifiedEvent) e);
+ }
+ });
+ break;
- case CACHE_ENTRY_REMOVED:
- this.executor.submit(new Runnable() {
- @Override public void run() {
- cacheEntryRemoved((CacheEntryRemovedEvent) e);
- }
- });
- break;
- }
+ case CACHE_ENTRY_REMOVED:
+ this.executor.submit(new Runnable() {
+ @Override public void run() {
+ cacheEntryRemoved((CacheEntryRemovedEvent) e);
+ }
+ });
+ break;
}
}
private void cacheEntryCreated(CacheEntryCreatedEvent event) {
- if (! (event.getKey() instanceof String) || ! (event.getValue() instanceof String[])) {
+ if (! (event.getKey() instanceof String)) {
return;
}
+
String httpSessionId = (String) event.getKey();
- String[] value = (String[]) event.getValue();
+
+ if (idMapper.hasSession(httpSessionId)) {
+ // Ignore local events generated by remote store
+ LOG.tracev("IGNORING cacheEntryCreated {0}", httpSessionId);
+ return;
+ }
+
+ String[] value = ssoCache.get((String) httpSessionId);
+
String ssoId = value[0];
String principal = value[1];
diff --git a/adapters/saml/as7-eap6/pom.xml b/adapters/saml/as7-eap6/pom.xml
index 66bdf0d5ad..ecef244c1e 100755
--- a/adapters/saml/as7-eap6/pom.xml
+++ b/adapters/saml/as7-eap6/pom.xml
@@ -20,7 +20,7 @@
keycloak-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
../../../pom.xml
Keycloak SAML EAP Integration
diff --git a/adapters/saml/as7-eap6/subsystem/pom.xml b/adapters/saml/as7-eap6/subsystem/pom.xml
index d3c2a5d9a4..e9a8b37608 100755
--- a/adapters/saml/as7-eap6/subsystem/pom.xml
+++ b/adapters/saml/as7-eap6/subsystem/pom.xml
@@ -21,7 +21,7 @@
org.keycloak
keycloak-saml-eap-integration-pom
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
../pom.xml
diff --git a/adapters/saml/as7-eap6/subsystem/src/main/java/org/keycloak/subsystem/saml/as7/KeycloakClusteredSsoDeploymentProcessor.java b/adapters/saml/as7-eap6/subsystem/src/main/java/org/keycloak/subsystem/saml/as7/KeycloakClusteredSsoDeploymentProcessor.java
new file mode 100644
index 0000000000..0333bc9dee
--- /dev/null
+++ b/adapters/saml/as7-eap6/subsystem/src/main/java/org/keycloak/subsystem/saml/as7/KeycloakClusteredSsoDeploymentProcessor.java
@@ -0,0 +1,157 @@
+/*
+ * Copyright 2017 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.subsystem.saml.as7;
+
+import org.keycloak.adapters.saml.AdapterConstants;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+import org.jboss.as.server.deployment.DeploymentPhaseContext;
+import org.jboss.as.server.deployment.DeploymentUnit;
+import org.jboss.as.server.deployment.DeploymentUnitProcessingException;
+import org.jboss.as.server.deployment.DeploymentUnitProcessor;
+import org.jboss.as.web.deployment.WarMetaData;
+import org.jboss.logging.Logger;
+import org.jboss.metadata.javaee.spec.ParamValueMetaData;
+import org.jboss.metadata.web.jboss.JBossWebMetaData;
+import org.jboss.metadata.web.spec.LoginConfigMetaData;
+import org.jboss.msc.service.ServiceName;
+import org.jboss.msc.service.ServiceTarget;
+
+/**
+ *
+ * @author hmlnarik
+ */
+public class KeycloakClusteredSsoDeploymentProcessor implements DeploymentUnitProcessor {
+
+ private static final Logger LOG = Logger.getLogger(KeycloakClusteredSsoDeploymentProcessor.class);
+
+ private static final String DEFAULT_CACHE_CONTAINER = "web";
+ private static final String SSO_CACHE_CONTAINER_NAME_PARAM_NAME = "keycloak.sessionIdMapperUpdater.infinispan.containerName";
+ private static final String SSO_CACHE_NAME_PARAM_NAME = "keycloak.sessionIdMapperUpdater.infinispan.cacheName";
+
+ @Override
+ public void deploy(DeploymentPhaseContext phaseContext) throws DeploymentUnitProcessingException {
+ final DeploymentUnit deploymentUnit = phaseContext.getDeploymentUnit();
+
+ if (isKeycloakSamlAuthMethod(deploymentUnit) && isDistributable(deploymentUnit)) {
+ addSamlReplicationConfiguration(deploymentUnit, phaseContext);
+ }
+ }
+
+ public static boolean isDistributable(final DeploymentUnit deploymentUnit) {
+ WarMetaData warMetaData = deploymentUnit.getAttachment(WarMetaData.ATTACHMENT_KEY);
+ if (warMetaData == null) {
+ return false;
+ }
+ JBossWebMetaData webMetaData = warMetaData.getMergedJBossWebMetaData();
+ if (webMetaData == null) {
+ return false;
+ }
+
+ return webMetaData.getDistributable() != null || webMetaData.getReplicationConfig() != null;
+ }
+
+ public static boolean isKeycloakSamlAuthMethod(final DeploymentUnit deploymentUnit) {
+ WarMetaData warMetaData = deploymentUnit.getAttachment(WarMetaData.ATTACHMENT_KEY);
+ if (warMetaData == null) {
+ return false;
+ }
+ JBossWebMetaData webMetaData = warMetaData.getMergedJBossWebMetaData();
+ if (webMetaData == null) {
+ return false;
+ }
+
+ if (Configuration.INSTANCE.isSecureDeployment(deploymentUnit)) {
+ return true;
+ }
+
+ LoginConfigMetaData loginConfig = webMetaData.getLoginConfig();
+
+ return loginConfig != null && Objects.equals(loginConfig.getAuthMethod(), "KEYCLOAK-SAML");
+ }
+
+ @Override
+ public void undeploy(DeploymentUnit du) {
+
+ }
+
+ private void addSamlReplicationConfiguration(DeploymentUnit deploymentUnit, DeploymentPhaseContext context) {
+ WarMetaData warMetaData = deploymentUnit.getAttachment(WarMetaData.ATTACHMENT_KEY);
+ if (warMetaData == null) {
+ return;
+ }
+
+ JBossWebMetaData webMetaData = warMetaData.getMergedJBossWebMetaData();
+ if (webMetaData == null) {
+ webMetaData = new JBossWebMetaData();
+ warMetaData.setMergedJBossWebMetaData(webMetaData);
+ }
+
+ // Find out default names of cache container and cache
+ String cacheContainer = DEFAULT_CACHE_CONTAINER;
+ String deploymentSessionCacheName =
+ (deploymentUnit.getParent() == null
+ ? ""
+ : deploymentUnit.getParent().getName() + ".")
+ + deploymentUnit.getName();
+
+ // Update names from jboss-web.xml's
+ if (webMetaData.getReplicationConfig() != null && webMetaData.getReplicationConfig().getCacheName() != null) {
+ ServiceName sn = ServiceName.parse(webMetaData.getReplicationConfig().getCacheName());
+ cacheContainer = sn.getParent().getSimpleName();
+ deploymentSessionCacheName = sn.getSimpleName();
+ }
+ String ssoCacheName = deploymentSessionCacheName + ".ssoCache";
+
+ // Override if they were set in the context parameters
+ List contextParams = webMetaData.getContextParams();
+ if (contextParams == null) {
+ contextParams = new ArrayList<>();
+ }
+ for (ParamValueMetaData contextParam : contextParams) {
+ if (Objects.equals(contextParam.getParamName(), SSO_CACHE_CONTAINER_NAME_PARAM_NAME)) {
+ cacheContainer = contextParam.getParamValue();
+ } else if (Objects.equals(contextParam.getParamName(), SSO_CACHE_NAME_PARAM_NAME)) {
+ ssoCacheName = contextParam.getParamValue();
+ }
+ }
+
+ LOG.debugv("Determined SSO cache container configuration: container: {0}, cache: {1}", cacheContainer, ssoCacheName);
+// addCacheDependency(context, deploymentUnit, cacheContainer, cacheName);
+
+ // Set context parameters for SSO cache container/name
+ ParamValueMetaData paramContainer = new ParamValueMetaData();
+ paramContainer.setParamName(AdapterConstants.REPLICATION_CONFIG_CONTAINER_PARAM_NAME);
+ paramContainer.setParamValue(cacheContainer);
+ contextParams.add(paramContainer);
+
+ ParamValueMetaData paramSsoCache = new ParamValueMetaData();
+ paramSsoCache.setParamName(AdapterConstants.REPLICATION_CONFIG_SSO_CACHE_PARAM_NAME);
+ paramSsoCache.setParamValue(ssoCacheName);
+ contextParams.add(paramSsoCache);
+
+ webMetaData.setContextParams(contextParams);
+ }
+
+ private void addCacheDependency(DeploymentPhaseContext context, DeploymentUnit deploymentUnit, String cacheContainer, String cacheName) {
+ ServiceName jbossAsCacheContainerService = ServiceName.of("jboss", "infinispan", cacheContainer);
+ ServiceTarget st = context.getServiceTarget();
+ st.addDependency(jbossAsCacheContainerService.append(cacheName));
+ }
+
+}
diff --git a/adapters/saml/as7-eap6/subsystem/src/main/java/org/keycloak/subsystem/saml/as7/KeycloakSubsystemAdd.java b/adapters/saml/as7-eap6/subsystem/src/main/java/org/keycloak/subsystem/saml/as7/KeycloakSubsystemAdd.java
index d583db43d1..30a853ffa6 100755
--- a/adapters/saml/as7-eap6/subsystem/src/main/java/org/keycloak/subsystem/saml/as7/KeycloakSubsystemAdd.java
+++ b/adapters/saml/as7-eap6/subsystem/src/main/java/org/keycloak/subsystem/saml/as7/KeycloakSubsystemAdd.java
@@ -48,6 +48,10 @@ class KeycloakSubsystemAdd extends AbstractBoottimeAddStepHandler {
Phase.POST_MODULE, // PHASE
Phase.POST_MODULE_VALIDATOR_FACTORY - 1, // PRIORITY
chooseConfigDeploymentProcessor());
+ processorTarget.addDeploymentProcessor(KeycloakSamlExtension.SUBSYSTEM_NAME,
+ Phase.POST_MODULE, // PHASE
+ Phase.POST_MODULE_VALIDATOR_FACTORY - 1, // PRIORITY
+ chooseClusteredSsoDeploymentProcessor());
}
}, OperationContext.Stage.RUNTIME);
}
@@ -60,6 +64,10 @@ class KeycloakSubsystemAdd extends AbstractBoottimeAddStepHandler {
return new KeycloakAdapterConfigDeploymentProcessor();
}
+ private DeploymentUnitProcessor chooseClusteredSsoDeploymentProcessor() {
+ return new KeycloakClusteredSsoDeploymentProcessor();
+ }
+
@Override
protected void populateModel(ModelNode operation, ModelNode model) throws OperationFailedException {
}
diff --git a/adapters/saml/core-public/pom.xml b/adapters/saml/core-public/pom.xml
index 29e35a9761..d8d2404092 100755
--- a/adapters/saml/core-public/pom.xml
+++ b/adapters/saml/core-public/pom.xml
@@ -21,7 +21,7 @@
keycloak-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
../../../pom.xml
4.0.0
diff --git a/adapters/saml/core/pom.xml b/adapters/saml/core/pom.xml
index be1e686dc0..7e7e479c66 100755
--- a/adapters/saml/core/pom.xml
+++ b/adapters/saml/core/pom.xml
@@ -21,7 +21,7 @@
keycloak-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
../../../pom.xml
4.0.0
diff --git a/adapters/saml/core/src/main/java/org/keycloak/adapters/saml/AdapterConstants.java b/adapters/saml/core/src/main/java/org/keycloak/adapters/saml/AdapterConstants.java
index 8b94068229..3646ed4554 100755
--- a/adapters/saml/core/src/main/java/org/keycloak/adapters/saml/AdapterConstants.java
+++ b/adapters/saml/core/src/main/java/org/keycloak/adapters/saml/AdapterConstants.java
@@ -23,4 +23,6 @@ package org.keycloak.adapters.saml;
*/
public class AdapterConstants {
public static final String AUTH_DATA_PARAM_NAME="org.keycloak.saml.xml.adapterConfig";
+ public static final String REPLICATION_CONFIG_CONTAINER_PARAM_NAME = "org.keycloak.saml.replication.container";
+ public static final String REPLICATION_CONFIG_SSO_CACHE_PARAM_NAME = "org.keycloak.saml.replication.cache.sso";
}
diff --git a/adapters/saml/core/src/main/java/org/keycloak/adapters/saml/profile/AbstractSamlAuthenticationHandler.java b/adapters/saml/core/src/main/java/org/keycloak/adapters/saml/profile/AbstractSamlAuthenticationHandler.java
index 2b40a424e8..12cb924868 100644
--- a/adapters/saml/core/src/main/java/org/keycloak/adapters/saml/profile/AbstractSamlAuthenticationHandler.java
+++ b/adapters/saml/core/src/main/java/org/keycloak/adapters/saml/profile/AbstractSamlAuthenticationHandler.java
@@ -187,7 +187,7 @@ public abstract class AbstractSamlAuthenticationHandler implements SamlAuthentic
final StatusResponseType statusResponse = (StatusResponseType) holder.getSamlObject();
// validate destination
if (!requestUri.equals(statusResponse.getDestination())) {
- log.error("Request URI does not match SAML request destination");
+ log.error("Request URI '" + requestUri + "' does not match SAML request destination '" + statusResponse.getDestination() + "'");
return AuthOutcome.FAILED;
}
diff --git a/adapters/saml/jetty/jetty-core/pom.xml b/adapters/saml/jetty/jetty-core/pom.xml
index 316cb7e6b1..98b180e25b 100755
--- a/adapters/saml/jetty/jetty-core/pom.xml
+++ b/adapters/saml/jetty/jetty-core/pom.xml
@@ -21,7 +21,7 @@
keycloak-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
../../../../pom.xml
4.0.0
diff --git a/adapters/saml/jetty/jetty8.1/pom.xml b/adapters/saml/jetty/jetty8.1/pom.xml
index ca569821b3..3a649184f6 100755
--- a/adapters/saml/jetty/jetty8.1/pom.xml
+++ b/adapters/saml/jetty/jetty8.1/pom.xml
@@ -21,7 +21,7 @@
keycloak-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
../../../../pom.xml
4.0.0
diff --git a/adapters/saml/jetty/jetty9.1/pom.xml b/adapters/saml/jetty/jetty9.1/pom.xml
index c01af403a2..27e7aff14a 100755
--- a/adapters/saml/jetty/jetty9.1/pom.xml
+++ b/adapters/saml/jetty/jetty9.1/pom.xml
@@ -21,7 +21,7 @@
keycloak-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
../../../../pom.xml
4.0.0
diff --git a/adapters/saml/jetty/jetty9.2/pom.xml b/adapters/saml/jetty/jetty9.2/pom.xml
index 88bf685595..4664c1f75b 100755
--- a/adapters/saml/jetty/jetty9.2/pom.xml
+++ b/adapters/saml/jetty/jetty9.2/pom.xml
@@ -21,7 +21,7 @@
keycloak-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
../../../../pom.xml
4.0.0
diff --git a/adapters/saml/jetty/jetty9.3/pom.xml b/adapters/saml/jetty/jetty9.3/pom.xml
index d34f83e0ed..2ad1e2a27e 100644
--- a/adapters/saml/jetty/jetty9.3/pom.xml
+++ b/adapters/saml/jetty/jetty9.3/pom.xml
@@ -21,7 +21,7 @@
keycloak-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
../../../../pom.xml
4.0.0
diff --git a/adapters/saml/jetty/jetty9.4/pom.xml b/adapters/saml/jetty/jetty9.4/pom.xml
index cee8d453d9..14bb3cd9d0 100644
--- a/adapters/saml/jetty/jetty9.4/pom.xml
+++ b/adapters/saml/jetty/jetty9.4/pom.xml
@@ -21,7 +21,7 @@
keycloak-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
../../../../pom.xml
4.0.0
diff --git a/adapters/saml/jetty/pom.xml b/adapters/saml/jetty/pom.xml
index 2f53996d71..b646f8395f 100755
--- a/adapters/saml/jetty/pom.xml
+++ b/adapters/saml/jetty/pom.xml
@@ -20,7 +20,7 @@
keycloak-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
../../../pom.xml
Keycloak SAML Jetty Integration
diff --git a/adapters/saml/pom.xml b/adapters/saml/pom.xml
index 4ae655c4e9..8b1ce3c0e2 100755
--- a/adapters/saml/pom.xml
+++ b/adapters/saml/pom.xml
@@ -20,7 +20,7 @@
keycloak-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
../../pom.xml
Keycloak SAML Client Adapter Modules
diff --git a/adapters/saml/servlet-filter/pom.xml b/adapters/saml/servlet-filter/pom.xml
index fd7f9393ba..9b49f239d2 100755
--- a/adapters/saml/servlet-filter/pom.xml
+++ b/adapters/saml/servlet-filter/pom.xml
@@ -21,7 +21,7 @@
keycloak-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
../../../pom.xml
4.0.0
diff --git a/adapters/saml/tomcat/pom.xml b/adapters/saml/tomcat/pom.xml
index 0911796e01..897d3b8edf 100755
--- a/adapters/saml/tomcat/pom.xml
+++ b/adapters/saml/tomcat/pom.xml
@@ -20,7 +20,7 @@
keycloak-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
../../../pom.xml
Keycloak SAML Tomcat Integration
diff --git a/adapters/saml/tomcat/tomcat-core/pom.xml b/adapters/saml/tomcat/tomcat-core/pom.xml
index e493969a3f..e7f22241a5 100755
--- a/adapters/saml/tomcat/tomcat-core/pom.xml
+++ b/adapters/saml/tomcat/tomcat-core/pom.xml
@@ -21,7 +21,7 @@
keycloak-saml-tomcat-integration-pom
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
../pom.xml
4.0.0
diff --git a/adapters/saml/tomcat/tomcat6/pom.xml b/adapters/saml/tomcat/tomcat6/pom.xml
index 12ad22bb0a..245341679f 100755
--- a/adapters/saml/tomcat/tomcat6/pom.xml
+++ b/adapters/saml/tomcat/tomcat6/pom.xml
@@ -21,7 +21,7 @@
keycloak-saml-tomcat-integration-pom
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
../pom.xml
4.0.0
diff --git a/adapters/saml/tomcat/tomcat7/pom.xml b/adapters/saml/tomcat/tomcat7/pom.xml
index ff59bfc0ef..b7e4c76a0d 100755
--- a/adapters/saml/tomcat/tomcat7/pom.xml
+++ b/adapters/saml/tomcat/tomcat7/pom.xml
@@ -21,7 +21,7 @@
keycloak-saml-tomcat-integration-pom
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
../pom.xml
4.0.0
diff --git a/adapters/saml/tomcat/tomcat8/pom.xml b/adapters/saml/tomcat/tomcat8/pom.xml
index 835e4d52d2..047019abea 100755
--- a/adapters/saml/tomcat/tomcat8/pom.xml
+++ b/adapters/saml/tomcat/tomcat8/pom.xml
@@ -21,7 +21,7 @@
keycloak-saml-tomcat-integration-pom
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
../pom.xml
4.0.0
diff --git a/adapters/saml/undertow/pom.xml b/adapters/saml/undertow/pom.xml
index b314f7efaf..01fc1bcffc 100755
--- a/adapters/saml/undertow/pom.xml
+++ b/adapters/saml/undertow/pom.xml
@@ -21,7 +21,7 @@
keycloak-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
../../../pom.xml
4.0.0
diff --git a/adapters/saml/undertow/src/main/java/org/keycloak/adapters/saml/undertow/ServletSamlSessionStore.java b/adapters/saml/undertow/src/main/java/org/keycloak/adapters/saml/undertow/ServletSamlSessionStore.java
index 2bf2369ef1..7e8fb83456 100755
--- a/adapters/saml/undertow/src/main/java/org/keycloak/adapters/saml/undertow/ServletSamlSessionStore.java
+++ b/adapters/saml/undertow/src/main/java/org/keycloak/adapters/saml/undertow/ServletSamlSessionStore.java
@@ -152,12 +152,19 @@ public class ServletSamlSessionStore implements SamlSessionStore {
public boolean isLoggedIn() {
HttpSession session = getSession(false);
if (session == null) {
- log.debug("session was null, returning null");
+ log.debug("Session was not found");
return false;
}
+
+ if (! idMapper.hasSession(session.getId())) {
+ log.debugf("Session %s has expired on some other node", session.getId());
+ session.removeAttribute(SamlSession.class.getName());
+ return false;
+ }
+
final SamlSession samlSession = (SamlSession)session.getAttribute(SamlSession.class.getName());
if (samlSession == null) {
- log.debug("SamlSession was not in session, returning null");
+ log.debug("SamlSession was not found in the session");
return false;
}
diff --git a/adapters/saml/wildfly-elytron/pom.xml b/adapters/saml/wildfly-elytron/pom.xml
index 4161b092e9..1fbfb110a4 100755
--- a/adapters/saml/wildfly-elytron/pom.xml
+++ b/adapters/saml/wildfly-elytron/pom.xml
@@ -21,7 +21,7 @@
keycloak-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
../../../pom.xml
4.0.0
diff --git a/adapters/saml/wildfly-elytron/src/main/java/org/keycloak/adapters/saml/elytron/KeycloakSecurityRealm.java b/adapters/saml/wildfly-elytron/src/main/java/org/keycloak/adapters/saml/elytron/KeycloakSecurityRealm.java
index 3207835360..f79b60d25e 100644
--- a/adapters/saml/wildfly-elytron/src/main/java/org/keycloak/adapters/saml/elytron/KeycloakSecurityRealm.java
+++ b/adapters/saml/wildfly-elytron/src/main/java/org/keycloak/adapters/saml/elytron/KeycloakSecurityRealm.java
@@ -17,6 +17,7 @@
package org.keycloak.adapters.saml.elytron;
import java.security.Principal;
+import java.security.spec.AlgorithmParameterSpec;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -53,7 +54,7 @@ public class KeycloakSecurityRealm implements SecurityRealm {
}
@Override
- public SupportLevel getCredentialAcquireSupport(Class extends Credential> credentialType, String algorithmName) throws RealmUnavailableException {
+ public SupportLevel getCredentialAcquireSupport(Class extends Credential> aClass, String s, AlgorithmParameterSpec algorithmParameterSpec) throws RealmUnavailableException {
return SupportLevel.UNSUPPORTED;
}
@@ -90,7 +91,7 @@ public class KeycloakSecurityRealm implements SecurityRealm {
}
@Override
- public SupportLevel getCredentialAcquireSupport(Class extends Credential> credentialType, String algorithmName) throws RealmUnavailableException {
+ public SupportLevel getCredentialAcquireSupport(Class extends Credential> credentialType, String algorithmName, AlgorithmParameterSpec parameterSpec) throws RealmUnavailableException {
return SupportLevel.UNSUPPORTED;
}
diff --git a/adapters/saml/wildfly/pom.xml b/adapters/saml/wildfly/pom.xml
index 43108bb00f..fb4accca8d 100755
--- a/adapters/saml/wildfly/pom.xml
+++ b/adapters/saml/wildfly/pom.xml
@@ -20,7 +20,7 @@
keycloak-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
../../../pom.xml
Keycloak SAML Wildfly Integration
diff --git a/adapters/saml/wildfly/wildfly-adapter/pom.xml b/adapters/saml/wildfly/wildfly-adapter/pom.xml
index 3be5e7e4c0..8e15de0ab7 100755
--- a/adapters/saml/wildfly/wildfly-adapter/pom.xml
+++ b/adapters/saml/wildfly/wildfly-adapter/pom.xml
@@ -21,7 +21,7 @@
keycloak-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
../../../../pom.xml
4.0.0
@@ -70,6 +70,10 @@
org.infinispan
infinispan-core
+
+ org.infinispan
+ infinispan-cachestore-remote
+
org.picketbox
picketbox
diff --git a/adapters/saml/wildfly/wildfly-adapter/src/main/java/org/keycloak/adapters/saml/wildfly/infinispan/InfinispanSessionCacheIdMapperUpdater.java b/adapters/saml/wildfly/wildfly-adapter/src/main/java/org/keycloak/adapters/saml/wildfly/infinispan/InfinispanSessionCacheIdMapperUpdater.java
index 489d1d5c67..c35db63a1f 100644
--- a/adapters/saml/wildfly/wildfly-adapter/src/main/java/org/keycloak/adapters/saml/wildfly/infinispan/InfinispanSessionCacheIdMapperUpdater.java
+++ b/adapters/saml/wildfly/wildfly-adapter/src/main/java/org/keycloak/adapters/saml/wildfly/infinispan/InfinispanSessionCacheIdMapperUpdater.java
@@ -16,6 +16,7 @@
*/
package org.keycloak.adapters.saml.wildfly.infinispan;
+import org.keycloak.adapters.saml.AdapterConstants;
import org.keycloak.adapters.spi.SessionIdMapper;
import org.keycloak.adapters.spi.SessionIdMapperUpdater;
@@ -27,6 +28,8 @@ import org.infinispan.Cache;
import org.infinispan.configuration.cache.CacheMode;
import org.infinispan.configuration.cache.Configuration;
import org.infinispan.manager.EmbeddedCacheManager;
+import org.infinispan.persistence.manager.PersistenceManager;
+import org.infinispan.persistence.remote.RemoteStore;
import org.jboss.logging.Logger;
/**
@@ -37,64 +40,55 @@ public class InfinispanSessionCacheIdMapperUpdater {
private static final Logger LOG = Logger.getLogger(InfinispanSessionCacheIdMapperUpdater.class);
- public static final String DEFAULT_CACHE_CONTAINER_JNDI_NAME = "java:jboss/infinispan/container/web";
-
- private static final String DEPLOYMENT_CACHE_CONTAINER_JNDI_NAME_PARAM_NAME = "keycloak.sessionIdMapperUpdater.infinispan.cacheContainerJndi";
- private static final String DEPLOYMENT_CACHE_NAME_PARAM_NAME = "keycloak.sessionIdMapperUpdater.infinispan.deploymentCacheName";
- private static final String SSO_CACHE_NAME_PARAM_NAME = "keycloak.sessionIdMapperUpdater.infinispan.cacheName";
+ public static final String DEFAULT_CACHE_CONTAINER_JNDI_NAME = "java:jboss/infinispan/container";
public static SessionIdMapperUpdater addTokenStoreUpdaters(DeploymentInfo deploymentInfo, SessionIdMapper mapper, SessionIdMapperUpdater previousIdMapperUpdater) {
- boolean distributable = Objects.equals(
- deploymentInfo.getSessionManagerFactory().getClass().getName(),
- "org.wildfly.clustering.web.undertow.session.DistributableSessionManagerFactory"
- );
+ Map initParameters = deploymentInfo.getInitParameters();
+ String containerName = initParameters == null ? null : initParameters.get(AdapterConstants.REPLICATION_CONFIG_CONTAINER_PARAM_NAME);
+ String cacheName = initParameters == null ? null : initParameters.get(AdapterConstants.REPLICATION_CONFIG_SSO_CACHE_PARAM_NAME);
+
+ if (containerName == null || cacheName == null) {
+ LOG.warnv("Cannot determine parameters of SSO cache for deployment {0}.", deploymentInfo.getDeploymentName());
- if (! distributable) {
- LOG.warnv("Deployment {0} does not use supported distributed session cache mechanism", deploymentInfo.getDeploymentName());
return previousIdMapperUpdater;
}
- Map initParameters = deploymentInfo.getInitParameters();
- String cacheContainerLookup = (initParameters != null && initParameters.get(DEPLOYMENT_CACHE_CONTAINER_JNDI_NAME_PARAM_NAME) != null)
- ? initParameters.get(DEPLOYMENT_CACHE_CONTAINER_JNDI_NAME_PARAM_NAME)
- : DEFAULT_CACHE_CONTAINER_JNDI_NAME;
- boolean deploymentSessionCacheNamePreset = initParameters != null && initParameters.get(DEPLOYMENT_CACHE_NAME_PARAM_NAME) != null;
- String deploymentSessionCacheName = deploymentSessionCacheNamePreset
- ? initParameters.get(DEPLOYMENT_CACHE_NAME_PARAM_NAME)
- : deploymentInfo.getDeploymentName();
- boolean ssoCacheNamePreset = initParameters != null && initParameters.get(SSO_CACHE_NAME_PARAM_NAME) != null;
- String ssoCacheName = ssoCacheNamePreset
- ? initParameters.get(SSO_CACHE_NAME_PARAM_NAME)
- : deploymentSessionCacheName + ".ssoCache";
+ String cacheContainerLookup = DEFAULT_CACHE_CONTAINER_JNDI_NAME + "/" + containerName;
+ String deploymentSessionCacheName = deploymentInfo.getDeploymentName();
try {
EmbeddedCacheManager cacheManager = (EmbeddedCacheManager) new InitialContext().lookup(cacheContainerLookup);
- Configuration ssoCacheConfiguration = cacheManager.getCacheConfiguration(ssoCacheName);
+ Configuration ssoCacheConfiguration = cacheManager.getCacheConfiguration(cacheName);
if (ssoCacheConfiguration == null) {
Configuration cacheConfiguration = cacheManager.getCacheConfiguration(deploymentSessionCacheName);
if (cacheConfiguration == null) {
- LOG.debugv("Using default cache container configuration for SSO cache. lookup={0}, looked up configuration of cache={1}", cacheContainerLookup, deploymentSessionCacheName);
+ LOG.debugv("Using default configuration for SSO cache {0}.{1}.", containerName, cacheName);
ssoCacheConfiguration = cacheManager.getDefaultCacheConfiguration();
} else {
- LOG.debugv("Using distributed HTTP session cache configuration for SSO cache. lookup={0}, configuration taken from cache={1}", cacheContainerLookup, deploymentSessionCacheName);
+ LOG.debugv("Using distributed HTTP session cache configuration for SSO cache {0}.{1}, configuration taken from cache {2}",
+ containerName, cacheName, deploymentSessionCacheName);
ssoCacheConfiguration = cacheConfiguration;
- cacheManager.defineConfiguration(ssoCacheName, ssoCacheConfiguration);
+ cacheManager.defineConfiguration(cacheName, ssoCacheConfiguration);
}
} else {
- LOG.debugv("Using custom configuration of SSO cache. lookup={0}, cache name={1}", cacheContainerLookup, ssoCacheName);
+ LOG.debugv("Using custom configuration of SSO cache {0}.{1}.", containerName, cacheName);
}
CacheMode ssoCacheMode = ssoCacheConfiguration.clustering().cacheMode();
if (ssoCacheMode != CacheMode.REPL_ASYNC && ssoCacheMode != CacheMode.REPL_SYNC) {
- LOG.warnv("SSO cache mode is {0}, it is recommended to use replicated mode instead", ssoCacheConfiguration.clustering().cacheModeString());
+ LOG.warnv("SSO cache mode is {0}, it is recommended to use replicated mode instead.", ssoCacheConfiguration.clustering().cacheModeString());
}
- Cache ssoCache = cacheManager.getCache(ssoCacheName, true);
- ssoCache.addListener(new SsoSessionCacheListener(mapper));
+ Cache ssoCache = cacheManager.getCache(cacheName, true);
+ final SsoSessionCacheListener listener = new SsoSessionCacheListener(ssoCache, mapper);
+ ssoCache.addListener(listener);
- LOG.debugv("Added distributed SSO session cache, lookup={0}, cache name={1}", cacheContainerLookup, deploymentSessionCacheName);
+ addSsoCacheCrossDcListener(ssoCache, listener);
+ LOG.debugv("Added distributed SSO session cache, lookup={0}, cache name={1}", cacheContainerLookup, cacheName);
+
+ LOG.debugv("Adding session listener for SSO session cache, lookup={0}, cache name={1}", cacheContainerLookup, cacheName);
SsoCacheSessionIdMapperUpdater updater = new SsoCacheSessionIdMapperUpdater(ssoCache, previousIdMapperUpdater);
deploymentInfo.addSessionListener(updater);
@@ -104,4 +98,25 @@ public class InfinispanSessionCacheIdMapperUpdater {
return previousIdMapperUpdater;
}
}
+
+ private static void addSsoCacheCrossDcListener(Cache ssoCache, SsoSessionCacheListener listener) {
+ if (ssoCache.getCacheConfiguration().persistence() == null) {
+ return;
+ }
+
+ final Set stores = getRemoteStores(ssoCache);
+ if (stores == null || stores.isEmpty()) {
+ return;
+ }
+
+ LOG.infov("Listening for events on remote stores configured for cache {0}", ssoCache.getName());
+
+ for (RemoteStore store : stores) {
+ store.getRemoteCache().addClientListener(listener);
+ }
+ }
+
+ public static Set getRemoteStores(Cache ispnCache) {
+ return ispnCache.getAdvancedCache().getComponentRegistry().getComponent(PersistenceManager.class).getStores(RemoteStore.class);
+ }
}
diff --git a/adapters/saml/wildfly/wildfly-adapter/src/main/java/org/keycloak/adapters/saml/wildfly/infinispan/SsoSessionCacheListener.java b/adapters/saml/wildfly/wildfly-adapter/src/main/java/org/keycloak/adapters/saml/wildfly/infinispan/SsoSessionCacheListener.java
index ccd102e713..6d53485aa5 100644
--- a/adapters/saml/wildfly/wildfly-adapter/src/main/java/org/keycloak/adapters/saml/wildfly/infinispan/SsoSessionCacheListener.java
+++ b/adapters/saml/wildfly/wildfly-adapter/src/main/java/org/keycloak/adapters/saml/wildfly/infinispan/SsoSessionCacheListener.java
@@ -20,6 +20,12 @@ import org.keycloak.adapters.spi.SessionIdMapper;
import java.util.*;
import java.util.concurrent.*;
+import org.infinispan.Cache;
+import org.infinispan.client.hotrod.annotation.ClientCacheEntryCreated;
+import org.infinispan.client.hotrod.annotation.ClientCacheEntryRemoved;
+import org.infinispan.client.hotrod.annotation.ClientListener;
+import org.infinispan.client.hotrod.event.ClientCacheEntryCreatedEvent;
+import org.infinispan.client.hotrod.event.ClientCacheEntryRemovedEvent;
import org.infinispan.notifications.Listener;
import org.infinispan.notifications.cachelistener.annotation.*;
import org.infinispan.notifications.cachelistener.event.*;
@@ -34,6 +40,7 @@ import org.jboss.logging.Logger;
* @author hmlnarik
*/
@Listener
+@ClientListener
public class SsoSessionCacheListener {
private static final Logger LOG = Logger.getLogger(SsoSessionCacheListener.class);
@@ -42,14 +49,21 @@ public class SsoSessionCacheListener {
private final SessionIdMapper idMapper;
+ private final Cache ssoCache;
+
private ExecutorService executor = Executors.newSingleThreadExecutor();
- public SsoSessionCacheListener(SessionIdMapper idMapper) {
+ public SsoSessionCacheListener(Cache ssoCache, SessionIdMapper idMapper) {
+ this.ssoCache = ssoCache;
this.idMapper = idMapper;
}
@TransactionRegistered
public void startTransaction(TransactionRegisteredEvent event) {
+ if (event.getGlobalTransaction() == null) {
+ return;
+ }
+
map.put(event.getGlobalTransaction().globalId(), new ConcurrentLinkedQueue());
}
@@ -66,42 +80,56 @@ public class SsoSessionCacheListener {
@CacheEntryCreated
@CacheEntryRemoved
public void addEvent(TransactionalEvent event) {
- if (event.isPre() == false) {
+ if (event.isOriginLocal()) {
+ // Local events are processed by local HTTP session listener
+ return;
+ }
+
+ if (event.isPre()) { // only handle post events
+ return;
+ }
+
+ if (event.getGlobalTransaction() != null) {
map.get(event.getGlobalTransaction().globalId()).add(event);
+ } else {
+ processEvent(event);
}
}
@TransactionCompleted
public void endTransaction(TransactionCompletedEvent event) {
+ if (event.getGlobalTransaction() == null) {
+ return;
+ }
+
Queue events = map.remove(event.getGlobalTransaction().globalId());
if (events == null || ! event.isTransactionSuccessful()) {
return;
}
- if (event.isOriginLocal()) {
- // Local events are processed by local HTTP session listener
- return;
- }
-
for (final Event e : events) {
- switch (e.getType()) {
- case CACHE_ENTRY_CREATED:
- this.executor.submit(new Runnable() {
- @Override public void run() {
- cacheEntryCreated((CacheEntryCreatedEvent) e);
- }
- });
- break;
+ processEvent(e);
+ }
+ }
- case CACHE_ENTRY_REMOVED:
- this.executor.submit(new Runnable() {
- @Override public void run() {
- cacheEntryRemoved((CacheEntryRemovedEvent) e);
- }
- });
- break;
- }
+ private void processEvent(final Event e) {
+ switch (e.getType()) {
+ case CACHE_ENTRY_CREATED:
+ this.executor.submit(new Runnable() {
+ @Override public void run() {
+ cacheEntryCreated((CacheEntryCreatedEvent) e);
+ }
+ });
+ break;
+
+ case CACHE_ENTRY_REMOVED:
+ this.executor.submit(new Runnable() {
+ @Override public void run() {
+ cacheEntryRemoved((CacheEntryRemovedEvent) e);
+ }
+ });
+ break;
}
}
@@ -128,4 +156,40 @@ public class SsoSessionCacheListener {
this.idMapper.removeSession((String) event.getKey());
}
+
+ @ClientCacheEntryCreated
+ public void remoteCacheEntryCreated(ClientCacheEntryCreatedEvent event) {
+ if (! (event.getKey() instanceof String)) {
+ return;
+ }
+
+ String httpSessionId = (String) event.getKey();
+
+ if (idMapper.hasSession(httpSessionId)) {
+ // Ignore local events generated by remote store
+ LOG.tracev("IGNORING remoteCacheEntryCreated {0}", httpSessionId);
+ return;
+ }
+
+ String[] value = ssoCache.get((String) httpSessionId);
+
+ if (value != null) {
+ String ssoId = value[0];
+ String principal = value[1];
+
+ LOG.tracev("remoteCacheEntryCreated {0}:{1}", httpSessionId, ssoId);
+
+ this.idMapper.map(ssoId, principal, httpSessionId);
+ } else {
+ LOG.tracev("remoteCacheEntryCreated {0}", event.getKey());
+
+ }
+ }
+
+ @ClientCacheEntryRemoved
+ public void remoteCacheEntryRemoved(ClientCacheEntryRemovedEvent event) {
+ LOG.tracev("remoteCacheEntryRemoved {0}", event.getKey());
+
+ this.idMapper.removeSession((String) event.getKey());
+ }
}
diff --git a/adapters/saml/wildfly/wildfly-subsystem/pom.xml b/adapters/saml/wildfly/wildfly-subsystem/pom.xml
index acaf7f160f..bb370c0340 100755
--- a/adapters/saml/wildfly/wildfly-subsystem/pom.xml
+++ b/adapters/saml/wildfly/wildfly-subsystem/pom.xml
@@ -21,7 +21,7 @@
org.keycloak
keycloak-parent
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
../../../../pom.xml
diff --git a/adapters/saml/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/saml/extension/KeycloakClusteredSsoDeploymentProcessor.java b/adapters/saml/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/saml/extension/KeycloakClusteredSsoDeploymentProcessor.java
new file mode 100644
index 0000000000..3be66deb79
--- /dev/null
+++ b/adapters/saml/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/saml/extension/KeycloakClusteredSsoDeploymentProcessor.java
@@ -0,0 +1,178 @@
+/*
+ * Copyright 2017 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.subsystem.adapter.saml.extension;
+
+import org.keycloak.adapters.saml.AdapterConstants;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+import org.jboss.as.controller.capability.CapabilityServiceSupport;
+import org.jboss.as.server.deployment.Attachments;
+import org.jboss.as.server.deployment.DeploymentPhaseContext;
+import org.jboss.as.server.deployment.DeploymentUnit;
+import org.jboss.as.server.deployment.DeploymentUnitProcessingException;
+import org.jboss.as.server.deployment.DeploymentUnitProcessor;
+import org.jboss.as.web.common.WarMetaData;
+import org.jboss.logging.Logger;
+import org.jboss.metadata.javaee.spec.ParamValueMetaData;
+import org.jboss.metadata.web.jboss.JBossWebMetaData;
+import org.jboss.metadata.web.spec.LoginConfigMetaData;
+import org.jboss.msc.service.ServiceController;
+import org.jboss.msc.service.ServiceName;
+import org.jboss.msc.service.ServiceTarget;
+
+/**
+ *
+ * @author hmlnarik
+ */
+public class KeycloakClusteredSsoDeploymentProcessor implements DeploymentUnitProcessor {
+
+ private static final Logger LOG = Logger.getLogger(KeycloakClusteredSsoDeploymentProcessor.class);
+
+ private static final String DEFAULT_CACHE_CONTAINER = "web";
+ private static final String SSO_CACHE_CONTAINER_NAME_PARAM_NAME = "keycloak.sessionIdMapperUpdater.infinispan.containerName";
+ private static final String SSO_CACHE_NAME_PARAM_NAME = "keycloak.sessionIdMapperUpdater.infinispan.cacheName";
+
+ @Override
+ public void deploy(DeploymentPhaseContext phaseContext) throws DeploymentUnitProcessingException {
+ final DeploymentUnit deploymentUnit = phaseContext.getDeploymentUnit();
+
+ if (isKeycloakSamlAuthMethod(deploymentUnit) && isDistributable(deploymentUnit)) {
+ addSamlReplicationConfiguration(deploymentUnit, phaseContext);
+ }
+ }
+
+ public static boolean isDistributable(final DeploymentUnit deploymentUnit) {
+ WarMetaData warMetaData = deploymentUnit.getAttachment(WarMetaData.ATTACHMENT_KEY);
+ if (warMetaData == null) {
+ return false;
+ }
+ JBossWebMetaData webMetaData = warMetaData.getMergedJBossWebMetaData();
+ if (webMetaData == null) {
+ return false;
+ }
+
+ return webMetaData.getDistributable() != null || webMetaData.getReplicationConfig() != null;
+ }
+
+ public static boolean isKeycloakSamlAuthMethod(final DeploymentUnit deploymentUnit) {
+ if (Configuration.INSTANCE.getSecureDeployment(deploymentUnit) != null) {
+ return true;
+ }
+
+ WarMetaData warMetaData = deploymentUnit.getAttachment(WarMetaData.ATTACHMENT_KEY);
+ if (warMetaData == null) {
+ return false;
+ }
+ JBossWebMetaData webMetaData = warMetaData.getMergedJBossWebMetaData();
+ if (webMetaData == null) {
+ return false;
+ }
+
+ LoginConfigMetaData loginConfig = webMetaData.getLoginConfig();
+
+ return loginConfig != null && Objects.equals(loginConfig.getAuthMethod(), "KEYCLOAK-SAML");
+ }
+
+ @Override
+ public void undeploy(DeploymentUnit du) {
+
+ }
+
+ private void addSamlReplicationConfiguration(DeploymentUnit deploymentUnit, DeploymentPhaseContext context) {
+ WarMetaData warMetaData = deploymentUnit.getAttachment(WarMetaData.ATTACHMENT_KEY);
+ if (warMetaData == null) {
+ return;
+ }
+
+ JBossWebMetaData webMetaData = warMetaData.getMergedJBossWebMetaData();
+ if (webMetaData == null) {
+ webMetaData = new JBossWebMetaData();
+ warMetaData.setMergedJBossWebMetaData(webMetaData);
+ }
+
+ // Find out default names of cache container and cache
+ String cacheContainer = DEFAULT_CACHE_CONTAINER;
+ String deploymentSessionCacheName =
+ (deploymentUnit.getParent() == null
+ ? ""
+ : deploymentUnit.getParent().getName() + ".")
+ + deploymentUnit.getName();
+
+ // Update names from jboss-web.xml's
+ if (webMetaData.getReplicationConfig() != null && webMetaData.getReplicationConfig().getCacheName() != null) {
+ ServiceName sn = ServiceName.parse(webMetaData.getReplicationConfig().getCacheName());
+ cacheContainer = sn.getParent().getSimpleName();
+ deploymentSessionCacheName = sn.getSimpleName();
+ }
+ String ssoCacheName = deploymentSessionCacheName + ".ssoCache";
+
+ // Override if they were set in the context parameters
+ List contextParams = webMetaData.getContextParams();
+ if (contextParams == null) {
+ contextParams = new ArrayList<>();
+ }
+ for (ParamValueMetaData contextParam : contextParams) {
+ if (Objects.equals(contextParam.getParamName(), SSO_CACHE_CONTAINER_NAME_PARAM_NAME)) {
+ cacheContainer = contextParam.getParamValue();
+ } else if (Objects.equals(contextParam.getParamName(), SSO_CACHE_NAME_PARAM_NAME)) {
+ ssoCacheName = contextParam.getParamValue();
+ }
+ }
+
+ LOG.debugv("Determined SSO cache container configuration: container: {0}, cache: {1}", cacheContainer, ssoCacheName);
+ addCacheDependency(context, deploymentUnit, cacheContainer, ssoCacheName);
+
+ // Set context parameters for SSO cache container/name
+ ParamValueMetaData paramContainer = new ParamValueMetaData();
+ paramContainer.setParamName(AdapterConstants.REPLICATION_CONFIG_CONTAINER_PARAM_NAME);
+ paramContainer.setParamValue(cacheContainer);
+ contextParams.add(paramContainer);
+
+ ParamValueMetaData paramSsoCache = new ParamValueMetaData();
+ paramSsoCache.setParamName(AdapterConstants.REPLICATION_CONFIG_SSO_CACHE_PARAM_NAME);
+ paramSsoCache.setParamValue(ssoCacheName);
+ contextParams.add(paramSsoCache);
+
+ webMetaData.setContextParams(contextParams);
+ }
+
+ private void addCacheDependency(DeploymentPhaseContext context, DeploymentUnit deploymentUnit, String cacheContainer, String cacheName) {
+ ServiceName wf10CacheContainerServiceName = ServiceName.of("jboss", "infinispan", cacheContainer);
+ final ServiceController> wf10CacheContainerService = context.getServiceRegistry().getService(wf10CacheContainerServiceName);
+
+ boolean legacy = wf10CacheContainerService != null;
+ ServiceTarget st = context.getServiceTarget();
+
+ if (legacy) {
+ ServiceName cacheServiceName = wf10CacheContainerServiceName.append(cacheName);
+ ServiceController> cacheService = context.getServiceRegistry().getService(cacheServiceName);
+ if (cacheService != null) {
+ st.addDependency(cacheServiceName);
+ }
+ } else {
+ CapabilityServiceSupport support = deploymentUnit.getAttachment(Attachments.CAPABILITY_SERVICE_SUPPORT);
+
+ ServiceName cacheServiceName = support.getCapabilityServiceName("org.wildfly.clustering.infinispan.cache." + cacheContainer + "." + cacheName);
+ ServiceController> cacheService = context.getServiceRegistry().getService(cacheServiceName);
+ if (cacheService != null) {
+ st.addDependency(cacheServiceName);
+ }
+ }
+ }
+
+}
diff --git a/adapters/saml/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/saml/extension/KeycloakSubsystemAdd.java b/adapters/saml/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/saml/extension/KeycloakSubsystemAdd.java
index 79a49812d3..e9ef1a3ee1 100755
--- a/adapters/saml/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/saml/extension/KeycloakSubsystemAdd.java
+++ b/adapters/saml/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/saml/extension/KeycloakSubsystemAdd.java
@@ -43,6 +43,10 @@ class KeycloakSubsystemAdd extends AbstractBoottimeAddStepHandler {
Phase.POST_MODULE, // PHASE
Phase.POST_MODULE_VALIDATOR_FACTORY - 1, // PRIORITY
chooseConfigDeploymentProcessor());
+ processorTarget.addDeploymentProcessor(KeycloakSamlExtension.SUBSYSTEM_NAME,
+ Phase.POST_MODULE, // PHASE
+ Phase.POST_MODULE_VALIDATOR_FACTORY - 1, // PRIORITY
+ chooseClusteredSsoDeploymentProcessor());
}
}, OperationContext.Stage.RUNTIME);
}
@@ -54,4 +58,8 @@ class KeycloakSubsystemAdd extends AbstractBoottimeAddStepHandler {
private DeploymentUnitProcessor chooseConfigDeploymentProcessor() {
return new KeycloakAdapterConfigDeploymentProcessor();
}
+
+ private DeploymentUnitProcessor chooseClusteredSsoDeploymentProcessor() {
+ return new KeycloakClusteredSsoDeploymentProcessor();
+ }
}
diff --git a/adapters/spi/adapter-spi/pom.xml b/adapters/spi/adapter-spi/pom.xml
index 0145009a5f..28a74bcfdb 100755
--- a/adapters/spi/adapter-spi/pom.xml
+++ b/adapters/spi/adapter-spi/pom.xml
@@ -21,7 +21,7 @@
keycloak-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
../../../pom.xml
4.0.0
diff --git a/adapters/spi/adapter-spi/src/main/java/org/keycloak/adapters/spi/InMemorySessionIdMapper.java b/adapters/spi/adapter-spi/src/main/java/org/keycloak/adapters/spi/InMemorySessionIdMapper.java
index a00ae829f0..7ca8af6e70 100755
--- a/adapters/spi/adapter-spi/src/main/java/org/keycloak/adapters/spi/InMemorySessionIdMapper.java
+++ b/adapters/spi/adapter-spi/src/main/java/org/keycloak/adapters/spi/InMemorySessionIdMapper.java
@@ -67,6 +67,11 @@ public class InMemorySessionIdMapper implements SessionIdMapper {
ssoToSession.put(sso, session);
sessionToSso.put(session, sso);
}
+
+ if (principal == null) {
+ return;
+ }
+
Set userSessions = principalToSession.get(principal);
if (userSessions == null) {
final Set tmp = Collections.synchronizedSet(new HashSet());
diff --git a/adapters/spi/jboss-adapter-core/pom.xml b/adapters/spi/jboss-adapter-core/pom.xml
index 41be1d3d19..69a59e23a9 100755
--- a/adapters/spi/jboss-adapter-core/pom.xml
+++ b/adapters/spi/jboss-adapter-core/pom.xml
@@ -21,7 +21,7 @@
keycloak-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
../../../pom.xml
4.0.0
diff --git a/adapters/spi/jetty-adapter-spi/pom.xml b/adapters/spi/jetty-adapter-spi/pom.xml
index 03adfdf126..bbaf8bdd8d 100755
--- a/adapters/spi/jetty-adapter-spi/pom.xml
+++ b/adapters/spi/jetty-adapter-spi/pom.xml
@@ -21,7 +21,7 @@
keycloak-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
../../../pom.xml
4.0.0
diff --git a/adapters/spi/pom.xml b/adapters/spi/pom.xml
index 45805179b1..8f1ba6756f 100755
--- a/adapters/spi/pom.xml
+++ b/adapters/spi/pom.xml
@@ -20,7 +20,7 @@
keycloak-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
../../pom.xml
Keycloak Client Adapter SPI Modules
diff --git a/adapters/spi/servlet-adapter-spi/pom.xml b/adapters/spi/servlet-adapter-spi/pom.xml
index c9228b6e7f..54b6e6b9a7 100755
--- a/adapters/spi/servlet-adapter-spi/pom.xml
+++ b/adapters/spi/servlet-adapter-spi/pom.xml
@@ -21,7 +21,7 @@
keycloak-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
../../../pom.xml
4.0.0
diff --git a/adapters/spi/tomcat-adapter-spi/pom.xml b/adapters/spi/tomcat-adapter-spi/pom.xml
index dcf55e5f50..38b5d94cb9 100755
--- a/adapters/spi/tomcat-adapter-spi/pom.xml
+++ b/adapters/spi/tomcat-adapter-spi/pom.xml
@@ -21,7 +21,7 @@
keycloak-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
../../../pom.xml
4.0.0
diff --git a/adapters/spi/undertow-adapter-spi/pom.xml b/adapters/spi/undertow-adapter-spi/pom.xml
index 0f04bdb14d..73b9e0225b 100755
--- a/adapters/spi/undertow-adapter-spi/pom.xml
+++ b/adapters/spi/undertow-adapter-spi/pom.xml
@@ -21,7 +21,7 @@
keycloak-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
../../../pom.xml
4.0.0
diff --git a/authz/client/pom.xml b/authz/client/pom.xml
index c45476a6e0..08cbab4429 100644
--- a/authz/client/pom.xml
+++ b/authz/client/pom.xml
@@ -7,7 +7,7 @@
org.keycloak
keycloak-authz-parent
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
../pom.xml
diff --git a/authz/policy/common/pom.xml b/authz/policy/common/pom.xml
index 193dcf49af..a16944e1df 100644
--- a/authz/policy/common/pom.xml
+++ b/authz/policy/common/pom.xml
@@ -25,7 +25,7 @@
org.keycloak
keycloak-authz-provider-parent
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
../pom.xml
diff --git a/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/client/ClientPolicyProviderFactory.java b/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/client/ClientPolicyProviderFactory.java
index 6d7ed543ac..13602970d0 100644
--- a/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/client/ClientPolicyProviderFactory.java
+++ b/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/client/ClientPolicyProviderFactory.java
@@ -108,7 +108,7 @@ public class ClientPolicyProviderFactory implements PolicyProviderFactory {
diff --git a/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/role/RolePolicyProviderFactory.java b/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/role/RolePolicyProviderFactory.java
index 933a85971d..4769ee3ef2 100644
--- a/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/role/RolePolicyProviderFactory.java
+++ b/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/role/RolePolicyProviderFactory.java
@@ -222,7 +222,7 @@ public class RolePolicyProviderFactory implements PolicyProviderFactory {
diff --git a/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/user/UserPolicyProviderFactory.java b/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/user/UserPolicyProviderFactory.java
index 5a90f93227..28d4d0b86c 100644
--- a/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/user/UserPolicyProviderFactory.java
+++ b/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/user/UserPolicyProviderFactory.java
@@ -181,7 +181,7 @@ public class UserPolicyProviderFactory implements PolicyProviderFactory {
- ResourceServer resourceServer = resourceServerStore.findByClient(clientModel.getId());
+ ResourceServer resourceServer = resourceServerStore.findById(clientModel.getId());
if (resourceServer != null) {
policyStore.findByType(getId(), resourceServer.getId()).forEach(policy -> {
diff --git a/authz/policy/drools/pom.xml b/authz/policy/drools/pom.xml
index eb6674110d..bdc830cf90 100644
--- a/authz/policy/drools/pom.xml
+++ b/authz/policy/drools/pom.xml
@@ -7,7 +7,7 @@
org.keycloak
keycloak-authz-provider-parent
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
../pom.xml
diff --git a/authz/policy/pom.xml b/authz/policy/pom.xml
index f119652c85..7c9a43c7fe 100644
--- a/authz/policy/pom.xml
+++ b/authz/policy/pom.xml
@@ -7,7 +7,7 @@
org.keycloak
keycloak-authz-parent
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
../pom.xml
diff --git a/authz/pom.xml b/authz/pom.xml
index 36c54baf5e..65260f57ca 100644
--- a/authz/pom.xml
+++ b/authz/pom.xml
@@ -7,7 +7,7 @@
org.keycloak
keycloak-parent
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
../pom.xml
diff --git a/boms/adapter/pom.xml b/boms/adapter/pom.xml
index 47333617df..9b0c4fa85e 100644
--- a/boms/adapter/pom.xml
+++ b/boms/adapter/pom.xml
@@ -22,7 +22,7 @@
org.keycloak.bom
keycloak-bom-parent
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
org.keycloak.bom
@@ -37,97 +37,97 @@
org.keycloak
keycloak-core
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
org.keycloak
keycloak-adapter-core
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
org.keycloak
keycloak-adapter-spi
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
org.keycloak
keycloak-wildfly-adapter-dist
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
org.keycloak
keycloak-saml-adapter-core
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
org.keycloak
keycloak-saml-adapter-api-public
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
org.keycloak
keycloak-tomcat8-adapter
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
org.keycloak
keycloak-tomcat7-adapter
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
org.keycloak
keycloak-tomcat6-adapter
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
org.keycloak
keycloak-jetty81-adapter
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
org.keycloak
keycloak-jetty91-adapter
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
org.keycloak
keycloak-jetty92-adapter
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
org.keycloak
keycloak-jetty93-adapter
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
org.keycloak
keycloak-undertow-adapter
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
org.keycloak
keycloak-spring-boot-adapter
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
org.keycloak
spring-boot-container-bundle
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
org.keycloak
keycloak-spring-security-adapter
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
org.keycloak
keycloak-spring-boot-starter
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
org.keycloak
keycloak-authz-client
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
diff --git a/boms/pom.xml b/boms/pom.xml
index bbbc0dbaf5..a076fc912d 100644
--- a/boms/pom.xml
+++ b/boms/pom.xml
@@ -26,7 +26,7 @@
org.keycloak.bom
keycloak-bom-parent
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
pom
diff --git a/boms/spi/pom.xml b/boms/spi/pom.xml
index 9d970d1df0..ec688251a7 100644
--- a/boms/spi/pom.xml
+++ b/boms/spi/pom.xml
@@ -23,7 +23,7 @@
org.keycloak.bom
keycloak-bom-parent
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
org.keycloak.bom
@@ -38,12 +38,12 @@
org.keycloak
keycloak-core
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
org.keycloak
keycloak-server-spi
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
diff --git a/common/pom.xml b/common/pom.xml
index 70476b6743..6b93036ba3 100755
--- a/common/pom.xml
+++ b/common/pom.xml
@@ -21,7 +21,7 @@
keycloak-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
../pom.xml
4.0.0
diff --git a/core/pom.xml b/core/pom.xml
index c759a8a8ff..76cb21ef19 100755
--- a/core/pom.xml
+++ b/core/pom.xml
@@ -21,7 +21,7 @@
keycloak-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
../pom.xml
4.0.0
diff --git a/core/src/main/java/org/keycloak/OAuth2Constants.java b/core/src/main/java/org/keycloak/OAuth2Constants.java
index 2e585c3278..20d6e7388c 100644
--- a/core/src/main/java/org/keycloak/OAuth2Constants.java
+++ b/core/src/main/java/org/keycloak/OAuth2Constants.java
@@ -97,6 +97,9 @@ public interface OAuth2Constants {
String AUDIENCE="audience";
String SUBJECT_TOKEN="subject_token";
String SUBJECT_TOKEN_TYPE="subject_token_type";
+ String REQUESTED_TOKEN_TYPE="requested_token_type";
+ String ISSUED_TOKEN_TYPE="issued_token_type";
+ String REQUESTED_ISSUER="requested_issuer";
String ACCESS_TOKEN_TYPE="urn:ietf:params:oauth:token-type:access_token";
String REFRESH_TOKEN_TYPE="urn:ietf:params:oauth:token-type:refresh_token";
String JWT_TOKEN_TYPE="urn:ietf:params:oauth:token-type:jwt";
diff --git a/core/src/main/java/org/keycloak/representations/account/ClientRepresentation.java b/core/src/main/java/org/keycloak/representations/account/ClientRepresentation.java
new file mode 100644
index 0000000000..c2964268a8
--- /dev/null
+++ b/core/src/main/java/org/keycloak/representations/account/ClientRepresentation.java
@@ -0,0 +1,25 @@
+package org.keycloak.representations.account;
+
+/**
+ * Created by st on 29/03/17.
+ */
+public class ClientRepresentation {
+ private String clientId;
+ private String clientName;
+
+ public String getClientId() {
+ return clientId;
+ }
+
+ public void setClientId(String clientId) {
+ this.clientId = clientId;
+ }
+
+ public String getClientName() {
+ return clientName;
+ }
+
+ public void setClientName(String clientName) {
+ this.clientName = clientName;
+ }
+}
diff --git a/core/src/main/java/org/keycloak/representations/account/SessionRepresentation.java b/core/src/main/java/org/keycloak/representations/account/SessionRepresentation.java
new file mode 100644
index 0000000000..8e4d96fbd2
--- /dev/null
+++ b/core/src/main/java/org/keycloak/representations/account/SessionRepresentation.java
@@ -0,0 +1,64 @@
+package org.keycloak.representations.account;
+
+import java.util.List;
+
+/**
+ * Created by st on 29/03/17.
+ */
+public class SessionRepresentation {
+
+ private String id;
+ private String ipAddress;
+ private int started;
+ private int lastAccess;
+ private int expires;
+ private List clients;
+
+ public String getId() {
+ return id;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ public String getIpAddress() {
+ return ipAddress;
+ }
+
+ public void setIpAddress(String ipAddress) {
+ this.ipAddress = ipAddress;
+ }
+
+ public int getStarted() {
+ return started;
+ }
+
+ public void setStarted(int started) {
+ this.started = started;
+ }
+
+ public int getLastAccess() {
+ return lastAccess;
+ }
+
+ public void setLastAccess(int lastAccess) {
+ this.lastAccess = lastAccess;
+ }
+
+ public int getExpires() {
+ return expires;
+ }
+
+ public void setExpires(int expires) {
+ this.expires = expires;
+ }
+
+ public List getClients() {
+ return clients;
+ }
+
+ public void setClients(List clients) {
+ this.clients = clients;
+ }
+}
diff --git a/core/src/main/java/org/keycloak/representations/account/UserRepresentation.java b/core/src/main/java/org/keycloak/representations/account/UserRepresentation.java
new file mode 100755
index 0000000000..f457b180ed
--- /dev/null
+++ b/core/src/main/java/org/keycloak/representations/account/UserRepresentation.java
@@ -0,0 +1,97 @@
+/*
+ * 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.representations.account;
+
+import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
+import org.keycloak.json.StringListMapDeserializer;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @author Stian Thorgersen
+ */
+public class UserRepresentation {
+
+ private String id;
+ private String username;
+ private String firstName;
+ private String lastName;
+ private String email;
+ private boolean emailVerified;
+
+ @JsonDeserialize(using = StringListMapDeserializer.class)
+ private Map> attributes;
+
+ public String getId() {
+ return id;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ public String getUsername() {
+ return username;
+ }
+
+ public void setUsername(String username) {
+ this.username = username;
+ }
+
+ public String getFirstName() {
+ return firstName;
+ }
+
+ public void setFirstName(String firstName) {
+ this.firstName = firstName;
+ }
+
+ public String getLastName() {
+ return lastName;
+ }
+
+ public void setLastName(String lastName) {
+ this.lastName = lastName;
+ }
+
+ public String getEmail() {
+ return email;
+ }
+
+ public void setEmail(String email) {
+ this.email = email;
+ }
+
+ public boolean isEmailVerified() {
+ return emailVerified;
+ }
+
+ public void setEmailVerified(boolean emailVerified) {
+ this.emailVerified = emailVerified;
+ }
+
+ public Map> getAttributes() {
+ return attributes;
+ }
+
+ public void setAttributes(Map> attributes) {
+ this.attributes = attributes;
+ }
+
+}
diff --git a/core/src/main/java/org/keycloak/representations/idm/PublishedRealmRepresentation.java b/core/src/main/java/org/keycloak/representations/idm/PublishedRealmRepresentation.java
index eceb7592fc..ea11f4f14d 100755
--- a/core/src/main/java/org/keycloak/representations/idm/PublishedRealmRepresentation.java
+++ b/core/src/main/java/org/keycloak/representations/idm/PublishedRealmRepresentation.java
@@ -39,9 +39,6 @@ public class PublishedRealmRepresentation {
@JsonProperty("account-service")
protected String accountServiceUrl;
- @JsonProperty("admin-api")
- protected String adminApiUrl;
-
@JsonProperty("tokens-not-before")
protected int notBefore;
@@ -101,14 +98,6 @@ public class PublishedRealmRepresentation {
this.accountServiceUrl = accountServiceUrl;
}
- public String getAdminApiUrl() {
- return adminApiUrl;
- }
-
- public void setAdminApiUrl(String adminApiUrl) {
- this.adminApiUrl = adminApiUrl;
- }
-
public int getNotBefore() {
return notBefore;
}
diff --git a/core/src/main/java/org/keycloak/representations/idm/UserRepresentation.java b/core/src/main/java/org/keycloak/representations/idm/UserRepresentation.java
index 4dcea953df..7f0e0a0d1c 100755
--- a/core/src/main/java/org/keycloak/representations/idm/UserRepresentation.java
+++ b/core/src/main/java/org/keycloak/representations/idm/UserRepresentation.java
@@ -23,6 +23,7 @@ import org.keycloak.json.StringListMapDeserializer;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
+import java.util.ArrayList;
import java.util.Map;
import java.util.Set;
@@ -55,6 +56,7 @@ public class UserRepresentation {
protected List realmRoles;
protected Map> clientRoles;
protected List clientConsents;
+ protected Integer notBefore;
@Deprecated
protected Map> applicationRoles;
@@ -156,7 +158,7 @@ public class UserRepresentation {
public UserRepresentation singleAttribute(String name, String value) {
if (this.attributes == null) attributes = new HashMap<>();
- attributes.put(name, Arrays.asList(value));
+ attributes.put(name, (value == null ? new ArrayList() : Arrays.asList(value)));
return this;
}
@@ -216,6 +218,14 @@ public class UserRepresentation {
this.clientConsents = clientConsents;
}
+ public Integer getNotBefore() {
+ return notBefore;
+ }
+
+ public void setNotBefore(Integer notBefore) {
+ this.notBefore = notBefore;
+ }
+
@Deprecated
public Map> getApplicationRoles() {
return applicationRoles;
diff --git a/dependencies/pom.xml b/dependencies/pom.xml
index f0b973029d..c00393b47c 100755
--- a/dependencies/pom.xml
+++ b/dependencies/pom.xml
@@ -21,7 +21,7 @@
keycloak-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
4.0.0
diff --git a/dependencies/server-all/pom.xml b/dependencies/server-all/pom.xml
index 4061b97a97..91fa28581b 100755
--- a/dependencies/server-all/pom.xml
+++ b/dependencies/server-all/pom.xml
@@ -21,7 +21,7 @@
keycloak-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
../../pom.xml
4.0.0
diff --git a/dependencies/server-min/pom.xml b/dependencies/server-min/pom.xml
index 216bbad7e2..fd55eff273 100755
--- a/dependencies/server-min/pom.xml
+++ b/dependencies/server-min/pom.xml
@@ -21,7 +21,7 @@
keycloak-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
../../pom.xml
4.0.0
diff --git a/distribution/adapters/as7-eap6-adapter/as7-adapter-zip/pom.xml b/distribution/adapters/as7-eap6-adapter/as7-adapter-zip/pom.xml
index f10d11a7eb..ee1c6b2fa6 100755
--- a/distribution/adapters/as7-eap6-adapter/as7-adapter-zip/pom.xml
+++ b/distribution/adapters/as7-eap6-adapter/as7-adapter-zip/pom.xml
@@ -21,7 +21,7 @@
keycloak-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
../../../../pom.xml
diff --git a/distribution/adapters/as7-eap6-adapter/as7-modules/pom.xml b/distribution/adapters/as7-eap6-adapter/as7-modules/pom.xml
index 2529bc45db..1ff7fc0326 100755
--- a/distribution/adapters/as7-eap6-adapter/as7-modules/pom.xml
+++ b/distribution/adapters/as7-eap6-adapter/as7-modules/pom.xml
@@ -25,7 +25,7 @@
keycloak-as7-eap6-adapter-dist-pom
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
../pom.xml
diff --git a/distribution/adapters/as7-eap6-adapter/eap6-adapter-zip/pom.xml b/distribution/adapters/as7-eap6-adapter/eap6-adapter-zip/pom.xml
index f2c5dac490..7b96da355f 100755
--- a/distribution/adapters/as7-eap6-adapter/eap6-adapter-zip/pom.xml
+++ b/distribution/adapters/as7-eap6-adapter/eap6-adapter-zip/pom.xml
@@ -21,7 +21,7 @@
keycloak-as7-eap6-adapter-dist-pom
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
../pom.xml
diff --git a/distribution/adapters/as7-eap6-adapter/pom.xml b/distribution/adapters/as7-eap6-adapter/pom.xml
index e94db3a959..26c79f432b 100644
--- a/distribution/adapters/as7-eap6-adapter/pom.xml
+++ b/distribution/adapters/as7-eap6-adapter/pom.xml
@@ -20,7 +20,7 @@
keycloak-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
../../../pom.xml
Keycloak AS7 / JBoss EAP 6 Adapter Distros
diff --git a/distribution/adapters/fuse-adapter-zip/pom.xml b/distribution/adapters/fuse-adapter-zip/pom.xml
index 03db2b4868..fc31f43764 100644
--- a/distribution/adapters/fuse-adapter-zip/pom.xml
+++ b/distribution/adapters/fuse-adapter-zip/pom.xml
@@ -21,7 +21,7 @@
keycloak-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
../../../pom.xml
diff --git a/distribution/adapters/jetty81-adapter-zip/pom.xml b/distribution/adapters/jetty81-adapter-zip/pom.xml
index 5cfa1988a1..b48d8dce95 100755
--- a/distribution/adapters/jetty81-adapter-zip/pom.xml
+++ b/distribution/adapters/jetty81-adapter-zip/pom.xml
@@ -21,7 +21,7 @@
keycloak-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
../../../pom.xml
diff --git a/distribution/adapters/jetty91-adapter-zip/pom.xml b/distribution/adapters/jetty91-adapter-zip/pom.xml
index 506bf22f29..e5e7147e3b 100755
--- a/distribution/adapters/jetty91-adapter-zip/pom.xml
+++ b/distribution/adapters/jetty91-adapter-zip/pom.xml
@@ -21,7 +21,7 @@
keycloak-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
../../../pom.xml
diff --git a/distribution/adapters/jetty92-adapter-zip/pom.xml b/distribution/adapters/jetty92-adapter-zip/pom.xml
index 62c81b80a8..247270850b 100755
--- a/distribution/adapters/jetty92-adapter-zip/pom.xml
+++ b/distribution/adapters/jetty92-adapter-zip/pom.xml
@@ -21,7 +21,7 @@
keycloak-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
../../../pom.xml
diff --git a/distribution/adapters/jetty93-adapter-zip/pom.xml b/distribution/adapters/jetty93-adapter-zip/pom.xml
index f42fcd9283..e713de6bd4 100644
--- a/distribution/adapters/jetty93-adapter-zip/pom.xml
+++ b/distribution/adapters/jetty93-adapter-zip/pom.xml
@@ -21,7 +21,7 @@
keycloak-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
../../../pom.xml
diff --git a/distribution/adapters/jetty94-adapter-zip/pom.xml b/distribution/adapters/jetty94-adapter-zip/pom.xml
index bd199c9f5e..0a4f66af8e 100644
--- a/distribution/adapters/jetty94-adapter-zip/pom.xml
+++ b/distribution/adapters/jetty94-adapter-zip/pom.xml
@@ -21,7 +21,7 @@
keycloak-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
../../../pom.xml
diff --git a/distribution/adapters/js-adapter-zip/assembly.xml b/distribution/adapters/js-adapter-zip/assembly.xml
index 14e0cc00b6..8111f783ea 100755
--- a/distribution/adapters/js-adapter-zip/assembly.xml
+++ b/distribution/adapters/js-adapter-zip/assembly.xml
@@ -30,6 +30,7 @@
**/*.js
+ **/*.map
**/*.d.ts
**/*.html
diff --git a/distribution/adapters/js-adapter-zip/pom.xml b/distribution/adapters/js-adapter-zip/pom.xml
index be37dc8729..f92cdc7413 100755
--- a/distribution/adapters/js-adapter-zip/pom.xml
+++ b/distribution/adapters/js-adapter-zip/pom.xml
@@ -21,7 +21,7 @@
keycloak-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
../../../pom.xml
@@ -50,7 +50,7 @@
org.keycloak
keycloak-js-adapter
${project.build.directory}/unpacked/js-adapter
- *.js,*.d.ts
+ *.js,*.map,*.d.ts
**/welcome-content/*
diff --git a/distribution/adapters/osgi/features/pom.xml b/distribution/adapters/osgi/features/pom.xml
index 36ef9f35af..8b23c60ca5 100755
--- a/distribution/adapters/osgi/features/pom.xml
+++ b/distribution/adapters/osgi/features/pom.xml
@@ -21,7 +21,7 @@
keycloak-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
../../../../pom.xml
Keycloak OSGI Features
diff --git a/distribution/adapters/osgi/jaas/pom.xml b/distribution/adapters/osgi/jaas/pom.xml
index 2994b3cea2..29ab2932f1 100755
--- a/distribution/adapters/osgi/jaas/pom.xml
+++ b/distribution/adapters/osgi/jaas/pom.xml
@@ -21,7 +21,7 @@
keycloak-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
../../../../pom.xml
Keycloak OSGI JAAS Realm Configuration
diff --git a/distribution/adapters/osgi/pom.xml b/distribution/adapters/osgi/pom.xml
index 61b801af46..53da019d24 100755
--- a/distribution/adapters/osgi/pom.xml
+++ b/distribution/adapters/osgi/pom.xml
@@ -21,7 +21,7 @@
keycloak-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
../../../pom.xml
Keycloak OSGI Integration
diff --git a/distribution/adapters/osgi/thirdparty/pom.xml b/distribution/adapters/osgi/thirdparty/pom.xml
index bf42fa8ca3..15bbf6fb29 100755
--- a/distribution/adapters/osgi/thirdparty/pom.xml
+++ b/distribution/adapters/osgi/thirdparty/pom.xml
@@ -21,7 +21,7 @@
keycloak-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
../../../../pom.xml
diff --git a/distribution/adapters/pom.xml b/distribution/adapters/pom.xml
index 6e4193fe2f..5f13934833 100755
--- a/distribution/adapters/pom.xml
+++ b/distribution/adapters/pom.xml
@@ -20,7 +20,7 @@
keycloak-distribution-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
Adapters Distribution Parent
diff --git a/distribution/adapters/shared-cli/adapter-elytron-install.cli b/distribution/adapters/shared-cli/adapter-elytron-install.cli
index 16f17ce9a8..6ef26d01e5 100644
--- a/distribution/adapters/shared-cli/adapter-elytron-install.cli
+++ b/distribution/adapters/shared-cli/adapter-elytron-install.cli
@@ -36,10 +36,10 @@ else
end-if
if (outcome != success) of /subsystem=elytron/aggregate-http-server-mechanism-factory=keycloak-http-server-mechanism-factory:read-resource
- /subsystem=elytron/aggregate-http-server-mechanism-factory=keycloak-http-server-mechanism-factory:add(http-server-factories=[keycloak-oidc-http-server-mechanism-factory, global])
+ /subsystem=elytron/aggregate-http-server-mechanism-factory=keycloak-http-server-mechanism-factory:add(http-server-mechanism-factories=[keycloak-oidc-http-server-mechanism-factory, global])
else
echo Keycloak HTTP Mechanism Factory already installed. Trying to install Keycloak OpenID Connect HTTP Mechanism Factory.
- /subsystem=elytron/aggregate-http-server-mechanism-factory=keycloak-http-server-mechanism-factory:list-add(name=http-server-factories, value=keycloak-oidc-http-server-mechanism-factory)
+ /subsystem=elytron/aggregate-http-server-mechanism-factory=keycloak-http-server-mechanism-factory:list-add(name=http-server-mechanism-factories, value=keycloak-oidc-http-server-mechanism-factory)
end-if
diff --git a/distribution/adapters/tomcat6-adapter-zip/pom.xml b/distribution/adapters/tomcat6-adapter-zip/pom.xml
index 1ba65022c0..57e22dce90 100755
--- a/distribution/adapters/tomcat6-adapter-zip/pom.xml
+++ b/distribution/adapters/tomcat6-adapter-zip/pom.xml
@@ -21,7 +21,7 @@
keycloak-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
../../../pom.xml
diff --git a/distribution/adapters/tomcat7-adapter-zip/pom.xml b/distribution/adapters/tomcat7-adapter-zip/pom.xml
index 391c642dc8..0da1f19bae 100755
--- a/distribution/adapters/tomcat7-adapter-zip/pom.xml
+++ b/distribution/adapters/tomcat7-adapter-zip/pom.xml
@@ -21,7 +21,7 @@
keycloak-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
../../../pom.xml
diff --git a/distribution/adapters/tomcat8-adapter-zip/pom.xml b/distribution/adapters/tomcat8-adapter-zip/pom.xml
index d87f87b67b..905574fa42 100755
--- a/distribution/adapters/tomcat8-adapter-zip/pom.xml
+++ b/distribution/adapters/tomcat8-adapter-zip/pom.xml
@@ -21,7 +21,7 @@
keycloak-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
../../../pom.xml
diff --git a/distribution/adapters/wf8-adapter/pom.xml b/distribution/adapters/wf8-adapter/pom.xml
index 05b72b5ef1..1487850966 100644
--- a/distribution/adapters/wf8-adapter/pom.xml
+++ b/distribution/adapters/wf8-adapter/pom.xml
@@ -20,7 +20,7 @@
keycloak-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
../../../pom.xml
Keycloak Wildfly 8 Adapter
diff --git a/distribution/adapters/wf8-adapter/wf8-adapter-zip/pom.xml b/distribution/adapters/wf8-adapter/wf8-adapter-zip/pom.xml
index a88f373c91..02d7d6169a 100755
--- a/distribution/adapters/wf8-adapter/wf8-adapter-zip/pom.xml
+++ b/distribution/adapters/wf8-adapter/wf8-adapter-zip/pom.xml
@@ -21,7 +21,7 @@
keycloak-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
../../../../pom.xml
diff --git a/distribution/adapters/wf8-adapter/wf8-modules/pom.xml b/distribution/adapters/wf8-adapter/wf8-modules/pom.xml
index 88f191bffb..8ad11c2a64 100755
--- a/distribution/adapters/wf8-adapter/wf8-modules/pom.xml
+++ b/distribution/adapters/wf8-adapter/wf8-modules/pom.xml
@@ -25,7 +25,7 @@
keycloak-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
../../../../pom.xml
diff --git a/distribution/adapters/wildfly-adapter/cli/adapter-elytron-install-offline.cli b/distribution/adapters/wildfly-adapter/cli/adapter-elytron-install-offline.cli
index 8e0335ac02..76ec08cb17 100644
--- a/distribution/adapters/wildfly-adapter/cli/adapter-elytron-install-offline.cli
+++ b/distribution/adapters/wildfly-adapter/cli/adapter-elytron-install-offline.cli
@@ -38,10 +38,10 @@ else
end-if
if (outcome != success) of /subsystem=elytron/aggregate-http-server-mechanism-factory=keycloak-http-server-mechanism-factory:read-resource
- /subsystem=elytron/aggregate-http-server-mechanism-factory=keycloak-http-server-mechanism-factory:add(http-server-factories=[keycloak-oidc-http-server-mechanism-factory, global])
+ /subsystem=elytron/aggregate-http-server-mechanism-factory=keycloak-http-server-mechanism-factory:add(http-server-mechanism-factories=[keycloak-oidc-http-server-mechanism-factory, global])
else
echo Keycloak HTTP Mechanism Factory already installed. Trying to install Keycloak OpenID Connect HTTP Mechanism Factory.
- /subsystem=elytron/aggregate-http-server-mechanism-factory=keycloak-http-server-mechanism-factory:list-add(name=http-server-factories, value=keycloak-oidc-http-server-mechanism-factory)
+ /subsystem=elytron/aggregate-http-server-mechanism-factory=keycloak-http-server-mechanism-factory:list-add(name=http-server-mechanism-factories, value=keycloak-oidc-http-server-mechanism-factory)
end-if
diff --git a/distribution/adapters/wildfly-adapter/pom.xml b/distribution/adapters/wildfly-adapter/pom.xml
index d116ab1a5f..b36f521cdb 100644
--- a/distribution/adapters/wildfly-adapter/pom.xml
+++ b/distribution/adapters/wildfly-adapter/pom.xml
@@ -21,7 +21,7 @@
keycloak-adapters-distribution-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
keycloak-wildfly-adapter-dist
diff --git a/distribution/api-docs-dist/pom.xml b/distribution/api-docs-dist/pom.xml
index a13c521235..252bc61e0e 100755
--- a/distribution/api-docs-dist/pom.xml
+++ b/distribution/api-docs-dist/pom.xml
@@ -21,7 +21,7 @@
keycloak-distribution-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
keycloak-api-docs-dist
diff --git a/distribution/demo-dist/pom.xml b/distribution/demo-dist/pom.xml
index 95ae460f83..5a5ac14076 100755
--- a/distribution/demo-dist/pom.xml
+++ b/distribution/demo-dist/pom.xml
@@ -21,7 +21,7 @@
keycloak-distribution-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
keycloak-demo-dist
diff --git a/distribution/demo-dist/src/main/xslt/standalone.xsl b/distribution/demo-dist/src/main/xslt/standalone.xsl
index 5ea7e93ce0..f800ae2359 100755
--- a/distribution/demo-dist/src/main/xslt/standalone.xsl
+++ b/distribution/demo-dist/src/main/xslt/standalone.xsl
@@ -17,10 +17,10 @@
diff --git a/distribution/downloads/pom.xml b/distribution/downloads/pom.xml
index 4c9211911e..9dd7b22870 100755
--- a/distribution/downloads/pom.xml
+++ b/distribution/downloads/pom.xml
@@ -21,7 +21,7 @@
keycloak-distribution-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
keycloak-dist-downloads
diff --git a/distribution/examples-dist/pom.xml b/distribution/examples-dist/pom.xml
index 5db83ef6a8..794c799578 100755
--- a/distribution/examples-dist/pom.xml
+++ b/distribution/examples-dist/pom.xml
@@ -21,7 +21,7 @@
keycloak-distribution-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
keycloak-examples-dist
diff --git a/distribution/feature-packs/adapter-feature-pack/pom.xml b/distribution/feature-packs/adapter-feature-pack/pom.xml
index 6f4b77b49c..ff661ce617 100755
--- a/distribution/feature-packs/adapter-feature-pack/pom.xml
+++ b/distribution/feature-packs/adapter-feature-pack/pom.xml
@@ -19,7 +19,7 @@
org.keycloak
feature-packs-parent
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
4.0.0
diff --git a/distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/add-ons/keycloak/org/keycloak/keycloak-wildfly-subsystem/main/module.xml b/distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/add-ons/keycloak/org/keycloak/keycloak-wildfly-subsystem/main/module.xml
index 025f15271b..32849fc6f1 100755
--- a/distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/add-ons/keycloak/org/keycloak/keycloak-wildfly-subsystem/main/module.xml
+++ b/distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/add-ons/keycloak/org/keycloak/keycloak-wildfly-subsystem/main/module.xml
@@ -38,5 +38,9 @@
+
+
+
+
diff --git a/distribution/feature-packs/pom.xml b/distribution/feature-packs/pom.xml
index b32593d23e..4fd074480a 100644
--- a/distribution/feature-packs/pom.xml
+++ b/distribution/feature-packs/pom.xml
@@ -20,7 +20,7 @@
keycloak-distribution-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
Feature Pack Builds
diff --git a/distribution/feature-packs/server-feature-pack/pom.xml b/distribution/feature-packs/server-feature-pack/pom.xml
index e2f1f4144b..8b426ac656 100644
--- a/distribution/feature-packs/server-feature-pack/pom.xml
+++ b/distribution/feature-packs/server-feature-pack/pom.xml
@@ -19,7 +19,7 @@
org.keycloak
feature-packs-parent
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
../pom.xml
4.0.0
diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/configuration/domain/subsystems.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/configuration/domain/subsystems.xml
index ab9bfa9dcb..7a841483af 100755
--- a/distribution/feature-packs/server-feature-pack/src/main/resources/configuration/domain/subsystems.xml
+++ b/distribution/feature-packs/server-feature-pack/src/main/resources/configuration/domain/subsystems.xml
@@ -27,10 +27,8 @@
keycloak-infinispan.xml
jaxrs.xml
jca.xml
- jdr.xml
jmx.xml
jpa.xml
- jsf.xml
mail.xml
naming.xml
remoting.xml
@@ -54,11 +52,9 @@
keycloak-infinispan.xml
jaxrs.xml
jca.xml
- jdr.xml
jgroups.xml
jmx.xml
jpa.xml
- jsf.xml
mail.xml
mod_cluster.xml
naming.xml
diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/configuration/standalone/subsystems-ha.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/configuration/standalone/subsystems-ha.xml
index 9d9954de9b..e19734cf21 100755
--- a/distribution/feature-packs/server-feature-pack/src/main/resources/configuration/standalone/subsystems-ha.xml
+++ b/distribution/feature-packs/server-feature-pack/src/main/resources/configuration/standalone/subsystems-ha.xml
@@ -29,11 +29,9 @@
keycloak-infinispan.xml
jaxrs.xml
jca.xml
- jdr.xml
jgroups.xml
jmx.xml
jpa.xml
- jsf.xml
mail.xml
mod_cluster.xml
naming.xml
diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/configuration/standalone/subsystems.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/configuration/standalone/subsystems.xml
index 823b45cebc..a1a5035ab3 100755
--- a/distribution/feature-packs/server-feature-pack/src/main/resources/configuration/standalone/subsystems.xml
+++ b/distribution/feature-packs/server-feature-pack/src/main/resources/configuration/standalone/subsystems.xml
@@ -21,18 +21,16 @@
logging.xml
bean-validation.xml
- keycloak-datasources2.xml
+ keycloak-datasources.xml
deployment-scanner.xml
ee.xml
ejb3.xml
io.xml
- keycloak-infinispan2.xml
+ keycloak-infinispan.xml
jaxrs.xml
jca.xml
- jdr.xml
jmx.xml
jpa.xml
- jsf.xml
mail.xml
naming.xml
remoting.xml
diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-server-spi-private/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-server-spi-private/main/module.xml
index 0f136fde63..be103dde61 100755
--- a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-server-spi-private/main/module.xml
+++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-server-spi-private/main/module.xml
@@ -36,5 +36,7 @@
+
+
diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-services/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-services/main/module.xml
index 968895d023..18e162abd3 100755
--- a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-services/main/module.xml
+++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-services/main/module.xml
@@ -49,7 +49,6 @@
-
diff --git a/distribution/pom.xml b/distribution/pom.xml
index 165323ddc8..a5f1fc73fd 100755
--- a/distribution/pom.xml
+++ b/distribution/pom.xml
@@ -20,7 +20,7 @@
keycloak-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
../pom.xml
@@ -34,9 +34,9 @@
adapters
saml-adapters
+ feature-packs
server-dist
server-overlay
- feature-packs
diff --git a/distribution/proxy-dist/pom.xml b/distribution/proxy-dist/pom.xml
index 79d4468de6..959be2a9d3 100755
--- a/distribution/proxy-dist/pom.xml
+++ b/distribution/proxy-dist/pom.xml
@@ -21,7 +21,7 @@
keycloak-distribution-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
keycloak-proxy-dist
diff --git a/distribution/saml-adapters/as7-eap6-adapter/as7-adapter-zip/pom.xml b/distribution/saml-adapters/as7-eap6-adapter/as7-adapter-zip/pom.xml
index 4165230f30..5f7b4751bc 100755
--- a/distribution/saml-adapters/as7-eap6-adapter/as7-adapter-zip/pom.xml
+++ b/distribution/saml-adapters/as7-eap6-adapter/as7-adapter-zip/pom.xml
@@ -21,7 +21,7 @@
keycloak-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
../../../../pom.xml
diff --git a/distribution/saml-adapters/as7-eap6-adapter/as7-modules/pom.xml b/distribution/saml-adapters/as7-eap6-adapter/as7-modules/pom.xml
index f2650dfd1d..9297bbaf6e 100755
--- a/distribution/saml-adapters/as7-eap6-adapter/as7-modules/pom.xml
+++ b/distribution/saml-adapters/as7-eap6-adapter/as7-modules/pom.xml
@@ -25,7 +25,7 @@
keycloak-saml-as7-eap6-adapter-dist-pom
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
../pom.xml
diff --git a/distribution/saml-adapters/as7-eap6-adapter/as7-modules/src/main/resources/modules/org/keycloak/keycloak-saml-as7-adapter/main/module.xml b/distribution/saml-adapters/as7-eap6-adapter/as7-modules/src/main/resources/modules/org/keycloak/keycloak-saml-as7-adapter/main/module.xml
index fd9d2e4089..885470fb2e 100755
--- a/distribution/saml-adapters/as7-eap6-adapter/as7-modules/src/main/resources/modules/org/keycloak/keycloak-saml-as7-adapter/main/module.xml
+++ b/distribution/saml-adapters/as7-eap6-adapter/as7-modules/src/main/resources/modules/org/keycloak/keycloak-saml-as7-adapter/main/module.xml
@@ -34,7 +34,6 @@
-
diff --git a/distribution/saml-adapters/as7-eap6-adapter/eap6-adapter-zip/pom.xml b/distribution/saml-adapters/as7-eap6-adapter/eap6-adapter-zip/pom.xml
index 54c249d8ff..5e5c14675a 100755
--- a/distribution/saml-adapters/as7-eap6-adapter/eap6-adapter-zip/pom.xml
+++ b/distribution/saml-adapters/as7-eap6-adapter/eap6-adapter-zip/pom.xml
@@ -21,7 +21,7 @@
keycloak-saml-as7-eap6-adapter-dist-pom
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
../pom.xml
diff --git a/distribution/saml-adapters/as7-eap6-adapter/pom.xml b/distribution/saml-adapters/as7-eap6-adapter/pom.xml
index e1c378c220..c7175bb171 100755
--- a/distribution/saml-adapters/as7-eap6-adapter/pom.xml
+++ b/distribution/saml-adapters/as7-eap6-adapter/pom.xml
@@ -20,7 +20,7 @@
keycloak-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
../../../pom.xml
Keycloak SAML AS7 / JBoss EAP 6 Adapter Distros
diff --git a/distribution/saml-adapters/jetty81-adapter-zip/pom.xml b/distribution/saml-adapters/jetty81-adapter-zip/pom.xml
index 8c8f99f986..15e43564b6 100755
--- a/distribution/saml-adapters/jetty81-adapter-zip/pom.xml
+++ b/distribution/saml-adapters/jetty81-adapter-zip/pom.xml
@@ -21,7 +21,7 @@
keycloak-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
../../../pom.xml
diff --git a/distribution/saml-adapters/jetty92-adapter-zip/pom.xml b/distribution/saml-adapters/jetty92-adapter-zip/pom.xml
index f5c3481c22..35b2d86f66 100755
--- a/distribution/saml-adapters/jetty92-adapter-zip/pom.xml
+++ b/distribution/saml-adapters/jetty92-adapter-zip/pom.xml
@@ -21,7 +21,7 @@
keycloak-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
../../../pom.xml
diff --git a/distribution/saml-adapters/jetty93-adapter-zip/pom.xml b/distribution/saml-adapters/jetty93-adapter-zip/pom.xml
index e6ef28e651..df95b97ea7 100644
--- a/distribution/saml-adapters/jetty93-adapter-zip/pom.xml
+++ b/distribution/saml-adapters/jetty93-adapter-zip/pom.xml
@@ -21,7 +21,7 @@
keycloak-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
../../../pom.xml
diff --git a/distribution/saml-adapters/jetty94-adapter-zip/pom.xml b/distribution/saml-adapters/jetty94-adapter-zip/pom.xml
index 8b86d43d74..f2c8e2a358 100644
--- a/distribution/saml-adapters/jetty94-adapter-zip/pom.xml
+++ b/distribution/saml-adapters/jetty94-adapter-zip/pom.xml
@@ -21,7 +21,7 @@
keycloak-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
../../../pom.xml
diff --git a/distribution/saml-adapters/pom.xml b/distribution/saml-adapters/pom.xml
index 81828d285e..b3bc83abce 100755
--- a/distribution/saml-adapters/pom.xml
+++ b/distribution/saml-adapters/pom.xml
@@ -20,7 +20,7 @@
keycloak-distribution-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
SAML Adapters Distribution Parent
diff --git a/distribution/saml-adapters/shared-cli/adapter-elytron-install-saml.cli b/distribution/saml-adapters/shared-cli/adapter-elytron-install-saml.cli
index 1f24085459..a76109b809 100755
--- a/distribution/saml-adapters/shared-cli/adapter-elytron-install-saml.cli
+++ b/distribution/saml-adapters/shared-cli/adapter-elytron-install-saml.cli
@@ -36,10 +36,10 @@ else
end-if
if (outcome != success) of /subsystem=elytron/aggregate-http-server-mechanism-factory=keycloak-http-server-mechanism-factory:read-resource
- /subsystem=elytron/aggregate-http-server-mechanism-factory=keycloak-http-server-mechanism-factory:add(http-server-factories=[keycloak-saml-http-server-mechanism-factory, global])
+ /subsystem=elytron/aggregate-http-server-mechanism-factory=keycloak-http-server-mechanism-factory:add(http-server-mechanism-factories=[keycloak-saml-http-server-mechanism-factory, global])
else
echo Keycloak HTTP Mechanism Factory already installed. Trying to install Keycloak SAML HTTP Mechanism Factory.
- /subsystem=elytron/aggregate-http-server-mechanism-factory=keycloak-http-server-mechanism-factory:list-add(name=http-server-factories, value=keycloak-saml-http-server-mechanism-factory)
+ /subsystem=elytron/aggregate-http-server-mechanism-factory=keycloak-http-server-mechanism-factory:list-add(name=http-server-mechanism-factories, value=keycloak-saml-http-server-mechanism-factory)
end-if
if (outcome != success) of /subsystem=elytron/http-authentication-factory=keycloak-http-authentication:read-resource
diff --git a/distribution/saml-adapters/tomcat6-adapter-zip/pom.xml b/distribution/saml-adapters/tomcat6-adapter-zip/pom.xml
index 01cdab6a52..3b0eb2aad2 100755
--- a/distribution/saml-adapters/tomcat6-adapter-zip/pom.xml
+++ b/distribution/saml-adapters/tomcat6-adapter-zip/pom.xml
@@ -21,7 +21,7 @@
keycloak-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
../../../pom.xml
diff --git a/distribution/saml-adapters/tomcat7-adapter-zip/pom.xml b/distribution/saml-adapters/tomcat7-adapter-zip/pom.xml
index f4a5a2d125..5cb56b7dc9 100755
--- a/distribution/saml-adapters/tomcat7-adapter-zip/pom.xml
+++ b/distribution/saml-adapters/tomcat7-adapter-zip/pom.xml
@@ -21,7 +21,7 @@
keycloak-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
../../../pom.xml
diff --git a/distribution/saml-adapters/tomcat8-adapter-zip/pom.xml b/distribution/saml-adapters/tomcat8-adapter-zip/pom.xml
index da7c2187d6..37d00abfb8 100755
--- a/distribution/saml-adapters/tomcat8-adapter-zip/pom.xml
+++ b/distribution/saml-adapters/tomcat8-adapter-zip/pom.xml
@@ -21,7 +21,7 @@
keycloak-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
../../../pom.xml
diff --git a/distribution/saml-adapters/wildfly-adapter/pom.xml b/distribution/saml-adapters/wildfly-adapter/pom.xml
index 6d2a6e2c2e..9f084b1cdb 100755
--- a/distribution/saml-adapters/wildfly-adapter/pom.xml
+++ b/distribution/saml-adapters/wildfly-adapter/pom.xml
@@ -20,7 +20,7 @@
keycloak-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
../../../pom.xml
Keycloak Wildfly SAML Adapter
diff --git a/distribution/saml-adapters/wildfly-adapter/wildfly-adapter-zip/pom.xml b/distribution/saml-adapters/wildfly-adapter/wildfly-adapter-zip/pom.xml
index 1b80a59d54..6f68ed0be3 100755
--- a/distribution/saml-adapters/wildfly-adapter/wildfly-adapter-zip/pom.xml
+++ b/distribution/saml-adapters/wildfly-adapter/wildfly-adapter-zip/pom.xml
@@ -21,7 +21,7 @@
keycloak-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
../../../../pom.xml
diff --git a/distribution/saml-adapters/wildfly-adapter/wildfly-modules/pom.xml b/distribution/saml-adapters/wildfly-adapter/wildfly-modules/pom.xml
index e398bbbe5f..4123be58d4 100755
--- a/distribution/saml-adapters/wildfly-adapter/wildfly-modules/pom.xml
+++ b/distribution/saml-adapters/wildfly-adapter/wildfly-modules/pom.xml
@@ -25,7 +25,7 @@
keycloak-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
../../../../pom.xml
diff --git a/distribution/saml-adapters/wildfly-adapter/wildfly-modules/src/main/resources/modules/org/keycloak/keycloak-saml-wildfly-subsystem/main/module.xml b/distribution/saml-adapters/wildfly-adapter/wildfly-modules/src/main/resources/modules/org/keycloak/keycloak-saml-wildfly-subsystem/main/module.xml
index 857a8e31b8..b61266df6c 100755
--- a/distribution/saml-adapters/wildfly-adapter/wildfly-modules/src/main/resources/modules/org/keycloak/keycloak-saml-wildfly-subsystem/main/module.xml
+++ b/distribution/saml-adapters/wildfly-adapter/wildfly-modules/src/main/resources/modules/org/keycloak/keycloak-saml-wildfly-subsystem/main/module.xml
@@ -40,5 +40,6 @@
+
diff --git a/distribution/server-dist/assembly.xml b/distribution/server-dist/assembly.xml
index dc0790454f..f966cff11e 100755
--- a/distribution/server-dist/assembly.xml
+++ b/distribution/server-dist/assembly.xml
@@ -33,6 +33,19 @@
**/module.xml
+
target/${project.build.finalName}
@@ -40,6 +53,10 @@
false
bin/*.sh
+
module.xml
welcome-content/**
appclient/**
@@ -49,8 +66,20 @@
themes/**
version.txt
${profileExcludes}
+
+
target/${project.build.finalName}
diff --git a/distribution/server-dist/pom.xml b/distribution/server-dist/pom.xml
index 6b425c0a13..334e2ee8dc 100755
--- a/distribution/server-dist/pom.xml
+++ b/distribution/server-dist/pom.xml
@@ -21,7 +21,7 @@
keycloak-distribution-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
keycloak-server-dist
diff --git a/distribution/server-overlay/pom.xml b/distribution/server-overlay/pom.xml
index f8a0c538ba..b42f7e872b 100755
--- a/distribution/server-overlay/pom.xml
+++ b/distribution/server-overlay/pom.xml
@@ -21,7 +21,7 @@
keycloak-distribution-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
keycloak-server-overlay
diff --git a/distribution/server-overlay/src/main/modules/layers.conf b/distribution/server-overlay/src/main/modules/layers.conf
new file mode 100644
index 0000000000..74f44850c7
--- /dev/null
+++ b/distribution/server-overlay/src/main/modules/layers.conf
@@ -0,0 +1 @@
+layers=keycloak
\ No newline at end of file
diff --git a/examples/admin-client/pom.xml b/examples/admin-client/pom.xml
index c5ac43eafb..bf10c78529 100755
--- a/examples/admin-client/pom.xml
+++ b/examples/admin-client/pom.xml
@@ -22,7 +22,7 @@
keycloak-examples-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
Keycloak Examples - Admin Client
diff --git a/examples/authz/hello-world-authz-service/pom.xml b/examples/authz/hello-world-authz-service/pom.xml
index 26c1777330..a36e305e73 100755
--- a/examples/authz/hello-world-authz-service/pom.xml
+++ b/examples/authz/hello-world-authz-service/pom.xml
@@ -24,7 +24,7 @@
org.keycloak
keycloak-authz-example-parent
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
../pom.xml
diff --git a/examples/authz/hello-world/pom.xml b/examples/authz/hello-world/pom.xml
index afdc3fb879..31e48ec3b8 100755
--- a/examples/authz/hello-world/pom.xml
+++ b/examples/authz/hello-world/pom.xml
@@ -24,7 +24,7 @@
org.keycloak
keycloak-authz-example-parent
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
../pom.xml
diff --git a/examples/authz/photoz/photoz-authz-policy/pom.xml b/examples/authz/photoz/photoz-authz-policy/pom.xml
index 08267aa479..7d89b93eda 100755
--- a/examples/authz/photoz/photoz-authz-policy/pom.xml
+++ b/examples/authz/photoz/photoz-authz-policy/pom.xml
@@ -6,7 +6,7 @@
org.keycloak
keycloak-authz-photoz-parent
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
../pom.xml
diff --git a/examples/authz/photoz/photoz-authz-policy/src/main/resources/com.photoz.authz.policy.admin/Main.drl b/examples/authz/photoz/photoz-authz-policy/src/main/resources/com.photoz.authz.policy.admin/Main.drl
index deb1c84757..c807f9b7ab 100644
--- a/examples/authz/photoz/photoz-authz-policy/src/main/resources/com.photoz.authz.policy.admin/Main.drl
+++ b/examples/authz/photoz/photoz-authz-policy/src/main/resources/com.photoz.authz.policy.admin/Main.drl
@@ -7,7 +7,7 @@ rule "Authorize Admin Resources"
when
$evaluation : Evaluation(
$identity : context.identity,
- $identity.hasRole("admin")
+ $identity.hasRealmRole("admin")
)
then
$evaluation.grant();
diff --git a/examples/authz/photoz/photoz-authz-policy/src/main/resources/com.photoz.authz.policy.user/Main.drl b/examples/authz/photoz/photoz-authz-policy/src/main/resources/com.photoz.authz.policy.user/Main.drl
index 9b1677edca..2ebc457ea4 100644
--- a/examples/authz/photoz/photoz-authz-policy/src/main/resources/com.photoz.authz.policy.user/Main.drl
+++ b/examples/authz/photoz/photoz-authz-policy/src/main/resources/com.photoz.authz.policy.user/Main.drl
@@ -7,7 +7,7 @@ rule "Authorize View User Album"
when
$evaluation : Evaluation(
$identity : context.identity,
- $identity.hasRole("user")
+ $identity.hasRealmRole("user")
)
then
$evaluation.grant();
diff --git a/examples/authz/photoz/photoz-html5-client/pom.xml b/examples/authz/photoz/photoz-html5-client/pom.xml
index 5ff5fdb136..e4fb521d9c 100755
--- a/examples/authz/photoz/photoz-html5-client/pom.xml
+++ b/examples/authz/photoz/photoz-html5-client/pom.xml
@@ -5,7 +5,7 @@
org.keycloak
keycloak-authz-photoz-parent
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
../pom.xml
diff --git a/examples/authz/photoz/photoz-restful-api/pom.xml b/examples/authz/photoz/photoz-restful-api/pom.xml
index 94b73dc07b..4e65c16232 100755
--- a/examples/authz/photoz/photoz-restful-api/pom.xml
+++ b/examples/authz/photoz/photoz-restful-api/pom.xml
@@ -6,7 +6,7 @@
org.keycloak
keycloak-authz-photoz-parent
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
../pom.xml
diff --git a/examples/authz/photoz/photoz-restful-api/src/main/resources/photoz-restful-api-authz-service.json b/examples/authz/photoz/photoz-restful-api/src/main/resources/photoz-restful-api-authz-service.json
index b6a93bc4f0..28b87bc579 100644
--- a/examples/authz/photoz/photoz-restful-api/src/main/resources/photoz-restful-api-authz-service.json
+++ b/examples/authz/photoz/photoz-restful-api/src/main/resources/photoz-restful-api-authz-service.json
@@ -113,7 +113,7 @@
"logic": "POSITIVE",
"decisionStrategy": "UNANIMOUS",
"config": {
- "code": "var context = $evaluation.getContext();\nvar identity = context.getIdentity();\nvar attributes = identity.getAttributes();\nvar email = attributes.getValue('email').asString(0);\n\nif (identity.hasRole('admin') || email.endsWith('@keycloak.org')) {\n $evaluation.grant();\n}"
+ "code": "var context = $evaluation.getContext();\nvar identity = context.getIdentity();\nvar attributes = identity.getAttributes();\nvar email = attributes.getValue('email').asString(0);\n\nif (identity.hasRealmRole('admin') || email.endsWith('@keycloak.org')) {\n $evaluation.grant();\n}"
}
},
{
diff --git a/examples/authz/photoz/pom.xml b/examples/authz/photoz/pom.xml
index cbaeb243ec..26f377aa0c 100755
--- a/examples/authz/photoz/pom.xml
+++ b/examples/authz/photoz/pom.xml
@@ -6,7 +6,7 @@
org.keycloak
keycloak-authz-example-parent
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
../pom.xml
diff --git a/examples/authz/pom.xml b/examples/authz/pom.xml
index 06adb3ca98..a81552d604 100755
--- a/examples/authz/pom.xml
+++ b/examples/authz/pom.xml
@@ -6,7 +6,7 @@
keycloak-examples-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
../pom.xml
diff --git a/examples/authz/servlet-authz/pom.xml b/examples/authz/servlet-authz/pom.xml
index ffcf7f2085..b730ba566a 100755
--- a/examples/authz/servlet-authz/pom.xml
+++ b/examples/authz/servlet-authz/pom.xml
@@ -6,7 +6,7 @@
org.keycloak
keycloak-authz-example-parent
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
../pom.xml
diff --git a/examples/basic-auth/pom.xml b/examples/basic-auth/pom.xml
index af19e13ef0..c8576f1e58 100755
--- a/examples/basic-auth/pom.xml
+++ b/examples/basic-auth/pom.xml
@@ -23,7 +23,7 @@
keycloak-examples-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
Keycloak Examples - Basic Auth
diff --git a/examples/broker/facebook-authentication/pom.xml b/examples/broker/facebook-authentication/pom.xml
index 0fb71b4a4e..f8edf4829e 100755
--- a/examples/broker/facebook-authentication/pom.xml
+++ b/examples/broker/facebook-authentication/pom.xml
@@ -23,7 +23,7 @@
keycloak-examples-broker-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
Keycloak Broker Examples - Facebook Authentication
diff --git a/examples/broker/google-authentication/pom.xml b/examples/broker/google-authentication/pom.xml
index e89fbc560f..0cc37e980d 100755
--- a/examples/broker/google-authentication/pom.xml
+++ b/examples/broker/google-authentication/pom.xml
@@ -23,7 +23,7 @@
keycloak-examples-broker-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
Keycloak Broker Examples - Google Authentication
diff --git a/examples/broker/pom.xml b/examples/broker/pom.xml
index 5797474cc6..ad206a7f76 100755
--- a/examples/broker/pom.xml
+++ b/examples/broker/pom.xml
@@ -20,7 +20,7 @@
keycloak-examples-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
Broker Examples
diff --git a/examples/broker/saml-broker-authentication/pom.xml b/examples/broker/saml-broker-authentication/pom.xml
index 3226fbc353..7207ab34a2 100755
--- a/examples/broker/saml-broker-authentication/pom.xml
+++ b/examples/broker/saml-broker-authentication/pom.xml
@@ -23,7 +23,7 @@
keycloak-examples-broker-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
Keycloak Broker Examples - SAML Identity Provider Brokering
diff --git a/examples/broker/twitter-authentication/pom.xml b/examples/broker/twitter-authentication/pom.xml
index 188035d0e8..514da61bf9 100755
--- a/examples/broker/twitter-authentication/pom.xml
+++ b/examples/broker/twitter-authentication/pom.xml
@@ -23,7 +23,7 @@
keycloak-examples-broker-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
Keycloak Broker Examples - Twitter Authentication
diff --git a/examples/cors/angular-product-app/pom.xml b/examples/cors/angular-product-app/pom.xml
index 28e65fcf6b..143592d331 100755
--- a/examples/cors/angular-product-app/pom.xml
+++ b/examples/cors/angular-product-app/pom.xml
@@ -21,7 +21,7 @@
keycloak-examples-cors-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
4.0.0
diff --git a/examples/cors/database-service/pom.xml b/examples/cors/database-service/pom.xml
index 80ccf115b2..404e8fc021 100755
--- a/examples/cors/database-service/pom.xml
+++ b/examples/cors/database-service/pom.xml
@@ -21,7 +21,7 @@
keycloak-examples-cors-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
4.0.0
diff --git a/examples/cors/pom.xml b/examples/cors/pom.xml
index 3e4d71ad6d..4ff72bc8e3 100755
--- a/examples/cors/pom.xml
+++ b/examples/cors/pom.xml
@@ -21,7 +21,7 @@
keycloak-examples-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
Keycloak Examples - CORS
diff --git a/examples/demo-template/admin-access-app/pom.xml b/examples/demo-template/admin-access-app/pom.xml
index fd2565f340..665e65f53b 100755
--- a/examples/demo-template/admin-access-app/pom.xml
+++ b/examples/demo-template/admin-access-app/pom.xml
@@ -21,7 +21,7 @@
keycloak-examples-demo-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
4.0.0
diff --git a/examples/demo-template/angular-product-app/pom.xml b/examples/demo-template/angular-product-app/pom.xml
index 06c4b2ed08..3a29e3baa3 100755
--- a/examples/demo-template/angular-product-app/pom.xml
+++ b/examples/demo-template/angular-product-app/pom.xml
@@ -21,7 +21,7 @@
keycloak-examples-demo-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
4.0.0
diff --git a/examples/demo-template/customer-app-cli/pom.xml b/examples/demo-template/customer-app-cli/pom.xml
index f58edd5749..6852841935 100755
--- a/examples/demo-template/customer-app-cli/pom.xml
+++ b/examples/demo-template/customer-app-cli/pom.xml
@@ -21,7 +21,7 @@
keycloak-examples-demo-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
4.0.0
diff --git a/examples/demo-template/customer-app-filter/pom.xml b/examples/demo-template/customer-app-filter/pom.xml
index 3b8146fe15..cc6f621903 100755
--- a/examples/demo-template/customer-app-filter/pom.xml
+++ b/examples/demo-template/customer-app-filter/pom.xml
@@ -21,7 +21,7 @@
keycloak-examples-demo-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
4.0.0
diff --git a/examples/demo-template/customer-app-js/pom.xml b/examples/demo-template/customer-app-js/pom.xml
index e5e6ca9af5..d3d78636d3 100755
--- a/examples/demo-template/customer-app-js/pom.xml
+++ b/examples/demo-template/customer-app-js/pom.xml
@@ -21,7 +21,7 @@
keycloak-examples-demo-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
4.0.0
diff --git a/examples/demo-template/customer-app/pom.xml b/examples/demo-template/customer-app/pom.xml
index 7c59225647..d057f29cee 100755
--- a/examples/demo-template/customer-app/pom.xml
+++ b/examples/demo-template/customer-app/pom.xml
@@ -21,7 +21,7 @@
keycloak-examples-demo-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
4.0.0
diff --git a/examples/demo-template/database-service/pom.xml b/examples/demo-template/database-service/pom.xml
index e4252a4049..e81fac22bb 100755
--- a/examples/demo-template/database-service/pom.xml
+++ b/examples/demo-template/database-service/pom.xml
@@ -21,7 +21,7 @@
keycloak-examples-demo-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
4.0.0
diff --git a/examples/demo-template/example-ear/pom.xml b/examples/demo-template/example-ear/pom.xml
index 3c4d3a0f95..864b5d7d98 100755
--- a/examples/demo-template/example-ear/pom.xml
+++ b/examples/demo-template/example-ear/pom.xml
@@ -21,7 +21,7 @@
keycloak-examples-demo-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
4.0.0
diff --git a/examples/demo-template/offline-access-app/pom.xml b/examples/demo-template/offline-access-app/pom.xml
index f2af2fb3fa..7c9484a2d8 100755
--- a/examples/demo-template/offline-access-app/pom.xml
+++ b/examples/demo-template/offline-access-app/pom.xml
@@ -21,7 +21,7 @@
keycloak-examples-demo-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
4.0.0
diff --git a/examples/demo-template/pom.xml b/examples/demo-template/pom.xml
index 19f8b9184b..5ddedefbc2 100755
--- a/examples/demo-template/pom.xml
+++ b/examples/demo-template/pom.xml
@@ -20,7 +20,7 @@
keycloak-examples-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
Demo Examples
diff --git a/examples/demo-template/product-app/pom.xml b/examples/demo-template/product-app/pom.xml
index c565ceefd0..e52a3c816d 100755
--- a/examples/demo-template/product-app/pom.xml
+++ b/examples/demo-template/product-app/pom.xml
@@ -21,7 +21,7 @@
keycloak-examples-demo-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
4.0.0
diff --git a/examples/demo-template/service-account/pom.xml b/examples/demo-template/service-account/pom.xml
index 3f8526639b..d61ea68c8e 100755
--- a/examples/demo-template/service-account/pom.xml
+++ b/examples/demo-template/service-account/pom.xml
@@ -21,7 +21,7 @@
keycloak-examples-demo-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
4.0.0
diff --git a/examples/demo-template/third-party-cdi/pom.xml b/examples/demo-template/third-party-cdi/pom.xml
index 20a7e7eef1..3bc6a2f503 100755
--- a/examples/demo-template/third-party-cdi/pom.xml
+++ b/examples/demo-template/third-party-cdi/pom.xml
@@ -21,7 +21,7 @@
keycloak-examples-demo-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
4.0.0
diff --git a/examples/demo-template/third-party/pom.xml b/examples/demo-template/third-party/pom.xml
index 6aad96ccc7..8bd4694d60 100755
--- a/examples/demo-template/third-party/pom.xml
+++ b/examples/demo-template/third-party/pom.xml
@@ -21,7 +21,7 @@
keycloak-examples-demo-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
4.0.0
diff --git a/examples/fuse/camel/pom.xml b/examples/fuse/camel/pom.xml
index 0ca3c4e831..b8f0984e9a 100755
--- a/examples/fuse/camel/pom.xml
+++ b/examples/fuse/camel/pom.xml
@@ -21,7 +21,7 @@
keycloak-examples-fuse-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
4.0.0
diff --git a/examples/fuse/customer-app-fuse/pom.xml b/examples/fuse/customer-app-fuse/pom.xml
index 3c4bfd414d..752ff87052 100755
--- a/examples/fuse/customer-app-fuse/pom.xml
+++ b/examples/fuse/customer-app-fuse/pom.xml
@@ -21,7 +21,7 @@
keycloak-examples-fuse-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
4.0.0
diff --git a/examples/fuse/cxf-jaxrs/pom.xml b/examples/fuse/cxf-jaxrs/pom.xml
index 9d3faa06c9..51fb7340f6 100755
--- a/examples/fuse/cxf-jaxrs/pom.xml
+++ b/examples/fuse/cxf-jaxrs/pom.xml
@@ -21,7 +21,7 @@
keycloak-examples-fuse-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
4.0.0
diff --git a/examples/fuse/cxf-jaxws/pom.xml b/examples/fuse/cxf-jaxws/pom.xml
index f53164ca97..594fe509d1 100755
--- a/examples/fuse/cxf-jaxws/pom.xml
+++ b/examples/fuse/cxf-jaxws/pom.xml
@@ -21,7 +21,7 @@
keycloak-examples-fuse-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
4.0.0
diff --git a/examples/fuse/external-config/pom.xml b/examples/fuse/external-config/pom.xml
index 3f9f36df60..151ddab78e 100755
--- a/examples/fuse/external-config/pom.xml
+++ b/examples/fuse/external-config/pom.xml
@@ -21,7 +21,7 @@
keycloak-examples-fuse-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
Keycloak Examples - External Config
diff --git a/examples/fuse/features/pom.xml b/examples/fuse/features/pom.xml
index a5fe72e3ea..11b8d2fb45 100755
--- a/examples/fuse/features/pom.xml
+++ b/examples/fuse/features/pom.xml
@@ -21,7 +21,7 @@
keycloak-examples-fuse-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
4.0.0
diff --git a/examples/fuse/pom.xml b/examples/fuse/pom.xml
index 48e01255b1..1742a01190 100755
--- a/examples/fuse/pom.xml
+++ b/examples/fuse/pom.xml
@@ -20,7 +20,7 @@
keycloak-examples-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
Fuse Examples
diff --git a/examples/fuse/product-app-fuse/pom.xml b/examples/fuse/product-app-fuse/pom.xml
index e69578e4df..e95917f0b7 100755
--- a/examples/fuse/product-app-fuse/pom.xml
+++ b/examples/fuse/product-app-fuse/pom.xml
@@ -21,7 +21,7 @@
keycloak-examples-fuse-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
4.0.0
diff --git a/examples/js-console/pom.xml b/examples/js-console/pom.xml
index 37a64e2c79..7886ae2b39 100755
--- a/examples/js-console/pom.xml
+++ b/examples/js-console/pom.xml
@@ -21,7 +21,7 @@
keycloak-examples-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
4.0.0
diff --git a/examples/kerberos/README.md b/examples/kerberos/README.md
index 2c1d335ace..7aafdacd97 100644
--- a/examples/kerberos/README.md
+++ b/examples/kerberos/README.md
@@ -47,7 +47,7 @@ is in your `/etc/hosts` before other records for the 127.0.0.1 host to avoid iss
**5)** Configure Kerberos client (On linux it's in file `/etc/krb5.conf` ). You need to configure `KEYCLOAK.ORG` realm for host `localhost` and enable `forwardable` flag, which is needed
for credential delegation example, as application needs to forward Kerberos ticket and authenticate with it against LDAP server.
-See [this file](https://github.com/keycloak/keycloak/blob/master/testsuite/integration-arquillian/tests/base/src/test/resources/kerberos/test-krb5.conf) for inspiration.
+See [this file](../../testsuite/integration-arquillian/tests/base/src/test/resources/kerberos/test-krb5.conf) for inspiration.
On OS X the file to edit (or create) is `/Library/Preferences/edu.mit.Kerberos` with the same syntax as `krb5.conf`.
On Windows the file to edit (or create) is `c:\Windows\krb5.ini` with the same syntax as `krb5.conf`.
diff --git a/examples/kerberos/pom.xml b/examples/kerberos/pom.xml
index 6d2d5b1814..20b4327339 100755
--- a/examples/kerberos/pom.xml
+++ b/examples/kerberos/pom.xml
@@ -22,7 +22,7 @@
keycloak-examples-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
Keycloak Examples - Kerberos Credential Delegation
diff --git a/examples/ldap/pom.xml b/examples/ldap/pom.xml
index 62c4d1bb67..29f59c2151 100644
--- a/examples/ldap/pom.xml
+++ b/examples/ldap/pom.xml
@@ -22,7 +22,7 @@
keycloak-examples-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
4.0.0
diff --git a/examples/multi-tenant/pom.xml b/examples/multi-tenant/pom.xml
index 6c45be0c04..f96beb3576 100755
--- a/examples/multi-tenant/pom.xml
+++ b/examples/multi-tenant/pom.xml
@@ -21,7 +21,7 @@
keycloak-examples-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
Keycloak Examples - Multi Tenant
diff --git a/examples/pom.xml b/examples/pom.xml
index 0421e888cd..de9e92f7ac 100755
--- a/examples/pom.xml
+++ b/examples/pom.xml
@@ -20,7 +20,7 @@
keycloak-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
Keycloak Examples
diff --git a/examples/providers/authenticator/pom.xml b/examples/providers/authenticator/pom.xml
index a4042c7b42..d5305cadac 100755
--- a/examples/providers/authenticator/pom.xml
+++ b/examples/providers/authenticator/pom.xml
@@ -20,7 +20,7 @@
keycloak-examples-providers-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
Authenticator Example
diff --git a/examples/providers/authenticator/src/main/java/org/keycloak/examples/authenticator/SecretQuestionAuthenticator.java b/examples/providers/authenticator/src/main/java/org/keycloak/examples/authenticator/SecretQuestionAuthenticator.java
index fb71a7c9cf..73d821fbcd 100755
--- a/examples/providers/authenticator/src/main/java/org/keycloak/examples/authenticator/SecretQuestionAuthenticator.java
+++ b/examples/providers/authenticator/src/main/java/org/keycloak/examples/authenticator/SecretQuestionAuthenticator.java
@@ -47,7 +47,7 @@ public class SecretQuestionAuthenticator implements Authenticator {
Cookie cookie = context.getHttpRequest().getHttpHeaders().getCookies().get("SECRET_QUESTION_ANSWERED");
boolean result = cookie != null;
if (result) {
- System.out.println("Bypassing secret question because cookie as set");
+ System.out.println("Bypassing secret question because cookie is set");
}
return result;
}
diff --git a/examples/providers/domain-extension/pom.xml b/examples/providers/domain-extension/pom.xml
index 8203215750..fc5a61c397 100755
--- a/examples/providers/domain-extension/pom.xml
+++ b/examples/providers/domain-extension/pom.xml
@@ -20,7 +20,7 @@
keycloak-examples-providers-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
Domain Extension Example
diff --git a/examples/providers/event-listener-sysout/pom.xml b/examples/providers/event-listener-sysout/pom.xml
index 6448f1ef48..1d3602de1b 100755
--- a/examples/providers/event-listener-sysout/pom.xml
+++ b/examples/providers/event-listener-sysout/pom.xml
@@ -20,7 +20,7 @@
keycloak-examples-providers-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
Event Listener System.out Example
diff --git a/examples/providers/event-store-mem/pom.xml b/examples/providers/event-store-mem/pom.xml
index ab431451b9..ad7153fd12 100755
--- a/examples/providers/event-store-mem/pom.xml
+++ b/examples/providers/event-store-mem/pom.xml
@@ -20,7 +20,7 @@
keycloak-examples-providers-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
Event Store In-Mem Example
diff --git a/examples/providers/pom.xml b/examples/providers/pom.xml
index a55f520678..061d775776 100755
--- a/examples/providers/pom.xml
+++ b/examples/providers/pom.xml
@@ -20,7 +20,7 @@
keycloak-examples-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
Provider Examples
diff --git a/examples/providers/rest/pom.xml b/examples/providers/rest/pom.xml
index 9570a740f7..8791c3c898 100755
--- a/examples/providers/rest/pom.xml
+++ b/examples/providers/rest/pom.xml
@@ -20,7 +20,7 @@
keycloak-examples-providers-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
REST Example
diff --git a/examples/providers/rest/src/main/java/org/keycloak/examples/rest/HelloResourceProvider.java b/examples/providers/rest/src/main/java/org/keycloak/examples/rest/HelloResourceProvider.java
index aebd677221..ebd8d1c991 100644
--- a/examples/providers/rest/src/main/java/org/keycloak/examples/rest/HelloResourceProvider.java
+++ b/examples/providers/rest/src/main/java/org/keycloak/examples/rest/HelloResourceProvider.java
@@ -22,7 +22,6 @@ import org.keycloak.services.resource.RealmResourceProvider;
import javax.ws.rs.GET;
import javax.ws.rs.Produces;
-import javax.ws.rs.core.MediaType;
/**
* @author Stian Thorgersen
@@ -41,7 +40,7 @@ public class HelloResourceProvider implements RealmResourceProvider {
}
@GET
- @Produces(MediaType.TEXT_PLAIN)
+ @Produces("text/plain; charset=utf-8")
public String get() {
String name = session.getContext().getRealm().getDisplayName();
if (name == null) {
diff --git a/examples/providers/user-storage-jpa/pom.xml b/examples/providers/user-storage-jpa/pom.xml
index a1a5637ed5..ba21ac49f6 100755
--- a/examples/providers/user-storage-jpa/pom.xml
+++ b/examples/providers/user-storage-jpa/pom.xml
@@ -20,10 +20,10 @@
keycloak-examples-providers-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
- User Storage JPA Provider Exapmle
+ User Storage JPA Provider Example
4.0.0
diff --git a/examples/providers/user-storage-simple/pom.xml b/examples/providers/user-storage-simple/pom.xml
index 36a41cb173..48bdcba434 100755
--- a/examples/providers/user-storage-simple/pom.xml
+++ b/examples/providers/user-storage-simple/pom.xml
@@ -20,7 +20,7 @@
keycloak-examples-providers-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
UserStorageProvider Simple Example
diff --git a/examples/saml/pom.xml b/examples/saml/pom.xml
index e69c6df1c5..7ebf384e07 100755
--- a/examples/saml/pom.xml
+++ b/examples/saml/pom.xml
@@ -20,7 +20,7 @@
keycloak-examples-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
SAML Examples
diff --git a/examples/saml/post-with-encryption/pom.xml b/examples/saml/post-with-encryption/pom.xml
index d4bed04efa..0295e2f400 100755
--- a/examples/saml/post-with-encryption/pom.xml
+++ b/examples/saml/post-with-encryption/pom.xml
@@ -22,7 +22,7 @@
keycloak-examples-saml-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
saml-post-encryption
diff --git a/examples/saml/post-with-signature/pom.xml b/examples/saml/post-with-signature/pom.xml
index 02713e6f6e..23c508315b 100755
--- a/examples/saml/post-with-signature/pom.xml
+++ b/examples/saml/post-with-signature/pom.xml
@@ -22,7 +22,7 @@
keycloak-examples-saml-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
sales-post-sig
diff --git a/examples/saml/redirect-with-signature/pom.xml b/examples/saml/redirect-with-signature/pom.xml
index 9f42085afb..278c63a075 100755
--- a/examples/saml/redirect-with-signature/pom.xml
+++ b/examples/saml/redirect-with-signature/pom.xml
@@ -22,7 +22,7 @@
keycloak-examples-saml-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
saml-redirect-signatures
diff --git a/examples/saml/servlet-filter/pom.xml b/examples/saml/servlet-filter/pom.xml
index e586f3e586..83348d85bd 100755
--- a/examples/saml/servlet-filter/pom.xml
+++ b/examples/saml/servlet-filter/pom.xml
@@ -22,7 +22,7 @@
keycloak-examples-saml-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
saml-servlet-filter
diff --git a/examples/themes/pom.xml b/examples/themes/pom.xml
index 7d18fdf4ce..d49da0d959 100755
--- a/examples/themes/pom.xml
+++ b/examples/themes/pom.xml
@@ -20,7 +20,7 @@
keycloak-examples-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
Themes Examples
diff --git a/federation/kerberos/pom.xml b/federation/kerberos/pom.xml
index 6b026eb08c..d319be05fd 100755
--- a/federation/kerberos/pom.xml
+++ b/federation/kerberos/pom.xml
@@ -20,7 +20,7 @@
keycloak-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
../../pom.xml
4.0.0
diff --git a/federation/ldap/pom.xml b/federation/ldap/pom.xml
index 4618792225..061ddd871b 100755
--- a/federation/ldap/pom.xml
+++ b/federation/ldap/pom.xml
@@ -20,7 +20,7 @@
keycloak-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
../../pom.xml
4.0.0
diff --git a/federation/ldap/src/main/java/org/keycloak/storage/ldap/LDAPStorageProvider.java b/federation/ldap/src/main/java/org/keycloak/storage/ldap/LDAPStorageProvider.java
index d8653de170..e77df53622 100755
--- a/federation/ldap/src/main/java/org/keycloak/storage/ldap/LDAPStorageProvider.java
+++ b/federation/ldap/src/main/java/org/keycloak/storage/ldap/LDAPStorageProvider.java
@@ -17,6 +17,17 @@
package org.keycloak.storage.ldap;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import javax.naming.AuthenticationException;
+
import org.jboss.logging.Logger;
import org.keycloak.common.constants.KerberosConstants;
import org.keycloak.component.ComponentModel;
@@ -33,14 +44,15 @@ import org.keycloak.models.KeycloakSession;
import org.keycloak.models.LDAPConstants;
import org.keycloak.models.ModelDuplicateException;
import org.keycloak.models.ModelException;
-import org.keycloak.models.utils.ReadOnlyUserModelDelegate;
import org.keycloak.models.RealmModel;
import org.keycloak.models.RoleModel;
import org.keycloak.models.UserCredentialModel;
-import org.keycloak.models.UserModel;
import org.keycloak.models.UserManager;
+import org.keycloak.models.UserModel;
import org.keycloak.models.cache.UserCache;
import org.keycloak.models.credential.PasswordUserCredentialModel;
+import org.keycloak.models.utils.KeycloakModelUtils;
+import org.keycloak.models.utils.ReadOnlyUserModelDelegate;
import org.keycloak.storage.ReadOnlyException;
import org.keycloak.storage.StorageId;
import org.keycloak.storage.UserStorageProvider;
@@ -62,16 +74,6 @@ import org.keycloak.storage.user.UserLookupProvider;
import org.keycloak.storage.user.UserQueryProvider;
import org.keycloak.storage.user.UserRegistrationProvider;
-import javax.naming.AuthenticationException;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
/**
* @author Marek Posolda
* @author Bill Burke
@@ -216,7 +218,30 @@ public class LDAPStorageProvider implements UserStorageProvider,
@Override
public List searchForUserByUserAttribute(String attrName, String attrValue, RealmModel realm) {
- return Collections.EMPTY_LIST;
+ LDAPQuery ldapQuery = LDAPUtils.createQueryForUserSearch(this, realm);
+ LDAPQueryConditionsBuilder conditionsBuilder = new LDAPQueryConditionsBuilder();
+
+ Condition attrCondition = conditionsBuilder.equal(attrName, attrValue, EscapeStrategy.DEFAULT);
+ ldapQuery.addWhereCondition(attrCondition);
+
+ List ldapObjects = ldapQuery.getResultList();
+
+ if (ldapObjects == null || ldapObjects.isEmpty()) {
+ return Collections.emptyList();
+ }
+
+ List searchResults =new LinkedList();
+
+ for (LDAPObject ldapUser : ldapObjects) {
+ String ldapUsername = LDAPUtils.getUsername(ldapUser, this.ldapIdentityStore.getConfig());
+ if (session.userLocalStorage().getUserByUsername(ldapUsername, realm) == null) {
+ UserModel imported = importUserFromLDAP(session, realm, ldapUser);
+ searchResults.add(imported);
+ }
+ }
+
+ return searchResults;
+
}
public boolean synchronizeRegistrations() {
diff --git a/federation/pom.xml b/federation/pom.xml
index 9136832004..921d27958f 100755
--- a/federation/pom.xml
+++ b/federation/pom.xml
@@ -22,7 +22,7 @@
keycloak-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
../pom.xml
4.0.0
diff --git a/federation/sssd/pom.xml b/federation/sssd/pom.xml
index 1e40781d8a..e023800ab9 100644
--- a/federation/sssd/pom.xml
+++ b/federation/sssd/pom.xml
@@ -4,7 +4,7 @@
keycloak-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
../../pom.xml
4.0.0
diff --git a/integration/admin-client/pom.xml b/integration/admin-client/pom.xml
index ee006ef079..cfdc820f45 100755
--- a/integration/admin-client/pom.xml
+++ b/integration/admin-client/pom.xml
@@ -22,7 +22,7 @@
keycloak-integration-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
4.0.0
diff --git a/integration/client-cli/admin-cli/pom.xml b/integration/client-cli/admin-cli/pom.xml
index 10d629bed7..b1bfd81c3b 100755
--- a/integration/client-cli/admin-cli/pom.xml
+++ b/integration/client-cli/admin-cli/pom.xml
@@ -21,7 +21,7 @@
keycloak-client-cli-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
4.0.0
diff --git a/integration/client-cli/client-cli-dist/pom.xml b/integration/client-cli/client-cli-dist/pom.xml
index 38a1d5631f..5a2c10cb2f 100755
--- a/integration/client-cli/client-cli-dist/pom.xml
+++ b/integration/client-cli/client-cli-dist/pom.xml
@@ -21,7 +21,7 @@
keycloak-client-cli-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
keycloak-client-cli-dist
diff --git a/integration/client-cli/client-registration-cli/pom.xml b/integration/client-cli/client-registration-cli/pom.xml
index 6a76bf0397..48cb8ae369 100755
--- a/integration/client-cli/client-registration-cli/pom.xml
+++ b/integration/client-cli/client-registration-cli/pom.xml
@@ -21,7 +21,7 @@
keycloak-client-cli-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
4.0.0
diff --git a/integration/client-cli/pom.xml b/integration/client-cli/pom.xml
index 1ffbf10e33..e2b5922d93 100644
--- a/integration/client-cli/pom.xml
+++ b/integration/client-cli/pom.xml
@@ -20,7 +20,7 @@
keycloak-integration-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
Keycloak Client CLI
diff --git a/integration/client-registration/pom.xml b/integration/client-registration/pom.xml
index c8d2d222a8..015d1d30e9 100755
--- a/integration/client-registration/pom.xml
+++ b/integration/client-registration/pom.xml
@@ -21,7 +21,7 @@
keycloak-integration-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
4.0.0
diff --git a/integration/pom.xml b/integration/pom.xml
index 2c829800dd..3e005e03de 100755
--- a/integration/pom.xml
+++ b/integration/pom.xml
@@ -20,7 +20,7 @@
keycloak-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
../pom.xml
Keycloak Integration
diff --git a/misc/CrossDataCenter.md b/misc/CrossDataCenter.md
index 3313f3fe4b..261d099500 100644
--- a/misc/CrossDataCenter.md
+++ b/misc/CrossDataCenter.md
@@ -3,116 +3,265 @@ Test Cross-Data-Center scenario (test with external JDG server)
These are temporary notes. This docs should be removed once we have cross-DC support finished and properly documented.
-Note that these steps are already automated, see Cross-DC tests section in [HOW-TO-RUN.md](../testsuite/integration-arquillian/HOW-TO-RUN.md) document.
+These steps are already automated for embedded Undertow, see Cross-DC tests section in [HOW-TO-RUN.md](../testsuite/integration-arquillian/HOW-TO-RUN.md) document. For Wildfly they are not yet automated.
+Following instructions are related to Wildfly server.
What is working right now is:
-- Propagating of invalidation messages for "realms" and "users" caches
-- All the other things provided by ClusterProvider, which is:
--- ClusterStartupTime (used for offlineSessions and revokeRefreshToken) is shared for all clusters in all datacenters
--- Periodic userStorage synchronization is always executed just on one node at a time. It won't be never executed concurrently on more nodes (Assuming "nodes" refer to all servers in all clusters in all datacenters)
-
-What doesn't work right now:
-- UserSessionProvider and offline sessions
+- Propagating of invalidation messages for `realms`, `users` and `authorization` caches
+- sessions, offline sessions and login failures are propagated between datacenters
Basic setup
===========
-This is setup with 2 keycloak nodes, which are NOT in cluster. They just share the same database and they will be configured with "work" infinispan cache with remoteStore, which will point
-to external JDG server.
+This is the example setup simulating 2 datacenters `site1` and `site2` . Each datacenter consists of 1 infinispan server and 2 Keycloak servers.
+So 2 infinispan servers and 4 Keycloak servers are totally in the testing setup.
-JDG Server setup
-----------------
-- Download JDG 7.0 server and unzip to some folder
+* Site1 consists of infinispan server `jdg1` and 2 Keycloak servers `node11` and `node12` .
-- Add this into JDG_HOME/standalone/configuration/standalone.xml under cache-container named "local" :
+* Site2 consists of infinispan server `jdg2` and 2 Keycloak servers `node21` and `node22` .
+
+* Infinispan servers `jdg1` and `jdg2` forms cluster with each other. The communication between them is the only communication between the 2 datacenters.
+
+* Keycloak servers `node11` and `node12` forms cluster with each other, but they don't communicate with any server in `site2` . They communicate with infinispan server `jdg1` through the HotRod protocol (Remote cache).
+
+* Same applies for `node21` and `node22` . They have cluster with each other and communicate just with `jdg2` server through the HotRod protocol.
+
+TODO: Picture on blog
+
+* For example when some object (realm, client, role, user, ...) is updated on `node11`, the `node11` will send invalidation message. It does it by saving special cache entry to the remote cache `work` on `jdg1` .
+ The `jdg1` notifies client listeners in same DC (hence on `node12`) and propagate the message to it. But `jdg1` is in replicated cache with `jdg2` .
+ So the entry is saved on `jdg2` too and `jdg2` will notify client listeners on nodes `node21` and `node22`.
+ All the nodes know that they should invalidate the updated object from their caches. The caches with the actual data (`realms`, `users` and `authorization`) are infinispan local caches.
+
+TODO: Picture and better explanation?
+
+* For example when some userSession is created/updated/removed on `node11` it is saved in cluster on current DC, so the `node12` can see it. But it's saved also to remote cache on `jdg1` server.
+ The userSession is then automatically seen on `jdg2` server because there is replicated cache `sessions` between `jdg1` and `jdg2` . Server `jdg2` then notifies nodes `node21` and `node22` through
+ the client listeners (Feature of Remote Cache and HotRod protocol. See infinispan docs for details). The node, who is owner of the userSession (either `node21` or `node22`) will update userSession in the cluster
+ on `site2` . Hence any user requests coming to Keycloak nodes on `site2` will see latest updates.
+
+TODO: Picture and better explanation?
+
+Example setup assumes all 6 servers are bootstrapped on localhost, but each on different ports.
+
+
+Infinispan Server setup
+-----------------------
+
+1) Download Infinispan 8.2.6 server and unzip to some folder
+
+2) Add this into `JDG1_HOME/standalone/configuration/clustered.xml` under cache-container named `clustered` :
+
+```xml
+
+ ...
+
+
+
+
+
+
+
+
+
+
+
+```
+
+3) Copy the server into the second location referred later as `JDG2_HOME`
+
+4) Start server `jdg1`:
```
-
+cd JDG1_HOME/bin
+./standalone.sh -c clustered.xml -Djava.net.preferIPv4Stack=true \
+-Djboss.socket.binding.port-offset=1010 -Djboss.default.multicast.address=234.56.78.99 \
+-Djboss.node.name=jdg1
```
-- Start server:
+5) Start server `jdg2`:
+
```
-cd JDG_HOME/bin
-./standalone.sh -Djboss.socket.binding.port-offset=100
+cd JDG2_HOME/bin
+./standalone.sh -c clustered.xml -Djava.net.preferIPv4Stack=true \
+-Djboss.socket.binding.port-offset=2010 -Djboss.default.multicast.address=234.56.78.99 \
+-Djboss.node.name=jdg2
+```
+
+6) There should be message in the log that nodes are in cluster with each other:
+
+```
+Received new cluster view for channel clustered: [jdg1|1] (2) [jdg1, jdg2]
```
Keycloak servers setup
----------------------
-You need to setup 2 Keycloak nodes in this way.
+1) Download Keycloak 3.3.0.CR1 and unzip to some location referred later as `NODE11`
-For now, it's recommended to test Keycloak overlay on EAP7 because of infinispan bug, which is fixed in EAP 7.0 (infinispan 8.1.2), but not
-yet on Wildfly 10 (infinispan 8.1.0). See below for details.
+2) Configure shared database for KeycloakDS datasource. Recommended to use MySQL, MariaDB or PostgreSQL. See Keycloak docs for more details
+
+3) Edit `NODE11/standalone/configuration/standalone-ha.xml` :
-1) Configure shared database in KEYCLOAK_HOME/standalone/configuration/standalone.xml . For example MySQL
-
-2) Add `module` attribute to the infinispan keycloak container:
+3.1) Add attribute `site` to the JGroups UDP protocol:
+```xml
+
+
```
-
-```
-
-3) Configure `work` cache to use remoteStore. You should use this:
+3.2) Add output-socket-binding for `remote-cache` under `socket-binding-group` element:
+
+```xml
+
+ ...
+
+
+
+
+
```
-
+
+3.3) Add this `module` attribute under `cache-container` element of name `keycloak` :
+
+```xml
+
+```
+
+3.4) Add the `remote-store` under `work` cache:
+
+```xml
+
true
org.keycloak.cluster.infinispan.KeycloakHotRodMarshallerFactory
-
+
```
-4) Configure connection to the external JDG server. Because we used port offset 100 for JDG (see above), the HotRod endpoint is running on 11322 .
-So add the config like this to the bottom of standalone.xml under `socket-binding-group` element:
+3.5) Add the `store` like this under `sessions` cache:
-```
-
-
-
+```xml
+
+
+ sessions
+ work
+
+
```
-5) Optional: Configure logging in standalone.xml to see what invalidation events were send:
-````
+3.6) Same for `offlineSessions` and `loginFailures` caches:
+
+```xml
+
+
+ offlineSessions
+ work
+
+
+
+
+
+ loginFailures
+ work
+
+
+```
+
+3.7) The configuration of distributed cache `authenticationSessions` and other caches is left unchanged.
+
+3.8) Optionally enable DEBUG logging under `logging` subsystem:
+
+```xml
-
+
+
+
+
+
+
+
+```
+
+4) Copy the `NODE11` to 3 other directories referred later as `NODE12`, `NODE21` and `NODE22`.
+
+5) Start `NODE11` :
+
+```
+cd NODE11/bin
+./standalone.sh -c standalone-ha.xml -Djboss.node.name=node11 -Djboss.site.name=site1 \
+-Djboss.default.multicast.address=234.56.78.100 -Dremote.cache.port=12232 -Djava.net.preferIPv4Stack=true \
+-Djboss.socket.binding.port-offset=3000
+
+```
+
+6) Start `NODE12` :
+
+````
+cd NODE12/bin
+./standalone.sh -c standalone-ha.xml -Djboss.node.name=node12 -Djboss.site.name=site1 \
+-Djboss.default.multicast.address=234.56.78.100 -Dremote.cache.port=12232 -Djava.net.preferIPv4Stack=true \
+-Djboss.socket.binding.port-offset=4000
````
-
-6) Setup Keycloak node2 . Just copy Keycloak to another location on your laptop and repeat steps 1-5 above for second server too.
-
-7) Run server 1 with parameters like (assuming you have virtual hosts "node1" and "node2" defined in your `/etc/hosts` ):
-```
-./standalone.sh -Djboss.node.name=node1 -b node1 -bmanagement node1
-```
-and server2 with:
-```
-./standalone.sh -Djboss.node.name=node2 -b node2 -bmanagement node2
-```
-
-8) Note something like this in both `KEYCLOAK_HOME/standalone/log/server.log` on both nodes. Note that cluster Startup Time will be same time on both nodes:
-```
-2016-11-16 22:12:52,080 DEBUG [org.keycloak.cluster.infinispan.InfinispanClusterProviderFactory] (ServerService Thread Pool -- 62) My address: node1-1953169551
-2016-11-16 22:12:52,081 DEBUG [org.keycloak.cluster.infinispan.CrossDCAwareCacheFactory] (ServerService Thread Pool -- 62) RemoteStore is available. Cross-DC scenario will be used
-2016-11-16 22:12:52,119 DEBUG [org.keycloak.cluster.infinispan.InfinispanClusterProviderFactory] (ServerService Thread Pool -- 62) Loaded cluster startup time: Wed Nov 16 22:09:48 CET 2016
-2016-11-16 22:12:52,128 DEBUG [org.keycloak.cluster.infinispan.InfinispanNotificationsManager] (ServerService Thread Pool -- 62) Added listener for HotRod remoteStore cache: work
-```
-
-9) Login to node1. Then change any realm on node2. You will see in the node2 server.log that RealmUpdatedEvent was sent and on node1 that this event was received.
-
-This is done even if node1 and node2 are NOT in cluster as it's the external JDG used for communication between 2 keycloak servers and sending/receiving cache invalidation events. But note that userSession
-doesn't yet work (eg. if you login to node1, you won't see the userSession on node2).
-
-
-WARNING: Previous steps works on Keycloak server overlay deployed on EAP 7.0 . With deploy on Wildfly 10.0.0.Final, you will see exception
-at startup caused by the bug https://issues.jboss.org/browse/ISPN-6203 .
-
-There is a workaround to add this line into KEYCLOAK_HOME/modules/system/layers/base/org/wildfly/clustering/service/main/module.xml :
+The cluster nodes should be connected. This should be in the log of both NODE11 and NODE12:
```
-
+Received new cluster view for channel hibernate: [node11|1] (2) [node11, node12]
```
+
+7) Start `NODE21` :
+
+```
+cd NODE21/bin
+./standalone.sh -c standalone-ha.xml -Djboss.node.name=node21 -Djboss.site.name=site2 \
+-Djboss.default.multicast.address=234.56.78.101 -Dremote.cache.port=13232 -Djava.net.preferIPv4Stack=true \
+-Djboss.socket.binding.port-offset=5000
+```
+
+It shouldn't be connected to the cluster with `NODE11` and `NODE12`, but to separate one:
+
+```
+Received new cluster view for channel hibernate: [node21|0] (1) [node21]
+```
+
+8) Start `NODE22` :
+
+```
+cd NODE22/bin
+./standalone.sh -c standalone-ha.xml -Djboss.node.name=node22 -Djboss.site.name=site2 \
+-Djboss.default.multicast.address=234.56.78.101 -Dremote.cache.port=13232 -Djava.net.preferIPv4Stack=true \
+-Djboss.socket.binding.port-offset=6000
+```
+
+It should be in cluster with `NODE21` :
+
+```
+Received new cluster view for channel server: [node21|1] (2) [node21, node22]
+```
+
+9) Test:
+
+9.1) Go to `http://localhost:11080/auth/` and create initial admin user
+
+9.2) Go to `http://localhost:11080/auth/admin` and login as admin to admin console
+
+9.3) Open 2nd browser and go to any of nodes `http://localhost:12080/auth/admin` or `http://localhost:13080/auth/admin` or `http://localhost:14080/auth/admin` . After login, you should be able to see
+the same sessions in tab `Sessions` of particular user, client or realm on all 4 servers
+
+9.4) After doing any change (eg. update some user), the update should be immediatelly visible on any of 4 nodes as caches should be properly invalidated everywhere.
+
+
+9.5) Check server.logs if needed. After login or logout, the message like this should be on all the nodes `NODEXY/standalone/log/server.log` :
+
+```
+2017-08-25 17:35:17,737 DEBUG [org.keycloak.models.sessions.infinispan.remotestore.RemoteCacheSessionListener] (Client-Listener-sessions-30012a77422542f5) Received event from remote store.
+Event 'CLIENT_CACHE_ENTRY_REMOVED', key '193489e7-e2bc-4069-afe8-f1dfa73084ea', skip 'false'
+```
+
+This is just a starting point and the instructions are subject to change. We plan performance improvements especially around performance. If you
+have any feedback regarding cross-dc scenario, please let us know on keycloak-user mailing list referred from [Keycloak home page](http://www.keycloak.org/community.html).
\ No newline at end of file
diff --git a/misc/Testsuite.md b/misc/Testsuite.md
index 7f5e036d62..f7b4e8e383 100644
--- a/misc/Testsuite.md
+++ b/misc/Testsuite.md
@@ -114,10 +114,10 @@ But additionally you can enable Kerberos authentication in LDAP provider with th
* Kerberos realm: KEYCLOAK.ORG
* Server Principal: HTTP/localhost@KEYCLOAK.ORG
-* KeyTab: $KEYCLOAK_SOURCES/testsuite/integration/src/test/resources/kerberos/http.keytab (Replace $KEYCLOAK_SOURCES with correct absolute path of your sources)
+* KeyTab: $KEYCLOAK_SOURCES/testsuite/integration-arquillian/tests/base/src/test/resources/kerberos/http.keytab (Replace $KEYCLOAK_SOURCES with correct absolute path of your sources)
Once you do this, you should also ensure that your Kerberos client configuration file is properly configured with KEYCLOAK.ORG domain.
-See [../testsuite/integration/src/test/resources/kerberos/test-krb5.conf](../testsuite/integration/src/test/resources/kerberos/test-krb5.conf) for inspiration. The location of Kerberos configuration file
+See [../testsuite/integration-arquillian/src/test/resources/kerberos/test-krb5.conf](../testsuite/integration-arquillian/src/test/resources/kerberos/test-krb5.conf) for inspiration. The location of Kerberos configuration file
is platform dependent (In linux it's file `/etc/krb5.conf` )
Then you need to configure your browser to allow SPNEGO/Kerberos login from `localhost` .
diff --git a/misc/UpdatingDatabaseSchema.md b/misc/UpdatingDatabaseSchema.md
index 363d1099f5..cb4a0f8bf4 100644
--- a/misc/UpdatingDatabaseSchema.md
+++ b/misc/UpdatingDatabaseSchema.md
@@ -35,7 +35,7 @@ You can also have Liquibase and Hibernate create one for you. To do this follow
3. Make a copy of the database:
`cp keycloak.h2.db keycloak-old.h2.db`
3. Run KeycloakServer to make Hibernate update the schema:
- `mvn -f testsuite/integration/pom.xml exec:java -Pkeycloak-server -Dkeycloak.connectionsJpa.url='jdbc:h2:keycloak' -Dkeycloak.connectionsJpa.databaseSchema='development-update'`
+ `mvn -f testsuite/utils/pom.xml exec:java -Pkeycloak-server -Dkeycloak.connectionsJpa.url='jdbc:h2:keycloak' -Dkeycloak.connectionsJpa.databaseSchema='development-update'`
4. Wait until server is completely started, then stop it
5. View the difference:
`mvn -f connections/jpa-liquibase/pom.xml liquibase:diff -Durl=jdbc:h2:keycloak-old -DreferenceUrl=jdbc:h2:keycloak`
@@ -50,11 +50,11 @@ add entries to the `change-set` to update existing data if required.
When you have update the change-set Hibernate can validate the schema for you. First run:
rm -rf keycloak*h2.db
- mvn -f testsuite/integration exec:java -Pkeycloak-server -Dkeycloak.connectionsJpa.url='jdbc:h2:keycloak' -Dkeycloak.connectionsJpa.databaseSchema='update'
+ mvn -f testsuite/utils/pom.xml exec:java -Pkeycloak-server -Dkeycloak.connectionsJpa.url='jdbc:h2:keycloak' -Dkeycloak.connectionsJpa.databaseSchema='update'
Once the server has started fully, stop it and run:
- mvn -f testsuite/integration exec:java -Pkeycloak-server -Dkeycloak.connectionsJpa.url='jdbc:h2:keycloak' -Dkeycloak.connectionsJpa.databaseSchema='development-validate'
+ mvn -f testsuite/utils/pom.xml exec:java -Pkeycloak-server -Dkeycloak.connectionsJpa.url='jdbc:h2:keycloak' -Dkeycloak.connectionsJpa.databaseSchema='development-validate'
Testing database migration
diff --git a/misc/keycloak-test-helper/pom.xml b/misc/keycloak-test-helper/pom.xml
index 8747ec19d9..c17e73e895 100644
--- a/misc/keycloak-test-helper/pom.xml
+++ b/misc/keycloak-test-helper/pom.xml
@@ -6,7 +6,7 @@
keycloak-misc-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
org.keycloak
keycloak-test-helper
diff --git a/misc/pom.xml b/misc/pom.xml
index d65bbe7b96..f72eb62a3c 100644
--- a/misc/pom.xml
+++ b/misc/pom.xml
@@ -3,7 +3,7 @@
keycloak-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
Keycloak Misc
diff --git a/misc/spring-boot-starter/keycloak-spring-boot-starter/pom.xml b/misc/spring-boot-starter/keycloak-spring-boot-starter/pom.xml
index 2f55a9ac55..999a3b1d98 100644
--- a/misc/spring-boot-starter/keycloak-spring-boot-starter/pom.xml
+++ b/misc/spring-boot-starter/keycloak-spring-boot-starter/pom.xml
@@ -4,7 +4,7 @@
org.keycloak
keycloak-spring-boot-starter-parent
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
keycloak-spring-boot-starter
Keycloak :: Spring :: Boot :: Default :: Starter
diff --git a/misc/spring-boot-starter/pom.xml b/misc/spring-boot-starter/pom.xml
index 70f7daf336..1092895ad1 100644
--- a/misc/spring-boot-starter/pom.xml
+++ b/misc/spring-boot-starter/pom.xml
@@ -5,7 +5,7 @@
keycloak-misc-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
org.keycloak
keycloak-spring-boot-starter-parent
@@ -20,7 +20,7 @@
org.keycloak.bom
keycloak-adapter-bom
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
pom
import
diff --git a/model/infinispan/pom.xml b/model/infinispan/pom.xml
index 7d7dfe1584..f94566132a 100755
--- a/model/infinispan/pom.xml
+++ b/model/infinispan/pom.xml
@@ -21,7 +21,7 @@
keycloak-parent
org.keycloak
- 3.3.0.CR1-SNAPSHOT
+ 3.4.0.CR1-SNAPSHOT
../../pom.xml
4.0.0
diff --git a/model/infinispan/src/main/java/org/keycloak/connections/infinispan/DefaultInfinispanConnectionProviderFactory.java b/model/infinispan/src/main/java/org/keycloak/connections/infinispan/DefaultInfinispanConnectionProviderFactory.java
index 86f607456f..5135e90bea 100755
--- a/model/infinispan/src/main/java/org/keycloak/connections/infinispan/DefaultInfinispanConnectionProviderFactory.java
+++ b/model/infinispan/src/main/java/org/keycloak/connections/infinispan/DefaultInfinispanConnectionProviderFactory.java
@@ -40,12 +40,9 @@ import org.jboss.logging.Logger;
import org.jgroups.JChannel;
import org.keycloak.Config;
import org.keycloak.cluster.infinispan.KeycloakHotRodMarshallerFactory;
-import org.keycloak.common.util.HostUtils;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.KeycloakSessionFactory;
-import org.keycloak.models.sessions.infinispan.remotestore.KcRemoteStoreConfigurationBuilder;
-import org.keycloak.models.sessions.infinispan.util.InfinispanUtil;
-import org.keycloak.models.utils.KeycloakModelUtils;
+import org.keycloak.models.sessions.infinispan.remotestore.KeycloakRemoteStoreConfigurationBuilder;
import javax.naming.InitialContext;
@@ -249,7 +246,7 @@ public class DefaultInfinispanConnectionProviderFactory implements InfinispanCon
if (jdgEnabled) {
sessionConfigBuilder = new ConfigurationBuilder();
sessionConfigBuilder.read(sessionCacheConfigurationBase);
- configureRemoteCacheStore(sessionConfigBuilder, async, InfinispanConnectionProvider.SESSION_CACHE_NAME, KcRemoteStoreConfigurationBuilder.class);
+ configureRemoteCacheStore(sessionConfigBuilder, async, InfinispanConnectionProvider.SESSION_CACHE_NAME, KeycloakRemoteStoreConfigurationBuilder.class);
}
Configuration sessionCacheConfiguration = sessionConfigBuilder.build();
cacheManager.defineConfiguration(InfinispanConnectionProvider.SESSION_CACHE_NAME, sessionCacheConfiguration);
@@ -257,12 +254,19 @@ public class DefaultInfinispanConnectionProviderFactory implements InfinispanCon
if (jdgEnabled) {
sessionConfigBuilder = new ConfigurationBuilder();
sessionConfigBuilder.read(sessionCacheConfigurationBase);
- configureRemoteCacheStore(sessionConfigBuilder, async, InfinispanConnectionProvider.OFFLINE_SESSION_CACHE_NAME, KcRemoteStoreConfigurationBuilder.class);
+ configureRemoteCacheStore(sessionConfigBuilder, async, InfinispanConnectionProvider.OFFLINE_SESSION_CACHE_NAME, KeycloakRemoteStoreConfigurationBuilder.class);
}
sessionCacheConfiguration = sessionConfigBuilder.build();
cacheManager.defineConfiguration(InfinispanConnectionProvider.OFFLINE_SESSION_CACHE_NAME, sessionCacheConfiguration);
- cacheManager.defineConfiguration(InfinispanConnectionProvider.LOGIN_FAILURE_CACHE_NAME, sessionCacheConfigurationBase);
+ if (jdgEnabled) {
+ sessionConfigBuilder = new ConfigurationBuilder();
+ sessionConfigBuilder.read(sessionCacheConfigurationBase);
+ configureRemoteCacheStore(sessionConfigBuilder, async, InfinispanConnectionProvider.LOGIN_FAILURE_CACHE_NAME, KeycloakRemoteStoreConfigurationBuilder.class);
+ }
+ sessionCacheConfiguration = sessionConfigBuilder.build();
+ cacheManager.defineConfiguration(InfinispanConnectionProvider.LOGIN_FAILURE_CACHE_NAME, sessionCacheConfiguration);
+
cacheManager.defineConfiguration(InfinispanConnectionProvider.AUTHENTICATION_SESSIONS_CACHE_NAME, sessionCacheConfigurationBase);
// Retrieve caches to enforce rebalance
diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/UserCacheSession.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/UserCacheSession.java
index 0d971f70b9..390c25c158 100755
--- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/UserCacheSession.java
+++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/UserCacheSession.java
@@ -334,6 +334,8 @@ public class UserCacheSession implements UserCache {
}
protected UserModel cacheUser(RealmModel realm, UserModel delegate, Long revision) {
+ int notBefore = getDelegate().getNotBeforeOfUser(realm, delegate);
+
StorageId storageId = new StorageId(delegate.getId());
CachedUser cached = null;
if (!storageId.isLocal()) {
@@ -343,7 +345,7 @@ public class UserCacheSession implements UserCache {
if (policy != null && policy == UserStorageProviderModel.CachePolicy.NO_CACHE) {
return delegate;
}
- cached = new CachedUser(revision, realm, delegate);
+ cached = new CachedUser(revision, realm, delegate, notBefore);
if (policy == null || policy == UserStorageProviderModel.CachePolicy.DEFAULT) {
cache.addRevisioned(cached, startupRevision);
} else {
@@ -366,7 +368,7 @@ public class UserCacheSession implements UserCache {
}
}
} else {
- cached = new CachedUser(revision, realm, delegate);
+ cached = new CachedUser(revision, realm, delegate, notBefore);
cache.addRevisioned(cached, startupRevision);
}
UserAdapter adapter = new UserAdapter(cached, this, session, realm);
@@ -765,6 +767,32 @@ public class UserCacheSession implements UserCache {
return consentModel;
}
+ @Override
+ public void setNotBeforeForUser(RealmModel realm, UserModel user, int notBefore) {
+ if (!isRegisteredForInvalidation(realm, user.getId())) {
+ UserModel foundUser = getUserById(user.getId(), realm);
+ if (foundUser instanceof UserAdapter) {
+ ((UserAdapter) foundUser).invalidate();
+ }
+ }
+
+ getDelegate().setNotBeforeForUser(realm, user, notBefore);
+
+ }
+
+ @Override
+ public int getNotBeforeOfUser(RealmModel realm, UserModel user) {
+ if (isRegisteredForInvalidation(realm, user.getId())) {
+ return getDelegate().getNotBeforeOfUser(realm, user);
+ }
+
+ UserModel foundUser = getUserById(user.getId(), realm);
+ if (foundUser instanceof UserAdapter) {
+ return ((UserAdapter) foundUser).cached.getNotBefore();
+ } else {
+ return getDelegate().getNotBeforeOfUser(realm, user);
+ }
+ }
@Override
public UserModel addUser(RealmModel realm, String id, String username, boolean addDefaultRoles, boolean addDefaultRequiredActions) {
diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/ResourceAdapter.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/ResourceAdapter.java
index dc721b7112..5e9b7d3431 100644
--- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/ResourceAdapter.java
+++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/ResourceAdapter.java
@@ -46,7 +46,7 @@ public class ResourceAdapter implements Resource, CachedModel {
@Override
public Resource getDelegateForUpdate() {
if (updated == null) {
- cacheSession.registerResourceInvalidation(cached.getId(), cached.getName(), cached.getType(), cached.getUri(), cached.getScopesIds(), cached.getResourceServerId());
+ cacheSession.registerResourceInvalidation(cached.getId(), cached.getName(), cached.getType(), cached.getUri(), cached.getScopesIds(), cached.getResourceServerId(), cached.getOwner());
updated = cacheSession.getResourceStoreDelegate().findById(cached.getId(), cached.getResourceServerId());
if (updated == null) throw new IllegalStateException("Not found in database");
}
@@ -95,7 +95,7 @@ public class ResourceAdapter implements Resource, CachedModel {
@Override
public void setName(String name) {
getDelegateForUpdate();
- cacheSession.registerResourceInvalidation(cached.getId(), name, cached.getType(), cached.getUri(), cached.getScopesIds(), cached.getResourceServerId());
+ cacheSession.registerResourceInvalidation(cached.getId(), name, cached.getType(), cached.getUri(), cached.getScopesIds(), cached.getResourceServerId(), cached.getOwner());
updated.setName(name);
}
@@ -127,7 +127,7 @@ public class ResourceAdapter implements Resource, CachedModel {
@Override
public void setUri(String uri) {
getDelegateForUpdate();
- cacheSession.registerResourceInvalidation(cached.getId(), cached.getName(), cached.getType(), uri, cached.getScopesIds(), cached.getResourceServerId());
+ cacheSession.registerResourceInvalidation(cached.getId(), cached.getName(), cached.getType(), uri, cached.getScopesIds(), cached.getResourceServerId(), cached.getOwner());
updated.setUri(uri);
}
@@ -140,7 +140,7 @@ public class ResourceAdapter implements Resource, CachedModel {
@Override
public void setType(String type) {
getDelegateForUpdate();
- cacheSession.registerResourceInvalidation(cached.getId(), cached.getName(), type, cached.getUri(), cached.getScopesIds(), cached.getResourceServerId());
+ cacheSession.registerResourceInvalidation(cached.getId(), cached.getName(), type, cached.getUri(), cached.getScopesIds(), cached.getResourceServerId(), cached.getOwner());
updated.setType(type);
}
@@ -168,7 +168,7 @@ public class ResourceAdapter implements Resource, CachedModel {
@Override
public void updateScopes(Set scopes) {
getDelegateForUpdate();
- cacheSession.registerResourceInvalidation(cached.getId(), cached.getName(), cached.getType(), cached.getUri(), scopes.stream().map(scope1 -> scope1.getId()).collect(Collectors.toSet()), cached.getResourceServerId());
+ cacheSession.registerResourceInvalidation(cached.getId(), cached.getName(), cached.getType(), cached.getUri(), scopes.stream().map(scope1 -> scope1.getId()).collect(Collectors.toSet()), cached.getResourceServerId(), cached.getOwner());
updated.updateScopes(scopes);
}
diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/ResourceServerAdapter.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/ResourceServerAdapter.java
index bb3ec6cbc0..7d72c9890e 100644
--- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/ResourceServerAdapter.java
+++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/ResourceServerAdapter.java
@@ -38,7 +38,7 @@ public class ResourceServerAdapter implements ResourceServer, CachedModel invalidations) {
+ public void resourceServerUpdated(String id, Set invalidations) {
invalidations.add(id);
- invalidations.add(StoreFactoryCacheSession.getResourceServerByClientCacheKey(clientId));
+ invalidations.add(StoreFactoryCacheSession.getResourceServerByClientCacheKey(id));
}
- public void resourceServerRemoval(String id, String name, Set invalidations) {
- resourceServerUpdated(id, name, invalidations);
+ public void resourceServerRemoval(String id, Set invalidations) {
+ resourceServerUpdated(id, invalidations);
addInvalidations(InResourceServerPredicate.create().resourceServer(id), invalidations);
}
@@ -75,9 +75,10 @@ public class StoreFactoryCacheManager extends CacheManager {
addInvalidations(InScopePredicate.create().scope(id), invalidations);
}
- public void resourceUpdated(String id, String name, String type, String uri, Set scopes, String serverId, Set invalidations) {
+ public void resourceUpdated(String id, String name, String type, String uri, Set scopes, String serverId, String owner, Set invalidations) {
invalidations.add(id);
invalidations.add(StoreFactoryCacheSession.getResourceByNameCacheKey(name, serverId));
+ invalidations.add(StoreFactoryCacheSession.getResourceByOwnerCacheKey(owner, serverId));
if (type != null) {
invalidations.add(StoreFactoryCacheSession.getResourceByTypeCacheKey(type, serverId));
@@ -97,8 +98,7 @@ public class StoreFactoryCacheManager extends CacheManager {
}
public void resourceRemoval(String id, String name, String type, String uri, String owner, Set scopes, String serverId, Set invalidations) {
- resourceUpdated(id, name, type, uri, scopes, serverId, invalidations);
- invalidations.add(StoreFactoryCacheSession.getResourceByOwnerCacheKey(owner, serverId));
+ resourceUpdated(id, name, type, uri, scopes, serverId, owner, invalidations);
addInvalidations(InResourcePredicate.create().resource(id), invalidations);
}
diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/StoreFactoryCacheSession.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/StoreFactoryCacheSession.java
index a169235643..c70a43a5e7 100644
--- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/StoreFactoryCacheSession.java
+++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/StoreFactoryCacheSession.java
@@ -229,12 +229,12 @@ public class StoreFactoryCacheSession implements CachedStoreFactoryProvider {
return invalidations.contains(id);
}
- public void registerResourceServerInvalidation(String id, String clientId) {
- cache.resourceServerUpdated(id, clientId, invalidations);
+ public void registerResourceServerInvalidation(String id) {
+ cache.resourceServerUpdated(id, invalidations);
ResourceServerAdapter adapter = managedResourceServers.get(id);
if (adapter != null) adapter.invalidateFlag();
- invalidationEvents.add(ResourceServerUpdatedEvent.create(id, clientId));
+ invalidationEvents.add(ResourceServerUpdatedEvent.create(id));
}
public void registerScopeInvalidation(String id, String name, String serverId) {
@@ -245,12 +245,12 @@ public class StoreFactoryCacheSession implements CachedStoreFactoryProvider {
invalidationEvents.add(ScopeUpdatedEvent.create(id, name, serverId));
}
- public void registerResourceInvalidation(String id, String name, String type, String uri, Set scopes, String serverId) {
- cache.resourceUpdated(id, name, type, uri, scopes, serverId, invalidations);
+ public void registerResourceInvalidation(String id, String name, String type, String uri, Set scopes, String serverId, String owner) {
+ cache.resourceUpdated(id, name, type, uri, scopes, serverId, owner, invalidations);
ResourceAdapter adapter = managedResources.get(id);
if (adapter != null) adapter.invalidateFlag();
- invalidationEvents.add(ResourceUpdatedEvent.create(id, name, type, uri, scopes, serverId));
+ invalidationEvents.add(ResourceUpdatedEvent.create(id, name, type, uri, scopes, serverId, owner));
}
public void registerPolicyInvalidation(String id, String name, Set resources, Set scopes, String serverId) {
@@ -350,7 +350,7 @@ public class StoreFactoryCacheSession implements CachedStoreFactoryProvider {
@Override
public ResourceServer create(String clientId) {
ResourceServer server = getResourceServerStoreDelegate().create(clientId);
- registerResourceServerInvalidation(server.getId(), server.getClientId());
+ registerResourceServerInvalidation(server.getId());
return server;
}
@@ -361,8 +361,8 @@ public class StoreFactoryCacheSession implements CachedStoreFactoryProvider {
if (server == null) return;
cache.invalidateObject(id);
- invalidationEvents.add(ResourceServerRemovedEvent.create(id, server.getClientId()));
- cache.resourceServerRemoval(id, server.getClientId(), invalidations);
+ invalidationEvents.add(ResourceServerRemovedEvent.create(id, server.getId()));
+ cache.resourceServerRemoval(id, invalidations);
getResourceServerStoreDelegate().delete(id);
}
@@ -392,33 +392,6 @@ public class StoreFactoryCacheSession implements CachedStoreFactoryProvider {
managedResourceServers.put(id, adapter);
return adapter;
}
-
-
- @Override
- public ResourceServer findByClient(String clientId) {
- String cacheKey = getResourceServerByClientCacheKey(clientId);
- ResourceServerListQuery query = cache.get(cacheKey, ResourceServerListQuery.class);
- if (query != null) {
- logger.tracev("ResourceServer by clientId cache hit: {0}", clientId);
- }
- if (query == null) {
- Long loaded = cache.getCurrentRevision(cacheKey);
- ResourceServer model = getResourceServerStoreDelegate().findByClient(clientId);
- if (model == null) return null;
- if (invalidations.contains(model.getId())) return model;
- query = new ResourceServerListQuery(loaded, cacheKey, model.getId());
- cache.addRevisioned(query, startupRevision);
- return model;
- } else if (invalidations.contains(cacheKey)) {
- return getResourceServerStoreDelegate().findByClient(clientId);
- } else {
- String serverId = query.getResourceServers().iterator().next();
- if (invalidations.contains(serverId)) {
- return getResourceServerStoreDelegate().findByClient(clientId);
- }
- return findById(serverId);
- }
- }
}
protected class ScopeCache implements ScopeStore {
@@ -509,8 +482,9 @@ public class StoreFactoryCacheSession implements CachedStoreFactoryProvider {
@Override
public Resource create(String name, ResourceServer resourceServer, String owner) {
Resource resource = getResourceStoreDelegate().create(name, resourceServer, owner);
- registerResourceInvalidation(resource.getId(), resource.getName(), resource.getType(), resource.getUri(), resource.getScopes().stream().map(scope -> scope.getId()).collect(Collectors.toSet()), resourceServer.getId());
- return resource;
+ Resource cached = findById(resource.getId(), resourceServer.getId());
+ registerResourceInvalidation(resource.getId(), resource.getName(), resource.getType(), resource.getUri(), resource.getScopes().stream().map(scope -> scope.getId()).collect(Collectors.toSet()), resourceServer.getId(), resource.getOwner());
+ return cached;
}
@Override
diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/entities/CachedResourceServer.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/entities/CachedResourceServer.java
index 7dfb5fbf86..a904bd1a3d 100644
--- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/entities/CachedResourceServer.java
+++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/entities/CachedResourceServer.java
@@ -22,29 +22,20 @@ import org.keycloak.authorization.model.ResourceServer;
import org.keycloak.models.cache.infinispan.entities.AbstractRevisioned;
import org.keycloak.representations.idm.authorization.PolicyEnforcementMode;
-import java.io.Serializable;
-
/**
* @author Pedro Igor
*/
public class CachedResourceServer extends AbstractRevisioned {
- private String clientId;
private boolean allowRemoteResourceManagement;
private PolicyEnforcementMode policyEnforcementMode;
public CachedResourceServer(Long revision, ResourceServer resourceServer) {
super(revision, resourceServer.getId());
- this.clientId = resourceServer.getClientId();
this.allowRemoteResourceManagement = resourceServer.isAllowRemoteResourceManagement();
this.policyEnforcementMode = resourceServer.getPolicyEnforcementMode();
}
-
- public String getClientId() {
- return this.clientId;
- }
-
public boolean isAllowRemoteResourceManagement() {
return this.allowRemoteResourceManagement;
}
diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/events/ResourceServerRemovedEvent.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/events/ResourceServerRemovedEvent.java
index fbe5a7aa48..74b8d0c26d 100644
--- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/events/ResourceServerRemovedEvent.java
+++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/events/ResourceServerRemovedEvent.java
@@ -49,6 +49,6 @@ public class ResourceServerRemovedEvent extends InvalidationEvent implements Aut
@Override
public void addInvalidations(StoreFactoryCacheManager cache, Set invalidations) {
- cache.resourceServerRemoval(id, clientId, invalidations);
+ cache.resourceServerRemoval(id, invalidations);
}
}
diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/events/ResourceServerUpdatedEvent.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/events/ResourceServerUpdatedEvent.java
index 2034c9b4d6..1862345887 100644
--- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/events/ResourceServerUpdatedEvent.java
+++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/events/ResourceServerUpdatedEvent.java
@@ -28,12 +28,10 @@ import java.util.Set;
public class ResourceServerUpdatedEvent extends InvalidationEvent implements AuthorizationCacheInvalidationEvent {
private String id;
- private String clientId;
- public static ResourceServerUpdatedEvent create(String id, String clientId) {
+ public static ResourceServerUpdatedEvent create(String id) {
ResourceServerUpdatedEvent event = new ResourceServerUpdatedEvent();
event.id = id;
- event.clientId = clientId;
return event;
}
@@ -44,11 +42,11 @@ public class ResourceServerUpdatedEvent extends InvalidationEvent implements Aut
@Override
public String toString() {
- return String.format("ResourceServerRemovedEvent [ id=%s, clientId=%s ]", id, clientId);
+ return String.format("ResourceServerRemovedEvent [ id=%s, clientId=%s ]", id, id);
}
@Override
public void addInvalidations(StoreFactoryCacheManager cache, Set invalidations) {
- cache.resourceServerUpdated(id, clientId, invalidations);
+ cache.resourceServerUpdated(id, invalidations);
}
}
diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/events/ResourceUpdatedEvent.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/events/ResourceUpdatedEvent.java
index cc30f230d9..3f85a6d5b0 100644
--- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/events/ResourceUpdatedEvent.java
+++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/events/ResourceUpdatedEvent.java
@@ -33,8 +33,9 @@ public class ResourceUpdatedEvent extends InvalidationEvent implements Authoriza
private String type;
private String uri;
private Set scopes;
+ private String owner;
- public static ResourceUpdatedEvent create(String id, String name, String type, String uri, Set scopes, String serverId) {
+ public static ResourceUpdatedEvent create(String id, String name, String type, String uri, Set scopes, String serverId, String owner) {
ResourceUpdatedEvent event = new ResourceUpdatedEvent();
event.id = id;
event.name = name;
@@ -42,6 +43,7 @@ public class ResourceUpdatedEvent extends InvalidationEvent implements Authoriza
event.uri = uri;
event.scopes = scopes;
event.serverId = serverId;
+ event.owner = owner;
return event;
}
@@ -57,6 +59,6 @@ public class ResourceUpdatedEvent extends InvalidationEvent implements Authoriza
@Override
public void addInvalidations(StoreFactoryCacheManager cache, Set invalidations) {
- cache.resourceUpdated(id, name, type, uri, scopes, serverId, invalidations);
+ cache.resourceUpdated(id, name, type, uri, scopes, serverId, owner, invalidations);
}
}
diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/entities/CachedUser.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/entities/CachedUser.java
index 1bf6e426a0..68dfc372cb 100755
--- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/entities/CachedUser.java
+++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/entities/CachedUser.java
@@ -45,10 +45,11 @@ public class CachedUser extends AbstractExtendableRevisioned implements InRealm
private Set requiredActions = new HashSet<>();
private Set roleMappings = new HashSet<>();
private Set groups = new HashSet<>();
+ private int notBefore;
- public CachedUser(Long revision, RealmModel realm, UserModel user) {
+ public CachedUser(Long revision, RealmModel realm, UserModel user, int notBefore) {
super(revision, user.getId());
this.realm = realm.getId();
this.username = user.getUsername();
@@ -71,6 +72,7 @@ public class CachedUser extends AbstractExtendableRevisioned implements InRealm
groups.add(group.getId());
}
}
+ this.notBefore = notBefore;
}
public String getRealm() {
@@ -129,4 +131,7 @@ public class CachedUser extends AbstractExtendableRevisioned implements InRealm
return groups;
}
+ public int getNotBefore() {
+ return notBefore;
+ }
}
diff --git a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/InfinispanUserSessionProvider.java b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/InfinispanUserSessionProvider.java
index c1a8ed688b..48d1965fca 100755
--- a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/InfinispanUserSessionProvider.java
+++ b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/InfinispanUserSessionProvider.java
@@ -42,7 +42,6 @@ import org.keycloak.models.sessions.infinispan.entities.AuthenticatedClientSessi
import org.keycloak.models.sessions.infinispan.entities.LoginFailureEntity;
import org.keycloak.models.sessions.infinispan.entities.LoginFailureKey;
import org.keycloak.models.sessions.infinispan.entities.UserSessionEntity;
-import org.keycloak.models.sessions.infinispan.events.ClientRemovedSessionEvent;
import org.keycloak.models.sessions.infinispan.events.RealmRemovedSessionEvent;
import org.keycloak.models.sessions.infinispan.events.RemoveAllUserLoginFailuresEvent;
import org.keycloak.models.sessions.infinispan.events.RemoveUserSessionsEvent;
@@ -52,6 +51,7 @@ import org.keycloak.models.sessions.infinispan.stream.Mappers;
import org.keycloak.models.sessions.infinispan.stream.SessionPredicate;
import org.keycloak.models.sessions.infinispan.stream.UserLoginFailurePredicate;
import org.keycloak.models.sessions.infinispan.stream.UserSessionPredicate;
+import org.keycloak.models.sessions.infinispan.util.FuturesHelper;
import org.keycloak.models.sessions.infinispan.util.InfinispanUtil;
import java.util.Iterator;
@@ -59,6 +59,7 @@ import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.Future;
import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.stream.Stream;
@@ -74,11 +75,11 @@ public class InfinispanUserSessionProvider implements UserSessionProvider {
protected final Cache> sessionCache;
protected final Cache> offlineSessionCache;
- protected final Cache loginFailureCache;
+ protected final Cache> loginFailureCache;
- protected final InfinispanChangelogBasedTransaction sessionTx;
- protected final InfinispanChangelogBasedTransaction offlineSessionTx;
- protected final InfinispanKeycloakTransaction tx;
+ protected final InfinispanChangelogBasedTransaction sessionTx;
+ protected final InfinispanChangelogBasedTransaction offlineSessionTx;
+ protected final InfinispanChangelogBasedTransaction loginFailuresTx;
protected final SessionEventsSenderTransaction clusterEventsSenderTx;
@@ -91,7 +92,7 @@ public class InfinispanUserSessionProvider implements UserSessionProvider {
LastSessionRefreshStore offlineLastSessionRefreshStore,
Cache> sessionCache,
Cache> offlineSessionCache,
- Cache loginFailureCache) {
+ Cache> loginFailureCache) {
this.session = session;
this.sessionCache = sessionCache;
@@ -101,24 +102,24 @@ public class InfinispanUserSessionProvider implements UserSessionProvider {
this.sessionTx = new InfinispanChangelogBasedTransaction<>(session, InfinispanConnectionProvider.SESSION_CACHE_NAME, sessionCache, remoteCacheInvoker);
this.offlineSessionTx = new InfinispanChangelogBasedTransaction<>(session, InfinispanConnectionProvider.OFFLINE_SESSION_CACHE_NAME, offlineSessionCache, remoteCacheInvoker);
- this.tx = new InfinispanKeycloakTransaction();
+ this.loginFailuresTx = new InfinispanChangelogBasedTransaction<>(session, InfinispanConnectionProvider.LOGIN_FAILURE_CACHE_NAME, loginFailureCache, remoteCacheInvoker);
this.clusterEventsSenderTx = new SessionEventsSenderTransaction(session);
this.lastSessionRefreshStore = lastSessionRefreshStore;
this.offlineLastSessionRefreshStore = offlineLastSessionRefreshStore;
- session.getTransactionManager().enlistAfterCompletion(tx);
session.getTransactionManager().enlistAfterCompletion(clusterEventsSenderTx);
session.getTransactionManager().enlistAfterCompletion(sessionTx);
session.getTransactionManager().enlistAfterCompletion(offlineSessionTx);
+ session.getTransactionManager().enlistAfterCompletion(loginFailuresTx);
}
protected Cache> getCache(boolean offline) {
return offline ? offlineSessionCache : sessionCache;
}
- protected InfinispanChangelogBasedTransaction getTransaction(boolean offline) {
+ protected InfinispanChangelogBasedTransaction getTransaction(boolean offline) {
return offline ? offlineSessionTx : sessionTx;
}
@@ -134,7 +135,7 @@ public class InfinispanUserSessionProvider implements UserSessionProvider {
public AuthenticatedClientSessionModel createClientSession(RealmModel realm, ClientModel client, UserSessionModel userSession) {
AuthenticatedClientSessionEntity entity = new AuthenticatedClientSessionEntity();
- InfinispanChangelogBasedTransaction updateTx = getTransaction(false);
+ InfinispanChangelogBasedTransaction updateTx = getTransaction(false);
AuthenticatedClientSessionAdapter adapter = new AuthenticatedClientSessionAdapter(entity, client, (UserSessionAdapter) userSession, this, updateTx);
adapter.setUserSession(userSession);
return adapter;
@@ -200,7 +201,7 @@ public class InfinispanUserSessionProvider implements UserSessionProvider {
}
private UserSessionEntity getUserSessionEntity(String id, boolean offline) {
- InfinispanChangelogBasedTransaction tx = getTransaction(offline);
+ InfinispanChangelogBasedTransaction tx = getTransaction(offline);
SessionEntityWrapper entityWrapper = tx.get(id);
return entityWrapper==null ? null : entityWrapper.getEntity();
}
@@ -309,7 +310,7 @@ public class InfinispanUserSessionProvider implements UserSessionProvider {
UserSessionModel remoteSessionAdapter = wrap(realm, remoteSessionEntity, offline);
if (predicate.test(remoteSessionAdapter)) {
- InfinispanChangelogBasedTransaction tx = getTransaction(offline);
+ InfinispanChangelogBasedTransaction tx = getTransaction(offline);
// Remote entity contains our predicate. Update local cache with the remote entity
SessionEntityWrapper sessionWrapper = remoteSessionEntity.mergeRemoteEntityWithLocalEntity(tx.get(id));
@@ -396,11 +397,11 @@ public class InfinispanUserSessionProvider implements UserSessionProvider {
int expired = Time.currentTime() - realm.getSsoSessionMaxLifespan();
int expiredRefresh = Time.currentTime() - realm.getSsoSessionIdleTimeout();
+ FuturesHelper futures = new FuturesHelper();
+
// Each cluster node cleanups just local sessions, which are those owned by himself (+ few more taking l1 cache into account)
Cache> localCache = CacheDecorators.localCache(sessionCache);
- int[] counter = { 0 };
-
Cache> localCacheStoreIgnore = CacheDecorators.skipCacheLoaders(localCache);
// Ignore remoteStore for stream iteration. But we will invoke remoteStore for userSession removal propagate
@@ -413,14 +414,15 @@ public class InfinispanUserSessionProvider implements UserSessionProvider {
@Override
public void accept(String sessionId) {
- counter[0]++;
- tx.remove(localCache, sessionId);
+ Future future = localCache.removeAsync(sessionId);
+ futures.addTask(future);
}
});
+ futures.waitForAllToFinish();
- log.debugf("Removed %d expired user sessions for realm '%s'", counter[0], realm.getName());
+ log.debugf("Removed %d expired user sessions for realm '%s'", futures.size(), realm.getName());
}
private void removeExpiredOfflineUserSessions(RealmModel realm) {
@@ -432,7 +434,7 @@ public class InfinispanUserSessionProvider implements UserSessionProvider {
UserSessionPredicate predicate = UserSessionPredicate.create(realm.getId()).expired(null, expiredOffline);
- final int[] counter = { 0 };
+ FuturesHelper futures = new FuturesHelper();
Cache> localCacheStoreIgnore = CacheDecorators.skipCacheLoaders(localCache);
@@ -446,8 +448,8 @@ public class InfinispanUserSessionProvider implements UserSessionProvider {
@Override
public void accept(UserSessionEntity userSessionEntity) {
- counter[0]++;
- tx.remove(localCache, userSessionEntity.getId());
+ Future future = localCache.removeAsync(userSessionEntity.getId());
+ futures.addTask(future);
// TODO:mposolda can be likely optimized to delete all expired at one step
persister.removeUserSession( userSessionEntity.getId(), true);
@@ -459,7 +461,9 @@ public class InfinispanUserSessionProvider implements UserSessionProvider {
}
});
- log.debugf("Removed %d expired offline user sessions for realm '%s'", counter, realm.getName());
+ futures.waitForAllToFinish();
+
+ log.debugf("Removed %d expired offline user sessions for realm '%s'", futures.size(), realm.getName());
}
@Override
@@ -475,6 +479,8 @@ public class InfinispanUserSessionProvider implements UserSessionProvider {
}
private void removeLocalUserSessions(String realmId, boolean offline) {
+ FuturesHelper futures = new FuturesHelper();
+
Cache> cache = getCache(offline);
Cache> localCache = CacheDecorators.localCache(cache);
@@ -489,17 +495,29 @@ public class InfinispanUserSessionProvider implements UserSessionProvider {
@Override
public void accept(String sessionId) {
- // Remove session from remoteCache too
- localCache.remove(sessionId);
+ // Remove session from remoteCache too. Use removeAsync for better perf
+ Future future = localCache.removeAsync(sessionId);
+ futures.addTask(future);
}
});
+
+ futures.waitForAllToFinish();
+
+ log.debugf("Removed %d sessions in realm %s. Offline: %b", (Object) futures.size(), realmId, offline);
}
@Override
public UserLoginFailureModel getUserLoginFailure(RealmModel realm, String userId) {
LoginFailureKey key = new LoginFailureKey(realm.getId(), userId);
- return wrap(key, loginFailureCache.get(key));
+ LoginFailureEntity entity = getLoginFailureEntity(key);
+ return wrap(key, entity);
+ }
+
+ private LoginFailureEntity getLoginFailureEntity(LoginFailureKey key) {
+ InfinispanChangelogBasedTransaction tx = getLoginFailuresTx();
+ SessionEntityWrapper entityWrapper = tx.get(key);
+ return entityWrapper==null ? null : entityWrapper.getEntity();
}
@Override
@@ -508,13 +526,53 @@ public class InfinispanUserSessionProvider implements UserSessionProvider {
LoginFailureEntity entity = new LoginFailureEntity();
entity.setRealm(realm.getId());
entity.setUserId(userId);
- tx.put(loginFailureCache, key, entity);
+
+ SessionUpdateTask createLoginFailureTask = new SessionUpdateTask() {
+
+ @Override
+ public void runUpdate(LoginFailureEntity session) {
+
+ }
+
+ @Override
+ public CacheOperation getOperation(LoginFailureEntity session) {
+ return CacheOperation.ADD_IF_ABSENT;
+ }
+
+ @Override
+ public CrossDCMessageStatus getCrossDCMessageStatus(SessionEntityWrapper sessionWrapper) {
+ return CrossDCMessageStatus.SYNC;
+ }
+
+ };
+
+ loginFailuresTx.addTask(key, createLoginFailureTask, entity);
+
return wrap(key, entity);
}
@Override
public void removeUserLoginFailure(RealmModel realm, String userId) {
- tx.remove(loginFailureCache, new LoginFailureKey(realm.getId(), userId));
+ SessionUpdateTask removeTask = new SessionUpdateTask() {
+
+ @Override
+ public void runUpdate(LoginFailureEntity entity) {
+
+ }
+
+ @Override
+ public CacheOperation getOperation(LoginFailureEntity entity) {
+ return CacheOperation.REMOVE;
+ }
+
+ @Override
+ public CrossDCMessageStatus getCrossDCMessageStatus(SessionEntityWrapper sessionWrapper) {
+ return CrossDCMessageStatus.SYNC;
+ }
+
+ };
+
+ loginFailuresTx.addTask(new LoginFailureKey(realm.getId(), userId), removeTask);
}
@Override
@@ -529,9 +587,11 @@ public class InfinispanUserSessionProvider implements UserSessionProvider {
}
private void removeAllLocalUserLoginFailuresEvent(String realmId) {
- Cache localCache = CacheDecorators.localCache(loginFailureCache);
+ FuturesHelper futures = new FuturesHelper();
- Cache localCacheStoreIgnore = CacheDecorators.skipCacheLoaders(localCache);
+ Cache> localCache = CacheDecorators.localCache(loginFailureCache);
+
+ Cache> localCacheStoreIgnore = CacheDecorators.skipCacheLoaders(localCache);
localCacheStoreIgnore
.entrySet()
@@ -539,9 +599,14 @@ public class InfinispanUserSessionProvider implements UserSessionProvider {
.filter(UserLoginFailurePredicate.create(realmId))
.map(Mappers.loginFailureId())
.forEach(loginFailureKey -> {
- // Remove loginFailure from remoteCache too
- localCache.remove(loginFailureKey);
+ // Remove loginFailure from remoteCache too. Use removeAsync for better perf
+ Future future = localCache.removeAsync(loginFailureKey);
+ futures.addTask(future);
});
+
+ futures.waitForAllToFinish();
+
+ log.debugf("Removed %d login failures in realm %s", futures.size(), realmId);
}
@Override
@@ -574,8 +639,7 @@ public class InfinispanUserSessionProvider implements UserSessionProvider {
removeUserSessions(realm, user, true);
removeUserSessions(realm, user, false);
- loginFailureCache.remove(new LoginFailureKey(realm.getId(), user.getUsername()));
- loginFailureCache.remove(new LoginFailureKey(realm.getId(), user.getEmail()));
+ removeUserLoginFailure(realm, user.getId());
}
@Override
@@ -583,7 +647,7 @@ public class InfinispanUserSessionProvider implements UserSessionProvider {
}
protected void removeUserSession(UserSessionEntity sessionEntity, boolean offline) {
- InfinispanChangelogBasedTransaction tx = getTransaction(offline);
+ InfinispanChangelogBasedTransaction tx = getTransaction(offline);
SessionUpdateTask removeTask = new SessionUpdateTask() {
@@ -607,17 +671,17 @@ public class InfinispanUserSessionProvider implements UserSessionProvider {
tx.addTask(sessionEntity.getId(), removeTask);
}
- InfinispanKeycloakTransaction getTx() {
- return tx;
+ InfinispanChangelogBasedTransaction getLoginFailuresTx() {
+ return loginFailuresTx;
}
UserSessionAdapter wrap(RealmModel realm, UserSessionEntity entity, boolean offline) {
- InfinispanChangelogBasedTransaction tx = getTransaction(offline);
+ InfinispanChangelogBasedTransaction tx = getTransaction(offline);
return entity != null ? new UserSessionAdapter(session, this, tx, realm, entity, offline) : null;
}
UserLoginFailureModel wrap(LoginFailureKey key, LoginFailureEntity entity) {
- return entity != null ? new UserLoginFailureAdapter(this, loginFailureCache, key, entity) : null;
+ return entity != null ? new UserLoginFailureAdapter(this, key, entity) : null;
}
UserSessionEntity getUserSessionEntity(UserSessionModel userSession, boolean offline) {
@@ -720,7 +784,7 @@ public class InfinispanUserSessionProvider implements UserSessionProvider {
entity.setLastSessionRefresh(userSession.getLastSessionRefresh());
- InfinispanChangelogBasedTransaction tx = getTransaction(offline);
+ InfinispanChangelogBasedTransaction tx = getTransaction(offline);
SessionUpdateTask importTask = new SessionUpdateTask() {
@@ -756,7 +820,7 @@ public class InfinispanUserSessionProvider implements UserSessionProvider {
private AuthenticatedClientSessionAdapter importClientSession(UserSessionAdapter importedUserSession, AuthenticatedClientSessionModel clientSession,
- InfinispanChangelogBasedTransaction updateTx) {
+ InfinispanChangelogBasedTransaction updateTx) {
AuthenticatedClientSessionEntity entity = new AuthenticatedClientSessionEntity();
entity.setAction(clientSession.getAction());
diff --git a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/InfinispanUserSessionProviderFactory.java b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/InfinispanUserSessionProviderFactory.java
index 110a8124f8..df30b4e927 100755
--- a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/InfinispanUserSessionProviderFactory.java
+++ b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/InfinispanUserSessionProviderFactory.java
@@ -85,7 +85,7 @@ public class InfinispanUserSessionProviderFactory implements UserSessionProvider
InfinispanConnectionProvider connections = session.getProvider(InfinispanConnectionProvider.class);
Cache> cache = connections.getCache(InfinispanConnectionProvider.SESSION_CACHE_NAME);
Cache> offlineSessionsCache = connections.getCache(InfinispanConnectionProvider.OFFLINE_SESSION_CACHE_NAME);
- Cache loginFailures = connections.getCache(InfinispanConnectionProvider.LOGIN_FAILURE_CACHE_NAME);
+ Cache> loginFailures = connections.getCache(InfinispanConnectionProvider.LOGIN_FAILURE_CACHE_NAME);
return new InfinispanUserSessionProvider(session, remoteCacheInvoker, lastSessionRefreshStore, offlineLastSessionRefreshStore, cache, offlineSessionsCache, loginFailures);
}
@@ -224,6 +224,11 @@ public class InfinispanUserSessionProviderFactory implements UserSessionProvider
if (offlineSessionsRemoteCache) {
offlineLastSessionRefreshStore = new LastSessionRefreshStoreFactory().createAndInit(session, offlineSessionsCache, true);
}
+
+ Cache loginFailuresCache = ispn.getCache(InfinispanConnectionProvider.LOGIN_FAILURE_CACHE_NAME);
+ boolean loginFailuresRemoteCache = checkRemoteCache(session, loginFailuresCache, (RealmModel realm) -> {
+ return realm.getMaxDeltaTimeSeconds() * 1000;
+ });
}
private boolean checkRemoteCache(KeycloakSession session, Cache ispnCache, RemoteCacheInvoker.MaxIdleTimeLoader maxIdleLoader) {
@@ -248,12 +253,12 @@ public class InfinispanUserSessionProviderFactory implements UserSessionProvider
private void loadSessionsFromRemoteCaches(KeycloakSession session) {
for (String cacheName : remoteCacheInvoker.getRemoteCacheNames()) {
- loadSessionsFromRemoteCache(session.getKeycloakSessionFactory(), cacheName, getMaxErrors());
+ loadSessionsFromRemoteCache(session.getKeycloakSessionFactory(), cacheName, getSessionsPerSegment(), getMaxErrors());
}
}
- private void loadSessionsFromRemoteCache(final KeycloakSessionFactory sessionFactory, String cacheName, final int maxErrors) {
+ private void loadSessionsFromRemoteCache(final KeycloakSessionFactory sessionFactory, String cacheName, final int sessionsPerSegment, final int maxErrors) {
log.debugf("Check pre-loading userSessions from remote cache '%s'", cacheName);
KeycloakModelUtils.runJobInTransaction(sessionFactory, new KeycloakSessionTask() {
@@ -263,8 +268,7 @@ public class InfinispanUserSessionProviderFactory implements UserSessionProvider
InfinispanConnectionProvider connections = session.getProvider(InfinispanConnectionProvider.class);
Cache workCache = connections.getCache(InfinispanConnectionProvider.WORK_CACHE_NAME);
- // Use limit for sessionsPerSegment as RemoteCache bulk load doesn't have support for pagination :/
- BaseCacheInitializer initializer = new SingleWorkerCacheInitializer(session, workCache, new RemoteCacheSessionsLoader(cacheName), "remoteCacheLoad::" + cacheName);
+ InfinispanCacheInitializer initializer = new InfinispanCacheInitializer(sessionFactory, workCache, new RemoteCacheSessionsLoader(cacheName), "remoteCacheLoad::" + cacheName, sessionsPerSegment, maxErrors);
initializer.initCache();
initializer.loadSessions();
diff --git a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/UserLoginFailureAdapter.java b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/UserLoginFailureAdapter.java
index a41777dc43..0971c26212 100755
--- a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/UserLoginFailureAdapter.java
+++ b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/UserLoginFailureAdapter.java
@@ -17,8 +17,8 @@
package org.keycloak.models.sessions.infinispan;
-import org.infinispan.Cache;
import org.keycloak.models.UserLoginFailureModel;
+import org.keycloak.models.sessions.infinispan.changes.LoginFailuresUpdateTask;
import org.keycloak.models.sessions.infinispan.entities.LoginFailureEntity;
import org.keycloak.models.sessions.infinispan.entities.LoginFailureKey;
@@ -28,13 +28,11 @@ import org.keycloak.models.sessions.infinispan.entities.LoginFailureKey;
public class UserLoginFailureAdapter implements UserLoginFailureModel {
private InfinispanUserSessionProvider provider;
- private Cache cache;
private LoginFailureKey key;
private LoginFailureEntity entity;
- public UserLoginFailureAdapter(InfinispanUserSessionProvider provider, Cache cache, LoginFailureKey key, LoginFailureEntity entity) {
+ public UserLoginFailureAdapter(InfinispanUserSessionProvider provider, LoginFailureKey key, LoginFailureEntity entity) {
this.provider = provider;
- this.cache = cache;
this.key = key;
this.entity = entity;
}
@@ -51,8 +49,16 @@ public class UserLoginFailureAdapter implements UserLoginFailureModel {
@Override
public void setFailedLoginNotBefore(int notBefore) {
- entity.setFailedLoginNotBefore(notBefore);
- update();
+ LoginFailuresUpdateTask task = new LoginFailuresUpdateTask() {
+
+ @Override
+ public void runUpdate(LoginFailureEntity entity) {
+ entity.setFailedLoginNotBefore(notBefore);
+ }
+
+ };
+
+ update(task);
}
@Override
@@ -62,14 +68,30 @@ public class UserLoginFailureAdapter implements UserLoginFailureModel {
@Override
public void incrementFailures() {
- entity.setNumFailures(getNumFailures() + 1);
- update();
+ LoginFailuresUpdateTask task = new LoginFailuresUpdateTask() {
+
+ @Override
+ public void runUpdate(LoginFailureEntity entity) {
+ entity.setNumFailures(entity.getNumFailures() + 1);
+ }
+
+ };
+
+ update(task);
}
@Override
public void clearFailures() {
- entity.clearFailures();
- update();
+ LoginFailuresUpdateTask task = new LoginFailuresUpdateTask() {
+
+ @Override
+ public void runUpdate(LoginFailureEntity entity) {
+ entity.clearFailures();
+ }
+
+ };
+
+ update(task);
}
@Override
@@ -79,8 +101,16 @@ public class UserLoginFailureAdapter implements UserLoginFailureModel {
@Override
public void setLastFailure(long lastFailure) {
- entity.setLastFailure(lastFailure);
- update();
+ LoginFailuresUpdateTask task = new LoginFailuresUpdateTask() {
+
+ @Override
+ public void runUpdate(LoginFailureEntity entity) {
+ entity.setLastFailure(lastFailure);
+ }
+
+ };
+
+ update(task);
}
@Override
@@ -90,12 +120,20 @@ public class UserLoginFailureAdapter implements UserLoginFailureModel {
@Override
public void setLastIPFailure(String ip) {
- entity.setLastIPFailure(ip);
- update();
+ LoginFailuresUpdateTask task = new LoginFailuresUpdateTask() {
+
+ @Override
+ public void runUpdate(LoginFailureEntity entity) {
+ entity.setLastIPFailure(ip);
+ }
+
+ };
+
+ update(task);
}
- void update() {
- provider.getTx().replace(cache, key, entity);
+ void update(LoginFailuresUpdateTask task) {
+ provider.getLoginFailuresTx().addTask(key, task);
}
}
diff --git a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/UserSessionAdapter.java b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/UserSessionAdapter.java
index 3f09773c11..635d4f7a0c 100755
--- a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/UserSessionAdapter.java
+++ b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/UserSessionAdapter.java
@@ -82,25 +82,28 @@ public class UserSessionAdapter implements UserSessionModel {
});
}
- // Update user session
- if (!removedClientUUIDS.isEmpty()) {
- UserSessionUpdateTask task = new UserSessionUpdateTask() {
-
- @Override
- public void runUpdate(UserSessionEntity entity) {
- for (String clientUUID : removedClientUUIDS) {
- entity.getAuthenticatedClientSessions().remove(clientUUID);
- }
- }
-
- };
-
- update(task);
- }
+ removeAuthenticatedClientSessions(removedClientUUIDS);
return Collections.unmodifiableMap(result);
}
+ @Override
+ public void removeAuthenticatedClientSessions(Iterable removedClientUUIDS) {
+ if (removedClientUUIDS == null || ! removedClientUUIDS.iterator().hasNext()) {
+ return;
+ }
+
+ // Update user session
+ UserSessionUpdateTask task = new UserSessionUpdateTask() {
+ @Override
+ public void runUpdate(UserSessionEntity entity) {
+ removedClientUUIDS.forEach(entity.getAuthenticatedClientSessions()::remove);
+ }
+ };
+
+ update(task);
+ }
+
public String getId() {
return entity.getId();
}
diff --git a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/changes/InfinispanChangelogBasedTransaction.java b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/changes/InfinispanChangelogBasedTransaction.java
index 43bb2b3929..e5a7a47c78 100644
--- a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/changes/InfinispanChangelogBasedTransaction.java
+++ b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/changes/InfinispanChangelogBasedTransaction.java
@@ -33,18 +33,18 @@ import org.keycloak.models.sessions.infinispan.remotestore.RemoteCacheInvoker;
/**
* @author Marek Posolda
*/
-public class InfinispanChangelogBasedTransaction extends AbstractKeycloakTransaction {
+public class InfinispanChangelogBasedTransaction extends AbstractKeycloakTransaction {
public static final Logger logger = Logger.getLogger(InfinispanChangelogBasedTransaction.class);
private final KeycloakSession kcSession;
private final String cacheName;
- private final Cache> cache;
+ private final Cache> cache;
private final RemoteCacheInvoker remoteCacheInvoker;
- private final Map> updates = new HashMap<>();
+ private final Map> updates = new HashMap<>();
- public InfinispanChangelogBasedTransaction(KeycloakSession kcSession, String cacheName, Cache> cache, RemoteCacheInvoker remoteCacheInvoker) {
+ public InfinispanChangelogBasedTransaction(KeycloakSession kcSession, String cacheName, Cache> cache, RemoteCacheInvoker remoteCacheInvoker) {
this.kcSession = kcSession;
this.cacheName = cacheName;
this.cache = cache;
@@ -52,11 +52,11 @@ public class InfinispanChangelogBasedTransaction extend
}
- public void addTask(String key, SessionUpdateTask task) {
- SessionUpdatesList myUpdates = updates.get(key);
+ public void addTask(K key, SessionUpdateTask task) {
+ SessionUpdatesList myUpdates = updates.get(key);
if (myUpdates == null) {
// Lookup entity from cache
- SessionEntityWrapper wrappedEntity = cache.get(key);
+ SessionEntityWrapper wrappedEntity = cache.get(key);
if (wrappedEntity == null) {
logger.warnf("Not present cache item for key %s", key);
return;
@@ -75,14 +75,14 @@ public class InfinispanChangelogBasedTransaction extend
// Create entity and new version for it
- public void addTask(String key, SessionUpdateTask task, S entity) {
+ public void addTask(K key, SessionUpdateTask task, V entity) {
if (entity == null) {
throw new IllegalArgumentException("Null entity not allowed");
}
RealmModel realm = kcSession.realms().getRealm(entity.getRealm());
- SessionEntityWrapper wrappedEntity = new SessionEntityWrapper<>(entity);
- SessionUpdatesList myUpdates = new SessionUpdatesList<>(realm, wrappedEntity);
+ SessionEntityWrapper wrappedEntity = new SessionEntityWrapper<>(entity);
+ SessionUpdatesList myUpdates = new SessionUpdatesList<>(realm, wrappedEntity);
updates.put(key, myUpdates);
// Run the update now, so reader in same transaction can see it
@@ -91,19 +91,19 @@ public class InfinispanChangelogBasedTransaction extend
}
- public void reloadEntityInCurrentTransaction(RealmModel realm, String key, SessionEntityWrapper entity) {
+ public void reloadEntityInCurrentTransaction(RealmModel realm, K key, SessionEntityWrapper entity) {
if (entity == null) {
throw new IllegalArgumentException("Null entity not allowed");
}
- SessionEntityWrapper latestEntity = cache.get(key);
+ SessionEntityWrapper latestEntity = cache.get(key);
if (latestEntity == null) {
return;
}
- SessionUpdatesList newUpdates = new SessionUpdatesList<>(realm, latestEntity);
+ SessionUpdatesList newUpdates = new SessionUpdatesList<>(realm, latestEntity);
- SessionUpdatesList existingUpdates = updates.get(key);
+ SessionUpdatesList existingUpdates = updates.get(key);
if (existingUpdates != null) {
newUpdates.setUpdateTasks(existingUpdates.getUpdateTasks());
}
@@ -112,10 +112,10 @@ public class InfinispanChangelogBasedTransaction extend
}
- public SessionEntityWrapper get(String key) {
- SessionUpdatesList myUpdates = updates.get(key);
+ public SessionEntityWrapper get(K key) {
+ SessionUpdatesList myUpdates = updates.get(key);
if (myUpdates == null) {
- SessionEntityWrapper wrappedEntity = cache.get(key);
+ SessionEntityWrapper wrappedEntity = cache.get(key);
if (wrappedEntity == null) {
return null;
}
@@ -127,7 +127,7 @@ public class InfinispanChangelogBasedTransaction extend
return wrappedEntity;
} else {
- S entity = myUpdates.getEntityWrapper().getEntity();
+ V entity = myUpdates.getEntityWrapper().getEntity();
// If entity is scheduled for remove, we don't return it.
boolean scheduledForRemove = myUpdates.getUpdateTasks().stream().filter((SessionUpdateTask task) -> {
@@ -143,13 +143,13 @@ public class InfinispanChangelogBasedTransaction extend
@Override
protected void commitImpl() {
- for (Map.Entry> entry : updates.entrySet()) {
- SessionUpdatesList sessionUpdates = entry.getValue();
- SessionEntityWrapper sessionWrapper = sessionUpdates.getEntityWrapper();
+ for (Map.Entry> entry : updates.entrySet()) {
+ SessionUpdatesList sessionUpdates = entry.getValue();
+ SessionEntityWrapper sessionWrapper = sessionUpdates.getEntityWrapper();
RealmModel realm = sessionUpdates.getRealm();
- MergedUpdate merged = MergedUpdate.computeUpdate(sessionUpdates.getUpdateTasks(), sessionWrapper);
+ MergedUpdate merged = MergedUpdate.computeUpdate(sessionUpdates.getUpdateTasks(), sessionWrapper);
if (merged != null) {
// Now run the operation in our cluster
@@ -162,8 +162,8 @@ public class InfinispanChangelogBasedTransaction extend
}
- private void runOperationInCluster(String key, MergedUpdate task, SessionEntityWrapper sessionWrapper) {
- S session = sessionWrapper.getEntity();
+ private void runOperationInCluster(K key, MergedUpdate task, SessionEntityWrapper sessionWrapper) {
+ V session = sessionWrapper.getEntity();
SessionUpdateTask.CacheOperation operation = task.getOperation(session);
// Don't need to run update of underlying entity. Local updates were already run
@@ -182,9 +182,14 @@ public class InfinispanChangelogBasedTransaction extend
.put(key, sessionWrapper, task.getLifespanMs(), TimeUnit.MILLISECONDS);
break;
case ADD_IF_ABSENT:
- SessionEntityWrapper existing = cache.putIfAbsent(key, sessionWrapper);
+ SessionEntityWrapper existing = cache.putIfAbsent(key, sessionWrapper);
if (existing != null) {
- throw new IllegalStateException("There is already existing value in cache for key " + key);
+ logger.debugf("Existing entity in cache for key: %s . Will update it", key);
+
+ // Apply updates on the existing entity and replace it
+ task.runUpdate(existing.getEntity());
+
+ replace(key, task, existing);
}
break;
case REPLACE:
@@ -197,12 +202,12 @@ public class InfinispanChangelogBasedTransaction extend
}
- private void replace(String key, MergedUpdate task, SessionEntityWrapper oldVersionEntity) {
+ private void replace(K key, MergedUpdate task, SessionEntityWrapper oldVersionEntity) {
boolean replaced = false;
- S session = oldVersionEntity.getEntity();
+ V session = oldVersionEntity.getEntity();
while (!replaced) {
- SessionEntityWrapper newVersionEntity = generateNewVersionAndWrapEntity(session, oldVersionEntity.getLocalMetadata());
+ SessionEntityWrapper newVersionEntity = generateNewVersionAndWrapEntity(session, oldVersionEntity.getLocalMetadata());
// Atomic cluster-aware replace
replaced = cache.replace(key, oldVersionEntity, newVersionEntity);
@@ -235,7 +240,7 @@ public class InfinispanChangelogBasedTransaction extend
protected void rollbackImpl() {
}
- private SessionEntityWrapper generateNewVersionAndWrapEntity(S entity, Map localMetadata) {
+ private SessionEntityWrapper generateNewVersionAndWrapEntity(V entity, Map localMetadata) {
return new SessionEntityWrapper<>(localMetadata, entity);
}
diff --git a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/changes/LoginFailuresUpdateTask.java b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/changes/LoginFailuresUpdateTask.java
new file mode 100644
index 0000000000..04ed05a318
--- /dev/null
+++ b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/changes/LoginFailuresUpdateTask.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2017 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.models.sessions.infinispan.changes;
+
+import org.keycloak.models.sessions.infinispan.entities.LoginFailureEntity;
+
+/**
+ * @author Marek Posolda
+ */
+public abstract class LoginFailuresUpdateTask implements SessionUpdateTask {
+
+ @Override
+ public CacheOperation getOperation(LoginFailureEntity session) {
+ return CacheOperation.REPLACE;
+ }
+
+ @Override
+ public CrossDCMessageStatus getCrossDCMessageStatus(SessionEntityWrapper sessionWrapper) {
+ return CrossDCMessageStatus.SYNC;
+ }
+}
diff --git a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/changes/MergedUpdate.java b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/changes/MergedUpdate.java
index 1f24f84faf..8e0cf0ed82 100644
--- a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/changes/MergedUpdate.java
+++ b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/changes/MergedUpdate.java
@@ -32,7 +32,7 @@ class MergedUpdate implements SessionUpdateTask {
private CrossDCMessageStatus crossDCMessageStatus;
- public MergedUpdate(CacheOperation operation, CrossDCMessageStatus crossDCMessageStatus) {
+ private MergedUpdate(CacheOperation operation, CrossDCMessageStatus crossDCMessageStatus) {
this.operation = operation;
this.crossDCMessageStatus = crossDCMessageStatus;
}
diff --git a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/changes/SessionUpdateTask.java b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/changes/SessionUpdateTask.java
index 66f88baa05..244a88bd99 100644
--- a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/changes/SessionUpdateTask.java
+++ b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/changes/SessionUpdateTask.java
@@ -17,8 +17,6 @@
package org.keycloak.models.sessions.infinispan.changes;
-import org.keycloak.models.KeycloakSession;
-import org.keycloak.models.RealmModel;
import org.keycloak.models.sessions.infinispan.entities.SessionEntity;
/**
@@ -51,7 +49,7 @@ public interface SessionUpdateTask {
if (this == ADD | this == ADD_IF_ABSENT) {
if (other == ADD | other == ADD_IF_ABSENT) {
- throw new IllegalStateException("Illegal state. Task already in progress for session " + entity.getId());
+ throw new IllegalStateException("Illegal state. Task already in progress for session " + entity.toString());
}
return this;
diff --git a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/changes/UserSessionUpdateTask.java b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/changes/UserSessionUpdateTask.java
index 4fd4bbebf1..1db36a1c7e 100644
--- a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/changes/UserSessionUpdateTask.java
+++ b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/changes/UserSessionUpdateTask.java
@@ -17,8 +17,6 @@
package org.keycloak.models.sessions.infinispan.changes;
-import org.keycloak.models.KeycloakSession;
-import org.keycloak.models.RealmModel;
import org.keycloak.models.sessions.infinispan.entities.UserSessionEntity;
/**
diff --git a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/changes/sessions/LastSessionRefreshChecker.java b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/changes/sessions/LastSessionRefreshChecker.java
index f9adf9b8cb..25e0df942f 100644
--- a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/changes/sessions/LastSessionRefreshChecker.java
+++ b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/changes/sessions/LastSessionRefreshChecker.java
@@ -60,7 +60,7 @@ public class LastSessionRefreshChecker {
Integer lsrr = sessionWrapper.getLocalMetadataNoteInt(UserSessionEntity.LAST_SESSION_REFRESH_REMOTE);
if (lsrr == null) {
- logger.warnf("Not available lsrr note on user session %s.", sessionWrapper.getEntity().getId());
+ logger.debugf("Not available lsrr note on user session %s.", sessionWrapper.getEntity().getId());
return SessionUpdateTask.CrossDCMessageStatus.SYNC;
}
diff --git a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/entities/AuthenticationSessionEntity.java b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/entities/AuthenticationSessionEntity.java
index 0b992254b2..cdb841e6f2 100644
--- a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/entities/AuthenticationSessionEntity.java
+++ b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/entities/AuthenticationSessionEntity.java
@@ -21,6 +21,7 @@ import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
+import java.util.TreeSet;
import org.keycloak.sessions.AuthenticationSessionModel;
@@ -29,6 +30,8 @@ import org.keycloak.sessions.AuthenticationSessionModel;
*/
public class AuthenticationSessionEntity extends SessionEntity {
+ private String id;
+
private String clientUuid;
private String authUserId;
@@ -46,6 +49,14 @@ public class AuthenticationSessionEntity extends SessionEntity {
private Set requiredActions = new HashSet<>();
private Map userSessionNotes;
+ public String getId() {
+ return id;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
public String getClientUuid() {
return clientUuid;
}
@@ -149,4 +160,26 @@ public class AuthenticationSessionEntity extends SessionEntity {
public void setAuthNotes(Map authNotes) {
this.authNotes = authNotes;
}
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof AuthenticationSessionEntity)) return false;
+
+ AuthenticationSessionEntity that = (AuthenticationSessionEntity) o;
+
+ if (id != null ? !id.equals(that.id) : that.id != null) return false;
+
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ return id != null ? id.hashCode() : 0;
+ }
+
+ @Override
+ public String toString() {
+ return String.format("AuthenticationSessionEntity [id=%s, realm=%s, clientUuid=%s ]", getId(), getRealm(), getClientUuid());
+ }
}
diff --git a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/entities/LoginFailureEntity.java b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/entities/LoginFailureEntity.java
index d25f58b831..5b328ecc91 100644
--- a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/entities/LoginFailureEntity.java
+++ b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/entities/LoginFailureEntity.java
@@ -17,15 +17,12 @@
package org.keycloak.models.sessions.infinispan.entities;
-import java.io.Serializable;
-
/**
* @author Stian Thorgersen
*/
-public class LoginFailureEntity implements Serializable {
+public class LoginFailureEntity extends SessionEntity {
private String userId;
- private String realm;
private int failedLoginNotBefore;
private int numFailures;
private long lastFailure;
@@ -39,14 +36,6 @@ public class LoginFailureEntity implements Serializable {
this.userId = userId;
}
- public String getRealm() {
- return realm;
- }
-
- public void setRealm(String realm) {
- this.realm = realm;
- }
-
public int getFailedLoginNotBefore() {
return failedLoginNotBefore;
}
@@ -85,4 +74,30 @@ public class LoginFailureEntity implements Serializable {
this.lastFailure = 0;
this.lastIPFailure = null;
}
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof LoginFailureEntity)) return false;
+
+ LoginFailureEntity that = (LoginFailureEntity) o;
+
+ if (userId != null ? !userId.equals(that.userId) : that.userId != null) return false;
+ if (getRealm() != null ? !getRealm().equals(that.getRealm()) : that.getRealm() != null) return false;
+
+
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ int hashCode = getRealm() != null ? getRealm().hashCode() : 0;
+ hashCode = hashCode * 13 + (userId != null ? userId.hashCode() : 0);
+ return hashCode;
+ }
+
+ @Override
+ public String toString() {
+ return String.format("LoginFailureEntity [ userId=%s, realm=%s, numFailures=%d ]", userId, getRealm(), numFailures);
+ }
}
diff --git a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/entities/LoginFailureKey.java b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/entities/LoginFailureKey.java
index c45237963b..318b1ba547 100644
--- a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/entities/LoginFailureKey.java
+++ b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/entities/LoginFailureKey.java
@@ -52,4 +52,9 @@ public class LoginFailureKey implements Serializable {
return result;
}
+
+ @Override
+ public String toString() {
+ return String.format("LoginFailureKey [ realm=%s. userId=%s ]", realm, userId);
+ }
}
diff --git a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/entities/SessionEntity.java b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/entities/SessionEntity.java
index 25ac2a4efe..37f8e081ce 100755
--- a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/entities/SessionEntity.java
+++ b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/entities/SessionEntity.java
@@ -26,17 +26,8 @@ import org.keycloak.models.sessions.infinispan.changes.SessionEntityWrapper;
*/
public abstract class SessionEntity implements Serializable {
- private String id;
-
private String realm;
- public String getId() {
- return id;
- }
-
- public void setId(String id) {
- this.id = id;
- }
public String getRealm() {
return realm;
@@ -46,26 +37,13 @@ public abstract class SessionEntity implements Serializable {
this.realm = realm;
}
- @Override
- public boolean equals(Object o) {
- if (this == o) return true;
- if (!(o instanceof SessionEntity)) return false;
-
- SessionEntity that = (SessionEntity) o;
-
- if (id != null ? !id.equals(that.id) : that.id != null) return false;
-
- return true;
- }
-
- @Override
- public int hashCode() {
- return id != null ? id.hashCode() : 0;
- }
-
public SessionEntityWrapper mergeRemoteEntityWithLocalEntity(SessionEntityWrapper localEntityWrapper) {
- throw new IllegalStateException("Not yet implemented");
+ if (localEntityWrapper == null) {
+ return new SessionEntityWrapper<>(this);
+ } else {
+ return new SessionEntityWrapper<>(localEntityWrapper.getLocalMetadata(), this);
+ }
};
}
diff --git a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/entities/UserSessionEntity.java b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/entities/UserSessionEntity.java
index 5d0edb09fe..8ac85a17e4 100755
--- a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/entities/UserSessionEntity.java
+++ b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/entities/UserSessionEntity.java
@@ -43,6 +43,8 @@ public class UserSessionEntity extends SessionEntity {
// Metadata attribute, which contains the lastSessionRefresh available on remoteCache. Used in decide whether we need to write to remoteCache (DC) or not
public static final String LAST_SESSION_REFRESH_REMOTE = "lsrr";
+ private String id;
+
private String user;
private String brokerSessionId;
@@ -62,6 +64,14 @@ public class UserSessionEntity extends SessionEntity {
private UserSessionModel.State state;
+ public String getId() {
+ return id;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
private Map notes = new ConcurrentHashMap<>();
private Map authenticatedClientSessions = new ConcurrentHashMap<>();
@@ -162,6 +172,23 @@ public class UserSessionEntity extends SessionEntity {
this.brokerUserId = brokerUserId;
}
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof UserSessionEntity)) return false;
+
+ UserSessionEntity that = (UserSessionEntity) o;
+
+ if (id != null ? !id.equals(that.id) : that.id != null) return false;
+
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ return id != null ? id.hashCode() : 0;
+ }
+
@Override
public String toString() {
return String.format("UserSessionEntity [id=%s, realm=%s, lastSessionRefresh=%d, clients=%s]", getId(), getRealm(), getLastSessionRefresh(),
diff --git a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/initializer/BaseCacheInitializer.java b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/initializer/BaseCacheInitializer.java
index 43788d07fb..cca28cc656 100644
--- a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/initializer/BaseCacheInitializer.java
+++ b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/initializer/BaseCacheInitializer.java
@@ -106,7 +106,7 @@ public abstract class BaseCacheInitializer extends CacheInitializer {
private InitializerState getStateFromCache() {
- // We ignore cacheStore for now, so that in Cross-DC scenario (with RemoteStore enabled) is the remoteStore ignored. This means that every DC needs to load offline sessions separately.
+ // We ignore cacheStore for now, so that in Cross-DC scenario (with RemoteStore enabled) is the remoteStore ignored.
return (InitializerState) workCache.getAdvancedCache()
.withFlags(Flag.SKIP_CACHE_STORE, Flag.SKIP_CACHE_LOAD)
.get(stateKey);
@@ -122,7 +122,7 @@ public abstract class BaseCacheInitializer extends CacheInitializer {
public void run() {
// Save this synchronously to ensure all nodes read correct state
- // We ignore cacheStore for now, so that in Cross-DC scenario (with RemoteStore enabled) is the remoteStore ignored. This means that every DC needs to load offline sessions separately.
+ // We ignore cacheStore for now, so that in Cross-DC scenario (with RemoteStore enabled) is the remoteStore ignored.
BaseCacheInitializer.this.workCache.getAdvancedCache().
withFlags(Flag.IGNORE_RETURN_VALUES, Flag.FORCE_SYNCHRONOUS, Flag.SKIP_CACHE_STORE, Flag.SKIP_CACHE_LOAD)
.put(stateKey, state);
diff --git a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/initializer/InfinispanCacheInitializer.java b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/initializer/InfinispanCacheInitializer.java
index 620a9a8178..ef45bd9db5 100755
--- a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/initializer/InfinispanCacheInitializer.java
+++ b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/initializer/InfinispanCacheInitializer.java
@@ -35,7 +35,7 @@ import java.util.concurrent.Future;
* Startup initialization for reading persistent userSessions to be filled into infinispan/memory . In cluster,
* the initialization is distributed among all cluster nodes, so the startup time is even faster
*
- * TODO: Move to clusterService. Implementation is already pretty generic and doesn't contain any "userSession" specific stuff. All sessions-specific logic is in the SessionLoader implementation
+ * Implementation is pretty generic and doesn't contain any "userSession" specific stuff. All logic related to how are sessions loaded is in the SessionLoader implementation
*
* @author