diff --git a/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/AdapterDeploymentContext.java b/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/AdapterDeploymentContext.java index 47eb58e0a36..fd676f5a213 100755 --- a/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/AdapterDeploymentContext.java +++ b/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/AdapterDeploymentContext.java @@ -433,6 +433,16 @@ public class AdapterDeploymentContext { public void setPrincipalAttribute(String principalAttribute) { delegate.setPrincipalAttribute(principalAttribute); } + + @Override + public boolean isTurnOffChangeSessionIdOnLogin() { + return delegate.isTurnOffChangeSessionIdOnLogin(); + } + + @Override + public void setTurnOffChangeSessionIdOnLogin(boolean turnOffChangeSessionIdOnLogin) { + delegate.setTurnOffChangeSessionIdOnLogin(turnOffChangeSessionIdOnLogin); + } } protected KeycloakUriBuilder getBaseBuilder(HttpFacade facade, String base) { 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 5edaa817ff3..b97ecdb913d 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 @@ -57,6 +57,8 @@ public class KeycloakDeployment { protected boolean alwaysRefreshToken; protected boolean registerNodeAtStartup; protected int registerNodePeriod; + protected boolean turnOffChangeSessionIdOnLogin; + protected volatile int notBefore; public KeycloakDeployment() { @@ -361,4 +363,12 @@ public class KeycloakDeployment { public void setPrincipalAttribute(String principalAttribute) { this.principalAttribute = principalAttribute; } + + public boolean isTurnOffChangeSessionIdOnLogin() { + return turnOffChangeSessionIdOnLogin; + } + + public void setTurnOffChangeSessionIdOnLogin(boolean turnOffChangeSessionIdOnLogin) { + this.turnOffChangeSessionIdOnLogin = turnOffChangeSessionIdOnLogin; + } } diff --git a/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/KeycloakDeploymentBuilder.java b/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/KeycloakDeploymentBuilder.java index 14cf9ab6545..0bda9b25cb6 100755 --- a/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/KeycloakDeploymentBuilder.java +++ b/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/KeycloakDeploymentBuilder.java @@ -88,6 +88,9 @@ public class KeycloakDeploymentBuilder { throw new RuntimeException("You must specify auth-url"); } deployment.setAuthServerBaseUrl(adapterConfig); + if (adapterConfig.getTurnOffChangeSessionIdOnLogin() != null) { + deployment.setTurnOffChangeSessionIdOnLogin(adapterConfig.getTurnOffChangeSessionIdOnLogin()); + } log.debug("Use authServerUrl: " + deployment.getAuthServerBaseUrl() + ", tokenUrl: " + deployment.getTokenUrl() + ", relativeUrls: " + deployment.getRelativeUrls()); return deployment; 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 cc6b1882f9d..e69e6f2288e 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 @@ -293,7 +293,7 @@ public class OAuthRequestAuthenticator { strippedOauthParametersRequestUri = stripOauthParametersFromRedirect(); try { // For COOKIE store we don't have httpSessionId and single sign-out won't be available - String httpSessionId = deployment.getTokenStore() == TokenStore.SESSION ? reqAuthenticator.getHttpSessionId(true) : null; + String httpSessionId = deployment.getTokenStore() == TokenStore.SESSION ? reqAuthenticator.changeHttpSessionId(true) : null; tokenResponse = ServerRequest.invokeAccessCodeToToken(deployment, code, strippedOauthParametersRequestUri, httpSessionId); } catch (ServerRequest.HttpFailure failure) { log.error("failed to turn code into token"); diff --git a/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/RequestAuthenticator.java b/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/RequestAuthenticator.java index 6b4d9f003dd..8f695b00a86 100755 --- a/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/RequestAuthenticator.java +++ b/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/RequestAuthenticator.java @@ -141,7 +141,13 @@ public abstract class RequestAuthenticator { protected abstract void completeOAuthAuthentication(KeycloakPrincipal principal); protected abstract void completeBearerAuthentication(KeycloakPrincipal principal, String method); - protected abstract String getHttpSessionId(boolean create); + + /** + * After code is received, we change the session id if possible to guard against https://www.owasp.org/index.php/Session_Fixation + * @param create + * @return + */ + protected abstract String changeHttpSessionId(boolean create); protected void completeAuthentication(BearerTokenRequestAuthenticator bearer, String method) { RefreshableKeycloakSecurityContext session = new RefreshableKeycloakSecurityContext(deployment, null, bearer.getTokenString(), bearer.getToken(), null, null, null); diff --git a/adapters/oidc/as7-eap6/as7-subsystem/src/main/resources/schema/keycloak_1_1.xsd b/adapters/oidc/as7-eap6/as7-subsystem/src/main/resources/schema/keycloak_1_1.xsd index 75de38ad838..89b37b653dd 100755 --- a/adapters/oidc/as7-eap6/as7-subsystem/src/main/resources/schema/keycloak_1_1.xsd +++ b/adapters/oidc/as7-eap6/as7-subsystem/src/main/resources/schema/keycloak_1_1.xsd @@ -87,6 +87,7 @@ + diff --git a/adapters/oidc/jetty/jetty-core/src/main/java/org/keycloak/adapters/jetty/core/JettyRequestAuthenticator.java b/adapters/oidc/jetty/jetty-core/src/main/java/org/keycloak/adapters/jetty/core/JettyRequestAuthenticator.java index 2d0d2a2c20b..d9e9a393a98 100755 --- a/adapters/oidc/jetty/jetty-core/src/main/java/org/keycloak/adapters/jetty/core/JettyRequestAuthenticator.java +++ b/adapters/oidc/jetty/jetty-core/src/main/java/org/keycloak/adapters/jetty/core/JettyRequestAuthenticator.java @@ -76,7 +76,7 @@ public class JettyRequestAuthenticator extends RequestAuthenticator { @Override - protected String getHttpSessionId(boolean create) { + protected String changeHttpSessionId(boolean create) { HttpSession session = request.getSession(create); return session != null ? session.getId() : null; } diff --git a/adapters/oidc/jetty/jetty9.1/src/main/java/org/keycloak/adapters/jetty/Jetty91RequestAuthenticator.java b/adapters/oidc/jetty/jetty9.1/src/main/java/org/keycloak/adapters/jetty/Jetty91RequestAuthenticator.java new file mode 100755 index 00000000000..cc3395ff838 --- /dev/null +++ b/adapters/oidc/jetty/jetty9.1/src/main/java/org/keycloak/adapters/jetty/Jetty91RequestAuthenticator.java @@ -0,0 +1,30 @@ +package org.keycloak.adapters.jetty; + +import org.eclipse.jetty.server.Request; +import org.keycloak.adapters.AdapterTokenStore; +import org.keycloak.adapters.KeycloakDeployment; +import org.keycloak.adapters.jetty.core.JettyRequestAuthenticator; +import org.keycloak.adapters.spi.HttpFacade; + +import javax.servlet.http.HttpSession; + +/** + * @author Bill Burke + * @version $Revision: 1 $ + */ +public class Jetty91RequestAuthenticator extends JettyRequestAuthenticator { + public Jetty91RequestAuthenticator(HttpFacade facade, KeycloakDeployment deployment, AdapterTokenStore tokenStore, int sslRedirectPort, Request request) { + super(facade, deployment, tokenStore, sslRedirectPort, request); + } + + @Override + protected String changeHttpSessionId(boolean create) { + Request request = this.request; + HttpSession session = request.getSession(false); + if (session == null) { + return request.getSession(true).getId(); + } + if (deployment.isTurnOffChangeSessionIdOnLogin() == false) return request.changeSessionId(); + else return session.getId(); + } +} diff --git a/adapters/oidc/jetty/jetty9.1/src/main/java/org/keycloak/adapters/jetty/KeycloakJettyAuthenticator.java b/adapters/oidc/jetty/jetty9.1/src/main/java/org/keycloak/adapters/jetty/KeycloakJettyAuthenticator.java index a319266ae57..5c7570f5d41 100755 --- a/adapters/oidc/jetty/jetty9.1/src/main/java/org/keycloak/adapters/jetty/KeycloakJettyAuthenticator.java +++ b/adapters/oidc/jetty/jetty9.1/src/main/java/org/keycloak/adapters/jetty/KeycloakJettyAuthenticator.java @@ -7,7 +7,9 @@ import org.eclipse.jetty.server.UserIdentity; import org.keycloak.adapters.AdapterTokenStore; import org.keycloak.adapters.KeycloakDeployment; import org.keycloak.adapters.jetty.core.AbstractKeycloakJettyAuthenticator; +import org.keycloak.adapters.jetty.core.JettyRequestAuthenticator; import org.keycloak.adapters.jetty.core.JettySessionTokenStore; +import org.keycloak.adapters.jetty.spi.JettyHttpFacade; import javax.servlet.ServletRequest; @@ -42,5 +44,12 @@ public class KeycloakJettyAuthenticator extends AbstractKeycloakJettyAuthenticat }; } + @Override + protected JettyRequestAuthenticator createRequestAuthenticator(Request request, JettyHttpFacade facade, + KeycloakDeployment deployment, AdapterTokenStore tokenStore) { + return new Jetty91RequestAuthenticator(facade, deployment, tokenStore, -1, request); + } + + } diff --git a/adapters/oidc/jetty/jetty9.2/src/main/java/org/keycloak/adapters/jetty/Jetty92RequestAuthenticator.java b/adapters/oidc/jetty/jetty9.2/src/main/java/org/keycloak/adapters/jetty/Jetty92RequestAuthenticator.java new file mode 100755 index 00000000000..9c7e127009c --- /dev/null +++ b/adapters/oidc/jetty/jetty9.2/src/main/java/org/keycloak/adapters/jetty/Jetty92RequestAuthenticator.java @@ -0,0 +1,30 @@ +package org.keycloak.adapters.jetty; + +import org.eclipse.jetty.server.Request; +import org.keycloak.adapters.AdapterTokenStore; +import org.keycloak.adapters.KeycloakDeployment; +import org.keycloak.adapters.jetty.core.JettyRequestAuthenticator; +import org.keycloak.adapters.spi.HttpFacade; + +import javax.servlet.http.HttpSession; + +/** + * @author Bill Burke + * @version $Revision: 1 $ + */ +public class Jetty92RequestAuthenticator extends JettyRequestAuthenticator { + public Jetty92RequestAuthenticator(HttpFacade facade, KeycloakDeployment deployment, AdapterTokenStore tokenStore, int sslRedirectPort, Request request) { + super(facade, deployment, tokenStore, sslRedirectPort, request); + } + + @Override + protected String changeHttpSessionId(boolean create) { + Request request = this.request; + HttpSession session = request.getSession(false); + if (session == null) { + return request.getSession(true).getId(); + } + if (deployment.isTurnOffChangeSessionIdOnLogin() == false) return request.changeSessionId(); + else return session.getId(); + } +} diff --git a/adapters/oidc/jetty/jetty9.2/src/main/java/org/keycloak/adapters/jetty/KeycloakJettyAuthenticator.java b/adapters/oidc/jetty/jetty9.2/src/main/java/org/keycloak/adapters/jetty/KeycloakJettyAuthenticator.java index 2aec5ef6fd8..67841c1f773 100755 --- a/adapters/oidc/jetty/jetty9.2/src/main/java/org/keycloak/adapters/jetty/KeycloakJettyAuthenticator.java +++ b/adapters/oidc/jetty/jetty9.2/src/main/java/org/keycloak/adapters/jetty/KeycloakJettyAuthenticator.java @@ -7,7 +7,9 @@ import org.eclipse.jetty.server.UserIdentity; import org.keycloak.adapters.AdapterTokenStore; import org.keycloak.adapters.KeycloakDeployment; import org.keycloak.adapters.jetty.core.AbstractKeycloakJettyAuthenticator; +import org.keycloak.adapters.jetty.core.JettyRequestAuthenticator; import org.keycloak.adapters.jetty.core.JettySessionTokenStore; +import org.keycloak.adapters.jetty.spi.JettyHttpFacade; import javax.servlet.ServletRequest; @@ -41,4 +43,11 @@ public class KeycloakJettyAuthenticator extends AbstractKeycloakJettyAuthenticat public AdapterTokenStore createSessionTokenStore(Request request, KeycloakDeployment resolvedDeployment) { return new JettySessionTokenStore(request, resolvedDeployment, new JettyAdapterSessionStore(request)); } + + @Override + protected JettyRequestAuthenticator createRequestAuthenticator(Request request, JettyHttpFacade facade, + KeycloakDeployment deployment, AdapterTokenStore tokenStore) { + return new Jetty92RequestAuthenticator(facade, deployment, tokenStore, -1, request); + } + } diff --git a/adapters/oidc/jetty/pom.xml b/adapters/oidc/jetty/pom.xml index 86edf07f763..f1cd46b89ce 100755 --- a/adapters/oidc/jetty/pom.xml +++ b/adapters/oidc/jetty/pom.xml @@ -14,7 +14,6 @@ pom - jetty-adapter-spi jetty-core jetty8.1 jetty9.2 diff --git a/adapters/oidc/servlet-filter/src/main/java/org/keycloak/adapters/servlet/FilterRequestAuthenticator.java b/adapters/oidc/servlet-filter/src/main/java/org/keycloak/adapters/servlet/FilterRequestAuthenticator.java index 70cb7e9229c..40672663b58 100755 --- a/adapters/oidc/servlet-filter/src/main/java/org/keycloak/adapters/servlet/FilterRequestAuthenticator.java +++ b/adapters/oidc/servlet-filter/src/main/java/org/keycloak/adapters/servlet/FilterRequestAuthenticator.java @@ -78,7 +78,7 @@ public class FilterRequestAuthenticator extends RequestAuthenticator { } @Override - protected String getHttpSessionId(boolean create) { + protected String changeHttpSessionId(boolean create) { HttpSession session = request.getSession(create); return session != null ? session.getId() : null; } diff --git a/adapters/oidc/spring-security/src/main/java/org/keycloak/adapters/springsecurity/authentication/SpringSecurityRequestAuthenticator.java b/adapters/oidc/spring-security/src/main/java/org/keycloak/adapters/springsecurity/authentication/SpringSecurityRequestAuthenticator.java index 5e1ed058965..fada4555c05 100755 --- a/adapters/oidc/spring-security/src/main/java/org/keycloak/adapters/springsecurity/authentication/SpringSecurityRequestAuthenticator.java +++ b/adapters/oidc/spring-security/src/main/java/org/keycloak/adapters/springsecurity/authentication/SpringSecurityRequestAuthenticator.java @@ -82,7 +82,7 @@ public class SpringSecurityRequestAuthenticator extends RequestAuthenticator { } @Override - protected String getHttpSessionId(boolean create) { + protected String changeHttpSessionId(boolean create) { HttpSession session = request.getSession(create); return session != null ? session.getId() : null; } diff --git a/adapters/oidc/spring-security/src/test/java/org/keycloak/adapters/springsecurity/authentication/SpringSecurityRequestAuthenticatorTest.java b/adapters/oidc/spring-security/src/test/java/org/keycloak/adapters/springsecurity/authentication/SpringSecurityRequestAuthenticatorTest.java index c44610d97bb..89202fbcbcf 100755 --- a/adapters/oidc/spring-security/src/test/java/org/keycloak/adapters/springsecurity/authentication/SpringSecurityRequestAuthenticatorTest.java +++ b/adapters/oidc/spring-security/src/test/java/org/keycloak/adapters/springsecurity/authentication/SpringSecurityRequestAuthenticatorTest.java @@ -95,13 +95,13 @@ public class SpringSecurityRequestAuthenticatorTest { @Test public void testGetHttpSessionIdTrue() throws Exception { - String sessionId = authenticator.getHttpSessionId(true); + String sessionId = authenticator.changeHttpSessionId(true); assertNotNull(sessionId); } @Test public void testGetHttpSessionIdFalse() throws Exception { - String sessionId = authenticator.getHttpSessionId(false); + String sessionId = authenticator.changeHttpSessionId(false); assertNull(sessionId); } } 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 20c87bd4dd1..99ad2a7cbd3 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 @@ -185,7 +185,7 @@ public abstract class AbstractKeycloakAuthenticatorValve extends FormAuthenticat nodesRegistrationManagement.tryRegister(deployment); - CatalinaRequestAuthenticator authenticator = new CatalinaRequestAuthenticator(deployment, tokenStore, facade, request, createPrincipalFactory()); + CatalinaRequestAuthenticator authenticator = createRequestAuthenticator(request, facade, deployment, tokenStore); AuthOutcome outcome = authenticator.authenticate(); if (outcome == AuthOutcome.AUTHENTICATED) { if (facade.isEnded()) { @@ -200,6 +200,10 @@ public abstract class AbstractKeycloakAuthenticatorValve extends FormAuthenticat return false; } + protected CatalinaRequestAuthenticator createRequestAuthenticator(Request request, CatalinaHttpFacade facade, KeycloakDeployment deployment, AdapterTokenStore tokenStore) { + return new CatalinaRequestAuthenticator(deployment, tokenStore, facade, request, createPrincipalFactory()); + } + /** * Checks that access token is still valid. Will attempt refresh of token if it is not. * @@ -230,7 +234,7 @@ public abstract class AbstractKeycloakAuthenticatorValve extends FormAuthenticat } if (resolvedDeployment.getTokenStore() == TokenStore.SESSION) { - store = new CatalinaSessionTokenStore(request, resolvedDeployment, userSessionManagement, createPrincipalFactory(), this); + store = createSessionTokenStore(request, resolvedDeployment); } else { store = new CatalinaCookieTokenStore(request, facade, resolvedDeployment, createPrincipalFactory()); } @@ -239,4 +243,10 @@ public abstract class AbstractKeycloakAuthenticatorValve extends FormAuthenticat return store; } + private AdapterTokenStore createSessionTokenStore(Request request, KeycloakDeployment resolvedDeployment) { + AdapterTokenStore store; + store = new CatalinaSessionTokenStore(request, resolvedDeployment, userSessionManagement, createPrincipalFactory(), this); + return store; + } + } diff --git a/adapters/oidc/tomcat/tomcat-core/src/main/java/org/keycloak/adapters/tomcat/CatalinaRequestAuthenticator.java b/adapters/oidc/tomcat/tomcat-core/src/main/java/org/keycloak/adapters/tomcat/CatalinaRequestAuthenticator.java index 0883c762ef8..6c886208302 100755 --- a/adapters/oidc/tomcat/tomcat-core/src/main/java/org/keycloak/adapters/tomcat/CatalinaRequestAuthenticator.java +++ b/adapters/oidc/tomcat/tomcat-core/src/main/java/org/keycloak/adapters/tomcat/CatalinaRequestAuthenticator.java @@ -83,7 +83,7 @@ public class CatalinaRequestAuthenticator extends RequestAuthenticator { } @Override - protected String getHttpSessionId(boolean create) { + protected String changeHttpSessionId(boolean create) { HttpSession session = request.getSession(create); return session != null ? session.getId() : null; } 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 2e30429916b..e1426dcce80 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 @@ -6,6 +6,8 @@ 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.AdapterTokenStore; +import org.keycloak.adapters.KeycloakDeployment; import javax.servlet.ServletException; import javax.servlet.http.HttpServletResponse; @@ -55,4 +57,5 @@ public class KeycloakAuthenticatorValve extends AbstractKeycloakAuthenticatorVal } }; } + } 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 fa94c34e5d9..4dc19ddf991 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 @@ -5,6 +5,8 @@ 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.AdapterTokenStore; +import org.keycloak.adapters.KeycloakDeployment; import javax.servlet.ServletException; import javax.servlet.http.HttpServletResponse; @@ -51,4 +53,5 @@ public class KeycloakAuthenticatorValve extends AbstractKeycloakAuthenticatorVal } }; } + } 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 eea4f03276b..bd8cee6e796 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 @@ -7,6 +7,9 @@ import org.apache.catalina.core.StandardContext; import org.apache.catalina.realm.GenericPrincipal; import org.apache.tomcat.util.ExceptionUtils; import org.apache.tomcat.util.descriptor.web.LoginConfig; +import org.keycloak.adapters.AdapterTokenStore; +import org.keycloak.adapters.KeycloakDeployment; +import org.keycloak.adapters.spi.HttpFacade; import javax.servlet.RequestDispatcher; import javax.servlet.ServletException; @@ -71,4 +74,9 @@ public class KeycloakAuthenticatorValve extends AbstractKeycloakAuthenticatorVal } }; } + + @Override + protected AdapterTokenStore getTokenStore(Request request, HttpFacade facade, KeycloakDeployment resolvedDeployment) { + return super.getTokenStore(request, facade, resolvedDeployment); + } } diff --git a/adapters/oidc/tomcat/tomcat8/src/main/java/org/keycloak/adapters/tomcat/Tomcat8RequestAuthenticator.java b/adapters/oidc/tomcat/tomcat8/src/main/java/org/keycloak/adapters/tomcat/Tomcat8RequestAuthenticator.java new file mode 100755 index 00000000000..b2211294428 --- /dev/null +++ b/adapters/oidc/tomcat/tomcat8/src/main/java/org/keycloak/adapters/tomcat/Tomcat8RequestAuthenticator.java @@ -0,0 +1,28 @@ +package org.keycloak.adapters.tomcat; + +import org.apache.catalina.connector.Request; +import org.keycloak.adapters.AdapterTokenStore; +import org.keycloak.adapters.KeycloakDeployment; + +import javax.servlet.http.HttpSession; + +/** + * @author Bill Burke + * @version $Revision: 1 $ + */ +public class Tomcat8RequestAuthenticator extends CatalinaRequestAuthenticator { + public Tomcat8RequestAuthenticator(KeycloakDeployment deployment, AdapterTokenStore tokenStore, CatalinaHttpFacade facade, Request request, GenericPrincipalFactory principalFactory) { + super(deployment, tokenStore, facade, request, principalFactory); + } + + @Override + protected String changeHttpSessionId(boolean create) { + Request request = this.request; + HttpSession session = request.getSession(false); + if (session == null) { + return request.getSession(true).getId(); + } + if (deployment.isTurnOffChangeSessionIdOnLogin() == false) return request.changeSessionId(); + else return session.getId(); + } +} diff --git a/adapters/oidc/undertow/src/main/java/org/keycloak/adapters/undertow/AbstractUndertowRequestAuthenticator.java b/adapters/oidc/undertow/src/main/java/org/keycloak/adapters/undertow/AbstractUndertowRequestAuthenticator.java index 18c846c8aa4..ca938bb2c52 100755 --- a/adapters/oidc/undertow/src/main/java/org/keycloak/adapters/undertow/AbstractUndertowRequestAuthenticator.java +++ b/adapters/oidc/undertow/src/main/java/org/keycloak/adapters/undertow/AbstractUndertowRequestAuthenticator.java @@ -72,7 +72,7 @@ public abstract class AbstractUndertowRequestAuthenticator extends RequestAuthen } @Override - protected String getHttpSessionId(boolean create) { + protected String changeHttpSessionId(boolean create) { if (create) { Session session = Sessions.getOrCreateSession(exchange); return session.getId(); diff --git a/adapters/oidc/undertow/src/main/java/org/keycloak/adapters/undertow/KeycloakServletExtension.java b/adapters/oidc/undertow/src/main/java/org/keycloak/adapters/undertow/KeycloakServletExtension.java index 8696a04ddf7..39b4fa7985a 100755 --- a/adapters/oidc/undertow/src/main/java/org/keycloak/adapters/undertow/KeycloakServletExtension.java +++ b/adapters/oidc/undertow/src/main/java/org/keycloak/adapters/undertow/KeycloakServletExtension.java @@ -177,7 +177,7 @@ public class KeycloakServletExtension implements ServletExtension { ServletSessionConfig cookieConfig = new ServletSessionConfig(); cookieConfig.setPath(deploymentInfo.getContextPath()); deploymentInfo.setServletSessionConfig(cookieConfig); - ChangeSessionIdOnLogin.turnOffChangeSessionIdOnLogin(deploymentInfo); + ChangeSessionId.turnOffChangeSessionIdOnLogin(deploymentInfo); deploymentInfo.addListener(new ListenerInfo(UndertowNodesRegistrationManagementWrapper.class, new InstanceFactory() { @Override diff --git a/adapters/oidc/undertow/src/main/java/org/keycloak/adapters/undertow/ServletRequestAuthenticator.java b/adapters/oidc/undertow/src/main/java/org/keycloak/adapters/undertow/ServletRequestAuthenticator.java index 881407d205f..2c288acf605 100755 --- a/adapters/oidc/undertow/src/main/java/org/keycloak/adapters/undertow/ServletRequestAuthenticator.java +++ b/adapters/oidc/undertow/src/main/java/org/keycloak/adapters/undertow/ServletRequestAuthenticator.java @@ -63,6 +63,11 @@ public class ServletRequestAuthenticator extends AbstractUndertowRequestAuthenti } @Override + protected String changeHttpSessionId(boolean create) { + if (deployment.isTurnOffChangeSessionIdOnLogin() == false) return ChangeSessionId.changeSessionId(exchange, create); + else return getHttpSessionId(create); + } + protected String getHttpSessionId(boolean create) { HttpSession session = getSession(create); return session != null ? session.getId() : null; diff --git a/adapters/oidc/wildfly/wf8-subsystem/src/main/java/org/keycloak/subsystem/wf8/extension/SecureDeploymentDefinition.java b/adapters/oidc/wildfly/wf8-subsystem/src/main/java/org/keycloak/subsystem/wf8/extension/SecureDeploymentDefinition.java index d16a25e7f5c..0098a78707e 100755 --- a/adapters/oidc/wildfly/wf8-subsystem/src/main/java/org/keycloak/subsystem/wf8/extension/SecureDeploymentDefinition.java +++ b/adapters/oidc/wildfly/wf8-subsystem/src/main/java/org/keycloak/subsystem/wf8/extension/SecureDeploymentDefinition.java @@ -77,6 +77,12 @@ public class SecureDeploymentDefinition extends SimpleResourceDefinition { .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 List DEPLOYMENT_ONLY_ATTRIBUTES = new ArrayList(); static { @@ -86,6 +92,7 @@ public class SecureDeploymentDefinition extends SimpleResourceDefinition { 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); } protected static final List ALL_ATTRIBUTES = new ArrayList(); diff --git a/adapters/oidc/wildfly/wf8-subsystem/src/main/resources/org/keycloak/subsystem/wf8/extension/LocalDescriptions.properties b/adapters/oidc/wildfly/wf8-subsystem/src/main/resources/org/keycloak/subsystem/wf8/extension/LocalDescriptions.properties index c00bd8d2274..047e3ffa7ee 100755 --- a/adapters/oidc/wildfly/wf8-subsystem/src/main/resources/org/keycloak/subsystem/wf8/extension/LocalDescriptions.properties +++ b/adapters/oidc/wildfly/wf8-subsystem/src/main/resources/org/keycloak/subsystem/wf8/extension/LocalDescriptions.properties @@ -63,6 +63,7 @@ keycloak.secure-deployment.register-node-at-startup=Cluster setting keycloak.secure-deployment.register-node-period=how often to re-register node keycloak.secure-deployment.token-store=cookie or session storage for auth session data keycloak.secure-deployment.principal-attribute=token attribute to use to set Principal name +keycloak.secure-deployment.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-deployment.credential=Credential value diff --git a/adapters/oidc/wildfly/wf8-subsystem/src/main/resources/schema/wildfly-keycloak_1_1.xsd b/adapters/oidc/wildfly/wf8-subsystem/src/main/resources/schema/wildfly-keycloak_1_1.xsd index 75de38ad838..89b37b653dd 100755 --- a/adapters/oidc/wildfly/wf8-subsystem/src/main/resources/schema/wildfly-keycloak_1_1.xsd +++ b/adapters/oidc/wildfly/wf8-subsystem/src/main/resources/schema/wildfly-keycloak_1_1.xsd @@ -87,6 +87,7 @@ + diff --git a/adapters/oidc/wildfly/wf8-subsystem/src/test/resources/org/keycloak/subsystem/wf8/extension/keycloak-1.1.xml b/adapters/oidc/wildfly/wf8-subsystem/src/test/resources/org/keycloak/subsystem/wf8/extension/keycloak-1.1.xml old mode 100644 new mode 100755 index e512f0e85ad..e4e097d2306 --- a/adapters/oidc/wildfly/wf8-subsystem/src/test/resources/org/keycloak/subsystem/wf8/extension/keycloak-1.1.xml +++ b/adapters/oidc/wildfly/wf8-subsystem/src/test/resources/org/keycloak/subsystem/wf8/extension/keycloak-1.1.xml @@ -3,6 +3,7 @@ master web-console true + false MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC4siLKUew0WYxdtq6/rwk4Uj/4amGFFnE/yzIxQVU0PUqz3QBRVkUWpDj0K6ZnS5nzJV/y6DHLEy7hjZTdRDphyF1sq09aDOYnVpzu8o2sIlMM8q5RnUyEfIyUZqwo8pSZDJ90fS0s+IDUJNCSIrAKO3w1lqZDHL6E/YFHXyzkvQIDAQAB diff --git a/adapters/oidc/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/extension/SecureDeploymentDefinition.java b/adapters/oidc/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/extension/SecureDeploymentDefinition.java index 1932cc8e8e2..a09c3b859c4 100755 --- a/adapters/oidc/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/extension/SecureDeploymentDefinition.java +++ b/adapters/oidc/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/extension/SecureDeploymentDefinition.java @@ -77,6 +77,12 @@ public class SecureDeploymentDefinition extends SimpleResourceDefinition { .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 List DEPLOYMENT_ONLY_ATTRIBUTES = new ArrayList(); static { @@ -86,6 +92,7 @@ public class SecureDeploymentDefinition extends SimpleResourceDefinition { 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); } protected static final List ALL_ATTRIBUTES = new ArrayList(); 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 c00bd8d2274..047e3ffa7ee 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 @@ -63,6 +63,7 @@ keycloak.secure-deployment.register-node-at-startup=Cluster setting keycloak.secure-deployment.register-node-period=how often to re-register node keycloak.secure-deployment.token-store=cookie or session storage for auth session data keycloak.secure-deployment.principal-attribute=token attribute to use to set Principal name +keycloak.secure-deployment.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-deployment.credential=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 0abaac18d83..c6298f8fe25 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 @@ -87,6 +87,7 @@ + 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 old mode 100644 new mode 100755 index e512f0e85ad..e4e097d2306 --- 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 @@ -3,6 +3,7 @@ master web-console true + false MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC4siLKUew0WYxdtq6/rwk4Uj/4amGFFnE/yzIxQVU0PUqz3QBRVkUWpDj0K6ZnS5nzJV/y6DHLEy7hjZTdRDphyF1sq09aDOYnVpzu8o2sIlMM8q5RnUyEfIyUZqwo8pSZDJ90fS0s+IDUJNCSIrAKO3w1lqZDHL6E/YFHXyzkvQIDAQAB diff --git a/adapters/saml/core/src/main/java/org/keycloak/adapters/saml/DefaultSamlDeployment.java b/adapters/saml/core/src/main/java/org/keycloak/adapters/saml/DefaultSamlDeployment.java index 7aab09546ba..2c925e02f98 100755 --- a/adapters/saml/core/src/main/java/org/keycloak/adapters/saml/DefaultSamlDeployment.java +++ b/adapters/saml/core/src/main/java/org/keycloak/adapters/saml/DefaultSamlDeployment.java @@ -201,6 +201,7 @@ public class DefaultSamlDeployment implements SamlDeployment { private String nameIDPolicyFormat; private boolean forceAuthentication; private boolean isPassive; + private boolean turnOffChangeSessionIdOnLogin; private PrivateKey decryptionKey; private KeyPair signingKeyPair; private String assertionConsumerServiceUrl; @@ -211,6 +212,16 @@ public class DefaultSamlDeployment implements SamlDeployment { private SignatureAlgorithm signatureAlgorithm; private String signatureCanonicalizationMethod; + @Override + public boolean turnOffChangeSessionIdOnLogin() { + return turnOffChangeSessionIdOnLogin; + } + + public void setTurnOffChangeSessionIdOnLogin(boolean turnOffChangeSessionIdOnLogin) { + this.turnOffChangeSessionIdOnLogin = turnOffChangeSessionIdOnLogin; + } + + @Override public IDP getIDP() { return idp; diff --git a/adapters/saml/core/src/main/java/org/keycloak/adapters/saml/SamlDeployment.java b/adapters/saml/core/src/main/java/org/keycloak/adapters/saml/SamlDeployment.java index 8c532366031..14ce5a354ed 100755 --- a/adapters/saml/core/src/main/java/org/keycloak/adapters/saml/SamlDeployment.java +++ b/adapters/saml/core/src/main/java/org/keycloak/adapters/saml/SamlDeployment.java @@ -57,6 +57,7 @@ public interface SamlDeployment { String getNameIDPolicyFormat(); boolean isForceAuthentication(); boolean isIsPassive(); + boolean turnOffChangeSessionIdOnLogin(); PrivateKey getDecryptionKey(); KeyPair getSigningKeyPair(); String getSignatureCanonicalizationMethod(); diff --git a/adapters/saml/core/src/main/java/org/keycloak/adapters/saml/config/SP.java b/adapters/saml/core/src/main/java/org/keycloak/adapters/saml/config/SP.java index 5203b13c231..17c8343244e 100755 --- a/adapters/saml/core/src/main/java/org/keycloak/adapters/saml/config/SP.java +++ b/adapters/saml/core/src/main/java/org/keycloak/adapters/saml/config/SP.java @@ -34,6 +34,7 @@ public class SP implements Serializable { private String sslPolicy; private boolean forceAuthentication; private boolean isPassive; + private boolean turnOffChangeSessionIdOnLogin; private String logoutPage; private List keys; private String nameIDPolicyFormat; @@ -73,6 +74,14 @@ public class SP implements Serializable { this.isPassive = isPassive; } + public boolean isTurnOffChangeSessionIdOnLogin() { + return turnOffChangeSessionIdOnLogin; + } + + public void setTurnOffChangeSessionIdOnLogin(boolean turnOffChangeSessionIdOnLogin) { + this.turnOffChangeSessionIdOnLogin = turnOffChangeSessionIdOnLogin; + } + public List getKeys() { return keys; } diff --git a/adapters/saml/core/src/main/java/org/keycloak/adapters/saml/config/parsers/ConfigXmlConstants.java b/adapters/saml/core/src/main/java/org/keycloak/adapters/saml/config/parsers/ConfigXmlConstants.java index 91a016c65fe..87069c39da8 100755 --- a/adapters/saml/core/src/main/java/org/keycloak/adapters/saml/config/parsers/ConfigXmlConstants.java +++ b/adapters/saml/core/src/main/java/org/keycloak/adapters/saml/config/parsers/ConfigXmlConstants.java @@ -12,6 +12,7 @@ public class ConfigXmlConstants { public static final String NAME_ID_POLICY_FORMAT_ATTR = "nameIDPolicyFormat"; public static final String FORCE_AUTHENTICATION_ATTR = "forceAuthentication"; public static final String IS_PASSIVE_ATTR = "isPassive"; + public static final String TURN_OFF_CHANGE_SESSSION_ID_ON_LOGIN_ATTR = "turnOffChangeSessionIdOnLogin"; public static final String SIGNATURE_ALGORITHM_ATTR = "signatureAlgorithm"; public static final String SIGNATURE_CANONICALIZATION_METHOD_ATTR = "signatureCanonicalizationMethod"; public static final String LOGOUT_PAGE_ATTR = "logoutPage"; diff --git a/adapters/saml/core/src/main/java/org/keycloak/adapters/saml/config/parsers/SPXmlParser.java b/adapters/saml/core/src/main/java/org/keycloak/adapters/saml/config/parsers/SPXmlParser.java index 14b04e1110d..7d6d57af7d7 100755 --- a/adapters/saml/core/src/main/java/org/keycloak/adapters/saml/config/parsers/SPXmlParser.java +++ b/adapters/saml/core/src/main/java/org/keycloak/adapters/saml/config/parsers/SPXmlParser.java @@ -66,6 +66,7 @@ public class SPXmlParser extends AbstractParser { sp.setNameIDPolicyFormat(getAttributeValue(startElement, ConfigXmlConstants.NAME_ID_POLICY_FORMAT_ATTR)); sp.setForceAuthentication(getBooleanAttributeValue(startElement, ConfigXmlConstants.FORCE_AUTHENTICATION_ATTR)); sp.setIsPassive(getBooleanAttributeValue(startElement, ConfigXmlConstants.IS_PASSIVE_ATTR)); + sp.setTurnOffChangeSessionIdOnLogin(getBooleanAttributeValue(startElement, ConfigXmlConstants.TURN_OFF_CHANGE_SESSSION_ID_ON_LOGIN_ATTR)); while (xmlEventReader.hasNext()) { XMLEvent xmlEvent = StaxParserUtil.peek(xmlEventReader); if (xmlEvent == null) diff --git a/adapters/saml/core/src/main/resources/schema/keycloak_saml_adapter_1_6.xsd b/adapters/saml/core/src/main/resources/schema/keycloak_saml_adapter_1_6.xsd index d3e55f9dc14..1f8b26b57da 100755 --- a/adapters/saml/core/src/main/resources/schema/keycloak_saml_adapter_1_6.xsd +++ b/adapters/saml/core/src/main/resources/schema/keycloak_saml_adapter_1_6.xsd @@ -34,6 +34,7 @@ + diff --git a/adapters/saml/jetty/jetty-core/src/main/java/org/keycloak/adapters/saml/jetty/AbstractSamlAuthenticator.java b/adapters/saml/jetty/jetty-core/src/main/java/org/keycloak/adapters/saml/jetty/AbstractSamlAuthenticator.java index 2df0fad9883..5028542766b 100755 --- a/adapters/saml/jetty/jetty-core/src/main/java/org/keycloak/adapters/saml/jetty/AbstractSamlAuthenticator.java +++ b/adapters/saml/jetty/jetty-core/src/main/java/org/keycloak/adapters/saml/jetty/AbstractSamlAuthenticator.java @@ -75,12 +75,18 @@ public abstract class AbstractSamlAuthenticator extends LoginAuthenticator { if (store != null) { return store; } - store = new JettySamlSessionStore(request, createSessionTokenStore(request, resolvedDeployment), facade, idMapper, new JettyUserSessionManagement(request.getSessionManager())); + store = createJettySamlSessionStore(request, facade, resolvedDeployment); request.setAttribute(TOKEN_STORE_NOTE, store); return store; } + protected JettySamlSessionStore createJettySamlSessionStore(Request request, HttpFacade facade, SamlDeployment resolvedDeployment) { + JettySamlSessionStore store; + store = new JettySamlSessionStore(request, createSessionTokenStore(request, resolvedDeployment), facade, idMapper, new JettyUserSessionManagement(request.getSessionManager()), resolvedDeployment); + return store; + } + public abstract AdapterSessionStore createSessionTokenStore(Request request, SamlDeployment resolvedDeployment); public void logoutCurrent(Request request) { diff --git a/adapters/saml/jetty/jetty-core/src/main/java/org/keycloak/adapters/saml/jetty/JettySamlSessionStore.java b/adapters/saml/jetty/jetty-core/src/main/java/org/keycloak/adapters/saml/jetty/JettySamlSessionStore.java index 6e51f110f8b..380066e36c0 100755 --- a/adapters/saml/jetty/jetty-core/src/main/java/org/keycloak/adapters/saml/jetty/JettySamlSessionStore.java +++ b/adapters/saml/jetty/jetty-core/src/main/java/org/keycloak/adapters/saml/jetty/JettySamlSessionStore.java @@ -2,6 +2,7 @@ package org.keycloak.adapters.saml.jetty; import org.eclipse.jetty.server.Request; import org.jboss.logging.Logger; +import org.keycloak.adapters.saml.SamlDeployment; import org.keycloak.adapters.spi.AdapterSessionStore; import org.keycloak.adapters.spi.HttpFacade; import org.keycloak.adapters.spi.SessionIdMapper; @@ -23,19 +24,21 @@ import java.util.Set; public class JettySamlSessionStore implements SamlSessionStore { public static final String SAML_REDIRECT_URI = "SAML_REDIRECT_URI"; private static final Logger log = Logger.getLogger(JettySamlSessionStore.class); - private Request request; + protected Request request; protected AdapterSessionStore sessionStore; protected HttpFacade facade; protected SessionIdMapper idMapper; protected JettyUserSessionManagement sessionManagement; + protected final SamlDeployment deployment; public JettySamlSessionStore(Request request, AdapterSessionStore sessionStore, HttpFacade facade, - SessionIdMapper idMapper, JettyUserSessionManagement sessionManagement) { + SessionIdMapper idMapper, JettyUserSessionManagement sessionManagement, SamlDeployment deployment) { this.request = request; this.sessionStore = sessionStore; this.facade = facade; this.idMapper = idMapper; this.sessionManagement = sessionManagement; + this.deployment = deployment; } @Override @@ -132,10 +135,14 @@ public class JettySamlSessionStore implements SamlSessionStore { HttpSession session = request.getSession(true); session.setAttribute(SamlSession.class.getName(), account); - idMapper.map(account.getSessionIndex(), account.getPrincipal().getSamlSubject(), session.getId()); + idMapper.map(account.getSessionIndex(), account.getPrincipal().getSamlSubject(), changeSessionId(session)); } + protected String changeSessionId(HttpSession session) { + return session.getId(); + } + @Override public SamlSession getAccount() { HttpSession session = request.getSession(true); diff --git a/adapters/saml/jetty/jetty9.1/src/main/java/org/keycloak/adapters/saml/jetty/Jetty9SamlSessionStore.java b/adapters/saml/jetty/jetty9.1/src/main/java/org/keycloak/adapters/saml/jetty/Jetty9SamlSessionStore.java new file mode 100755 index 00000000000..56a26ca83f7 --- /dev/null +++ b/adapters/saml/jetty/jetty9.1/src/main/java/org/keycloak/adapters/saml/jetty/Jetty9SamlSessionStore.java @@ -0,0 +1,27 @@ +package org.keycloak.adapters.saml.jetty; + +import org.eclipse.jetty.server.Request; +import org.keycloak.adapters.jetty.spi.JettyUserSessionManagement; +import org.keycloak.adapters.saml.SamlDeployment; +import org.keycloak.adapters.spi.AdapterSessionStore; +import org.keycloak.adapters.spi.HttpFacade; +import org.keycloak.adapters.spi.SessionIdMapper; + +import javax.servlet.http.HttpSession; + +/** + * @author Bill Burke + * @version $Revision: 1 $ + */ +public class Jetty9SamlSessionStore extends JettySamlSessionStore { + public Jetty9SamlSessionStore(Request request, AdapterSessionStore sessionStore, HttpFacade facade, SessionIdMapper idMapper, JettyUserSessionManagement sessionManagement, SamlDeployment deployment) { + super(request, sessionStore, facade, idMapper, sessionManagement, deployment); + } + + @Override + protected String changeSessionId(HttpSession session) { + Request request = this.request; + if (deployment.turnOffChangeSessionIdOnLogin() == false) return request.changeSessionId(); + else return session.getId(); + } +} diff --git a/adapters/saml/jetty/jetty9.1/src/main/java/org/keycloak/adapters/saml/jetty/KeycloakSamlAuthenticator.java b/adapters/saml/jetty/jetty9.1/src/main/java/org/keycloak/adapters/saml/jetty/KeycloakSamlAuthenticator.java index f5fdf7d8076..238c84b6e2f 100755 --- a/adapters/saml/jetty/jetty9.1/src/main/java/org/keycloak/adapters/saml/jetty/KeycloakSamlAuthenticator.java +++ b/adapters/saml/jetty/jetty9.1/src/main/java/org/keycloak/adapters/saml/jetty/KeycloakSamlAuthenticator.java @@ -4,8 +4,10 @@ import org.eclipse.jetty.server.Authentication; import org.eclipse.jetty.server.HttpChannel; import org.eclipse.jetty.server.Request; import org.eclipse.jetty.server.UserIdentity; +import org.keycloak.adapters.jetty.spi.JettyUserSessionManagement; import org.keycloak.adapters.spi.AdapterSessionStore; import org.keycloak.adapters.saml.SamlDeployment; +import org.keycloak.adapters.spi.HttpFacade; import javax.servlet.ServletRequest; @@ -40,5 +42,13 @@ public class KeycloakSamlAuthenticator extends AbstractSamlAuthenticator { }; } + @Override + protected JettySamlSessionStore createJettySamlSessionStore(Request request, HttpFacade facade, SamlDeployment resolvedDeployment) { + JettySamlSessionStore store; + store = new Jetty9SamlSessionStore(request, createSessionTokenStore(request, resolvedDeployment), facade, idMapper, new JettyUserSessionManagement(request.getSessionManager()), resolvedDeployment); + return store; + } + + } diff --git a/adapters/saml/jetty/jetty9.2/src/main/java/org/keycloak/adapters/saml/jetty/Jetty9SamlSessionStore.java b/adapters/saml/jetty/jetty9.2/src/main/java/org/keycloak/adapters/saml/jetty/Jetty9SamlSessionStore.java new file mode 100755 index 00000000000..56a26ca83f7 --- /dev/null +++ b/adapters/saml/jetty/jetty9.2/src/main/java/org/keycloak/adapters/saml/jetty/Jetty9SamlSessionStore.java @@ -0,0 +1,27 @@ +package org.keycloak.adapters.saml.jetty; + +import org.eclipse.jetty.server.Request; +import org.keycloak.adapters.jetty.spi.JettyUserSessionManagement; +import org.keycloak.adapters.saml.SamlDeployment; +import org.keycloak.adapters.spi.AdapterSessionStore; +import org.keycloak.adapters.spi.HttpFacade; +import org.keycloak.adapters.spi.SessionIdMapper; + +import javax.servlet.http.HttpSession; + +/** + * @author Bill Burke + * @version $Revision: 1 $ + */ +public class Jetty9SamlSessionStore extends JettySamlSessionStore { + public Jetty9SamlSessionStore(Request request, AdapterSessionStore sessionStore, HttpFacade facade, SessionIdMapper idMapper, JettyUserSessionManagement sessionManagement, SamlDeployment deployment) { + super(request, sessionStore, facade, idMapper, sessionManagement, deployment); + } + + @Override + protected String changeSessionId(HttpSession session) { + Request request = this.request; + if (deployment.turnOffChangeSessionIdOnLogin() == false) return request.changeSessionId(); + else return session.getId(); + } +} diff --git a/adapters/saml/jetty/jetty9.2/src/main/java/org/keycloak/adapters/saml/jetty/KeycloakSamlAuthenticator.java b/adapters/saml/jetty/jetty9.2/src/main/java/org/keycloak/adapters/saml/jetty/KeycloakSamlAuthenticator.java index 03ea508646c..fa802ba2c66 100755 --- a/adapters/saml/jetty/jetty9.2/src/main/java/org/keycloak/adapters/saml/jetty/KeycloakSamlAuthenticator.java +++ b/adapters/saml/jetty/jetty9.2/src/main/java/org/keycloak/adapters/saml/jetty/KeycloakSamlAuthenticator.java @@ -4,8 +4,10 @@ import org.eclipse.jetty.server.Authentication; import org.eclipse.jetty.server.HttpChannel; import org.eclipse.jetty.server.Request; import org.eclipse.jetty.server.UserIdentity; +import org.keycloak.adapters.jetty.spi.JettyUserSessionManagement; import org.keycloak.adapters.spi.AdapterSessionStore; import org.keycloak.adapters.saml.SamlDeployment; +import org.keycloak.adapters.spi.HttpFacade; import javax.servlet.ServletRequest; @@ -39,4 +41,11 @@ public class KeycloakSamlAuthenticator extends AbstractSamlAuthenticator { public AdapterSessionStore createSessionTokenStore(Request request, SamlDeployment resolvedDeployment) { return new JettyAdapterSessionStore(request); } + + @Override + protected JettySamlSessionStore createJettySamlSessionStore(Request request, HttpFacade facade, SamlDeployment resolvedDeployment) { + JettySamlSessionStore store; + store = new Jetty9SamlSessionStore(request, createSessionTokenStore(request, resolvedDeployment), facade, idMapper, new JettyUserSessionManagement(request.getSessionManager()), resolvedDeployment); + return store; + } } diff --git a/adapters/saml/tomcat/tomcat-core/src/main/java/org/keycloak/adapters/saml/AbstractSamlAuthenticatorValve.java b/adapters/saml/tomcat/tomcat-core/src/main/java/org/keycloak/adapters/saml/AbstractSamlAuthenticatorValve.java index 3119ba7c9e3..3ec5a8f88c2 100755 --- a/adapters/saml/tomcat/tomcat-core/src/main/java/org/keycloak/adapters/saml/AbstractSamlAuthenticatorValve.java +++ b/adapters/saml/tomcat/tomcat-core/src/main/java/org/keycloak/adapters/saml/AbstractSamlAuthenticatorValve.java @@ -61,7 +61,7 @@ public abstract class AbstractSamlAuthenticatorValve extends FormAuthenticator i protected void logoutInternal(Request request) { CatalinaHttpFacade facade = new CatalinaHttpFacade(null, request); SamlDeployment deployment = deploymentContext.resolveDeployment(facade); - SamlSessionStore tokenStore = getTokenStore(request, facade, deployment); + SamlSessionStore tokenStore = getSessionStore(request, facade, deployment); tokenStore.logoutAccount(); request.setUserPrincipal(null); } @@ -184,7 +184,7 @@ public abstract class AbstractSamlAuthenticatorValve extends FormAuthenticator i log.fine("deployment not configured"); return false; } - SamlSessionStore tokenStore = getTokenStore(request, facade, deployment); + SamlSessionStore tokenStore = getSessionStore(request, facade, deployment); CatalinaSamlAuthenticator authenticator = new CatalinaSamlAuthenticator(facade, deployment, tokenStore); @@ -229,16 +229,22 @@ public abstract class AbstractSamlAuthenticatorValve extends FormAuthenticator i } } - protected SamlSessionStore getTokenStore(Request request, HttpFacade facade, SamlDeployment resolvedDeployment) { + protected SamlSessionStore getSessionStore(Request request, HttpFacade facade, SamlDeployment resolvedDeployment) { SamlSessionStore store = (SamlSessionStore)request.getNote(TOKEN_STORE_NOTE); if (store != null) { return store; } - store = new CatalinaSamlSessionStore(userSessionManagement, createPrincipalFactory(), mapper, request, this, facade); + store = createSessionStore(request, facade, resolvedDeployment); request.setNote(TOKEN_STORE_NOTE, store); return store; } + protected SamlSessionStore createSessionStore(Request request, HttpFacade facade, SamlDeployment resolvedDeployment) { + SamlSessionStore store; + store = new CatalinaSamlSessionStore(userSessionManagement, createPrincipalFactory(), mapper, request, this, facade, resolvedDeployment); + return store; + } + } diff --git a/adapters/saml/tomcat/tomcat-core/src/main/java/org/keycloak/adapters/saml/CatalinaSamlSessionStore.java b/adapters/saml/tomcat/tomcat-core/src/main/java/org/keycloak/adapters/saml/CatalinaSamlSessionStore.java index 804acf36e16..340c8113e35 100755 --- a/adapters/saml/tomcat/tomcat-core/src/main/java/org/keycloak/adapters/saml/CatalinaSamlSessionStore.java +++ b/adapters/saml/tomcat/tomcat-core/src/main/java/org/keycloak/adapters/saml/CatalinaSamlSessionStore.java @@ -32,15 +32,18 @@ public class CatalinaSamlSessionStore implements SamlSessionStore { protected final Request request; protected final AbstractSamlAuthenticatorValve valve; protected final HttpFacade facade; + protected final SamlDeployment deployment; public CatalinaSamlSessionStore(CatalinaUserSessionManagement sessionManagement, GenericPrincipalFactory principalFactory, - SessionIdMapper idMapper, Request request, AbstractSamlAuthenticatorValve valve, HttpFacade facade) { + SessionIdMapper idMapper, Request request, AbstractSamlAuthenticatorValve valve, HttpFacade facade, + SamlDeployment deployment) { this.sessionManagement = sessionManagement; this.principalFactory = principalFactory; this.idMapper = idMapper; this.request = request; this.valve = valve; this.facade = facade; + this.deployment = deployment; } @Override @@ -173,10 +176,15 @@ public class CatalinaSamlSessionStore implements SamlSessionStore { } request.setUserPrincipal(principal); request.setAuthType("KEYCLOAK-SAML"); - idMapper.map(account.getSessionIndex(), account.getPrincipal().getSamlSubject(), session.getId()); + String newId = changeSessionId(session); + idMapper.map(account.getSessionIndex(), account.getPrincipal().getSamlSubject(), newId); } + protected String changeSessionId(Session session) { + return session.getId(); + } + @Override public SamlSession getAccount() { HttpSession session = getSession(true); diff --git a/adapters/saml/tomcat/tomcat8/src/main/java/org/keycloak/adapters/saml/tomcat/SamlAuthenticatorValve.java b/adapters/saml/tomcat/tomcat8/src/main/java/org/keycloak/adapters/saml/tomcat/SamlAuthenticatorValve.java index ead126a913c..7be5b69f3fc 100755 --- a/adapters/saml/tomcat/tomcat8/src/main/java/org/keycloak/adapters/saml/tomcat/SamlAuthenticatorValve.java +++ b/adapters/saml/tomcat/tomcat8/src/main/java/org/keycloak/adapters/saml/tomcat/SamlAuthenticatorValve.java @@ -6,6 +6,10 @@ import org.apache.catalina.core.StandardContext; import org.apache.catalina.realm.GenericPrincipal; import org.apache.tomcat.util.descriptor.web.LoginConfig; import org.keycloak.adapters.saml.AbstractSamlAuthenticatorValve; +import org.keycloak.adapters.saml.CatalinaSamlSessionStore; +import org.keycloak.adapters.saml.SamlDeployment; +import org.keycloak.adapters.saml.SamlSessionStore; +import org.keycloak.adapters.spi.HttpFacade; import org.keycloak.adapters.tomcat.GenericPrincipalFactory; import javax.servlet.http.HttpServletResponse; @@ -68,4 +72,12 @@ public class SamlAuthenticatorValve extends AbstractSamlAuthenticatorValve { } }; } + + @Override + protected SamlSessionStore createSessionStore(Request request, HttpFacade facade, SamlDeployment resolvedDeployment) { + SamlSessionStore store; + store = new Tomcat8SamlSessionStore(userSessionManagement, createPrincipalFactory(), mapper, request, this, facade, resolvedDeployment); + return store; + } + } diff --git a/adapters/saml/tomcat/tomcat8/src/main/java/org/keycloak/adapters/saml/tomcat/Tomcat8SamlSessionStore.java b/adapters/saml/tomcat/tomcat8/src/main/java/org/keycloak/adapters/saml/tomcat/Tomcat8SamlSessionStore.java new file mode 100755 index 00000000000..4bd9cfaabc3 --- /dev/null +++ b/adapters/saml/tomcat/tomcat8/src/main/java/org/keycloak/adapters/saml/tomcat/Tomcat8SamlSessionStore.java @@ -0,0 +1,28 @@ +package org.keycloak.adapters.saml.tomcat; + +import org.apache.catalina.Session; +import org.apache.catalina.connector.Request; +import org.keycloak.adapters.saml.AbstractSamlAuthenticatorValve; +import org.keycloak.adapters.saml.CatalinaSamlSessionStore; +import org.keycloak.adapters.saml.SamlDeployment; +import org.keycloak.adapters.spi.HttpFacade; +import org.keycloak.adapters.spi.SessionIdMapper; +import org.keycloak.adapters.tomcat.CatalinaUserSessionManagement; +import org.keycloak.adapters.tomcat.GenericPrincipalFactory; + +/** + * @author Bill Burke + * @version $Revision: 1 $ + */ +public class Tomcat8SamlSessionStore extends CatalinaSamlSessionStore { + public Tomcat8SamlSessionStore(CatalinaUserSessionManagement sessionManagement, GenericPrincipalFactory principalFactory, SessionIdMapper idMapper, Request request, AbstractSamlAuthenticatorValve valve, HttpFacade facade, SamlDeployment deployment) { + super(sessionManagement, principalFactory, idMapper, request, valve, facade, deployment); + } + + @Override + protected String changeSessionId(Session session) { + Request request = this.request; + if (deployment.turnOffChangeSessionIdOnLogin() == false) return request.changeSessionId(); + else return session.getId(); + } +} diff --git a/adapters/saml/undertow/src/main/java/org/keycloak/adapters/saml/undertow/SamlServletExtension.java b/adapters/saml/undertow/src/main/java/org/keycloak/adapters/saml/undertow/SamlServletExtension.java index 589835dd9b7..a7abb47b4ab 100755 --- a/adapters/saml/undertow/src/main/java/org/keycloak/adapters/saml/undertow/SamlServletExtension.java +++ b/adapters/saml/undertow/src/main/java/org/keycloak/adapters/saml/undertow/SamlServletExtension.java @@ -35,7 +35,7 @@ import org.keycloak.adapters.saml.SamlDeployment; import org.keycloak.adapters.saml.SamlDeploymentContext; import org.keycloak.adapters.saml.config.parsers.DeploymentBuilder; import org.keycloak.adapters.saml.config.parsers.ResourceLoader; -import org.keycloak.adapters.undertow.ChangeSessionIdOnLogin; +import org.keycloak.adapters.undertow.ChangeSessionId; import org.keycloak.adapters.undertow.UndertowUserSessionManagement; import org.keycloak.saml.common.exceptions.ParsingException; @@ -184,7 +184,7 @@ public class SamlServletExtension implements ServletExtension { ServletSessionConfig cookieConfig = new ServletSessionConfig(); cookieConfig.setPath(deploymentInfo.getContextPath()); deploymentInfo.setServletSessionConfig(cookieConfig); - ChangeSessionIdOnLogin.turnOffChangeSessionIdOnLogin(deploymentInfo); + ChangeSessionId.turnOffChangeSessionIdOnLogin(deploymentInfo); } diff --git a/adapters/saml/undertow/src/main/java/org/keycloak/adapters/saml/undertow/ServletSamlAuthMech.java b/adapters/saml/undertow/src/main/java/org/keycloak/adapters/saml/undertow/ServletSamlAuthMech.java index 9fe9085d06a..491e35e2686 100755 --- a/adapters/saml/undertow/src/main/java/org/keycloak/adapters/saml/undertow/ServletSamlAuthMech.java +++ b/adapters/saml/undertow/src/main/java/org/keycloak/adapters/saml/undertow/ServletSamlAuthMech.java @@ -32,7 +32,7 @@ public class ServletSamlAuthMech extends AbstractSamlAuthMech { @Override protected SamlSessionStore getTokenStore(HttpServerExchange exchange, HttpFacade facade, SamlDeployment deployment, SecurityContext securityContext) { - return new ServletSamlSessionStore(exchange, sessionManagement, securityContext, idMapper); + return new ServletSamlSessionStore(exchange, sessionManagement, securityContext, idMapper, deployment); } @Override 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 d9885d83f7a..cd6f217638d 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 @@ -7,9 +7,11 @@ import io.undertow.server.session.SessionManager; import io.undertow.servlet.handlers.ServletRequestContext; import io.undertow.servlet.spec.HttpSessionImpl; import org.jboss.logging.Logger; +import org.keycloak.adapters.saml.SamlDeployment; import org.keycloak.adapters.spi.SessionIdMapper; import org.keycloak.adapters.saml.SamlSession; import org.keycloak.adapters.saml.SamlSessionStore; +import org.keycloak.adapters.undertow.ChangeSessionId; import org.keycloak.adapters.undertow.SavedRequest; import org.keycloak.adapters.undertow.UndertowUserSessionManagement; import org.keycloak.common.util.KeycloakUriBuilder; @@ -36,15 +38,17 @@ public class ServletSamlSessionStore implements SamlSessionStore { private final UndertowUserSessionManagement sessionManagement; private final SecurityContext securityContext; private final SessionIdMapper idMapper; + protected final SamlDeployment deployment; public ServletSamlSessionStore(HttpServerExchange exchange, UndertowUserSessionManagement sessionManagement, SecurityContext securityContext, - SessionIdMapper idMapper) { + SessionIdMapper idMapper, SamlDeployment deployment) { this.exchange = exchange; this.sessionManagement = sessionManagement; this.securityContext = securityContext; this.idMapper = idMapper; + this.deployment = deployment; } @Override @@ -155,10 +159,16 @@ public class ServletSamlSessionStore implements SamlSessionStore { HttpSession session = getSession(true); session.setAttribute(SamlSession.class.getName(), account); sessionManagement.login(servletRequestContext.getDeployment().getSessionManager()); - idMapper.map(account.getSessionIndex(), account.getPrincipal().getSamlSubject(), session.getId()); + String sessionId = changeSessionId(session); + idMapper.map(account.getSessionIndex(), account.getPrincipal().getSamlSubject(), sessionId); } + protected String changeSessionId(HttpSession session) { + if (deployment.turnOffChangeSessionIdOnLogin() == false) return ChangeSessionId.changeSessionId(exchange, false); + else return session.getId(); + } + @Override public SamlSession getAccount() { HttpSession session = getSession(true); diff --git a/adapters/saml/wildfly/wildfly-adapter/src/main/java/org/keycloak/adapters/saml/wildfly/WildflySamlAuthMech.java b/adapters/saml/wildfly/wildfly-adapter/src/main/java/org/keycloak/adapters/saml/wildfly/WildflySamlAuthMech.java index e5322330922..46b82af734b 100755 --- a/adapters/saml/wildfly/wildfly-adapter/src/main/java/org/keycloak/adapters/saml/wildfly/WildflySamlAuthMech.java +++ b/adapters/saml/wildfly/wildfly-adapter/src/main/java/org/keycloak/adapters/saml/wildfly/WildflySamlAuthMech.java @@ -20,6 +20,6 @@ public class WildflySamlAuthMech extends ServletSamlAuthMech { @Override protected SamlSessionStore getTokenStore(HttpServerExchange exchange, HttpFacade facade, SamlDeployment deployment, SecurityContext securityContext) { - return new WildflySamlSessionStore(exchange, sessionManagement, securityContext, idMapper); + return new WildflySamlSessionStore(exchange, sessionManagement, securityContext, idMapper, deployment); } } diff --git a/adapters/saml/wildfly/wildfly-adapter/src/main/java/org/keycloak/adapters/saml/wildfly/WildflySamlSessionStore.java b/adapters/saml/wildfly/wildfly-adapter/src/main/java/org/keycloak/adapters/saml/wildfly/WildflySamlSessionStore.java index 45513337a49..8d038afbdb8 100755 --- a/adapters/saml/wildfly/wildfly-adapter/src/main/java/org/keycloak/adapters/saml/wildfly/WildflySamlSessionStore.java +++ b/adapters/saml/wildfly/wildfly-adapter/src/main/java/org/keycloak/adapters/saml/wildfly/WildflySamlSessionStore.java @@ -2,6 +2,7 @@ package org.keycloak.adapters.saml.wildfly; import io.undertow.security.api.SecurityContext; import io.undertow.server.HttpServerExchange; +import org.keycloak.adapters.saml.SamlDeployment; import org.keycloak.adapters.spi.SessionIdMapper; import org.keycloak.adapters.saml.SamlSession; import org.keycloak.adapters.saml.undertow.ServletSamlSessionStore; @@ -13,8 +14,8 @@ import org.keycloak.adapters.undertow.UndertowUserSessionManagement; */ public class WildflySamlSessionStore extends ServletSamlSessionStore { public WildflySamlSessionStore(HttpServerExchange exchange, UndertowUserSessionManagement sessionManagement, - SecurityContext securityContext, SessionIdMapper idMapper) { - super(exchange, sessionManagement, securityContext, idMapper); + SecurityContext securityContext, SessionIdMapper idMapper, SamlDeployment resolvedDeployment) { + super(exchange, sessionManagement, securityContext, idMapper, resolvedDeployment); } @Override diff --git a/adapters/saml/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/saml/extension/Constants.java b/adapters/saml/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/saml/extension/Constants.java old mode 100644 new mode 100755 index 9b89fb2c80d..14518f687e1 --- a/adapters/saml/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/saml/extension/Constants.java +++ b/adapters/saml/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/saml/extension/Constants.java @@ -30,6 +30,8 @@ public class Constants { static final String NAME_ID_POLICY_FORMAT = "name-id-policy-format"; static final String LOGOUT_PAGE = "logout-page"; static final String FORCE_AUTHENTICATION = "force-authentication"; + static final String IS_PASSIVE = "isPassive"; + static final String TURN_OFF_CHANGE_SESSSION_ID_ON_LOGIN = "turnOffChangeSessionIdOnLogin"; static final String ROLE_ATTRIBUTES = "role-attributes"; static final String SIGNING = "signing"; static final String ENCRYPTION = "encryption"; @@ -87,6 +89,8 @@ public class Constants { static final String KEY_STORE = "KeyStore"; static final String PRIVATE_KEY = "PrivateKey"; static final String CERTIFICATE = "Certificate"; + static final String IS_PASSIVE = "isPassive"; + static final String TURN_OFF_CHANGE_SESSSION_ID_ON_LOGIN = "turnOffChangeSessionIdOnLogin"; static final String PRIVATE_KEY_ALIAS = "alias"; static final String PRIVATE_KEY_PASSWORD = "password"; diff --git a/adapters/saml/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/saml/extension/ServiceProviderDefinition.java b/adapters/saml/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/saml/extension/ServiceProviderDefinition.java old mode 100644 new mode 100755 index cb84f1253da..56abc848140 --- a/adapters/saml/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/saml/extension/ServiceProviderDefinition.java +++ b/adapters/saml/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/saml/extension/ServiceProviderDefinition.java @@ -59,6 +59,15 @@ public class ServiceProviderDefinition extends SimpleResourceDefinition { .setXmlName(Constants.XML.FORCE_AUTHENTICATION) .build(); + static final SimpleAttributeDefinition IS_PASSIVE = + new SimpleAttributeDefinitionBuilder(Constants.Model.IS_PASSIVE, ModelType.BOOLEAN, true) + .setXmlName(Constants.XML.IS_PASSIVE) + .build(); + static final SimpleAttributeDefinition TURN_OFF_CHANGE_SESSSION_ID_ON_LOGIN = + new SimpleAttributeDefinitionBuilder(Constants.Model.TURN_OFF_CHANGE_SESSSION_ID_ON_LOGIN, ModelType.BOOLEAN, true) + .setXmlName(Constants.XML.TURN_OFF_CHANGE_SESSSION_ID_ON_LOGIN) + .build(); + static final SimpleAttributeDefinition PRINCIPAL_NAME_MAPPING_POLICY = new SimpleAttributeDefinitionBuilder(Constants.Model.PRINCIPAL_NAME_MAPPING_POLICY, ModelType.STRING, true) .setXmlName(Constants.XML.PRINCIPAL_NAME_MAPPING_POLICY) @@ -74,7 +83,7 @@ public class ServiceProviderDefinition extends SimpleResourceDefinition { .setAllowNull(false) .build(); - static final SimpleAttributeDefinition[] ATTRIBUTES = {SSL_POLICY, NAME_ID_POLICY_FORMAT, LOGOUT_PAGE, FORCE_AUTHENTICATION}; + static final SimpleAttributeDefinition[] ATTRIBUTES = {SSL_POLICY, NAME_ID_POLICY_FORMAT, LOGOUT_PAGE, FORCE_AUTHENTICATION, IS_PASSIVE, TURN_OFF_CHANGE_SESSSION_ID_ON_LOGIN}; static final AttributeDefinition[] ELEMENTS = {PRINCIPAL_NAME_MAPPING_POLICY, PRINCIPAL_NAME_MAPPING_ATTRIBUTE_NAME, ROLE_ATTRIBUTES}; diff --git a/adapters/saml/wildfly/wildfly-subsystem/src/main/resources/org/keycloak/subsystem/adapter/saml/extension/LocalDescriptions.properties b/adapters/saml/wildfly/wildfly-subsystem/src/main/resources/org/keycloak/subsystem/adapter/saml/extension/LocalDescriptions.properties index f8a4a115817..f4d9f32b4e4 100755 --- a/adapters/saml/wildfly/wildfly-subsystem/src/main/resources/org/keycloak/subsystem/adapter/saml/extension/LocalDescriptions.properties +++ b/adapters/saml/wildfly/wildfly-subsystem/src/main/resources/org/keycloak/subsystem/adapter/saml/extension/LocalDescriptions.properties @@ -15,6 +15,8 @@ keycloak-saml.service-provider.ssl-policy=SSL Policy to use keycloak-saml.service-provider.name-id-policy-format=Name ID policy format URN keycloak-saml.service-provider.logout-page=URI to a logout page keycloak-saml.service-provider.force-authentication=Redirected unauthenticated request to a login page +keycloak-saml.service-provider.isPassive=If user isn't logged in just return with an error. Used to check if a user is already logged in or not +keycloak-saml.service-provider.turnOffChangeSessionIdOnLogin=The session id is changed by default on a successful login. Change this to true if you want to turn this off keycloak-saml.service-provider.role-attributes=Role identifiers keycloak-saml.service-provider.principal-name-mapping-policy=Principal name mapping policy keycloak-saml.service-provider.principal-name-mapping-attribute-name=Principal name mapping attribute name diff --git a/adapters/saml/wildfly/wildfly-subsystem/src/main/resources/schema/wildfly-keycloak-saml_1_1.xsd b/adapters/saml/wildfly/wildfly-subsystem/src/main/resources/schema/wildfly-keycloak-saml_1_1.xsd index 725104ba362..9fa34ba19fa 100755 --- a/adapters/saml/wildfly/wildfly-subsystem/src/main/resources/schema/wildfly-keycloak-saml_1_1.xsd +++ b/adapters/saml/wildfly/wildfly-subsystem/src/main/resources/schema/wildfly-keycloak-saml_1_1.xsd @@ -66,6 +66,16 @@ Redirected unauthenticated request to a login page + + + If user isn't logged in just return with an error. Used to check if a user is already logged in or not + + + + + The session id is changed by default on a successful login. Change this to true if you want to turn this off + + diff --git a/adapters/saml/wildfly/wildfly-subsystem/src/test/resources/org/keycloak/subsystem/adapter/saml/extension/keycloak-saml-1.1.xml b/adapters/saml/wildfly/wildfly-subsystem/src/test/resources/org/keycloak/subsystem/adapter/saml/extension/keycloak-saml-1.1.xml old mode 100644 new mode 100755 index 6f56fb057b7..eead9bf7835 --- a/adapters/saml/wildfly/wildfly-subsystem/src/test/resources/org/keycloak/subsystem/adapter/saml/extension/keycloak-saml-1.1.xml +++ b/adapters/saml/wildfly/wildfly-subsystem/src/test/resources/org/keycloak/subsystem/adapter/saml/extension/keycloak-saml-1.1.xml @@ -4,7 +4,9 @@ sslPolicy="EXTERNAL" nameIDPolicyFormat="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified" logoutPage="/logout.jsp" - forceAuthentication="false"> + forceAuthentication="false" + isPassive="true" + turnOffChangeSessionIdOnLogin="true"> diff --git a/adapters/oidc/jetty/jetty-adapter-spi/pom.xml b/adapters/spi/jetty-adapter-spi/pom.xml similarity index 100% rename from adapters/oidc/jetty/jetty-adapter-spi/pom.xml rename to adapters/spi/jetty-adapter-spi/pom.xml diff --git a/adapters/oidc/jetty/jetty-adapter-spi/src/main/java/org/keycloak/adapters/jetty/spi/JettyHttpFacade.java b/adapters/spi/jetty-adapter-spi/src/main/java/org/keycloak/adapters/jetty/spi/JettyHttpFacade.java similarity index 100% rename from adapters/oidc/jetty/jetty-adapter-spi/src/main/java/org/keycloak/adapters/jetty/spi/JettyHttpFacade.java rename to adapters/spi/jetty-adapter-spi/src/main/java/org/keycloak/adapters/jetty/spi/JettyHttpFacade.java diff --git a/adapters/oidc/jetty/jetty-adapter-spi/src/main/java/org/keycloak/adapters/jetty/spi/JettyUserSessionManagement.java b/adapters/spi/jetty-adapter-spi/src/main/java/org/keycloak/adapters/jetty/spi/JettyUserSessionManagement.java similarity index 100% rename from adapters/oidc/jetty/jetty-adapter-spi/src/main/java/org/keycloak/adapters/jetty/spi/JettyUserSessionManagement.java rename to adapters/spi/jetty-adapter-spi/src/main/java/org/keycloak/adapters/jetty/spi/JettyUserSessionManagement.java diff --git a/adapters/oidc/jetty/jetty-adapter-spi/src/main/java/org/keycloak/adapters/jetty/spi/WrappingSessionHandler.java b/adapters/spi/jetty-adapter-spi/src/main/java/org/keycloak/adapters/jetty/spi/WrappingSessionHandler.java similarity index 100% rename from adapters/oidc/jetty/jetty-adapter-spi/src/main/java/org/keycloak/adapters/jetty/spi/WrappingSessionHandler.java rename to adapters/spi/jetty-adapter-spi/src/main/java/org/keycloak/adapters/jetty/spi/WrappingSessionHandler.java diff --git a/adapters/spi/pom.xml b/adapters/spi/pom.xml index f387e86f391..58ed45bd1b8 100755 --- a/adapters/spi/pom.xml +++ b/adapters/spi/pom.xml @@ -19,5 +19,6 @@ undertow-adapter-spi servlet-adapter-spi jboss-adapter-core + jetty-adapter-spi diff --git a/adapters/spi/undertow-adapter-spi/src/main/java/org/keycloak/adapters/undertow/ChangeSessionId.java b/adapters/spi/undertow-adapter-spi/src/main/java/org/keycloak/adapters/undertow/ChangeSessionId.java new file mode 100755 index 00000000000..83d41c653b0 --- /dev/null +++ b/adapters/spi/undertow-adapter-spi/src/main/java/org/keycloak/adapters/undertow/ChangeSessionId.java @@ -0,0 +1,53 @@ +package org.keycloak.adapters.undertow; + +import io.undertow.server.HttpServerExchange; +import io.undertow.server.session.Session; +import io.undertow.server.session.SessionConfig; +import io.undertow.server.session.SessionManager; +import io.undertow.servlet.api.DeploymentInfo; +import io.undertow.servlet.handlers.ServletRequestContext; +import io.undertow.servlet.spec.HttpSessionImpl; +import io.undertow.servlet.spec.ServletContextImpl; + +import java.lang.reflect.Method; +import java.security.AccessController; + +/** + * @author Bill Burke + * @version $Revision: 1 $ + */ +public class ChangeSessionId { + /** + * This is a hack to be backward compatible between Undertow 1.3+ and versions lower. In Undertow 1.3, a new + * switch was added setChangeSessionIdOnLogin, this screws up session management for keycloak as after the session id + * is uploaded to Keycloak, undertow changes the session id and it can't be invalidated. + * + * @param deploymentInfo + */ + public static void turnOffChangeSessionIdOnLogin(DeploymentInfo deploymentInfo) { + try { + Method method = DeploymentInfo.class.getMethod("setChangeSessionIdOnLogin", boolean.class); + method.invoke(deploymentInfo, false); + } catch (Exception ignore) { + + } + } + + public static String changeSessionId(HttpServerExchange exchange, boolean create) { + final ServletRequestContext sc = exchange.getAttachment(ServletRequestContext.ATTACHMENT_KEY); + ServletContextImpl currentServletContext = sc.getCurrentServletContext(); + HttpSessionImpl session = currentServletContext.getSession(exchange, create); + if (session == null) { + return null; + } + Session underlyingSession; + if(System.getSecurityManager() == null) { + underlyingSession = session.getSession(); + } else { + underlyingSession = AccessController.doPrivileged(new HttpSessionImpl.UnwrapSessionAction(session)); + } + + + return underlyingSession.changeSessionId(exchange, currentServletContext.getSessionConfig()); + } +} diff --git a/adapters/spi/undertow-adapter-spi/src/main/java/org/keycloak/adapters/undertow/ChangeSessionIdOnLogin.java b/adapters/spi/undertow-adapter-spi/src/main/java/org/keycloak/adapters/undertow/ChangeSessionIdOnLogin.java deleted file mode 100755 index 1e6869a3018..00000000000 --- a/adapters/spi/undertow-adapter-spi/src/main/java/org/keycloak/adapters/undertow/ChangeSessionIdOnLogin.java +++ /dev/null @@ -1,27 +0,0 @@ -package org.keycloak.adapters.undertow; - -import io.undertow.servlet.api.DeploymentInfo; - -import java.lang.reflect.Method; - -/** - * @author Bill Burke - * @version $Revision: 1 $ - */ -public class ChangeSessionIdOnLogin { - /** - * This is a hack to be backward compatible between Undertow 1.3+ and versions lower. In Undertow 1.3, a new - * switch was added setChangeSessionIdOnLogin, this screws up session management for keycloak as after the session id - * is uploaded to Keycloak, undertow changes the session id and it can't be invalidated. - * - * @param deploymentInfo - */ - public static void turnOffChangeSessionIdOnLogin(DeploymentInfo deploymentInfo) { - try { - Method method = DeploymentInfo.class.getMethod("setChangeSessionIdOnLogin", boolean.class); - method.invoke(deploymentInfo, false); - } catch (Exception ignore) { - - } - } -} diff --git a/core/src/main/java/org/keycloak/representations/adapters/config/AdapterConfig.java b/core/src/main/java/org/keycloak/representations/adapters/config/AdapterConfig.java index dcdb709ef45..c6aaa8cd85a 100755 --- a/core/src/main/java/org/keycloak/representations/adapters/config/AdapterConfig.java +++ b/core/src/main/java/org/keycloak/representations/adapters/config/AdapterConfig.java @@ -50,6 +50,8 @@ public class AdapterConfig extends BaseAdapterConfig { protected String tokenStore; @JsonProperty("principal-attribute") protected String principalAttribute; + @JsonProperty("turn-off-change-session-id-on-login") + protected Boolean turnOffChangeSessionIdOnLogin; public boolean isAllowAnyHostname() { return allowAnyHostname; @@ -162,4 +164,12 @@ public class AdapterConfig extends BaseAdapterConfig { public void setPrincipalAttribute(String principalAttribute) { this.principalAttribute = principalAttribute; } + + public Boolean getTurnOffChangeSessionIdOnLogin() { + return turnOffChangeSessionIdOnLogin; + } + + public void setTurnOffChangeSessionIdOnLogin(Boolean turnOffChangeSessionIdOnLogin) { + this.turnOffChangeSessionIdOnLogin = turnOffChangeSessionIdOnLogin; + } } diff --git a/docbook/auth-server-docs/reference/en/en-US/modules/MigrationFromOlderVersions.xml b/docbook/auth-server-docs/reference/en/en-US/modules/MigrationFromOlderVersions.xml index 544abfaca45..69ac70562ff 100755 --- a/docbook/auth-server-docs/reference/en/en-US/modules/MigrationFromOlderVersions.xml +++ b/docbook/auth-server-docs/reference/en/en-US/modules/MigrationFromOlderVersions.xml @@ -104,6 +104,14 @@ with mongo and infinispan under modules keycloak-model-mongo and keycloak-model-infinispan. + + For adapters, session id changed after login + + To plug a security attack vector, for platforms that support it (Tomcat 8, Undertow/Wildfly, Jetty 9), + the keycloak oidc and saml adapters will change the session id after login. You can turn off this behavior + check adapter config switches. + +
Migrating to 1.8.0 diff --git a/docbook/auth-server-docs/reference/en/en-US/modules/adapter-config.xml b/docbook/auth-server-docs/reference/en/en-US/modules/adapter-config.xml index f0f6c99dde0..f20469babfa 100755 --- a/docbook/auth-server-docs/reference/en/en-US/modules/adapter-config.xml +++ b/docbook/auth-server-docs/reference/en/en-US/modules/adapter-config.xml @@ -379,6 +379,15 @@ + + turn-off-change-session-id-on-login + + + The session id is changed by default on a successful login on some platforms to plug a security attack vector (Tomcat 8, Jetty9, Undertow/Wildfly). Change this to true if you want to turn this off + This is OPTIONAL. The default value is false. + + +
diff --git a/docbook/saml-adapter-docs/reference/en/en-US/modules/adapter-config.xml b/docbook/saml-adapter-docs/reference/en/en-US/modules/adapter-config.xml index 5335362ad94..f79561b68e2 100755 --- a/docbook/saml-adapter-docs/reference/en/en-US/modules/adapter-config.xml +++ b/docbook/saml-adapter-docs/reference/en/en-US/modules/adapter-config.xml @@ -12,7 +12,8 @@ nameIDPolicyFormat="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified" logoutPage="/logout.jsp" forceAuthentication="false" - isPassive="false"> + isPassive="false" + turnOffChangeSessionIdOnLogin="false"> @@ -125,6 +126,15 @@ + + turnOffChangeSessionIdOnLogin + + + The session id is changed by default on a successful login on some platforms to plug a security attack vector (Tomcat 8, Jetty9, Undertow/Wildfly). Change this to true if you want to turn this off + This is OPTIONAL. The default value is false. + + + diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/keycloaksaml/InputPage.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/keycloaksaml/InputPage.java new file mode 100755 index 00000000000..dd929e10403 --- /dev/null +++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/keycloaksaml/InputPage.java @@ -0,0 +1,35 @@ +package org.keycloak.testsuite.keycloaksaml; + +import org.keycloak.testsuite.pages.AbstractPage; +import org.openqa.selenium.WebElement; +import org.openqa.selenium.support.FindBy; + +/** + * @author Bill Burke + * @version $Revision: 1 $ + */ +public class InputPage extends AbstractPage { + @FindBy(id = "parameter") + private WebElement parameter; + + @FindBy(name = "submit") + private WebElement submit; + + public void execute(String param) { + parameter.clear(); + parameter.sendKeys(param); + + submit.click(); + } + + + public boolean isCurrent() { + return driver.getTitle().equals("Input Page"); + } + + @Override + public void open() { + } + + +} diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/keycloaksaml/InputServlet.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/keycloaksaml/InputServlet.java new file mode 100755 index 00000000000..5da5b9779cc --- /dev/null +++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/keycloaksaml/InputServlet.java @@ -0,0 +1,52 @@ +package org.keycloak.testsuite.keycloaksaml; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.io.PrintWriter; + +/** + * @author Bill Burke + */ +public class InputServlet extends HttpServlet { + + private static final String FORM_URLENCODED = "application/x-www-form-urlencoded"; + + @Override + protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + String appBase = System.getProperty("app.server.base.url", "http://localhost:8081"); + String actionUrl = appBase + "/input-portal/secured/post"; + + + resp.setContentType("text/html"); + PrintWriter pw = resp.getWriter(); + pw.printf("%s", "Input Page"); + pw.printf("
", actionUrl); + pw.println(""); + pw.println("
"); + pw.print(""); + pw.flush(); + + + } + + @Override + protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + if (!FORM_URLENCODED.equals(req.getContentType())) { + resp.setStatus(HttpServletResponse.SC_BAD_REQUEST); + PrintWriter pw = resp.getWriter(); + resp.setContentType("text/plain"); + pw.printf("Expecting content type " + FORM_URLENCODED + + ", received " + req.getContentType() + " instead"); + pw.flush(); + return; + } + resp.setContentType("text/plain"); + PrintWriter pw = resp.getWriter(); + pw.printf("parameter="+req.getParameter("parameter")); + pw.flush(); + } + +} diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/keycloaksaml/SamlAdapterTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/keycloaksaml/SamlAdapterTest.java index 9f23b7043aa..82a10064d72 100755 --- a/testsuite/integration/src/test/java/org/keycloak/testsuite/keycloaksaml/SamlAdapterTest.java +++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/keycloaksaml/SamlAdapterTest.java @@ -31,6 +31,8 @@ public class SamlAdapterTest { initializeSamlSecuredWar("/keycloak-saml/bad-client-signed-post", "/bad-client-sales-post-sig", "bad-client-post-sig.war", classLoader); initializeSamlSecuredWar("/keycloak-saml/bad-realm-signed-post", "/bad-realm-sales-post-sig", "bad-realm-post-sig.war", classLoader); initializeSamlSecuredWar("/keycloak-saml/encrypted-post", "/sales-post-enc", "post-enc.war", classLoader); + System.setProperty("app.server.base.url", "http://localhost:8081"); + initializeSamlSecuredWar("/keycloak-saml/simple-input", "/input-portal", "input.war", classLoader, InputServlet.class, "/secured/*"); SamlAdapterTestStrategy.uploadSP("http://localhost:8081/auth"); server.getServer().deploy(createDeploymentInfo("employee.war", "/employee", SamlSPFacade.class)); @@ -63,6 +65,11 @@ public class SamlAdapterTest { }); } + + //@Test Doesn't work for Wildfly as the input stream is read by getParameter for SAML POST binding + public void testSavedPostRequest() throws Exception { + testStrategy.testSavedPostRequest(); + } @Test public void testErrorHandling() throws Exception { testStrategy.testErrorHandling(); diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/keycloaksaml/SamlAdapterTestStrategy.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/keycloaksaml/SamlAdapterTestStrategy.java index 646c42b38cb..9f072395853 100755 --- a/testsuite/integration/src/test/java/org/keycloak/testsuite/keycloaksaml/SamlAdapterTestStrategy.java +++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/keycloaksaml/SamlAdapterTestStrategy.java @@ -3,6 +3,7 @@ package org.keycloak.testsuite.keycloaksaml; import org.apache.commons.io.IOUtils; import org.junit.Assert; import org.junit.rules.ExternalResource; +import org.keycloak.OAuth2Constants; import org.keycloak.adapters.saml.SamlAuthenticationError; import org.keycloak.adapters.saml.SamlPrincipal; import org.keycloak.admin.client.Keycloak; @@ -12,6 +13,7 @@ import org.keycloak.models.Constants; import org.keycloak.models.KeycloakSession; import org.keycloak.models.ProtocolMapperModel; import org.keycloak.models.RealmModel; +import org.keycloak.protocol.oidc.OIDCLoginProtocolService; import org.keycloak.protocol.saml.mappers.AttributeStatementHelper; import org.keycloak.protocol.saml.mappers.GroupMembershipMapper; import org.keycloak.protocol.saml.mappers.HardcodedAttributeMapper; @@ -27,6 +29,7 @@ import org.keycloak.saml.common.constants.JBossSAMLURIConstants; import org.keycloak.saml.processing.core.saml.v2.constants.X500SAMLProfileConstants; import org.keycloak.services.managers.RealmManager; import org.keycloak.testsuite.KeycloakServer; +import org.keycloak.testsuite.adapter.*; import org.keycloak.testsuite.pages.LoginPage; import org.keycloak.testsuite.rule.AbstractKeycloakRule; import org.keycloak.testsuite.rule.ErrorServlet; @@ -38,7 +41,10 @@ import org.w3c.dom.Document; import javax.ws.rs.client.Client; import javax.ws.rs.client.ClientBuilder; +import javax.ws.rs.client.Entity; +import javax.ws.rs.core.Form; import javax.ws.rs.core.Response; +import javax.ws.rs.core.UriBuilder; import java.io.IOException; import java.net.URI; import java.util.HashSet; @@ -70,6 +76,8 @@ public class SamlAdapterTestStrategy extends ExternalResource { protected WebDriver driver; @WebResource protected LoginPage loginPage; + @WebResource + protected InputPage inputPage; @Override protected void before() throws Throwable { @@ -101,6 +109,38 @@ public class SamlAdapterTestStrategy extends ExternalResource { Assert.assertTrue(driver.getCurrentUrl().startsWith(AUTH_SERVER_URL + "/realms/demo/protocol/saml")); } + public void testSavedPostRequest() throws Exception { + // test login to customer-portal which does a bearer request to customer-db + driver.navigate().to(APP_SERVER_BASE_URL + "/input-portal"); + System.out.println("Current url: " + driver.getCurrentUrl()); + Assert.assertTrue(driver.getCurrentUrl().startsWith(APP_SERVER_BASE_URL + "/input-portal")); + inputPage.execute("hello"); + + assertEquals(driver.getCurrentUrl(), AUTH_SERVER_URL + "/realms/demo/protocol/saml"); + loginPage.login("bburke@redhat.com", "password"); + System.out.println("Current url: " + driver.getCurrentUrl()); + Assert.assertEquals(driver.getCurrentUrl(), APP_SERVER_BASE_URL + "/input-portal/secured/post"); + String pageSource = driver.getPageSource(); + System.out.println(pageSource); + Assert.assertTrue(pageSource.contains("parameter=hello")); + + // test logout + + driver.navigate().to(APP_SERVER_BASE_URL + "/input-portal?GLO=true"); + + // test unsecured POST KEYCLOAK-901 + + Client client = ClientBuilder.newClient(); + Form form = new Form(); + form.param("parameter", "hello"); + String text = client.target(APP_SERVER_BASE_URL + "/input-portal/unsecured").request().post(Entity.form(form), String.class); + Assert.assertTrue(text.contains("parameter=hello")); + client.close(); + + } + + + public void testErrorHandling() throws Exception { ErrorServlet.authError = null; Client client = ClientBuilder.newClient(); diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/keycloaksaml/SamlKeycloakRule.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/keycloaksaml/SamlKeycloakRule.java index 5a1d01f8076..2b8b42d2b9f 100755 --- a/testsuite/integration/src/test/java/org/keycloak/testsuite/keycloaksaml/SamlKeycloakRule.java +++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/keycloaksaml/SamlKeycloakRule.java @@ -15,6 +15,7 @@ import io.undertow.servlet.api.WebResourceCollection; import org.keycloak.adapters.saml.undertow.SamlServletExtension; import org.keycloak.testsuite.rule.AbstractKeycloakRule; +import javax.servlet.Servlet; import java.io.IOException; import java.net.URL; @@ -92,12 +93,19 @@ public abstract class SamlKeycloakRule extends AbstractKeycloakRule { public void initializeSamlSecuredWar(String warResourcePath, String contextPath, String warDeploymentName, ClassLoader classLoader) { - ServletInfo regularServletInfo = new ServletInfo("servlet", SendUsernameServlet.class) + Class servletClass = SendUsernameServlet.class; + String constraintUrl = "/*"; + + initializeSamlSecuredWar(warResourcePath, contextPath, warDeploymentName, classLoader, servletClass, constraintUrl); + } + + public void initializeSamlSecuredWar(String warResourcePath, String contextPath, String warDeploymentName, ClassLoader classLoader, Class servletClass, String constraintUrl) { + ServletInfo regularServletInfo = new ServletInfo("servlet", servletClass) .addMapping("/*"); SecurityConstraint constraint = new SecurityConstraint(); WebResourceCollection collection = new WebResourceCollection(); - collection.addUrlPattern("/*"); + collection.addUrlPattern(constraintUrl); constraint.addWebResourceCollection(collection); constraint.addRoleAllowed("manager"); constraint.addRoleAllowed("el-jefe"); diff --git a/testsuite/integration/src/test/resources/keycloak-saml/simple-input/WEB-INF/keycloak-saml.xml b/testsuite/integration/src/test/resources/keycloak-saml/simple-input/WEB-INF/keycloak-saml.xml new file mode 100755 index 00000000000..fc8be19c240 --- /dev/null +++ b/testsuite/integration/src/test/resources/keycloak-saml/simple-input/WEB-INF/keycloak-saml.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/testsuite/integration/src/test/resources/keycloak-saml/testsaml.json b/testsuite/integration/src/test/resources/keycloak-saml/testsaml.json index 7a50a91c8af..4df617d64ac 100755 --- a/testsuite/integration/src/test/resources/keycloak-saml/testsaml.json +++ b/testsuite/integration/src/test/resources/keycloak-saml/testsaml.json @@ -85,6 +85,23 @@ "saml_idp_initiated_sso_url_name": "sales-post" } }, + { + "name": "http://localhost:8081/input-portal/", + "enabled": true, + "fullScopeAllowed": true, + "protocol": "saml", + "baseUrl": "http://localhost:8081/input-portal/", + "redirectUris": [ + "http://localhost:8081/input-portal/*" + ], + "attributes": { + "saml.authnstatement": "true", + "saml_assertion_consumer_url_post": "http://localhost:8081/input-portal/", + "saml_assertion_consumer_url_redirect": "http://localhost:8081/input-portal/", + "saml_single_logout_service_url_post": "http://localhost:8081/input-portal/", + "saml_single_logout_service_url_redirect": "http://localhost:8081/input-portal/" + } + }, { "name": "http://localhost:8081/sales-post-passive/", "enabled": true,