diff --git a/.gitignore b/.gitignore
index bf5d094f0c4..443e12ad50d 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 c2efec51d52..3fafffc6703 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 a2f5b5bcffc..431032105d6 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 5eed4329203..fd4544f637d 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 d5761bcf1ae..707b882220b 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 ee3f214e243..8d875ee4eb5 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 9efa614573c..c8bce94592e 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 89faf8b97bf..9e5887acc05 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 47e344f9142..d187857cdfd 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 00000000000..a8b800f38b5
--- /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 72088b3b7de..6a79f0b45c8 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 5a2d24e3e98..2bdce7028d8 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 4b5a4272ecc..72cada7a545 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 216c3b794ee..79b7f341c12 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 3c14afa2de0..d64b950209d 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 6f46e7c9ccc..44cd9e686ff 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 3ee1c5e155e..1a771e40b7e 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 312475509b3..74f86af7f93 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 c5a47847111..e8957b17e82 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 f8b6335404b..b2e4796dd91 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 c4cb37489a3..04c9ae11a1e 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 acb36c6bcc4..13fc4cdc086 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 5ec0c168b1a..8556e6bc2cc 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 8b4cc6789c7..e4d866f801a 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 a784936c78f..ab6f78826aa 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 26a90ec487c..537bcb2b44a 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 9207401a1c2..28f243b7045 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 3d81dc7322e..7e5bdcdee71 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 bb709f1dc26..a5b25f08ac5 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 49cab4ebe01..0b3d3c5e015 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 6a720f65a5b..c29a8d3f59f 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 00000000000..ae4836c7139
--- /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 00000000000..200a9035f1e
--- /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 00000000000..e8e599e40d3
--- /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 00000000000..689cc65274d
--- /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 b304cd5b0d0..008f38899bb 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 7e235ae5204..2e9ef40f6d4 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 d733dbd6999..4c33882cdb9 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 c47cc4dde9f..154bed1ca6f 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 69e993c80ee..123c2ec0aa4
--- 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 703709371c1..7356fe5de1f 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 d0b7059351b..087d0839c6f 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 00000000000..496eed3e684
--- /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 b9f4ab83230..8e0732487e2 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 d42530557ae..c09555126fb 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 00000000000..82796d66abe
--- /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 18195e354ac..49854ff81d1 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 8bf86063b0a..b6ad8322a1f 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 00000000000..82796d66abe
--- /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 d227353ec7d..9da6964405a 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 ccdc34e60ee..32b5b8ee805 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 71d56818183..811ffcf92f7 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 4472af75f90..4941275f1e3 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 6042ec82d13..eef2b269423 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 e93be16c2b5..b6a1db9b033 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 2afcf14cdf1..d04b8d1af6f 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 686661d8cf1..6fa127d4b6e 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 1d8e6cf9161..b73daf10703 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 110d385a756..55c83ca96bd 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 00000000000..613c946f4f5
--- /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 7088ec0cf90..2066aed3f48 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 908526c8288..127ea538f1b 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 24e9ac0b744..1500808e328 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 5a71e615a88..496c3119827 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 e306a7f6306..61d670c8cdd 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 d04e72d4030..52113c08251 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 00000000000..94fb8e566d1
--- /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 00000000000..1e177a49f4f
--- /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 79555e3b7bf..a8d50aeb3da 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 00000000000..7d8fd05dfdb
--- /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 c9cea777875..f6097ae5cf8 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 d8f5bc3d74d..caa147d8218 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 9d5f87ab39d..4adad9f21ad 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 246d76855fa..fce5c41dae7 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 21e23b987a1..96c56d5300b 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 dd8aff53177..2fdd3ee7280 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 b6f4c23f094..dd19a7b7e66 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 ee100ad3175..aded4a38e9b 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 66bdf0d5add..ecef244c1e1 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 d3c2a5d9a44..e9a8b37608b 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 00000000000..0333bc9dee8
--- /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 d583db43d1e..30a853ffa61 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 29e35a9761d..d8d24040925 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 be1e686dc04..7e7e479c66c 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 8b94068229f..3646ed45541 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 2b40a424e82..12cb9248685 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 316cb7e6b18..98b180e25bc 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 ca569821b36..3a649184f6e 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 c01af403a28..27e7aff14a6 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 88bf6855957..4664c1f75bb 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 d34f83e0ed1..2ad1e2a27ea 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 cee8d453d9f..14bb3cd9d0d 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 2f53996d718..b646f8395f5 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 4ae655c4e9d..8b1ce3c0e27 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 fd7f9393ba2..9b49f239d21 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 0911796e010..897d3b8edf9 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 e493969a3f4..e7f22241a50 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 12ad22bb0a2..245341679f2 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 ff59bfc0ef6..b7e4c76a0de 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 835e4d52d2c..047019abeae 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 b314f7efaf8..01fc1bcffc1 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 2bf2369ef17..7e8fb834568 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 4161b092e98..1fbfb110a46 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 3207835360d..f79b60d25e4 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 43108bb00f8..fb4accca8d7 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 3be5e7e4c0f..8e15de0ab7c 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 489d1d5c676..c35db63a1fe 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 ccd102e7133..6d53485aa55 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 acaf7f160fd..bb370c03402 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 00000000000..3be66deb796
--- /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 79a49812d33..e9ef1a3ee15 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 0145009a5fb..28a74bcfdb8 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 a00ae829f0a..7ca8af6e708 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 41be1d3d19f..69a59e23a95 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 03adfdf126f..bbaf8bdd8da 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 45805179b11..8f1ba6756f9 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 c9228b6e7f5..54b6e6b9a71 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 dcf55e5f50c..38b5d94cb91 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 0f04bdb14dd..73b9e0225b4 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 c45476a6e01..08cbab44295 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 193dcf49af6..a16944e1df5 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 6d7ed543ac0..13602970d00 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 933a85971db..4769ee3ef21 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 5a90f93227c..28d4d0b86ca 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 eb6674110d6..bdc830cf909 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 f119652c858..7c9a43c7fef 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 36c54baf5ef..65260f57ca5 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 47333617df2..9b0c4fa85e1 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 bbbc0dbaf5b..a076fc912da 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 9d970d1df08..ec688251a71 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 70476b6743f..6b93036ba30 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 c759a8a8ffa..76cb21ef192 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 2e585c32780..20d6e7388cd 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 00000000000..c2964268a87
--- /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 00000000000..8e4d96fbd22
--- /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 00000000000..f457b180ed7
--- /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 eceb7592fc9..ea11f4f14dd 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 4dcea953dfc..7f0e0a0d1c3 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 f0b973029d4..c00393b47c8 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 4061b97a97d..91fa28581b0 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 216bbad7e2d..fd55eff2732 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 f10d11a7eb6..ee1c6b2fa6d 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 2529bc45db0..1ff7fc03265 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 f2c5dac4904..7b96da355fe 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 e94db3a959c..26c79f432bc 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 03db2b4868d..fc31f437645 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 5cfa1988a19..b48d8dce955 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 506bf22f29c..e5e7147e3bc 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 62c81b80a8f..247270850bf 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 f42fcd9283d..e713de6bd43 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 bd199c9f5ef..0a4f66af8ec 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 14e0cc00b66..8111f783ea5 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 be37dc8729a..f92cdc7413e 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 36ef9f35afb..8b23c60ca54 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 2994b3cea2e..29ab2932f1b 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 61b801af46e..53da019d24f 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 bf42fa8ca32..15bbf6fb29d 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 6e4193fe2f1..5f139348338 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 16f17ce9a81..6ef26d01e58 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 1ba65022c00..57e22dce901 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 391c642dc89..0da1f19baee 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 d87f87b67b0..905574fa42f 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 05b72b5ef15..14878509660 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 a88f373c912..02d7d6169a1 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 88f191bffb8..8ad11c2a64a 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 8e0335ac02c..76ec08cb17b 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 d116ab1a5f7..b36f521cdb8 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 a13c5212359..252bc61e0e4 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 95ae460f83d..5a5ac140760 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 5ea7e93ce09..f800ae23592 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 4c9211911ea..9dd7b22870d 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 5db83ef6a8f..794c7995781 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 6f4b77b49cd..ff661ce6170 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 025f15271be..32849fc6f1e 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 b32593d23e5..4fd074480ab 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 e2f1f4144bc..8b426ac656b 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 ab9bfa9dcb6..7a841483afd 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 9d9954de9b6..e19734cf21a 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 823b45cebca..a1a5035ab32 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 0f136fde636..be103dde618 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 968895d023a..18e162abd38 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 165323ddc8c..a5f1fc73fd8 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 79d4468de63..959be2a9d3a 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 4165230f30d..5f7b4751bcc 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 f2650dfd1df..9297bbaf6e0 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 fd9d2e40899..885470fb2ee 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 54c249d8ffa..5e5c14675a2 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 e1c378c2208..c7175bb171e 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 8c8f99f9865..15e43564b63 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 f5c3481c221..35b2d86f66f 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 e6ef28e6519..df95b97ea78 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 8b86d43d740..f2c8e2a3589 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 81828d285e1..b3bc83abce2 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 1f240854590..a76109b8091 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 01cdab6a52d..3b0eb2aad25 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 f4a5a2d125a..5cb56b7dc93 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 da7c2187d60..37d00abfb83 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 6d2a6e2c2ea..9f084b1cdbe 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 1b80a59d549..6f68ed0be3c 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 e398bbbe5f2..4123be58d44 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 857a8e31b89..b61266df6c5 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 dc0790454fa..f966cff11e1 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 6b425c0a13d..334e2ee8dca 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 f8a0c538ba4..b42f7e872bc 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 00000000000..74f44850c7b
--- /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 c5ac43eafb8..bf10c785296 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 26c1777330a..a36e305e730 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 afdc3fb879a..31e48ec3b8c 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 08267aa4792..7d89b93eda7 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 deb1c84757f..c807f9b7ab0 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 9b1677edca9..2ebc457ea46 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 5ff5fdb1369..e4fb521d9c8 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 94b73dc07be..4e65c16232e 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 b6a93bc4f0e..28b87bc579c 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 cbaeb243ec0..26f377aa0c3 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 06adb3ca987..a81552d604e 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 ffcf7f20859..b730ba566a5 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 af19e13ef0a..c8576f1e58d 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 0fb71b4a4ea..f8edf4829e0 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 e89fbc560fa..0cc37e980d4 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 5797474cc68..ad206a7f766 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 3226fbc3534..7207ab34a2b 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 188035d0e86..514da61bf9e 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 28e65fcf6b3..143592d3316 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 80ccf115b2f..404e8fc0212 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 3e4d71ad6db..4ff72bc8e3d 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 fd2565f3406..665e65f53bc 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 06c4b2ed085..3a29e3baa3b 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 f58edd57494..68528419355 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 3b8146fe156..cc6f6219039 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 e5e6ca9af5f..d3d78636d3f 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 7c59225647c..d057f29cee0 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 e4252a40498..e81fac22bbf 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 3c4d3a0f95f..864b5d7d98e 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 f2af2fb3fa2..7c9484a2d83 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 19f8b9184bb..5ddedefbc27 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 c565ceefd07..e52a3c816da 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 3f8526639b6..d61ea68c8e2 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 20a7e7eef1b..3bc6a2f503b 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 6aad96ccc72..8bd4694d60e 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 0ca3c4e831f..b8f0984e9ae 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 3c4bfd414de..752ff870522 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 9d3faa06c96..51fb7340f6d 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 f53164ca977..594fe509d1d 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 3f9f36df602..151ddab78e6 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 a5fe72e3ea8..11b8d2fb456 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 48e01255b1c..1742a01190c 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 e69578e4df8..e95917f0b72 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 37a64e2c797..7886ae2b39d 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 2c1d335aceb..7aafdacd978 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 6d2d5b18140..20b43273399 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 62c4d1bb673..29f59c21516 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 6c45be0c04d..f96beb35762 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 0421e888cdb..de9e92f7ac5 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 a4042c7b425..d5305cadac1 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 fb71a7c9cfe..73d821fbcdb 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 82032157506..fc5a61c397a 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 6448f1ef483..1d3602de1b1 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 ab431451b97..ad7153fd12f 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 a55f5206786..061d7757761 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 9570a740f71..8791c3c8987 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 aebd6772218..ebd8d1c9916 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 a1a5637ed59..ba21ac49f6c 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 36a41cb1731..48bdcba4347 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 e69c6df1c5d..7ebf384e076 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 d4bed04efad..0295e2f4004 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 02713e6f6ee..23c508315b1 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 9f42085afb9..278c63a075f 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 e586f3e5868..83348d85bd2 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 7d18fdf4ced..d49da0d959e 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 6b026eb08cf..d319be05fdf 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 4618792225e..061ddd871bd 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 d8653de1704..e77df536229 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 91368320049..921d27958fa 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 1e40781d8a3..e023800ab93 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 ee006ef079a..cfdc820f45f 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 10d629bed73..b1bfd81c3b6 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 38a1d5631f7..5a2c10cb2f5 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 6a76bf03979..48cb8ae3695 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 1ffbf10e33f..e2b5922d931 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 c8d2d222a8b..015d1d30e96 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 2c829800ddc..3e005e03de1 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 3313f3fe4be..261d099500b 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 7f5e036d62e..f7b4e8e3838 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 363d1099f5b..cb4a0f8bf46 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 8747ec19d9f..c17e73e895c 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 d65bbe7b960..f72eb62a3c6 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 2f55a9ac554..999a3b1d981 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 70f7daf3361..1092895ad18 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 7d7dfe1584d..f94566132a8 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 86f607456f0..5135e90bea8 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 0d971f70b9f..390c25c158f 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 dc721b7112a..5e9b7d34310 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 bb3ec6cbc07..7d72c9890ed 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 a169235643f..c70a43a5e74 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 7dfb5fbf862..a904bd1a3d2 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 fbe5a7aa483..74b8d0c26d3 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 2034c9b4d60..18623458877 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 cc30f230d9b..3f85a6d5b0a 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 1bf6e426a09..68dfc372cb1 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 c1a8ed688bc..48d1965fca8 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 110a8124f83..df30b4e9272 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 a41777dc43a..0971c262126 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 3f09773c117..635d4f7a0c4 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 43bb2b39295..e5a7a47c786 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 00000000000..04ed05a3180
--- /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 1f24f84faf9..8e0cf0ed82b 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 66f88baa055..244a88bd990 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 4fd4bbebf1c..1db36a1c7e5 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 f9adf9b8cbe..25e0df942fe 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 0b992254b2d..cdb841e6f22 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 d25f58b831a..5b328ecc915 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 c45237963bf..318b1ba5479 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 25ac2a4efeb..37f8e081ce3 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 5d0edb09fe0..8ac85a17e48 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 43788d07fb4..cca28cc6560 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 620a9a8178c..ef45bd9db59 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