From fedf3d0e52b69b3dcd7ee9be466e15b16294dbd8 Mon Sep 17 00:00:00 2001 From: Bill Burke Date: Fri, 22 Jan 2016 17:00:51 -0500 Subject: [PATCH] KEYCLOAK-2377 --- .../adapters/AdapterDeploymentContext.java | 10 ++++ .../keycloak/adapters/KeycloakDeployment.java | 10 ++++ .../adapters/KeycloakDeploymentBuilder.java | 3 ++ .../adapters/OAuthRequestAuthenticator.java | 2 +- .../adapters/RequestAuthenticator.java | 8 ++- .../main/resources/schema/keycloak_1_1.xsd | 1 + .../jetty/core/JettyRequestAuthenticator.java | 2 +- .../jetty/Jetty91RequestAuthenticator.java | 30 +++++++++++ .../jetty/KeycloakJettyAuthenticator.java | 9 ++++ .../jetty/Jetty92RequestAuthenticator.java | 30 +++++++++++ .../jetty/KeycloakJettyAuthenticator.java | 9 ++++ adapters/oidc/jetty/pom.xml | 1 - .../servlet/FilterRequestAuthenticator.java | 2 +- .../SpringSecurityRequestAuthenticator.java | 2 +- ...pringSecurityRequestAuthenticatorTest.java | 4 +- .../AbstractKeycloakAuthenticatorValve.java | 14 ++++- .../tomcat/CatalinaRequestAuthenticator.java | 2 +- .../tomcat/KeycloakAuthenticatorValve.java | 3 ++ .../tomcat/KeycloakAuthenticatorValve.java | 3 ++ .../tomcat/KeycloakAuthenticatorValve.java | 8 +++ .../tomcat/Tomcat8RequestAuthenticator.java | 28 ++++++++++ .../AbstractUndertowRequestAuthenticator.java | 2 +- .../undertow/KeycloakServletExtension.java | 2 +- .../undertow/ServletRequestAuthenticator.java | 5 ++ .../extension/SecureDeploymentDefinition.java | 7 +++ .../extension/LocalDescriptions.properties | 1 + .../resources/schema/wildfly-keycloak_1_1.xsd | 1 + .../subsystem/wf8/extension/keycloak-1.1.xml | 1 + .../extension/SecureDeploymentDefinition.java | 7 +++ .../extension/LocalDescriptions.properties | 1 + .../resources/schema/wildfly-keycloak_1_1.xsd | 1 + .../adapter/extension/keycloak-1.1.xml | 1 + .../adapters/saml/DefaultSamlDeployment.java | 11 ++++ .../adapters/saml/SamlDeployment.java | 1 + .../org/keycloak/adapters/saml/config/SP.java | 9 ++++ .../config/parsers/ConfigXmlConstants.java | 1 + .../saml/config/parsers/SPXmlParser.java | 1 + .../schema/keycloak_saml_adapter_1_6.xsd | 1 + .../saml/jetty/AbstractSamlAuthenticator.java | 8 ++- .../saml/jetty/JettySamlSessionStore.java | 13 +++-- .../saml/jetty/Jetty9SamlSessionStore.java | 27 ++++++++++ .../saml/jetty/KeycloakSamlAuthenticator.java | 10 ++++ .../saml/jetty/Jetty9SamlSessionStore.java | 27 ++++++++++ .../saml/jetty/KeycloakSamlAuthenticator.java | 9 ++++ .../saml/AbstractSamlAuthenticatorValve.java | 14 +++-- .../saml/CatalinaSamlSessionStore.java | 12 ++++- .../saml/tomcat/SamlAuthenticatorValve.java | 12 +++++ .../saml/tomcat/Tomcat8SamlSessionStore.java | 28 ++++++++++ .../saml/undertow/SamlServletExtension.java | 4 +- .../saml/undertow/ServletSamlAuthMech.java | 2 +- .../undertow/ServletSamlSessionStore.java | 14 ++++- .../saml/wildfly/WildflySamlAuthMech.java | 2 +- .../saml/wildfly/WildflySamlSessionStore.java | 5 +- .../adapter/saml/extension/Constants.java | 4 ++ .../extension/ServiceProviderDefinition.java | 11 +++- .../extension/LocalDescriptions.properties | 2 + .../schema/wildfly-keycloak-saml_1_1.xsd | 10 ++++ .../saml/extension/keycloak-saml-1.1.xml | 4 +- .../jetty => spi}/jetty-adapter-spi/pom.xml | 0 .../adapters/jetty/spi/JettyHttpFacade.java | 0 .../jetty/spi/JettyUserSessionManagement.java | 0 .../jetty/spi/WrappingSessionHandler.java | 0 adapters/spi/pom.xml | 1 + .../adapters/undertow/ChangeSessionId.java | 53 +++++++++++++++++++ .../undertow/ChangeSessionIdOnLogin.java | 27 ---------- .../adapters/config/AdapterConfig.java | 10 ++++ .../modules/MigrationFromOlderVersions.xml | 8 +++ .../en/en-US/modules/adapter-config.xml | 9 ++++ .../en/en-US/modules/adapter-config.xml | 12 ++++- .../testsuite/keycloaksaml/InputPage.java | 35 ++++++++++++ .../testsuite/keycloaksaml/InputServlet.java | 52 ++++++++++++++++++ .../keycloaksaml/SamlAdapterTest.java | 7 +++ .../keycloaksaml/SamlAdapterTestStrategy.java | 40 ++++++++++++++ .../keycloaksaml/SamlKeycloakRule.java | 12 ++++- .../simple-input/WEB-INF/keycloak-saml.xml | 24 +++++++++ .../resources/keycloak-saml/testsaml.json | 17 ++++++ 76 files changed, 696 insertions(+), 63 deletions(-) create mode 100755 adapters/oidc/jetty/jetty9.1/src/main/java/org/keycloak/adapters/jetty/Jetty91RequestAuthenticator.java create mode 100755 adapters/oidc/jetty/jetty9.2/src/main/java/org/keycloak/adapters/jetty/Jetty92RequestAuthenticator.java create mode 100755 adapters/oidc/tomcat/tomcat8/src/main/java/org/keycloak/adapters/tomcat/Tomcat8RequestAuthenticator.java mode change 100644 => 100755 adapters/oidc/wildfly/wf8-subsystem/src/test/resources/org/keycloak/subsystem/wf8/extension/keycloak-1.1.xml mode change 100644 => 100755 adapters/oidc/wildfly/wildfly-subsystem/src/test/resources/org/keycloak/subsystem/adapter/extension/keycloak-1.1.xml create mode 100755 adapters/saml/jetty/jetty9.1/src/main/java/org/keycloak/adapters/saml/jetty/Jetty9SamlSessionStore.java create mode 100755 adapters/saml/jetty/jetty9.2/src/main/java/org/keycloak/adapters/saml/jetty/Jetty9SamlSessionStore.java create mode 100755 adapters/saml/tomcat/tomcat8/src/main/java/org/keycloak/adapters/saml/tomcat/Tomcat8SamlSessionStore.java mode change 100644 => 100755 adapters/saml/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/saml/extension/Constants.java mode change 100644 => 100755 adapters/saml/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/saml/extension/ServiceProviderDefinition.java mode change 100644 => 100755 adapters/saml/wildfly/wildfly-subsystem/src/test/resources/org/keycloak/subsystem/adapter/saml/extension/keycloak-saml-1.1.xml rename adapters/{oidc/jetty => spi}/jetty-adapter-spi/pom.xml (100%) rename adapters/{oidc/jetty => spi}/jetty-adapter-spi/src/main/java/org/keycloak/adapters/jetty/spi/JettyHttpFacade.java (100%) rename adapters/{oidc/jetty => spi}/jetty-adapter-spi/src/main/java/org/keycloak/adapters/jetty/spi/JettyUserSessionManagement.java (100%) rename adapters/{oidc/jetty => spi}/jetty-adapter-spi/src/main/java/org/keycloak/adapters/jetty/spi/WrappingSessionHandler.java (100%) create mode 100755 adapters/spi/undertow-adapter-spi/src/main/java/org/keycloak/adapters/undertow/ChangeSessionId.java delete mode 100755 adapters/spi/undertow-adapter-spi/src/main/java/org/keycloak/adapters/undertow/ChangeSessionIdOnLogin.java create mode 100755 testsuite/integration/src/test/java/org/keycloak/testsuite/keycloaksaml/InputPage.java create mode 100755 testsuite/integration/src/test/java/org/keycloak/testsuite/keycloaksaml/InputServlet.java create mode 100755 testsuite/integration/src/test/resources/keycloak-saml/simple-input/WEB-INF/keycloak-saml.xml 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 47eb58e0a3..fd676f5a21 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 5edaa817ff..b97ecdb913 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 14cf9ab654..0bda9b25cb 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 cc6b1882f9..e69e6f2288 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 6b4d9f003d..8f695b00a8 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 75de38ad83..89b37b653d 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 2d0d2a2c20..d9e9a393a9 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 0000000000..cc3395ff83 --- /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 a319266ae5..5c7570f5d4 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 0000000000..9c7e127009 --- /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 2aec5ef6fd..67841c1f77 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 86edf07f76..f1cd46b89c 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 70cb7e9229..40672663b5 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 5e1ed05896..fada4555c0 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 c44610d97b..89202fbcbc 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 20c87bd4dd..99ad2a7cbd 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 0883c762ef..6c88620830 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 2e30429916..e1426dcce8 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 fa94c34e5d..4dc19ddf99 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 eea4f03276..bd8cee6e79 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 0000000000..b221129442 --- /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 18c846c8aa..ca938bb2c5 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 8696a04ddf..39b4fa7985 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 881407d205..2c288acf60 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 d16a25e7f5..0098a78707 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 c00bd8d227..047e3ffa7e 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 75de38ad83..89b37b653d 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 e512f0e85a..e4e097d230 --- 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 1932cc8e8e..a09c3b859c 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 c00bd8d227..047e3ffa7e 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 0abaac18d8..c6298f8fe2 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 e512f0e85a..e4e097d230 --- 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 7aab09546b..2c925e02f9 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 8c53236603..14ce5a354e 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 5203b13c23..17c8343244 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 91a016c65f..87069c39da 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 14b04e1110..7d6d57af7d 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 d3e55f9dc1..1f8b26b57d 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 2df0fad988..5028542766 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 6e51f110f8..380066e36c 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 0000000000..56a26ca83f --- /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 f5fdf7d807..238c84b6e2 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 0000000000..56a26ca83f --- /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 03ea508646..fa802ba2c6 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 3119ba7c9e..3ec5a8f88c 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 804acf36e1..340c8113e3 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 ead126a913..7be5b69f3f 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 0000000000..4bd9cfaabc --- /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 589835dd9b..a7abb47b4a 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 9fe9085d06..491e35e268 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 d9885d83f7..cd6f217638 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 e532233092..46b82af734 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 45513337a4..8d038afbdb 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 9b89fb2c80..14518f687e --- 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 cb84f1253d..56abc84814 --- 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 f8a4a11581..f4d9f32b4e 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 725104ba36..9fa34ba19f 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 6f56fb057b..eead9bf783 --- 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 f387e86f39..58ed45bd1b 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 0000000000..83d41c653b --- /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 1e6869a301..0000000000 --- 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 dcdb709ef4..c6aaa8cd85 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 544abfaca4..69ac70562f 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 f0f6c99dde..f20469babf 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 5335362ad9..f79561b68e 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 0000000000..dd929e1040 --- /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 0000000000..5da5b9779c --- /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 9f23b7043a..82a10064d7 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 646c42b38c..9f07239585 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 5a1d01f807..2b8b42d2b9 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 0000000000..fc8be19c24 --- /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 7a50a91c8a..4df617d64a 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,