diff --git a/distribution/adapters/as7-eap6-adapter/as7-modules/build.xml b/distribution/adapters/as7-eap6-adapter/as7-modules/build.xml index e58f2b6a2f..cbf50eacfc 100755 --- a/distribution/adapters/as7-eap6-adapter/as7-modules/build.xml +++ b/distribution/adapters/as7-eap6-adapter/as7-modules/build.xml @@ -52,6 +52,7 @@ + diff --git a/distribution/adapters/as7-eap6-adapter/as7-modules/pom.xml b/distribution/adapters/as7-eap6-adapter/as7-modules/pom.xml index 4e23733f18..21eeb8148a 100755 --- a/distribution/adapters/as7-eap6-adapter/as7-modules/pom.xml +++ b/distribution/adapters/as7-eap6-adapter/as7-modules/pom.xml @@ -25,6 +25,10 @@ org.keycloak keycloak-adapter-spi + + org.keycloak + keycloak-as7-adapter-spi + org.keycloak keycloak-tomcat-adapter-spi diff --git a/distribution/adapters/as7-eap6-adapter/as7-modules/src/main/resources/modules/org/keycloak/keycloak-jboss-adapter-core/main/module.xml b/distribution/adapters/as7-eap6-adapter/as7-modules/src/main/resources/modules/org/keycloak/keycloak-jboss-adapter-core/main/module.xml index f1ee530cda..645d8ece20 100755 --- a/distribution/adapters/as7-eap6-adapter/as7-modules/src/main/resources/modules/org/keycloak/keycloak-jboss-adapter-core/main/module.xml +++ b/distribution/adapters/as7-eap6-adapter/as7-modules/src/main/resources/modules/org/keycloak/keycloak-jboss-adapter-core/main/module.xml @@ -11,7 +11,6 @@ - diff --git a/integration/adapter-core/src/main/java/org/keycloak/adapters/AdapterTokenStore.java b/integration/adapter-core/src/main/java/org/keycloak/adapters/AdapterTokenStore.java index 066a32a73f..70eeebb8e4 100755 --- a/integration/adapter-core/src/main/java/org/keycloak/adapters/AdapterTokenStore.java +++ b/integration/adapter-core/src/main/java/org/keycloak/adapters/AdapterTokenStore.java @@ -25,7 +25,7 @@ public interface AdapterTokenStore extends AdapterSessionStore { * * @param account */ - void saveAccountInfo(KeycloakAccount account); + void saveAccountInfo(OidcKeycloakAccount account); /** * Handle logout on store side and possibly propagate logout call to Keycloak diff --git a/integration/adapter-core/src/main/java/org/keycloak/adapters/OidcKeycloakAccount.java b/integration/adapter-core/src/main/java/org/keycloak/adapters/OidcKeycloakAccount.java new file mode 100755 index 0000000000..fffc2427c1 --- /dev/null +++ b/integration/adapter-core/src/main/java/org/keycloak/adapters/OidcKeycloakAccount.java @@ -0,0 +1,11 @@ +package org.keycloak.adapters; + +import org.keycloak.KeycloakSecurityContext; + +/** + * @author Bill Burke + * @version $Revision: 1 $ + */ +public interface OidcKeycloakAccount extends KeycloakAccount { + KeycloakSecurityContext getKeycloakSecurityContext(); +} diff --git a/integration/adapter-core/src/main/java/org/keycloak/adapters/KeycloakAccount.java b/integration/adapter-spi/src/main/java/org/keycloak/adapters/KeycloakAccount.java similarity index 73% rename from integration/adapter-core/src/main/java/org/keycloak/adapters/KeycloakAccount.java rename to integration/adapter-spi/src/main/java/org/keycloak/adapters/KeycloakAccount.java index a242779947..26299448ef 100755 --- a/integration/adapter-core/src/main/java/org/keycloak/adapters/KeycloakAccount.java +++ b/integration/adapter-spi/src/main/java/org/keycloak/adapters/KeycloakAccount.java @@ -1,7 +1,5 @@ package org.keycloak.adapters; -import org.keycloak.KeycloakSecurityContext; - import java.security.Principal; import java.util.Set; @@ -11,6 +9,6 @@ import java.util.Set; */ public interface KeycloakAccount { Principal getPrincipal(); + Set getRoles(); - KeycloakSecurityContext getKeycloakSecurityContext(); } diff --git a/integration/as7-eap6/as7-adapter-spi/pom.xml b/integration/as7-eap6/as7-adapter-spi/pom.xml new file mode 100755 index 0000000000..def1f56c23 --- /dev/null +++ b/integration/as7-eap6/as7-adapter-spi/pom.xml @@ -0,0 +1,85 @@ + + + + keycloak-parent + org.keycloak + 1.6.0.Final-SNAPSHOT + ../../../pom.xml + + 4.0.0 + + keycloak-as7-adapter-spi + Keycloak AS7 SPI + + + + + org.keycloak + keycloak-adapter-spi + + + org.apache.httpcomponents + httpclient + + + org.jboss.spec.javax.servlet + jboss-servlet-api_3.0_spec + provided + + + org.jboss.logging + jboss-logging + ${jboss.logging.version} + provided + + + org.jboss.web + jbossweb + 7.0.17.Final + provided + + + org.jboss.as + jboss-as-web + 7.1.2.Final + provided + + + org.keycloak + keycloak-tomcat-adapter-spi + + + org.apache.tomcat + tomcat-servlet-api + + + org.apache.tomcat + tomcat-catalina + + + org.apache.tomcat + catalina + + + + + junit + junit + test + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + ${maven.compiler.source} + ${maven.compiler.target} + + + + + + diff --git a/integration/as7-eap6/as7-adapter/src/main/java/org/keycloak/adapters/jbossweb/JBossWebPrincipalFactory.java b/integration/as7-eap6/as7-adapter-spi/src/main/java/org/keycloak/adapters/jbossweb/JBossWebPrincipalFactory.java similarity index 95% rename from integration/as7-eap6/as7-adapter/src/main/java/org/keycloak/adapters/jbossweb/JBossWebPrincipalFactory.java rename to integration/as7-eap6/as7-adapter-spi/src/main/java/org/keycloak/adapters/jbossweb/JBossWebPrincipalFactory.java index 8bc50c92e9..b3925955c3 100755 --- a/integration/as7-eap6/as7-adapter/src/main/java/org/keycloak/adapters/jbossweb/JBossWebPrincipalFactory.java +++ b/integration/as7-eap6/as7-adapter-spi/src/main/java/org/keycloak/adapters/jbossweb/JBossWebPrincipalFactory.java @@ -9,7 +9,6 @@ import org.jboss.security.SecurityContext; import org.jboss.security.SecurityContextAssociation; import org.jboss.security.SimpleGroup; import org.jboss.security.SimplePrincipal; -import org.keycloak.KeycloakSecurityContext; import org.keycloak.adapters.KeycloakAccount; import org.keycloak.adapters.tomcat.GenericPrincipalFactory; @@ -38,7 +37,7 @@ public class JBossWebPrincipalFactory extends GenericPrincipalFactory { } @Override - public GenericPrincipal createPrincipal(Realm realm, final Principal identity, final Set roleSet, final KeycloakSecurityContext securityContext) { + public GenericPrincipal createPrincipal(Realm realm, final Principal identity, final Set roleSet) { KeycloakAccount account = new KeycloakAccount() { @Override public Principal getPrincipal() { @@ -49,11 +48,6 @@ public class JBossWebPrincipalFactory extends GenericPrincipalFactory { public Set getRoles() { return roleSet; } - - @Override - public KeycloakSecurityContext getKeycloakSecurityContext() { - return securityContext; - } }; Subject subject = new Subject(); Set principals = subject.getPrincipals(); diff --git a/integration/as7-eap6/as7-adapter/src/test/java/org/keycloak/adapters/jbossweb/JBossWebPrincipalFactoryTest.java b/integration/as7-eap6/as7-adapter-spi/src/test/java/org/keycloak/adapters/jbossweb/JBossWebPrincipalFactoryTest.java similarity index 100% rename from integration/as7-eap6/as7-adapter/src/test/java/org/keycloak/adapters/jbossweb/JBossWebPrincipalFactoryTest.java rename to integration/as7-eap6/as7-adapter-spi/src/test/java/org/keycloak/adapters/jbossweb/JBossWebPrincipalFactoryTest.java diff --git a/integration/as7-eap6/as7-adapter/pom.xml b/integration/as7-eap6/as7-adapter/pom.xml index 9b938f4bf0..25a86a1f45 100755 --- a/integration/as7-eap6/as7-adapter/pom.xml +++ b/integration/as7-eap6/as7-adapter/pom.xml @@ -18,6 +18,10 @@ org.keycloak keycloak-core + + org.keycloak + keycloak-as7-adapter-spi + org.keycloak keycloak-adapter-spi diff --git a/integration/as7-eap6/pom.xml b/integration/as7-eap6/pom.xml old mode 100644 new mode 100755 index 0080f469a1..ce7f8c8e78 --- a/integration/as7-eap6/pom.xml +++ b/integration/as7-eap6/pom.xml @@ -14,6 +14,7 @@ pom + as7-adapter-spi as7-adapter as7-subsystem as7-server-subsystem diff --git a/integration/jboss-adapter-core/pom.xml b/integration/jboss-adapter-core/pom.xml index 50f0071e1c..427b534539 100755 --- a/integration/jboss-adapter-core/pom.xml +++ b/integration/jboss-adapter-core/pom.xml @@ -28,10 +28,6 @@ org.keycloak keycloak-adapter-spi - - org.keycloak - keycloak-adapter-core - org.apache.httpcomponents httpclient diff --git a/integration/jetty/jetty-core/src/main/java/org/keycloak/adapters/jetty/core/JettyCookieTokenStore.java b/integration/jetty/jetty-core/src/main/java/org/keycloak/adapters/jetty/core/JettyCookieTokenStore.java index 4c5b6ec435..cb7e0bc0d6 100755 --- a/integration/jetty/jetty-core/src/main/java/org/keycloak/adapters/jetty/core/JettyCookieTokenStore.java +++ b/integration/jetty/jetty-core/src/main/java/org/keycloak/adapters/jetty/core/JettyCookieTokenStore.java @@ -7,8 +7,8 @@ import org.keycloak.KeycloakSecurityContext; import org.keycloak.adapters.AdapterTokenStore; import org.keycloak.adapters.CookieTokenStore; import org.keycloak.adapters.HttpFacade; -import org.keycloak.adapters.KeycloakAccount; import org.keycloak.adapters.KeycloakDeployment; +import org.keycloak.adapters.OidcKeycloakAccount; import org.keycloak.adapters.RefreshableKeycloakSecurityContext; import org.keycloak.adapters.RequestAuthenticator; @@ -61,7 +61,7 @@ public class JettyCookieTokenStore implements AdapterTokenStore { } @Override - public void saveAccountInfo(KeycloakAccount account) { + public void saveAccountInfo(OidcKeycloakAccount account) { RefreshableKeycloakSecurityContext securityContext = (RefreshableKeycloakSecurityContext)account.getKeycloakSecurityContext(); CookieTokenStore.setTokenCookie(deployment, facade, securityContext); } diff --git a/integration/jetty/jetty-core/src/main/java/org/keycloak/adapters/jetty/core/JettyRequestAuthenticator.java b/integration/jetty/jetty-core/src/main/java/org/keycloak/adapters/jetty/core/JettyRequestAuthenticator.java index fbe20ba50b..1ab68b6afa 100755 --- a/integration/jetty/jetty-core/src/main/java/org/keycloak/adapters/jetty/core/JettyRequestAuthenticator.java +++ b/integration/jetty/jetty-core/src/main/java/org/keycloak/adapters/jetty/core/JettyRequestAuthenticator.java @@ -7,9 +7,9 @@ import org.keycloak.KeycloakSecurityContext; import org.keycloak.adapters.AdapterTokenStore; import org.keycloak.adapters.AdapterUtils; import org.keycloak.adapters.HttpFacade; -import org.keycloak.adapters.KeycloakAccount; import org.keycloak.adapters.KeycloakDeployment; import org.keycloak.adapters.OAuthRequestAuthenticator; +import org.keycloak.adapters.OidcKeycloakAccount; import org.keycloak.adapters.RefreshableKeycloakSecurityContext; import org.keycloak.adapters.RequestAuthenticator; @@ -41,7 +41,7 @@ public class JettyRequestAuthenticator extends RequestAuthenticator { principal = skp; final RefreshableKeycloakSecurityContext securityContext = skp.getKeycloakSecurityContext(); final Set roles = AdapterUtils.getRolesFromSecurityContext(securityContext); - KeycloakAccount account = new KeycloakAccount() { + OidcKeycloakAccount account = new OidcKeycloakAccount() { @Override public Principal getPrincipal() { diff --git a/integration/jetty/jetty-core/src/main/java/org/keycloak/adapters/jetty/core/JettySessionTokenStore.java b/integration/jetty/jetty-core/src/main/java/org/keycloak/adapters/jetty/core/JettySessionTokenStore.java index f4c8b359b1..b007b06841 100755 --- a/integration/jetty/jetty-core/src/main/java/org/keycloak/adapters/jetty/core/JettySessionTokenStore.java +++ b/integration/jetty/jetty-core/src/main/java/org/keycloak/adapters/jetty/core/JettySessionTokenStore.java @@ -7,8 +7,8 @@ import org.keycloak.KeycloakSecurityContext; import org.keycloak.adapters.AdapterSessionStore; import org.keycloak.adapters.AdapterTokenStore; import org.keycloak.adapters.AdapterUtils; -import org.keycloak.adapters.KeycloakAccount; import org.keycloak.adapters.KeycloakDeployment; +import org.keycloak.adapters.OidcKeycloakAccount; import org.keycloak.adapters.RefreshableKeycloakSecurityContext; import org.keycloak.adapters.RequestAuthenticator; @@ -77,7 +77,7 @@ public class JettySessionTokenStore implements AdapterTokenStore { } @Override - public void saveAccountInfo(KeycloakAccount account) { + public void saveAccountInfo(OidcKeycloakAccount account) { RefreshableKeycloakSecurityContext securityContext = (RefreshableKeycloakSecurityContext) account.getKeycloakSecurityContext(); request.getSession().setAttribute(KeycloakSecurityContext.class.getName(), securityContext); } diff --git a/integration/spring-security/src/main/java/org/keycloak/adapters/springsecurity/account/SimpleKeycloakAccount.java b/integration/spring-security/src/main/java/org/keycloak/adapters/springsecurity/account/SimpleKeycloakAccount.java old mode 100644 new mode 100755 index 338a72fd20..5d00165915 --- a/integration/spring-security/src/main/java/org/keycloak/adapters/springsecurity/account/SimpleKeycloakAccount.java +++ b/integration/spring-security/src/main/java/org/keycloak/adapters/springsecurity/account/SimpleKeycloakAccount.java @@ -1,6 +1,6 @@ package org.keycloak.adapters.springsecurity.account; -import org.keycloak.adapters.KeycloakAccount; +import org.keycloak.adapters.OidcKeycloakAccount; import org.keycloak.adapters.RefreshableKeycloakSecurityContext; import java.io.Serializable; @@ -8,12 +8,12 @@ import java.security.Principal; import java.util.Set; /** - * Concrete, serializable {@link KeycloakAccount} implementation. + * Concrete, serializable {@link org.keycloak.adapters.OidcKeycloakAccount} implementation. * * @author Scott Rossillo * @version $Revision: 1 $ */ -public class SimpleKeycloakAccount implements KeycloakAccount, Serializable { +public class SimpleKeycloakAccount implements OidcKeycloakAccount, Serializable { private Set roles; private Principal principal; diff --git a/integration/spring-security/src/main/java/org/keycloak/adapters/springsecurity/authentication/SpringSecurityRequestAuthenticator.java b/integration/spring-security/src/main/java/org/keycloak/adapters/springsecurity/authentication/SpringSecurityRequestAuthenticator.java old mode 100644 new mode 100755 index b224ccfa70..a080acf004 --- a/integration/spring-security/src/main/java/org/keycloak/adapters/springsecurity/authentication/SpringSecurityRequestAuthenticator.java +++ b/integration/spring-security/src/main/java/org/keycloak/adapters/springsecurity/authentication/SpringSecurityRequestAuthenticator.java @@ -8,20 +8,18 @@ import org.keycloak.adapters.HttpFacade; import org.keycloak.adapters.KeycloakAccount; import org.keycloak.adapters.KeycloakDeployment; import org.keycloak.adapters.OAuthRequestAuthenticator; +import org.keycloak.adapters.OidcKeycloakAccount; import org.keycloak.adapters.RefreshableKeycloakSecurityContext; import org.keycloak.adapters.RequestAuthenticator; import org.keycloak.adapters.springsecurity.account.SimpleKeycloakAccount; import org.keycloak.adapters.springsecurity.token.KeycloakAuthenticationToken; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.security.core.context.SecurityContext; import org.springframework.security.core.context.SecurityContextHolder; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpSession; -import java.security.Principal; import java.util.Set; -import java.util.logging.Level; /** * Request authenticator adapter for Spring Security. @@ -64,7 +62,7 @@ public class SpringSecurityRequestAuthenticator extends RequestAuthenticator { final RefreshableKeycloakSecurityContext securityContext = principal.getKeycloakSecurityContext(); final Set roles = AdapterUtils.getRolesFromSecurityContext(securityContext); - final KeycloakAccount account = new SimpleKeycloakAccount(principal, roles, securityContext); + final OidcKeycloakAccount account = new SimpleKeycloakAccount(principal, roles, securityContext); request.setAttribute(KeycloakSecurityContext.class.getName(), securityContext); this.tokenStore.saveAccountInfo(account); diff --git a/integration/spring-security/src/main/java/org/keycloak/adapters/springsecurity/filter/KeycloakPreAuthActionsFilter.java b/integration/spring-security/src/main/java/org/keycloak/adapters/springsecurity/filter/KeycloakPreAuthActionsFilter.java old mode 100644 new mode 100755 index 0f67ed1800..6605a6bbec --- a/integration/spring-security/src/main/java/org/keycloak/adapters/springsecurity/filter/KeycloakPreAuthActionsFilter.java +++ b/integration/spring-security/src/main/java/org/keycloak/adapters/springsecurity/filter/KeycloakPreAuthActionsFilter.java @@ -70,7 +70,7 @@ public class KeycloakPreAuthActionsFilter extends GenericFilterBean implements A HttpFacade facade = new SimpleHttpFacade((HttpServletRequest)request, (HttpServletResponse)response); PreAuthActionsHandler handler = new PreAuthActionsHandler(userSessionManagement, deploymentContext, facade); if (handler.handleRequest()) { - log.info("Pre-auth filter handled request: {}", ((HttpServletRequest) request).getRequestURI()); + log.debug("Pre-auth filter handled request: {}", ((HttpServletRequest) request).getRequestURI()); } else { chain.doFilter(request, response); } diff --git a/integration/spring-security/src/main/java/org/keycloak/adapters/springsecurity/token/KeycloakAuthenticationToken.java b/integration/spring-security/src/main/java/org/keycloak/adapters/springsecurity/token/KeycloakAuthenticationToken.java old mode 100644 new mode 100755 index da4c1922ef..12fed2d3c9 --- a/integration/spring-security/src/main/java/org/keycloak/adapters/springsecurity/token/KeycloakAuthenticationToken.java +++ b/integration/spring-security/src/main/java/org/keycloak/adapters/springsecurity/token/KeycloakAuthenticationToken.java @@ -1,6 +1,7 @@ package org.keycloak.adapters.springsecurity.token; import org.keycloak.adapters.KeycloakAccount; +import org.keycloak.adapters.OidcKeycloakAccount; import org.springframework.security.authentication.AbstractAuthenticationToken; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.core.Authentication; @@ -51,7 +52,7 @@ public class KeycloakAuthenticationToken extends AbstractAuthenticationToken imp return principal; } - public KeycloakAccount getAccount() { - return (KeycloakAccount) this.getDetails(); + public OidcKeycloakAccount getAccount() { + return (OidcKeycloakAccount) this.getDetails(); } } diff --git a/integration/spring-security/src/main/java/org/keycloak/adapters/springsecurity/token/SpringSecurityTokenStore.java b/integration/spring-security/src/main/java/org/keycloak/adapters/springsecurity/token/SpringSecurityTokenStore.java old mode 100644 new mode 100755 index c16d73f107..abe8cfb999 --- a/integration/spring-security/src/main/java/org/keycloak/adapters/springsecurity/token/SpringSecurityTokenStore.java +++ b/integration/spring-security/src/main/java/org/keycloak/adapters/springsecurity/token/SpringSecurityTokenStore.java @@ -2,8 +2,8 @@ package org.keycloak.adapters.springsecurity.token; import org.keycloak.KeycloakSecurityContext; import org.keycloak.adapters.AdapterTokenStore; -import org.keycloak.adapters.KeycloakAccount; import org.keycloak.adapters.KeycloakDeployment; +import org.keycloak.adapters.OidcKeycloakAccount; import org.keycloak.adapters.RefreshableKeycloakSecurityContext; import org.keycloak.adapters.RequestAuthenticator; import org.slf4j.Logger; @@ -58,12 +58,12 @@ public class SpringSecurityTokenStore implements AdapterTokenStore { return false; } - logger.info("Remote logged in already. Establishing state from security context."); + logger.debug("Remote logged in already. Establishing state from security context."); token = (KeycloakAuthenticationToken) context.getAuthentication(); keycloakSecurityContext = token.getAccount().getKeycloakSecurityContext(); if (!deployment.getRealm().equals(keycloakSecurityContext.getRealm())) { - logger.info("Account from security context is from a different realm than for the request."); + logger.debug("Account from security context is from a different realm than for the request."); logout(); return false; } @@ -79,7 +79,7 @@ public class SpringSecurityTokenStore implements AdapterTokenStore { } @Override - public void saveAccountInfo(KeycloakAccount account) { + public void saveAccountInfo(OidcKeycloakAccount account) { Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); diff --git a/integration/spring-security/src/test/java/org/keycloak/adapters/springsecurity/authentication/KeycloakLogoutHandlerTest.java b/integration/spring-security/src/test/java/org/keycloak/adapters/springsecurity/authentication/KeycloakLogoutHandlerTest.java old mode 100644 new mode 100755 index 6a035b5c78..cc751c4b76 --- a/integration/spring-security/src/test/java/org/keycloak/adapters/springsecurity/authentication/KeycloakLogoutHandlerTest.java +++ b/integration/spring-security/src/test/java/org/keycloak/adapters/springsecurity/authentication/KeycloakLogoutHandlerTest.java @@ -2,8 +2,8 @@ package org.keycloak.adapters.springsecurity.authentication; import org.junit.Before; import org.junit.Test; -import org.keycloak.adapters.KeycloakAccount; import org.keycloak.adapters.KeycloakDeployment; +import org.keycloak.adapters.OidcKeycloakAccount; import org.keycloak.adapters.RefreshableKeycloakSecurityContext; import org.keycloak.adapters.springsecurity.AdapterDeploymentContextBean; import org.keycloak.adapters.springsecurity.account.KeycloakRole; @@ -38,7 +38,7 @@ public class KeycloakLogoutHandlerTest { private AdapterDeploymentContextBean adapterDeploymentContextBean; @Mock - private KeycloakAccount keycloakAccount; + private OidcKeycloakAccount keycloakAccount; @Mock private KeycloakDeployment keycloakDeployment; diff --git a/integration/spring-security/src/test/java/org/keycloak/adapters/springsecurity/authentication/SpringSecurityRequestAuthenticatorTest.java b/integration/spring-security/src/test/java/org/keycloak/adapters/springsecurity/authentication/SpringSecurityRequestAuthenticatorTest.java old mode 100644 new mode 100755 index cdd305aaa4..301c344d8a --- a/integration/spring-security/src/test/java/org/keycloak/adapters/springsecurity/authentication/SpringSecurityRequestAuthenticatorTest.java +++ b/integration/spring-security/src/test/java/org/keycloak/adapters/springsecurity/authentication/SpringSecurityRequestAuthenticatorTest.java @@ -6,9 +6,9 @@ import org.keycloak.KeycloakPrincipal; import org.keycloak.KeycloakSecurityContext; import org.keycloak.adapters.AdapterTokenStore; import org.keycloak.adapters.HttpFacade; -import org.keycloak.adapters.KeycloakAccount; import org.keycloak.adapters.KeycloakDeployment; import org.keycloak.adapters.OAuthRequestAuthenticator; +import org.keycloak.adapters.OidcKeycloakAccount; import org.keycloak.adapters.RefreshableKeycloakSecurityContext; import org.keycloak.adapters.springsecurity.facade.SimpleHttpFacade; import org.keycloak.adapters.springsecurity.token.KeycloakAuthenticationToken; @@ -82,7 +82,7 @@ public class SpringSecurityRequestAuthenticatorTest { public void testCompleteOAuthAuthentication() throws Exception { authenticator.completeOAuthAuthentication(principal); verify(request).setAttribute(eq(KeycloakSecurityContext.class.getName()), eq(refreshableKeycloakSecurityContext)); - verify(tokenStore).saveAccountInfo(any(KeycloakAccount.class)); // FIXME: should verify account + verify(tokenStore).saveAccountInfo(any(OidcKeycloakAccount.class)); // FIXME: should verify account } @Test diff --git a/integration/spring-security/src/test/java/org/keycloak/adapters/springsecurity/client/KeycloakClientRequestFactoryTest.java b/integration/spring-security/src/test/java/org/keycloak/adapters/springsecurity/client/KeycloakClientRequestFactoryTest.java old mode 100644 new mode 100755 index e35efe622a..8796bf3eed --- a/integration/spring-security/src/test/java/org/keycloak/adapters/springsecurity/client/KeycloakClientRequestFactoryTest.java +++ b/integration/spring-security/src/test/java/org/keycloak/adapters/springsecurity/client/KeycloakClientRequestFactoryTest.java @@ -4,7 +4,7 @@ import org.apache.http.client.methods.HttpUriRequest; import org.junit.Before; import org.junit.Test; import org.keycloak.KeycloakSecurityContext; -import org.keycloak.adapters.KeycloakAccount; +import org.keycloak.adapters.OidcKeycloakAccount; import org.keycloak.adapters.springsecurity.account.KeycloakRole; import org.keycloak.adapters.springsecurity.token.KeycloakAuthenticationToken; import org.mockito.Mock; @@ -28,7 +28,7 @@ public class KeycloakClientRequestFactoryTest { private KeycloakClientRequestFactory factory; @Mock - private KeycloakAccount account; + private OidcKeycloakAccount account; @Mock private KeycloakAuthenticationToken keycloakAuthenticationToken; diff --git a/integration/spring-security/src/test/java/org/keycloak/adapters/springsecurity/filter/KeycloakAuthenticationProcessingFilterTest.java b/integration/spring-security/src/test/java/org/keycloak/adapters/springsecurity/filter/KeycloakAuthenticationProcessingFilterTest.java old mode 100644 new mode 100755 index b135906f7c..f1e29c5825 --- a/integration/spring-security/src/test/java/org/keycloak/adapters/springsecurity/filter/KeycloakAuthenticationProcessingFilterTest.java +++ b/integration/spring-security/src/test/java/org/keycloak/adapters/springsecurity/filter/KeycloakAuthenticationProcessingFilterTest.java @@ -6,6 +6,7 @@ import org.keycloak.KeycloakPrincipal; import org.keycloak.KeycloakSecurityContext; import org.keycloak.adapters.KeycloakAccount; import org.keycloak.adapters.KeycloakDeployment; +import org.keycloak.adapters.OidcKeycloakAccount; import org.keycloak.adapters.springsecurity.AdapterDeploymentContextBean; import org.keycloak.adapters.springsecurity.KeycloakAuthenticationException; import org.keycloak.adapters.springsecurity.account.KeycloakRole; @@ -67,7 +68,7 @@ public class KeycloakAuthenticationProcessingFilterTest { private AuthenticationFailureHandler failureHandler; @Mock - private KeycloakAccount keycloakAccount; + private OidcKeycloakAccount keycloakAccount; @Mock private KeycloakDeployment keycloakDeployment; diff --git a/integration/spring-security/src/test/java/org/keycloak/adapters/springsecurity/token/SpringSecurityTokenStoreTest.java b/integration/spring-security/src/test/java/org/keycloak/adapters/springsecurity/token/SpringSecurityTokenStoreTest.java old mode 100644 new mode 100755 index 7088951d5e..b1624aac6f --- a/integration/spring-security/src/test/java/org/keycloak/adapters/springsecurity/token/SpringSecurityTokenStoreTest.java +++ b/integration/spring-security/src/test/java/org/keycloak/adapters/springsecurity/token/SpringSecurityTokenStoreTest.java @@ -3,8 +3,8 @@ package org.keycloak.adapters.springsecurity.token; import org.junit.After; import org.junit.Before; import org.junit.Test; -import org.keycloak.adapters.KeycloakAccount; import org.keycloak.adapters.KeycloakDeployment; +import org.keycloak.adapters.OidcKeycloakAccount; import org.keycloak.adapters.RefreshableKeycloakSecurityContext; import org.keycloak.adapters.RequestAuthenticator; import org.keycloak.adapters.springsecurity.account.KeycloakRole; @@ -17,8 +17,6 @@ import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken; -import javax.servlet.http.HttpSession; - import java.security.Principal; import java.util.Collections; @@ -66,7 +64,7 @@ public class SpringSecurityTokenStoreTest { @Test public void testSaveAccountInfo() throws Exception { - KeycloakAccount account = new SimpleKeycloakAccount(principal, Collections.singleton("FOO"), keycloakSecurityContext); + OidcKeycloakAccount account = new SimpleKeycloakAccount(principal, Collections.singleton("FOO"), keycloakSecurityContext); Authentication authentication; store.saveAccountInfo(account); @@ -78,7 +76,7 @@ public class SpringSecurityTokenStoreTest { @Test(expected = IllegalStateException.class) public void testSaveAccountInfoInvalidAuthenticationType() throws Exception { - KeycloakAccount account = new SimpleKeycloakAccount(principal, Collections.singleton("FOO"), keycloakSecurityContext); + OidcKeycloakAccount account = new SimpleKeycloakAccount(principal, Collections.singleton("FOO"), keycloakSecurityContext); Authentication authentication = new PreAuthenticatedAuthenticationToken("foo", "bar", Collections.singleton(new KeycloakRole("ROLE_FOO"))); SecurityContextHolder.getContext().setAuthentication(authentication); store.saveAccountInfo(account); diff --git a/integration/tomcat/tomcat-core/src/main/java/org/keycloak/adapters/tomcat/GenericPrincipalFactory.java b/integration/tomcat/tomcat-adapter-spi/src/main/java/org/keycloak/adapters/tomcat/GenericPrincipalFactory.java similarity index 96% rename from integration/tomcat/tomcat-core/src/main/java/org/keycloak/adapters/tomcat/GenericPrincipalFactory.java rename to integration/tomcat/tomcat-adapter-spi/src/main/java/org/keycloak/adapters/tomcat/GenericPrincipalFactory.java index 00190b5585..201a409d00 100755 --- a/integration/tomcat/tomcat-core/src/main/java/org/keycloak/adapters/tomcat/GenericPrincipalFactory.java +++ b/integration/tomcat/tomcat-adapter-spi/src/main/java/org/keycloak/adapters/tomcat/GenericPrincipalFactory.java @@ -2,7 +2,6 @@ package org.keycloak.adapters.tomcat; import org.apache.catalina.Realm; import org.apache.catalina.realm.GenericPrincipal; -import org.keycloak.KeycloakSecurityContext; import javax.security.auth.Subject; import java.security.Principal; @@ -20,7 +19,7 @@ import java.util.Set; */ public abstract class GenericPrincipalFactory { - public GenericPrincipal createPrincipal(Realm realm, final Principal identity, final Set roleSet, final KeycloakSecurityContext securityContext) { + public GenericPrincipal createPrincipal(Realm realm, final Principal identity, final Set roleSet) { Subject subject = new Subject(); Set principals = subject.getPrincipals(); principals.add(identity); diff --git a/integration/tomcat/tomcat-core/src/main/java/org/keycloak/adapters/tomcat/CatalinaCookieTokenStore.java b/integration/tomcat/tomcat-core/src/main/java/org/keycloak/adapters/tomcat/CatalinaCookieTokenStore.java index b0b21ab8f6..c70fa06c0e 100755 --- a/integration/tomcat/tomcat-core/src/main/java/org/keycloak/adapters/tomcat/CatalinaCookieTokenStore.java +++ b/integration/tomcat/tomcat-core/src/main/java/org/keycloak/adapters/tomcat/CatalinaCookieTokenStore.java @@ -11,8 +11,8 @@ import org.keycloak.adapters.AdapterTokenStore; import org.keycloak.adapters.AdapterUtils; import org.keycloak.adapters.CookieTokenStore; import org.keycloak.adapters.HttpFacade; -import org.keycloak.adapters.KeycloakAccount; import org.keycloak.adapters.KeycloakDeployment; +import org.keycloak.adapters.OidcKeycloakAccount; import org.keycloak.adapters.RefreshableKeycloakSecurityContext; import org.keycloak.adapters.RequestAuthenticator; @@ -57,7 +57,7 @@ public class CatalinaCookieTokenStore implements AdapterTokenStore { securityContext.setCurrentRequestInfo(deployment, this); Set roles = AdapterUtils.getRolesFromSecurityContext(securityContext); - GenericPrincipal principal = principalFactory.createPrincipal(request.getContext().getRealm(), authenticatedPrincipal, roles, securityContext); + GenericPrincipal principal = principalFactory.createPrincipal(request.getContext().getRealm(), authenticatedPrincipal, roles); request.setAttribute(KeycloakSecurityContext.class.getName(), securityContext); request.setUserPrincipal(principal); @@ -69,7 +69,7 @@ public class CatalinaCookieTokenStore implements AdapterTokenStore { } @Override - public void saveAccountInfo(KeycloakAccount account) { + public void saveAccountInfo(OidcKeycloakAccount account) { RefreshableKeycloakSecurityContext securityContext = (RefreshableKeycloakSecurityContext)account.getKeycloakSecurityContext(); CookieTokenStore.setTokenCookie(deployment, facade, securityContext); } diff --git a/integration/tomcat/tomcat-core/src/main/java/org/keycloak/adapters/tomcat/CatalinaRequestAuthenticator.java b/integration/tomcat/tomcat-core/src/main/java/org/keycloak/adapters/tomcat/CatalinaRequestAuthenticator.java index 438f17015e..0883c762ef 100755 --- a/integration/tomcat/tomcat-core/src/main/java/org/keycloak/adapters/tomcat/CatalinaRequestAuthenticator.java +++ b/integration/tomcat/tomcat-core/src/main/java/org/keycloak/adapters/tomcat/CatalinaRequestAuthenticator.java @@ -1,19 +1,16 @@ package org.keycloak.adapters.tomcat; -import org.apache.catalina.authenticator.Constants; import org.apache.catalina.connector.Request; import org.keycloak.KeycloakPrincipal; import org.keycloak.KeycloakSecurityContext; import org.keycloak.adapters.AdapterTokenStore; import org.keycloak.adapters.AdapterUtils; -import org.keycloak.adapters.KeycloakAccount; import org.keycloak.adapters.KeycloakDeployment; import org.keycloak.adapters.OAuthRequestAuthenticator; +import org.keycloak.adapters.OidcKeycloakAccount; import org.keycloak.adapters.RefreshableKeycloakSecurityContext; import org.keycloak.adapters.RequestAuthenticator; -import org.keycloak.enums.TokenStore; -import java.io.IOException; import java.security.Principal; import java.util.Set; import java.util.logging.Level; @@ -49,7 +46,7 @@ public class CatalinaRequestAuthenticator extends RequestAuthenticator { protected void completeOAuthAuthentication(final KeycloakPrincipal skp) { final RefreshableKeycloakSecurityContext securityContext = skp.getKeycloakSecurityContext(); final Set roles = AdapterUtils.getRolesFromSecurityContext(securityContext); - KeycloakAccount account = new KeycloakAccount() { + OidcKeycloakAccount account = new OidcKeycloakAccount() { @Override public Principal getPrincipal() { @@ -79,7 +76,7 @@ public class CatalinaRequestAuthenticator extends RequestAuthenticator { if (log.isLoggable(Level.FINE)) { log.fine("Completing bearer authentication. Bearer roles: " + roles); } - Principal generalPrincipal = principalFactory.createPrincipal(request.getContext().getRealm(), principal, roles, securityContext); + Principal generalPrincipal = principalFactory.createPrincipal(request.getContext().getRealm(), principal, roles); request.setUserPrincipal(generalPrincipal); request.setAuthType(method); request.setAttribute(KeycloakSecurityContext.class.getName(), securityContext); diff --git a/integration/tomcat/tomcat-core/src/main/java/org/keycloak/adapters/tomcat/CatalinaSessionTokenStore.java b/integration/tomcat/tomcat-core/src/main/java/org/keycloak/adapters/tomcat/CatalinaSessionTokenStore.java index e0d3ca6fb4..9d147fa1df 100755 --- a/integration/tomcat/tomcat-core/src/main/java/org/keycloak/adapters/tomcat/CatalinaSessionTokenStore.java +++ b/integration/tomcat/tomcat-core/src/main/java/org/keycloak/adapters/tomcat/CatalinaSessionTokenStore.java @@ -5,12 +5,11 @@ import org.apache.catalina.connector.Request; import org.apache.catalina.realm.GenericPrincipal; import org.keycloak.KeycloakSecurityContext; import org.keycloak.adapters.AdapterTokenStore; -import org.keycloak.adapters.KeycloakAccount; import org.keycloak.adapters.KeycloakDeployment; +import org.keycloak.adapters.OidcKeycloakAccount; import org.keycloak.adapters.RefreshableKeycloakSecurityContext; import org.keycloak.adapters.RequestAuthenticator; -import java.io.IOException; import java.io.Serializable; import java.security.Principal; import java.util.Set; @@ -69,7 +68,7 @@ public class CatalinaSessionTokenStore extends CatalinaAdapterSessionStore imple } protected void cleanSession(Session catalinaSession) { - catalinaSession.getSession().removeAttribute(KeycloakAccount.class.getName()); + catalinaSession.getSession().removeAttribute(OidcKeycloakAccount.class.getName()); catalinaSession.setPrincipal(null); catalinaSession.setAuthType(null); } @@ -98,7 +97,7 @@ public class CatalinaSessionTokenStore extends CatalinaAdapterSessionStore imple GenericPrincipal principal = (GenericPrincipal) session.getPrincipal(); // in clustered environment in JBossWeb, principal is not serialized or saved if (principal == null) { - principal = principalFactory.createPrincipal(request.getContext().getRealm(), account.getPrincipal(), account.getRoles(), securityContext); + principal = principalFactory.createPrincipal(request.getContext().getRealm(), account.getPrincipal(), account.getRoles()); session.setPrincipal(principal); session.setAuthType("KEYCLOAK"); @@ -110,7 +109,7 @@ public class CatalinaSessionTokenStore extends CatalinaAdapterSessionStore imple return true; } - public static class SerializableKeycloakAccount implements KeycloakAccount, Serializable { + public static class SerializableKeycloakAccount implements OidcKeycloakAccount, Serializable { protected Set roles; protected Principal principal; protected RefreshableKeycloakSecurityContext securityContext; @@ -138,10 +137,10 @@ public class CatalinaSessionTokenStore extends CatalinaAdapterSessionStore imple } @Override - public void saveAccountInfo(KeycloakAccount account) { + public void saveAccountInfo(OidcKeycloakAccount account) { RefreshableKeycloakSecurityContext securityContext = (RefreshableKeycloakSecurityContext) account.getKeycloakSecurityContext(); Set roles = account.getRoles(); - GenericPrincipal principal = principalFactory.createPrincipal(request.getContext().getRealm(), account.getPrincipal(), roles, securityContext); + GenericPrincipal principal = principalFactory.createPrincipal(request.getContext().getRealm(), account.getPrincipal(), roles); SerializableKeycloakAccount sAccount = new SerializableKeycloakAccount(roles, account.getPrincipal(), securityContext); Session session = request.getSessionInternal(true); diff --git a/integration/undertow/src/main/java/org/keycloak/adapters/undertow/KeycloakUndertowAccount.java b/integration/undertow/src/main/java/org/keycloak/adapters/undertow/KeycloakUndertowAccount.java index ea9ab84cc2..c3a0184b26 100755 --- a/integration/undertow/src/main/java/org/keycloak/adapters/undertow/KeycloakUndertowAccount.java +++ b/integration/undertow/src/main/java/org/keycloak/adapters/undertow/KeycloakUndertowAccount.java @@ -21,9 +21,8 @@ import org.jboss.logging.Logger; import org.keycloak.KeycloakPrincipal; import org.keycloak.adapters.AdapterTokenStore; import org.keycloak.adapters.AdapterUtils; -import org.keycloak.adapters.HttpFacade; -import org.keycloak.adapters.KeycloakAccount; import org.keycloak.adapters.KeycloakDeployment; +import org.keycloak.adapters.OidcKeycloakAccount; import org.keycloak.adapters.RefreshableKeycloakSecurityContext; import java.io.Serializable; @@ -34,7 +33,7 @@ import java.util.Set; * @author Bill Burke * @version $Revision: 1 $ */ -public class KeycloakUndertowAccount implements Account, Serializable, KeycloakAccount { +public class KeycloakUndertowAccount implements Account, Serializable, OidcKeycloakAccount { protected static Logger log = Logger.getLogger(KeycloakUndertowAccount.class); protected KeycloakPrincipal principal; protected Set accountRoles; diff --git a/integration/undertow/src/main/java/org/keycloak/adapters/undertow/ServletSessionTokenStore.java b/integration/undertow/src/main/java/org/keycloak/adapters/undertow/ServletSessionTokenStore.java index 74ebf1cd20..5996589748 100755 --- a/integration/undertow/src/main/java/org/keycloak/adapters/undertow/ServletSessionTokenStore.java +++ b/integration/undertow/src/main/java/org/keycloak/adapters/undertow/ServletSessionTokenStore.java @@ -9,8 +9,8 @@ import io.undertow.servlet.handlers.ServletRequestContext; import org.jboss.logging.Logger; import org.keycloak.KeycloakSecurityContext; import org.keycloak.adapters.AdapterTokenStore; -import org.keycloak.adapters.KeycloakAccount; import org.keycloak.adapters.KeycloakDeployment; +import org.keycloak.adapters.OidcKeycloakAccount; import org.keycloak.adapters.RefreshableKeycloakSecurityContext; import org.keycloak.adapters.RequestAuthenticator; @@ -75,7 +75,7 @@ public class ServletSessionTokenStore implements AdapterTokenStore { } @Override - public void saveAccountInfo(KeycloakAccount account) { + public void saveAccountInfo(OidcKeycloakAccount account) { final ServletRequestContext servletRequestContext = exchange.getAttachment(ServletRequestContext.ATTACHMENT_KEY); HttpSession session = getSession(true); session.setAttribute(KeycloakUndertowAccount.class.getName(), account); diff --git a/integration/undertow/src/main/java/org/keycloak/adapters/undertow/UndertowCookieTokenStore.java b/integration/undertow/src/main/java/org/keycloak/adapters/undertow/UndertowCookieTokenStore.java index 7dddb74762..4be2bbeca9 100755 --- a/integration/undertow/src/main/java/org/keycloak/adapters/undertow/UndertowCookieTokenStore.java +++ b/integration/undertow/src/main/java/org/keycloak/adapters/undertow/UndertowCookieTokenStore.java @@ -6,8 +6,8 @@ import org.keycloak.KeycloakPrincipal; import org.keycloak.adapters.AdapterTokenStore; import org.keycloak.adapters.CookieTokenStore; import org.keycloak.adapters.HttpFacade; -import org.keycloak.adapters.KeycloakAccount; import org.keycloak.adapters.KeycloakDeployment; +import org.keycloak.adapters.OidcKeycloakAccount; import org.keycloak.adapters.RefreshableKeycloakSecurityContext; import org.keycloak.adapters.RequestAuthenticator; @@ -63,7 +63,7 @@ public class UndertowCookieTokenStore implements AdapterTokenStore { } @Override - public void saveAccountInfo(KeycloakAccount account) { + public void saveAccountInfo(OidcKeycloakAccount account) { RefreshableKeycloakSecurityContext secContext = (RefreshableKeycloakSecurityContext)account.getKeycloakSecurityContext(); CookieTokenStore.setTokenCookie(deployment, facade, secContext); } diff --git a/integration/undertow/src/main/java/org/keycloak/adapters/undertow/UndertowSessionTokenStore.java b/integration/undertow/src/main/java/org/keycloak/adapters/undertow/UndertowSessionTokenStore.java index 0dae4c9a43..f9fa6c0ce8 100755 --- a/integration/undertow/src/main/java/org/keycloak/adapters/undertow/UndertowSessionTokenStore.java +++ b/integration/undertow/src/main/java/org/keycloak/adapters/undertow/UndertowSessionTokenStore.java @@ -6,8 +6,8 @@ import io.undertow.server.session.Session; import io.undertow.util.Sessions; import org.jboss.logging.Logger; import org.keycloak.adapters.AdapterTokenStore; -import org.keycloak.adapters.KeycloakAccount; import org.keycloak.adapters.KeycloakDeployment; +import org.keycloak.adapters.OidcKeycloakAccount; import org.keycloak.adapters.RefreshableKeycloakSecurityContext; import org.keycloak.adapters.RequestAuthenticator; @@ -81,7 +81,7 @@ public class UndertowSessionTokenStore implements AdapterTokenStore { } @Override - public void saveAccountInfo(KeycloakAccount account) { + public void saveAccountInfo(OidcKeycloakAccount account) { Session session = Sessions.getOrCreateSession(exchange); session.setAttribute(KeycloakUndertowAccount.class.getName(), account); sessionManagement.login(session.getSessionManager()); diff --git a/pom.xml b/pom.xml index 36e8e3e0b1..4fc5896d65 100755 --- a/pom.xml +++ b/pom.xml @@ -768,6 +768,11 @@ keycloak-as7-adapter ${project.version} + + org.keycloak + keycloak-as7-adapter-spi + ${project.version} + org.keycloak keycloak-installed-adapter @@ -873,6 +878,11 @@ keycloak-tomcat6-adapter ${project.version} + + org.keycloak + keycloak-tomcat6-saml-adapter + ${project.version} + org.keycloak keycloak-tomcat7-adapter @@ -973,6 +983,11 @@ keycloak-saml-adapter-core ${project.version} + + org.keycloak + keycloak-tomcat-core-saml-adapter + ${project.version} + org.keycloak keycloak-undertow-saml-adapter diff --git a/saml/client-adapter/core/src/main/java/org/keycloak/adapters/saml/InitiateLogin.java b/saml/client-adapter/core/src/main/java/org/keycloak/adapters/saml/InitiateLogin.java index 1cef2b160a..bcba3d05ff 100755 --- a/saml/client-adapter/core/src/main/java/org/keycloak/adapters/saml/InitiateLogin.java +++ b/saml/client-adapter/core/src/main/java/org/keycloak/adapters/saml/InitiateLogin.java @@ -28,7 +28,7 @@ public class InitiateLogin implements AuthChallenge { @Override public boolean errorPage() { - return true; + return false; } @Override diff --git a/saml/client-adapter/core/src/main/java/org/keycloak/adapters/saml/SamlAuthenticator.java b/saml/client-adapter/core/src/main/java/org/keycloak/adapters/saml/SamlAuthenticator.java index ade3e47dcc..f95bb5d650 100755 --- a/saml/client-adapter/core/src/main/java/org/keycloak/adapters/saml/SamlAuthenticator.java +++ b/saml/client-adapter/core/src/main/java/org/keycloak/adapters/saml/SamlAuthenticator.java @@ -104,14 +104,9 @@ public abstract class SamlAuthenticator { try { SamlUtil.sendSaml(true, facade, deployment.getIDP().getSingleLogoutService().getRequestBindingUrl(), binding, logoutBuilder.buildDocument(), deployment.getIDP().getSingleLogoutService().getRequestBinding()); - } catch (ProcessingException e) { - throw new RuntimeException(e); - } catch (ConfigurationException e) { - throw new RuntimeException(e); - } catch (IOException e) { - throw new RuntimeException(e); - } catch (ParsingException e) { - throw new RuntimeException(e); + } catch (Exception e) { + log.error("Could not send global logout SAML request", e); + return AuthOutcome.FAILED; } return AuthOutcome.NOT_ATTEMPTED; } @@ -134,18 +129,24 @@ public abstract class SamlAuthenticator { RequestAbstractType requestAbstractType = (RequestAbstractType) holder.getSamlObject(); if (!requestUri.equals(requestAbstractType.getDestination().toString())) { log.error("expected destination '" + requestUri + "' got '" + requestAbstractType.getDestination() + "'"); - throw new RuntimeException("destination not equal to request."); + return AuthOutcome.FAILED; } if (requestAbstractType instanceof LogoutRequestType) { if (deployment.getIDP().getSingleLogoutService().validateRequestSignature()) { - validateSamlSignature(holder, postBinding, GeneralConstants.SAML_REQUEST_KEY); + try { + validateSamlSignature(holder, postBinding, GeneralConstants.SAML_REQUEST_KEY); + } catch (VerificationException e) { + log.error("Failed to verify saml request signature", e); + return AuthOutcome.FAILED; + } } LogoutRequestType logout = (LogoutRequestType) requestAbstractType; return logoutRequest(logout, relayState); } else { - throw new RuntimeException("unknown SAML request type"); + log.error("unknown SAML request type"); + return AuthOutcome.FAILED; } } @@ -173,12 +174,9 @@ public abstract class SamlAuthenticator { try { SamlUtil.sendSaml(false, facade, deployment.getIDP().getSingleLogoutService().getResponseBindingUrl(), binding, builder.buildDocument(), deployment.getIDP().getSingleLogoutService().getResponseBinding()); - } catch (ConfigurationException e) { - throw new RuntimeException(e); - } catch (ProcessingException e) { - throw new RuntimeException(e); - } catch (IOException e) { - throw new RuntimeException(e); + } catch (Exception e) { + log.error("Could not send logout response SAML request", e); + return AuthOutcome.FAILED; } return AuthOutcome.NOT_ATTEMPTED; @@ -202,17 +200,28 @@ public abstract class SamlAuthenticator { StatusResponseType statusResponse = (StatusResponseType)holder.getSamlObject(); // validate destination if (!requestUri.equals(statusResponse.getDestination())) { - throw new RuntimeException("destination not equal to request"); + log.error("Request URI does not match SAML request destination"); + return AuthOutcome.FAILED; } if (statusResponse instanceof ResponseType) { if (deployment.getIDP().getSingleSignOnService().validateResponseSignature()) { - validateSamlSignature(holder, postBinding, GeneralConstants.SAML_RESPONSE_KEY); + try { + validateSamlSignature(holder, postBinding, GeneralConstants.SAML_RESPONSE_KEY); + } catch (VerificationException e) { + log.error("Failed to verify saml response signature", e); + return AuthOutcome.FAILED; + } } return handleLoginResponse((ResponseType)statusResponse); } else { if (deployment.getIDP().getSingleLogoutService().validateResponseSignature()) { - validateSamlSignature(holder, postBinding, GeneralConstants.SAML_RESPONSE_KEY); + try { + validateSamlSignature(holder, postBinding, GeneralConstants.SAML_RESPONSE_KEY); + } catch (VerificationException e) { + log.error("Failed to verify saml response signature", e); + return AuthOutcome.FAILED; + } } // todo need to check that it is actually a LogoutResponse return handleLogoutResponse(holder, statusResponse, relayState); @@ -220,16 +229,11 @@ public abstract class SamlAuthenticator { } - private void validateSamlSignature(SAMLDocumentHolder holder, boolean postBinding, String paramKey) { - try { - if (postBinding) { - verifyPostBindingSignature(holder.getSamlDocument(), deployment.getIDP().getSignatureValidationKey()); - } else { - verifyRedirectBindingSignature(deployment.getIDP().getSignatureValidationKey(), paramKey); - } - } catch (VerificationException e) { - log.error("validation failed", e); - throw new RuntimeException("invalid document signature"); + private void validateSamlSignature(SAMLDocumentHolder holder, boolean postBinding, String paramKey) throws VerificationException { + if (postBinding) { + verifyPostBindingSignature(holder.getSamlDocument(), deployment.getIDP().getSignatureValidationKey()); + } else { + verifyRedirectBindingSignature(deployment.getIDP().getSignatureValidationKey(), paramKey); } } @@ -240,12 +244,9 @@ public abstract class SamlAuthenticator { if (AssertionUtil.hasExpired(assertion)) { return initiateLogin(); } - } catch (ParsingException e) { - throw new RuntimeException(e); - } catch (ProcessingException e) { - throw new RuntimeException(e); - } catch (ConfigurationException e) { - throw new RuntimeException(e); + } catch (Exception e) { + log.error("Error extracting SAML assertion, e"); + return AuthOutcome.FAILED; } SubjectType subject = assertion.getSubject(); @@ -269,6 +270,7 @@ public abstract class SamlAuthenticator { if (attributeValues != null) { for (Object attrValue : attributeValues) { String role = getAttributeValue(attrValue); + log.info("Add role: " + role); roles.add(role); } } @@ -314,22 +316,7 @@ public abstract class SamlAuthenticator { final SamlPrincipal principal = new SamlPrincipal(principalName, principalName, subjectNameID.getFormat().toString(), attributes, friendlyAttributes); String index = authn == null ? null : authn.getSessionIndex(); final String sessionIndex = index; - SamlSession account = new SamlSession() { - @Override - public SamlPrincipal getPrincipal() { - return principal; - } - - @Override - public Set getRoles() { - return roles; - } - - @Override - public String getSessionIndex() { - return sessionIndex; - } - }; + SamlSession account = new SamlSession(principal, roles, sessionIndex); sessionStore.saveAccount(account); completeAuthentication(account); @@ -343,7 +330,7 @@ public abstract class SamlAuthenticator { } else { log.debug("IDP initiated invocation"); } - + log.debug("AUTHENTICATED authn"); return AuthOutcome.AUTHENTICATED; } @@ -351,7 +338,7 @@ public abstract class SamlAuthenticator { protected abstract void completeAuthentication(SamlSession account); private String getAttributeValue(Object attrValue) { - String value; + String value = null; if (attrValue instanceof String) { value = (String)attrValue; } else if (attrValue instanceof Node) { @@ -360,8 +347,9 @@ public abstract class SamlAuthenticator { } else if (attrValue instanceof NameIDType) { NameIDType nameIdType = (NameIDType) attrValue; value = nameIdType.getValue(); - } else - throw new RuntimeException("Unknown attribute value type: " + attrValue.getClass().getName()); + } else { + log.warn("Unable to extract unknown SAML assertion attribute value type: " + attrValue.getClass().getName()); + } return value; } diff --git a/saml/client-adapter/core/src/main/java/org/keycloak/adapters/saml/SamlSession.java b/saml/client-adapter/core/src/main/java/org/keycloak/adapters/saml/SamlSession.java index b3a1833efa..df53ed6a6a 100755 --- a/saml/client-adapter/core/src/main/java/org/keycloak/adapters/saml/SamlSession.java +++ b/saml/client-adapter/core/src/main/java/org/keycloak/adapters/saml/SamlSession.java @@ -8,8 +8,29 @@ import java.util.Set; * @author Bill Burke * @version $Revision: 1 $ */ -public interface SamlSession extends Serializable { - SamlPrincipal getPrincipal(); - Set getRoles(); - String getSessionIndex(); +public class SamlSession implements Serializable { + private SamlPrincipal principal; + private Set roles; + private String sessionIndex; + + public SamlSession() { + } + + public SamlSession(SamlPrincipal principal, Set roles, String sessionIndex) { + this.principal = principal; + this.roles = roles; + this.sessionIndex = sessionIndex; + } + + public SamlPrincipal getPrincipal() { + return principal; + } + + public Set getRoles() { + return roles; + } + + public String getSessionIndex() { + return sessionIndex; + } } diff --git a/saml/client-adapter/pom.xml b/saml/client-adapter/pom.xml index e1c0b715a6..9c2ac047a9 100755 --- a/saml/client-adapter/pom.xml +++ b/saml/client-adapter/pom.xml @@ -16,5 +16,6 @@ core undertow + tomcat diff --git a/saml/client-adapter/tomcat/pom.xml b/saml/client-adapter/tomcat/pom.xml new file mode 100755 index 0000000000..141343cd3b --- /dev/null +++ b/saml/client-adapter/tomcat/pom.xml @@ -0,0 +1,22 @@ + + + keycloak-parent + org.keycloak + 1.6.0.Final-SNAPSHOT + ../../../pom.xml + + Keycloak SAML Tomcat Integration + + 4.0.0 + + keycloak-tomcat-saml-integration-pom + pom + + + tomcat-core + tomcat6 + tomcat7 + tomcat8 + + diff --git a/saml/client-adapter/tomcat/tomcat-core/pom.xml b/saml/client-adapter/tomcat/tomcat-core/pom.xml new file mode 100755 index 0000000000..5402eacdf9 --- /dev/null +++ b/saml/client-adapter/tomcat/tomcat-core/pom.xml @@ -0,0 +1,89 @@ + + + + keycloak-parent + org.keycloak + 1.6.0.Final-SNAPSHOT + ../../../../pom.xml + + 4.0.0 + + keycloak-tomcat-core-saml-adapter + Keycloak Tomcat Core SAML Integration + + + + 6.0.41 + + + + + + org.jboss.logging + jboss-logging + ${jboss.logging.version} + + + org.keycloak + keycloak-core + + + org.keycloak + keycloak-adapter-spi + + + org.keycloak + keycloak-tomcat-adapter-spi + + + org.apache.httpcomponents + httpclient + + + org.bouncycastle + bcprov-jdk15on + + + org.keycloak + keycloak-saml-core + + + org.keycloak + keycloak-saml-adapter-core + + + + org.apache.tomcat + catalina + ${tomcat.version} + compile + + + + junit + junit + test + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + 1.6 + 1.6 + + + + + + diff --git a/saml/client-adapter/tomcat/tomcat-core/src/main/java/org/keycloak/adapters/saml/AbstractSamlAuthenticatorValve.java b/saml/client-adapter/tomcat/tomcat-core/src/main/java/org/keycloak/adapters/saml/AbstractSamlAuthenticatorValve.java new file mode 100755 index 0000000000..bf21055c22 --- /dev/null +++ b/saml/client-adapter/tomcat/tomcat-core/src/main/java/org/keycloak/adapters/saml/AbstractSamlAuthenticatorValve.java @@ -0,0 +1,255 @@ +package org.keycloak.adapters.saml; + +import org.apache.catalina.Context; +import org.apache.catalina.Lifecycle; +import org.apache.catalina.LifecycleEvent; +import org.apache.catalina.LifecycleListener; +import org.apache.catalina.authenticator.FormAuthenticator; +import org.apache.catalina.connector.Request; +import org.apache.catalina.connector.Response; +import org.keycloak.KeycloakSecurityContext; +import org.keycloak.adapters.AuthChallenge; +import org.keycloak.adapters.AuthOutcome; +import org.keycloak.adapters.HttpFacade; +import org.keycloak.adapters.InMemorySessionIdMapper; +import org.keycloak.adapters.SessionIdMapper; +import org.keycloak.adapters.saml.config.parsers.DeploymentBuilder; +import org.keycloak.adapters.saml.config.parsers.ResourceLoader; +import org.keycloak.adapters.tomcat.CatalinaHttpFacade; +import org.keycloak.adapters.tomcat.CatalinaUserSessionManagement; +import org.keycloak.adapters.tomcat.GenericPrincipalFactory; +import org.keycloak.constants.AdapterConstants; +import org.keycloak.saml.common.exceptions.ParsingException; + +import javax.servlet.RequestDispatcher; +import javax.servlet.ServletContext; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletResponse; +import java.io.ByteArrayInputStream; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * Keycloak authentication valve + * + * @author Davide Ungari + * @author Bill Burke + * @version $Revision: 1 $ + */ +public abstract class AbstractSamlAuthenticatorValve extends FormAuthenticator implements LifecycleListener { + + public static final String TOKEN_STORE_NOTE = "TOKEN_STORE_NOTE"; + + private final static Logger log = Logger.getLogger(""+AbstractSamlAuthenticatorValve.class); + protected CatalinaUserSessionManagement userSessionManagement = new CatalinaUserSessionManagement(); + protected SamlDeploymentContext deploymentContext; + protected SessionIdMapper mapper = new InMemorySessionIdMapper(); + + @Override + public void lifecycleEvent(LifecycleEvent event) { + if (Lifecycle.START_EVENT.equals(event.getType())) { + cache = false; + } else if (Lifecycle.AFTER_START_EVENT.equals(event.getType())) { + keycloakInit(); + } else if (event.getType() == Lifecycle.BEFORE_STOP_EVENT) { + beforeStop(); + } + } + + protected void logoutInternal(Request request) { + KeycloakSecurityContext ksc = (KeycloakSecurityContext)request.getAttribute(KeycloakSecurityContext.class.getName()); + if (ksc != null) { + CatalinaHttpFacade facade = new CatalinaHttpFacade(null, request); + SamlDeployment deployment = deploymentContext.resolveDeployment(facade); + SamlSessionStore tokenStore = getTokenStore(request, facade, deployment); + tokenStore.logoutAccount(); + } + request.setUserPrincipal(null); + } + + @SuppressWarnings("UseSpecificCatch") + public void keycloakInit() { + // Possible scenarios: + // 1) The deployment has a keycloak.config.resolver specified and it exists: + // Outcome: adapter uses the resolver + // 2) The deployment has a keycloak.config.resolver and isn't valid (doesn't exists, isn't a resolver, ...) : + // Outcome: adapter is left unconfigured + // 3) The deployment doesn't have a keycloak.config.resolver , but has a keycloak.json (or equivalent) + // Outcome: adapter uses it + // 4) The deployment doesn't have a keycloak.config.resolver nor keycloak.json (or equivalent) + // Outcome: adapter is left unconfigured + + String configResolverClass = context.getServletContext().getInitParameter("keycloak.config.resolver"); + if (configResolverClass != null) { + try { + throw new RuntimeException("Not implemented yet"); + //KeycloakConfigResolver configResolver = (KeycloakConfigResolver) context.getLoader().getClassLoader().loadClass(configResolverClass).newInstance(); + //deploymentContext = new SamlDeploymentContext(configResolver); + //log.log(Level.INFO, "Using {0} to resolve Keycloak configuration on a per-request basis.", configResolverClass); + } catch (Exception ex) { + log.log(Level.FINE, "The specified resolver {0} could NOT be loaded. Keycloak is unconfigured and will deny all requests. Reason: {1}", new Object[]{configResolverClass, ex.getMessage()}); + //deploymentContext = new AdapterDeploymentContext(new KeycloakDeployment()); + } + } else { + InputStream is = getConfigInputStream(context); + final SamlDeployment deployment; + if (is == null) { + log.info("No adapter configuration. Keycloak is unconfigured and will deny all requests."); + deployment = new DefaultSamlDeployment(); + } else { + try { + ResourceLoader loader = new ResourceLoader() { + @Override + public InputStream getResourceAsStream(String resource) { + return context.getServletContext().getResourceAsStream(resource); + } + }; + deployment = new DeploymentBuilder().build(is, loader); + } catch (ParsingException e) { + throw new RuntimeException(e); + } + } + deploymentContext = new SamlDeploymentContext(deployment); + log.fine("Keycloak is using a per-deployment configuration."); + } + + context.getServletContext().setAttribute(SamlDeploymentContext.class.getName(), deploymentContext); + } + + protected void beforeStop() { + } + + private static InputStream getConfigFromServletContext(ServletContext servletContext) { + String xml = servletContext.getInitParameter(AdapterConstants.AUTH_DATA_PARAM_NAME); + if (xml == null) { + return null; + } + log.finest("**** using " + AdapterConstants.AUTH_DATA_PARAM_NAME); + log.finest(xml); + return new ByteArrayInputStream(xml.getBytes()); + } + + private static InputStream getConfigInputStream(Context context) { + InputStream is = getConfigFromServletContext(context.getServletContext()); + if (is == null) { + String path = context.getServletContext().getInitParameter("keycloak.config.file"); + if (path == null) { + log.fine("**** using /WEB-INF/keycloak-saml.xml"); + is = context.getServletContext().getResourceAsStream("/WEB-INF/keycloak-saml.xml"); + } else { + try { + is = new FileInputStream(path); + } catch (FileNotFoundException e) { + log.log(Level.SEVERE, "NOT FOUND {0}", path); + throw new RuntimeException(e); + } + } + } + return is; + } + + @Override + public void invoke(Request request, Response response) throws IOException, ServletException { + log.fine("*********************** SAML ************"); + try { + super.invoke(request, response); + } finally { + } + } + + protected abstract GenericPrincipalFactory createPrincipalFactory(); + protected abstract boolean forwardToErrorPageInternal(Request request, HttpServletResponse response, Object loginConfig) throws IOException; + protected void forwardToLogoutPage(Request request, HttpServletResponse response,SamlDeployment deployment) { + RequestDispatcher disp = request.getRequestDispatcher(deployment.getLogoutPage()); + //make sure the login page is never cached + response.setHeader("Cache-Control", "no-cache, no-store, must-revalidate"); + response.setHeader("Pragma", "no-cache"); + response.setHeader("Expires", "0"); + + + try { + disp.forward(request, response); + } catch (ServletException e) { + throw new RuntimeException(e); + } catch (IOException e) { + throw new RuntimeException(e); + } + + } + + protected boolean authenticateInternal(Request request, HttpServletResponse response, Object loginConfig) throws IOException { + log.info("authenticateInternal"); + CatalinaHttpFacade facade = new CatalinaHttpFacade(response, request); + SamlDeployment deployment = deploymentContext.resolveDeployment(facade); + if (deployment == null || !deployment.isConfigured()) { + log.fine("deployment not configured"); + return false; + } + SamlSessionStore tokenStore = getTokenStore(request, facade, deployment); + + + CatalinaSamlAuthenticator authenticator = new CatalinaSamlAuthenticator(facade, deployment, tokenStore); + AuthOutcome outcome = authenticator.authenticate(); + if (outcome == AuthOutcome.AUTHENTICATED) { + log.fine("AUTHENTICATED"); + if (facade.isEnded()) { + return false; + } + return true; + } + if (outcome == AuthOutcome.LOGGED_OUT) { + logoutInternal(request); + if (deployment.getLogoutPage() != null) { + forwardToLogoutPage(request, response, deployment); + + } + log.fine("Logging OUT"); + return false; + } + + AuthChallenge challenge = authenticator.getChallenge(); + if (challenge != null) { + log.fine("challenge"); + if (loginConfig == null) { + loginConfig = request.getContext().getLoginConfig(); + } + if (challenge.errorPage()) { + log.fine("error page"); + if (forwardToErrorPageInternal(request, response, loginConfig))return false; + } + log.fine("sending challenge"); + challenge.challenge(facade); + } + log.fine("No challenge, but failed authentication"); + return false; + } + + public void keycloakSaveRequest(Request request) throws IOException { + saveRequest(request, request.getSessionInternal(true)); + } + + public boolean keycloakRestoreRequest(Request request) { + try { + return restoreRequest(request, request.getSessionInternal()); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + protected SamlSessionStore getTokenStore(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); + + request.setNote(TOKEN_STORE_NOTE, store); + return store; + } + +} diff --git a/saml/client-adapter/tomcat/tomcat-core/src/main/java/org/keycloak/adapters/saml/CatalinaSamlAuthenticator.java b/saml/client-adapter/tomcat/tomcat-core/src/main/java/org/keycloak/adapters/saml/CatalinaSamlAuthenticator.java new file mode 100755 index 0000000000..2beb39cf8d --- /dev/null +++ b/saml/client-adapter/tomcat/tomcat-core/src/main/java/org/keycloak/adapters/saml/CatalinaSamlAuthenticator.java @@ -0,0 +1,18 @@ +package org.keycloak.adapters.saml; + +import org.keycloak.adapters.HttpFacade; + +/** + * @author Bill Burke + * @version $Revision: 1 $ + */ +public class CatalinaSamlAuthenticator extends SamlAuthenticator { + public CatalinaSamlAuthenticator(HttpFacade facade, SamlDeployment deployment, SamlSessionStore sessionStore) { + super(facade, deployment, sessionStore); + } + + @Override + protected void completeAuthentication(SamlSession account) { + // complete + } +} diff --git a/saml/client-adapter/tomcat/tomcat-core/src/main/java/org/keycloak/adapters/saml/CatalinaSamlSessionStore.java b/saml/client-adapter/tomcat/tomcat-core/src/main/java/org/keycloak/adapters/saml/CatalinaSamlSessionStore.java new file mode 100755 index 0000000000..4928a2627d --- /dev/null +++ b/saml/client-adapter/tomcat/tomcat-core/src/main/java/org/keycloak/adapters/saml/CatalinaSamlSessionStore.java @@ -0,0 +1,193 @@ +package org.keycloak.adapters.saml; + +import org.apache.catalina.Manager; +import org.apache.catalina.Session; +import org.apache.catalina.connector.Request; +import org.apache.catalina.realm.GenericPrincipal; +import org.jboss.logging.Logger; +import org.keycloak.adapters.HttpFacade; +import org.keycloak.adapters.SessionIdMapper; +import org.keycloak.adapters.tomcat.CatalinaUserSessionManagement; +import org.keycloak.adapters.tomcat.GenericPrincipalFactory; +import org.keycloak.util.KeycloakUriBuilder; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpSession; +import java.io.IOException; +import java.security.Principal; +import java.util.LinkedList; +import java.util.List; +import java.util.Set; + +/** + * @author Bill Burke + * @version $Revision: 1 $ + */ +public class CatalinaSamlSessionStore implements SamlSessionStore { + protected static Logger log = Logger.getLogger(SamlSessionStore.class); + public static final String SAML_REDIRECT_URI = "SAML_REDIRECT_URI"; + + private final CatalinaUserSessionManagement sessionManagement; + protected final GenericPrincipalFactory principalFactory; + private final SessionIdMapper idMapper; + protected final Request request; + protected final AbstractSamlAuthenticatorValve valve; + protected final HttpFacade facade; + + public CatalinaSamlSessionStore(CatalinaUserSessionManagement sessionManagement, GenericPrincipalFactory principalFactory, + SessionIdMapper idMapper, Request request, AbstractSamlAuthenticatorValve valve, HttpFacade facade) { + this.sessionManagement = sessionManagement; + this.principalFactory = principalFactory; + this.idMapper = idMapper; + this.request = request; + this.valve = valve; + this.facade = facade; + } + + @Override + public void logoutAccount() { + Session sessionInternal = request.getSessionInternal(false); + if (sessionInternal == null) return; + HttpSession session = sessionInternal.getSession(); + if (session != null) { + SamlSession samlSession = (SamlSession)session.getAttribute(SamlSession.class.getName()); + if (samlSession != null) { + if (samlSession.getSessionIndex() != null) { + idMapper.removeSession(session.getId()); + } + session.removeAttribute(SamlSession.class.getName()); + } + session.removeAttribute(SAML_REDIRECT_URI); + } + sessionInternal.setPrincipal(null); + sessionInternal.setAuthType(null); + } + + @Override + public void logoutByPrincipal(String principal) { + Set sessions = idMapper.getUserSessions(principal); + if (sessions != null) { + List ids = new LinkedList(); + ids.addAll(sessions); + logoutSessionIds(ids); + for (String id : ids) { + idMapper.removeSession(id); + } + } + + } + + @Override + public void logoutBySsoId(List ssoIds) { + if (ssoIds == null) return; + List sessionIds = new LinkedList(); + for (String id : ssoIds) { + String sessionId = idMapper.getSessionFromSSO(id); + if (sessionId != null) { + sessionIds.add(sessionId); + idMapper.removeSession(sessionId); + } + + } + logoutSessionIds(sessionIds); + } + + protected void logoutSessionIds(List sessionIds) { + if (sessionIds == null || sessionIds.isEmpty()) return; + Manager sessionManager = request.getContext().getManager(); + sessionManagement.logoutHttpSessions(sessionManager, sessionIds); + } + + @Override + public boolean isLoggedIn() { + Session session = request.getSessionInternal(false); + if (session == null) return false; + if (session == null) { + log.debug("session was null, returning null"); + return false; + } + final SamlSession samlSession = (SamlSession)session.getSession().getAttribute(SamlSession.class.getName()); + if (samlSession == null) { + log.debug("SamlSession was not in session, returning null"); + return false; + } + + GenericPrincipal principal = (GenericPrincipal) session.getPrincipal(); + if (samlSession.getPrincipal().getName().equals(principal.getName())) + // in clustered environment in JBossWeb, principal is not serialized or saved + if (principal == null) { + principal = principalFactory.createPrincipal(request.getContext().getRealm(), samlSession.getPrincipal(), samlSession.getRoles()); + session.setPrincipal(principal); + session.setAuthType("KEYCLOAK-SAML"); + + } else { + if (!principal.getUserPrincipal().getName().equals(samlSession.getPrincipal().getName())) { + throw new RuntimeException("Unknown State"); + } + log.debug("************principal already in"); + if (log.isDebugEnabled()) { + for (String role : principal.getRoles()) { + log.debug("principal role: " + role); + } + } + + } + request.setUserPrincipal(principal); + request.setAuthType("KEYCLOAK-SAML"); + restoreRequest(); + return true; + } + + @Override + public void saveAccount(SamlSession account) { + Session session = request.getSessionInternal(true); + session.getSession().setAttribute(SamlSession.class.getName(), account); + GenericPrincipal principal = (GenericPrincipal) session.getPrincipal(); + // in clustered environment in JBossWeb, principal is not serialized or saved + if (principal == null) { + principal = principalFactory.createPrincipal(request.getContext().getRealm(), account.getPrincipal(), account.getRoles()); + session.setPrincipal(principal); + session.setAuthType("KEYCLOAK-SAML"); + + } + request.setUserPrincipal(principal); + request.setAuthType("KEYCLOAK-SAML"); + idMapper.map(account.getSessionIndex(), account.getPrincipal().getSamlSubject(), session.getId()); + + } + + @Override + public SamlSession getAccount() { + HttpSession session = getSession(true); + return (SamlSession)session.getAttribute(SamlSession.class.getName()); + } + + @Override + public String getRedirectUri() { + return (String)getSession(true).getAttribute(SAML_REDIRECT_URI); + } + + @Override + public void saveRequest() { + try { + valve.keycloakSaveRequest(request); + } catch (IOException e) { + throw new RuntimeException(e); + } + + getSession(true).setAttribute(SAML_REDIRECT_URI, facade.getRequest().getURI()); + + } + + @Override + public boolean restoreRequest() { + getSession(true).removeAttribute(SAML_REDIRECT_URI); + return valve.keycloakRestoreRequest(request); + } + + protected HttpSession getSession(boolean create) { + Session session = request.getSessionInternal(create); + if (session == null) return null; + return session.getSession(); + } +} diff --git a/saml/client-adapter/tomcat/tomcat6/pom.xml b/saml/client-adapter/tomcat/tomcat6/pom.xml new file mode 100755 index 0000000000..9c8e6aca4a --- /dev/null +++ b/saml/client-adapter/tomcat/tomcat6/pom.xml @@ -0,0 +1,76 @@ + + + + keycloak-parent + org.keycloak + 1.6.0.Final-SNAPSHOT + ../../../../pom.xml + + 4.0.0 + + keycloak-tomcat6-saml-adapter + Keycloak Tomcat 6 Saml Integration + + 6.0.41 + + + + + + org.jboss.logging + jboss-logging + ${jboss.logging.version} + + + org.keycloak + keycloak-tomcat-core-saml-adapter + + + org.apache.tomcat + tomcat-servlet-api + + + org.apache.tomcat + tomcat-catalina + + + org.apache.tomcat + catalina + + + + + org.apache.httpcomponents + httpclient + + + org.bouncycastle + bcprov-jdk15on + + + org.apache.tomcat + catalina + ${tomcat.version} + provided + + + junit + junit + test + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + 1.6 + 1.6 + + + + + + diff --git a/saml/client-adapter/tomcat/tomcat6/src/main/java/org/keycloak/adapters/saml/tomcat/SamlAuthenticatorValve.java b/saml/client-adapter/tomcat/tomcat6/src/main/java/org/keycloak/adapters/saml/tomcat/SamlAuthenticatorValve.java new file mode 100755 index 0000000000..1541038de1 --- /dev/null +++ b/saml/client-adapter/tomcat/tomcat6/src/main/java/org/keycloak/adapters/saml/tomcat/SamlAuthenticatorValve.java @@ -0,0 +1,60 @@ +package org.keycloak.adapters.saml.tomcat; + +import org.apache.catalina.LifecycleException; +import org.apache.catalina.connector.Request; +import org.apache.catalina.connector.Response; +import org.apache.catalina.core.StandardContext; +import org.apache.catalina.deploy.LoginConfig; +import org.apache.catalina.realm.GenericPrincipal; +import org.keycloak.adapters.saml.AbstractSamlAuthenticatorValve; +import org.keycloak.adapters.tomcat.GenericPrincipalFactory; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.security.Principal; +import java.util.List; + +/** + * Keycloak authentication valve + * + * @author Bill Burke + * @version $Revision: 1 $ + */ +public class SamlAuthenticatorValve extends AbstractSamlAuthenticatorValve { + @Override + public boolean authenticate(Request request, Response response, LoginConfig config) throws IOException { + return authenticateInternal(request, response, config); + } + + @Override + protected boolean forwardToErrorPageInternal(Request request, HttpServletResponse response, Object loginConfig) throws IOException { + if (loginConfig == null) return false; + LoginConfig config = (LoginConfig)loginConfig; + if (config.getErrorPage() == null) return false; + forwardToErrorPage(request, (Response)response, config); + return true; + } + + + @Override + public void start() throws LifecycleException { + StandardContext standardContext = (StandardContext) context; + standardContext.addLifecycleListener(this); + super.start(); + } + + public void logout(Request request) throws ServletException { + logoutInternal(request); + } + + @Override + protected GenericPrincipalFactory createPrincipalFactory() { + return new GenericPrincipalFactory() { + @Override + protected GenericPrincipal createPrincipal(Principal userPrincipal, List roles) { + return new GenericPrincipal(null, userPrincipal.getName(), null, roles, userPrincipal, null); + } + }; + } +} diff --git a/saml/client-adapter/tomcat/tomcat7/pom.xml b/saml/client-adapter/tomcat/tomcat7/pom.xml new file mode 100755 index 0000000000..6a94f99f81 --- /dev/null +++ b/saml/client-adapter/tomcat/tomcat7/pom.xml @@ -0,0 +1,84 @@ + + + + keycloak-parent + org.keycloak + 1.6.0.Final-SNAPSHOT + ../../../../pom.xml + + 4.0.0 + + keycloak-tomcat7-saml-adapter + Keycloak Tomcat 7 SAML Integration + + + 7.0.52 + + + + + + org.jboss.logging + jboss-logging + ${jboss.logging.version} + + + org.keycloak + keycloak-tomcat-core-saml-adapter + + + org.apache.tomcat + tomcat-servlet-api + + + org.apache.tomcat + tomcat-catalina + + + org.apache.tomcat + catalina + + + + + org.apache.httpcomponents + httpclient + + + org.bouncycastle + bcprov-jdk15on + + + org.apache.tomcat + tomcat-servlet-api + ${tomcat.version} + provided + + + org.apache.tomcat + tomcat-catalina + ${tomcat.version} + provided + + + + junit + junit + test + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + 1.6 + 1.6 + + + + + + diff --git a/saml/client-adapter/tomcat/tomcat7/src/main/java/org/keycloak/adapters/saml/tomcat/SamlAuthenticatorValve.java b/saml/client-adapter/tomcat/tomcat7/src/main/java/org/keycloak/adapters/saml/tomcat/SamlAuthenticatorValve.java new file mode 100755 index 0000000000..54f9a4226a --- /dev/null +++ b/saml/client-adapter/tomcat/tomcat7/src/main/java/org/keycloak/adapters/saml/tomcat/SamlAuthenticatorValve.java @@ -0,0 +1,56 @@ +package org.keycloak.adapters.saml.tomcat; + +import org.apache.catalina.connector.Request; +import org.apache.catalina.connector.Response; +import org.apache.catalina.core.StandardContext; +import org.apache.catalina.deploy.LoginConfig; +import org.apache.catalina.realm.GenericPrincipal; +import org.keycloak.adapters.saml.AbstractSamlAuthenticatorValve; +import org.keycloak.adapters.tomcat.GenericPrincipalFactory; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.security.Principal; +import java.util.List; + +/** + * Keycloak authentication valve + * + * @author Bill Burke + * @version $Revision: 1 $ + */ +public class SamlAuthenticatorValve extends AbstractSamlAuthenticatorValve { + public boolean authenticate(Request request, HttpServletResponse response, LoginConfig config) throws IOException { + return authenticateInternal(request, response, config); + } + + @Override + protected boolean forwardToErrorPageInternal(Request request, HttpServletResponse response, Object loginConfig) throws IOException { + if (loginConfig == null) return false; + LoginConfig config = (LoginConfig)loginConfig; + if (config.getErrorPage() == null) return false; + forwardToErrorPage(request, (Response)response, config); + return true; + } + + + protected void initInternal() { + StandardContext standardContext = (StandardContext) context; + standardContext.addLifecycleListener(this); + } + + public void logout(Request request) throws ServletException { + logoutInternal(request); + } + + @Override + protected GenericPrincipalFactory createPrincipalFactory() { + return new GenericPrincipalFactory() { + @Override + protected GenericPrincipal createPrincipal(Principal userPrincipal, List roles) { + return new GenericPrincipal(userPrincipal.getName(), null, roles, userPrincipal, null); + } + }; + } +} diff --git a/saml/client-adapter/tomcat/tomcat8/pom.xml b/saml/client-adapter/tomcat/tomcat8/pom.xml new file mode 100755 index 0000000000..c3da5902fb --- /dev/null +++ b/saml/client-adapter/tomcat/tomcat8/pom.xml @@ -0,0 +1,83 @@ + + + + keycloak-parent + org.keycloak + 1.6.0.Final-SNAPSHOT + ../../../../pom.xml + + 4.0.0 + + keycloak-tomcat8-saml-adapter + Keycloak Tomcat 8 SAML Integration + + 8.0.14 + + + + + + org.jboss.logging + jboss-logging + ${jboss.logging.version} + + + org.apache.tomcat + tomcat-servlet-api + ${tomcat.version} + provided + + + org.apache.tomcat + tomcat-catalina + ${tomcat.version} + provided + + + + org.keycloak + keycloak-tomcat-core-saml-adapter + + + org.apache.tomcat + tomcat-servlet-api + + + org.apache.tomcat + tomcat-catalina + + + org.apache.tomcat + catalina + + + + + org.apache.httpcomponents + httpclient + + + org.bouncycastle + bcprov-jdk15on + + + junit + junit + test + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + 1.6 + 1.6 + + + + + + diff --git a/saml/client-adapter/tomcat/tomcat8/src/main/java/org/keycloak/adapters/saml/tomcat/SamlAuthenticatorValve.java b/saml/client-adapter/tomcat/tomcat8/src/main/java/org/keycloak/adapters/saml/tomcat/SamlAuthenticatorValve.java new file mode 100755 index 0000000000..ead126a913 --- /dev/null +++ b/saml/client-adapter/tomcat/tomcat8/src/main/java/org/keycloak/adapters/saml/tomcat/SamlAuthenticatorValve.java @@ -0,0 +1,71 @@ +package org.keycloak.adapters.saml.tomcat; + +import org.apache.catalina.authenticator.FormAuthenticator; +import org.apache.catalina.connector.Request; +import org.apache.catalina.core.StandardContext; +import org.apache.catalina.realm.GenericPrincipal; +import org.apache.tomcat.util.descriptor.web.LoginConfig; +import org.keycloak.adapters.saml.AbstractSamlAuthenticatorValve; +import org.keycloak.adapters.tomcat.GenericPrincipalFactory; + +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.lang.reflect.Method; +import java.security.Principal; +import java.util.List; + +/** + * Keycloak authentication valve + * + * @author Bill Burke + * @version $Revision: 1 $ + */ +public class SamlAuthenticatorValve extends AbstractSamlAuthenticatorValve { + public boolean authenticate(Request request, HttpServletResponse response) throws IOException { + return authenticateInternal(request, response, request.getContext().getLoginConfig()); + } + + @Override + protected boolean forwardToErrorPageInternal(Request request, HttpServletResponse response, Object loginConfig) throws IOException { + if (loginConfig == null) return false; + LoginConfig config = (LoginConfig)loginConfig; + if (config.getErrorPage() == null) return false; + // had to do this to get around compiler/IDE issues :( + try { + Method method = null; + /* + for (Method m : getClass().getDeclaredMethods()) { + if (m.getName().equals("forwardToErrorPage")) { + method = m; + break; + } + } + */ + method = FormAuthenticator.class.getDeclaredMethod("forwardToErrorPage", Request.class, HttpServletResponse.class, LoginConfig.class); + method.setAccessible(true); + method.invoke(this, request, response, config); + } catch (Exception e) { + throw new RuntimeException(e); + } + return true; + } + + protected void initInternal() { + StandardContext standardContext = (StandardContext) context; + standardContext.addLifecycleListener(this); + } + + public void logout(Request request) { + logoutInternal(request); + } + + @Override + protected GenericPrincipalFactory createPrincipalFactory() { + return new GenericPrincipalFactory() { + @Override + protected GenericPrincipal createPrincipal(Principal userPrincipal, List roles) { + return new GenericPrincipal(userPrincipal.getName(), null, roles, userPrincipal, null); + } + }; + } +} diff --git a/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SamlService.java b/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SamlService.java index 9521e0c5c7..6aae844da6 100755 --- a/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SamlService.java +++ b/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SamlService.java @@ -174,6 +174,7 @@ public class SamlService { if (client == null) { event.event(EventType.LOGIN); + event.client(issuer); event.error(Errors.CLIENT_NOT_FOUND); return ErrorPage.error(session, Messages.UNKNOWN_LOGIN_REQUESTER); } 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 new file mode 100755 index 0000000000..358fd23382 --- /dev/null +++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/keycloaksaml/SamlAdapterTest.java @@ -0,0 +1,138 @@ +package org.keycloak.testsuite.keycloaksaml; + +import org.junit.Assert; +import org.junit.ClassRule; +import org.junit.Rule; +import org.junit.Test; +import org.openqa.selenium.WebDriver; + +/** + * @author Bill Burke + * @version $Revision: 1 $ + */ +public class SamlAdapterTest { + + @ClassRule + public static SamlKeycloakRule keycloakRule = new SamlKeycloakRule() { + @Override + public void initWars() { + ClassLoader classLoader = SamlAdapterTest.class.getClassLoader(); + + initializeSamlSecuredWar("/keycloak-saml/simple-post", "/sales-post", "post.war", classLoader); + initializeSamlSecuredWar("/keycloak-saml/signed-post", "/sales-post-sig", "post-sig.war", classLoader); + initializeSamlSecuredWar("/keycloak-saml/signed-post-email", "/sales-post-sig-email", "post-sig-email.war", classLoader); + initializeSamlSecuredWar("/keycloak-saml/signed-post-transient", "/sales-post-sig-transient", "post-sig-transient.war", classLoader); + initializeSamlSecuredWar("/keycloak-saml/signed-post-persistent", "/sales-post-sig-persistent", "post-sig-persistent.war", classLoader); + initializeSamlSecuredWar("/keycloak-saml/signed-metadata", "/sales-metadata", "post-metadata.war", classLoader); + initializeSamlSecuredWar("/keycloak-saml/signed-get", "/employee-sig", "employee-sig.war", classLoader); + initializeSamlSecuredWar("/keycloak-saml/mappers", "/employee2", "employee2.war", classLoader); + initializeSamlSecuredWar("/keycloak-saml/signed-front-get", "/employee-sig-front", "employee-sig-front.war", classLoader); + 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); + SamlAdapterTestStrategy.uploadSP("http://localhost:8081/auth", this); + server.getServer().deploy(createDeploymentInfo("employee.war", "/employee", SamlSPFacade.class)); + + + + } + + @Override + public String getRealmJson() { + return "/keycloak-saml/testsaml.json"; + } + }; + + @Rule + public SamlAdapterTestStrategy testStrategy = new SamlAdapterTestStrategy("http://localhost:8081/auth", "http://localhost:8081", keycloakRule); + + @Test + public void testPostBadRealmSignature() { + testStrategy.testPostBadRealmSignature( new SamlAdapterTestStrategy.CheckAuthError() { + @Override + public void check(WebDriver driver) { + Assert.assertTrue(driver.getPageSource().contains("Forbidden")); + } + }); + } + + @Test + public void testPostSimpleUnauthorized() { + testStrategy.testPostSimpleUnauthorized( new SamlAdapterTestStrategy.CheckAuthError() { + @Override + public void check(WebDriver driver) { + Assert.assertTrue(driver.getPageSource().contains("Forbidden")); + } + }); + } + + @Test + public void testMetadataPostSignedLoginLogout() throws Exception { + testStrategy.testMetadataPostSignedLoginLogout(); + } + + @Test + public void testRedirectSignedLoginLogout() { + testStrategy.testRedirectSignedLoginLogout(); + } + + @Test + public void testPostSignedLoginLogoutEmailNameID() { + testStrategy.testPostSignedLoginLogoutEmailNameID(); + } + + @Test + public void testPostEncryptedLoginLogout() { + testStrategy.testPostEncryptedLoginLogout(); + } + + @Test + public void testRedirectSignedLoginLogoutFrontNoSSO() { + testStrategy.testRedirectSignedLoginLogoutFrontNoSSO(); + } + + @Test + public void testPostSimpleLoginLogout() { + testStrategy.testPostSimpleLoginLogout(); + } + + @Test + public void testPostSignedLoginLogoutTransientNameID() { + testStrategy.testPostSignedLoginLogoutTransientNameID(); + } + + @Test + public void testPostSimpleLoginLogoutIdpInitiated() { + testStrategy.testPostSimpleLoginLogoutIdpInitiated(); + } + + @Test + public void testAttributes() throws Exception { + testStrategy.testAttributes(); + } + + @Test + public void testPostSignedLoginLogoutPersistentNameID() { + testStrategy.testPostSignedLoginLogoutPersistentNameID(); + } + + @Test + public void testRelayStateEncoding() throws Exception { + testStrategy.testRelayStateEncoding(); + } + + @Test + public void testPostBadClientSignature() { + testStrategy.testPostBadClientSignature(); + } + + @Test + public void testRedirectSignedLoginLogoutFront() { + testStrategy.testRedirectSignedLoginLogoutFront(); + } + + @Test + public void testPostSignedLoginLogout() { + testStrategy.testPostSignedLoginLogout(); + } +} 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 new file mode 100755 index 0000000000..6e0817b1c0 --- /dev/null +++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/keycloaksaml/SamlAdapterTestStrategy.java @@ -0,0 +1,409 @@ +package org.keycloak.testsuite.keycloaksaml; + +import org.jboss.resteasy.plugins.providers.multipart.MultipartFormDataOutput; +import org.junit.Assert; +import org.junit.ClassRule; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExternalResource; +import org.keycloak.Config; +import org.keycloak.adapters.saml.SamlPrincipal; +import org.keycloak.models.ClientModel; +import org.keycloak.models.ClientSessionModel; +import org.keycloak.models.Constants; +import org.keycloak.models.KeycloakSession; +import org.keycloak.models.ProtocolMapperModel; +import org.keycloak.models.RealmModel; +import org.keycloak.models.UserModel; +import org.keycloak.models.UserSessionModel; +import org.keycloak.protocol.oidc.OIDCLoginProtocol; +import org.keycloak.protocol.oidc.TokenManager; +import org.keycloak.protocol.saml.mappers.AttributeStatementHelper; +import org.keycloak.protocol.saml.mappers.HardcodedAttributeMapper; +import org.keycloak.protocol.saml.mappers.HardcodedRole; +import org.keycloak.protocol.saml.mappers.RoleListMapper; +import org.keycloak.protocol.saml.mappers.RoleNameMapper; +import org.keycloak.representations.AccessToken; +import org.keycloak.representations.idm.RealmRepresentation; +import org.keycloak.saml.processing.core.saml.v2.constants.X500SAMLProfileConstants; +import org.keycloak.services.managers.RealmManager; +import org.keycloak.services.resources.admin.AdminRoot; +import org.keycloak.testsuite.KeycloakServer; +import org.keycloak.testsuite.pages.LoginPage; +import org.keycloak.testsuite.rule.AbstractKeycloakRule; +import org.keycloak.testsuite.rule.KeycloakRule; +import org.keycloak.testsuite.rule.WebResource; +import org.keycloak.testsuite.rule.WebRule; +import org.openqa.selenium.WebDriver; + +import javax.ws.rs.client.Client; +import javax.ws.rs.client.ClientBuilder; +import javax.ws.rs.client.ClientRequestContext; +import javax.ws.rs.client.ClientRequestFilter; +import javax.ws.rs.client.Entity; +import javax.ws.rs.client.WebTarget; +import javax.ws.rs.core.HttpHeaders; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.UriBuilder; +import java.io.IOException; +import java.io.InputStream; +import java.util.LinkedList; +import java.util.List; + +/** + * @author Bill Burke + * @version $Revision: 1 $ + */ +public class SamlAdapterTestStrategy extends ExternalResource { + protected String AUTH_SERVER_URL = "http://localhost:8081/auth"; + protected String APP_SERVER_BASE_URL = "http://localhost:8081"; + protected AbstractKeycloakRule keycloakRule; + + public SamlAdapterTestStrategy(String AUTH_SERVER_URL, String APP_SERVER_BASE_URL, AbstractKeycloakRule keycloakRule) { + this.AUTH_SERVER_URL = AUTH_SERVER_URL; + this.APP_SERVER_BASE_URL = APP_SERVER_BASE_URL; + this.keycloakRule = keycloakRule; + } + + public WebRule webRule = new WebRule(this); + + + @WebResource + protected WebDriver driver; + @WebResource + protected LoginPage loginPage; + + @Override + protected void before() throws Throwable { + super.before(); + webRule.before(); + } + + @Override + protected void after() { + super.after(); + webRule.after(); + } + + public static RealmModel baseAdapterTestInitialization(KeycloakSession session, RealmManager manager, RealmModel adminRealm, Class clazz) { + RealmRepresentation representation = KeycloakServer.loadJson(clazz.getResourceAsStream("/keycloak-saml/testsaml.json"), RealmRepresentation.class); + RealmModel demoRealm = manager.importRealm(representation); + return demoRealm; + } + + + + protected void checkLoggedOut(String mainUrl) { + String pageSource = driver.getPageSource(); + System.out.println("*** logout pagesource ***"); + System.out.println(pageSource); + System.out.println("driver url: " + driver.getCurrentUrl()); + Assert.assertTrue(pageSource.contains("request-path: /logout.jsp")); + driver.navigate().to(mainUrl); + Assert.assertTrue(driver.getCurrentUrl().startsWith(AUTH_SERVER_URL + "/realms/demo/protocol/saml")); + } + + public void testPostSimpleLoginLogout() { + driver.navigate().to(APP_SERVER_BASE_URL + "/sales-post/"); + Assert.assertEquals(driver.getCurrentUrl(), AUTH_SERVER_URL + "/realms/demo/protocol/saml"); + loginPage.login("bburke", "password"); + Assert.assertEquals(driver.getCurrentUrl(), APP_SERVER_BASE_URL + "/sales-post/"); + System.out.println(driver.getPageSource()); + Assert.assertTrue(driver.getPageSource().contains("bburke")); + driver.navigate().to(APP_SERVER_BASE_URL + "/sales-post?GLO=true"); + checkLoggedOut(APP_SERVER_BASE_URL + "/sales-post/"); + } + + public void testPostSimpleUnauthorized(CheckAuthError error) { + driver.navigate().to(APP_SERVER_BASE_URL + "/sales-post/"); + Assert.assertEquals(driver.getCurrentUrl(), AUTH_SERVER_URL + "/realms/demo/protocol/saml"); + loginPage.login("unauthorized", "password"); + Assert.assertEquals(driver.getCurrentUrl(), APP_SERVER_BASE_URL + "/sales-post/"); + System.out.println(driver.getPageSource()); + error.check(driver); + } + + public void testPostSimpleLoginLogoutIdpInitiated() { + driver.navigate().to(AUTH_SERVER_URL + "/realms/demo/protocol/saml/clients/sales-post"); + loginPage.login("bburke", "password"); + Assert.assertEquals(driver.getCurrentUrl(), APP_SERVER_BASE_URL + "/sales-post/"); + System.out.println(driver.getPageSource()); + Assert.assertTrue(driver.getPageSource().contains("bburke")); + driver.navigate().to(APP_SERVER_BASE_URL + "/sales-post?GLO=true"); + checkLoggedOut(APP_SERVER_BASE_URL + "/sales-post/"); + } + + public void testPostSignedLoginLogout() { + driver.navigate().to(APP_SERVER_BASE_URL + "/sales-post-sig/"); + Assert.assertEquals(driver.getCurrentUrl(), AUTH_SERVER_URL + "/realms/demo/protocol/saml"); + loginPage.login("bburke", "password"); + Assert.assertEquals(driver.getCurrentUrl(), APP_SERVER_BASE_URL + "/sales-post-sig/"); + Assert.assertTrue(driver.getPageSource().contains("bburke")); + driver.navigate().to(APP_SERVER_BASE_URL + "/sales-post-sig?GLO=true"); + checkLoggedOut(APP_SERVER_BASE_URL + "/sales-post-sig/"); + + } + public void testPostSignedLoginLogoutTransientNameID() { + driver.navigate().to(APP_SERVER_BASE_URL + "/sales-post-sig-transient/"); + Assert.assertEquals(driver.getCurrentUrl(), AUTH_SERVER_URL + "/realms/demo/protocol/saml"); + loginPage.login("bburke", "password"); + Assert.assertEquals(driver.getCurrentUrl(), APP_SERVER_BASE_URL + "/sales-post-sig-transient/"); + System.out.println(driver.getPageSource()); + Assert.assertFalse(driver.getPageSource().contains("bburke")); + Assert.assertTrue(driver.getPageSource().contains("principal=G-")); + driver.navigate().to(APP_SERVER_BASE_URL + "/sales-post-sig-transient?GLO=true"); + checkLoggedOut(APP_SERVER_BASE_URL + "/sales-post-sig-transient/"); + + } + public void testPostSignedLoginLogoutPersistentNameID() { + driver.navigate().to(APP_SERVER_BASE_URL + "/sales-post-sig-persistent/"); + Assert.assertEquals(driver.getCurrentUrl(), AUTH_SERVER_URL + "/realms/demo/protocol/saml"); + loginPage.login("bburke", "password"); + Assert.assertEquals(driver.getCurrentUrl(), APP_SERVER_BASE_URL + "/sales-post-sig-persistent/"); + System.out.println(driver.getPageSource()); + Assert.assertFalse(driver.getPageSource().contains("bburke")); + Assert.assertTrue(driver.getPageSource().contains("principal=G-")); + driver.navigate().to(APP_SERVER_BASE_URL + "/sales-post-sig-persistent?GLO=true"); + checkLoggedOut(APP_SERVER_BASE_URL + "/sales-post-sig-persistent/"); + + } + public void testPostSignedLoginLogoutEmailNameID() { + driver.navigate().to(APP_SERVER_BASE_URL + "/sales-post-sig-email/"); + Assert.assertEquals(driver.getCurrentUrl(), AUTH_SERVER_URL + "/realms/demo/protocol/saml"); + loginPage.login("bburke", "password"); + Assert.assertEquals(driver.getCurrentUrl(), APP_SERVER_BASE_URL + "/sales-post-sig-email/"); + System.out.println(driver.getPageSource()); + Assert.assertTrue(driver.getPageSource().contains("principal=bburke@redhat.com")); + driver.navigate().to(APP_SERVER_BASE_URL + "/sales-post-sig-email?GLO=true"); + checkLoggedOut(APP_SERVER_BASE_URL + "/sales-post-sig-email/"); + + } + + public void testRelayStateEncoding() throws Exception { + // this test has a hardcoded SAMLRequest and we hack a SP face servlet to get the SAMLResponse so we can look + // at the relay state + SamlSPFacade.samlResponse = null; + driver.navigate().to(APP_SERVER_BASE_URL + "/employee/"); + Assert.assertTrue(driver.getCurrentUrl().startsWith(AUTH_SERVER_URL + "/realms/demo/protocol/saml")); + System.out.println(driver.getCurrentUrl()); + loginPage.login("bburke", "password"); + Assert.assertEquals(driver.getCurrentUrl(), APP_SERVER_BASE_URL + "/employee/"); + Assert.assertEquals(SamlSPFacade.sentRelayState, SamlSPFacade.RELAY_STATE); + Assert.assertNotNull(SamlSPFacade.samlResponse); + + } + + public void testAttributes() throws Exception { + { + SendUsernameServlet.sentPrincipal = null; + SendUsernameServlet.checkRoles = null; + driver.navigate().to(APP_SERVER_BASE_URL + "/employee2/"); + Assert.assertTrue(driver.getCurrentUrl().startsWith(AUTH_SERVER_URL + "/realms/demo/protocol/saml")); + List requiredRoles = new LinkedList<>(); + requiredRoles.add("manager"); + requiredRoles.add("employee"); + requiredRoles.add("user"); + SendUsernameServlet.checkRoles = requiredRoles; + loginPage.login("bburke", "password"); + Assert.assertEquals(driver.getCurrentUrl(), APP_SERVER_BASE_URL + "/employee2/"); + SendUsernameServlet.checkRoles = null; + SamlPrincipal principal = (SamlPrincipal) SendUsernameServlet.sentPrincipal; + Assert.assertNotNull(principal); + Assert.assertEquals("bburke@redhat.com", principal.getAttribute(X500SAMLProfileConstants.EMAIL.get())); + Assert.assertEquals("bburke@redhat.com", principal.getFriendlyAttribute("email")); + Assert.assertEquals("617", principal.getAttribute("phone")); + Assert.assertNull(principal.getFriendlyAttribute("phone")); + driver.navigate().to(APP_SERVER_BASE_URL + "/employee2/?GLO=true"); + checkLoggedOut(APP_SERVER_BASE_URL + "/employee2/"); + + } + keycloakRule.update(new KeycloakRule.KeycloakSetup() { + @Override + public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) { + ClientModel app = appRealm.getClientByClientId(APP_SERVER_BASE_URL + "/employee2/"); + for (ProtocolMapperModel mapper : app.getProtocolMappers()) { + if (mapper.getName().equals("role-list")) { + app.removeProtocolMapper(mapper); + mapper.setId(null); + mapper.getConfig().put(RoleListMapper.SINGLE_ROLE_ATTRIBUTE, "true"); + mapper.getConfig().put(AttributeStatementHelper.SAML_ATTRIBUTE_NAME, "memberOf"); + app.addProtocolMapper(mapper); + } + } + app.addProtocolMapper(HardcodedAttributeMapper.create("hardcoded-attribute", "hardcoded-attribute", "Basic", null, "hard", false, null)); + app.addProtocolMapper(HardcodedRole.create("hardcoded-role", "hardcoded-role")); + app.addProtocolMapper(RoleNameMapper.create("renamed-role", "manager", "el-jefe")); + app.addProtocolMapper(RoleNameMapper.create("renamed-employee-role", APP_SERVER_BASE_URL + "/employee/.employee", "pee-on")); + } + }, "demo"); + + System.out.println(">>>>>>>>>> single role attribute <<<<<<<<"); + + { + SendUsernameServlet.sentPrincipal = null; + SendUsernameServlet.checkRoles = null; + driver.navigate().to(APP_SERVER_BASE_URL + "/employee2/"); + Assert.assertTrue(driver.getCurrentUrl().startsWith(AUTH_SERVER_URL + "/realms/demo/protocol/saml")); + List requiredRoles = new LinkedList<>(); + requiredRoles.add("el-jefe"); + requiredRoles.add("user"); + requiredRoles.add("hardcoded-role"); + requiredRoles.add("pee-on"); + SendUsernameServlet.checkRoles = requiredRoles; + loginPage.login("bburke", "password"); + Assert.assertEquals(driver.getCurrentUrl(), APP_SERVER_BASE_URL + "/employee2/"); + SendUsernameServlet.checkRoles = null; + SamlPrincipal principal = (SamlPrincipal) SendUsernameServlet.sentPrincipal; + Assert.assertNotNull(principal); + Assert.assertEquals("hard", principal.getAttribute("hardcoded-attribute")); + + + } + } + + public void testRedirectSignedLoginLogout() { + driver.navigate().to(APP_SERVER_BASE_URL + "/employee-sig/"); + Assert.assertTrue(driver.getCurrentUrl().startsWith(AUTH_SERVER_URL + "/realms/demo/protocol/saml")); + loginPage.login("bburke", "password"); + Assert.assertEquals(driver.getCurrentUrl(), APP_SERVER_BASE_URL + "/employee-sig/"); + Assert.assertTrue(driver.getPageSource().contains("bburke")); + driver.navigate().to(APP_SERVER_BASE_URL + "/employee-sig?GLO=true"); + checkLoggedOut(APP_SERVER_BASE_URL + "/employee-sig/"); + + } + + public void testRedirectSignedLoginLogoutFrontNoSSO() { + driver.navigate().to(APP_SERVER_BASE_URL + "/employee-sig-front/"); + Assert.assertTrue(driver.getCurrentUrl().startsWith(AUTH_SERVER_URL + "/realms/demo/protocol/saml")); + loginPage.login("bburke", "password"); + Assert.assertEquals(driver.getCurrentUrl(), APP_SERVER_BASE_URL + "/employee-sig-front/"); + Assert.assertTrue(driver.getPageSource().contains("bburke")); + driver.navigate().to(APP_SERVER_BASE_URL + "/employee-sig-front?GLO=true"); + checkLoggedOut(APP_SERVER_BASE_URL + "/employee-sig-front/"); + + } + + public void testRedirectSignedLoginLogoutFront() { + // visit 1st app an logg in + System.out.println("visit 1st app "); + driver.navigate().to(APP_SERVER_BASE_URL + "/employee-sig/"); + Assert.assertTrue(driver.getCurrentUrl().startsWith(AUTH_SERVER_URL + "/realms/demo/protocol/saml")); + System.out.println("login to form"); + loginPage.login("bburke", "password"); + Assert.assertEquals(driver.getCurrentUrl(), APP_SERVER_BASE_URL + "/employee-sig/"); + Assert.assertTrue(driver.getPageSource().contains("bburke")); + + // visit 2nd app + System.out.println("visit 2nd app "); + driver.navigate().to(APP_SERVER_BASE_URL + "/employee-sig-front/"); + Assert.assertEquals(driver.getCurrentUrl(), APP_SERVER_BASE_URL + "/employee-sig-front/"); + Assert.assertTrue(driver.getPageSource().contains("bburke")); + + // visit 3rd app + System.out.println("visit 3rd app "); + driver.navigate().to(APP_SERVER_BASE_URL + "/sales-post-sig/"); + Assert.assertEquals(driver.getCurrentUrl(), APP_SERVER_BASE_URL + "/sales-post-sig/"); + Assert.assertTrue(driver.getPageSource().contains("bburke")); + + // logout of first app + System.out.println("GLO"); + driver.navigate().to(APP_SERVER_BASE_URL + "/employee-sig?GLO=true"); + checkLoggedOut(APP_SERVER_BASE_URL + "/employee-sig/"); + driver.navigate().to(APP_SERVER_BASE_URL + "/employee-sig-front/"); + String currentUrl = driver.getCurrentUrl(); + Assert.assertTrue(currentUrl.startsWith(AUTH_SERVER_URL + "/realms/demo/protocol/saml")); + driver.navigate().to(APP_SERVER_BASE_URL + "/sales-post-sig/"); + Assert.assertTrue(driver.getCurrentUrl().startsWith(AUTH_SERVER_URL + "/realms/demo/protocol/saml")); + + } + + public void testPostEncryptedLoginLogout() { + driver.navigate().to(APP_SERVER_BASE_URL + "/sales-post-enc/"); + Assert.assertEquals(driver.getCurrentUrl(), AUTH_SERVER_URL + "/realms/demo/protocol/saml"); + loginPage.login("bburke", "password"); + Assert.assertEquals(driver.getCurrentUrl(), APP_SERVER_BASE_URL + "/sales-post-enc/"); + Assert.assertTrue(driver.getPageSource().contains("bburke")); + driver.navigate().to(APP_SERVER_BASE_URL + "/sales-post-enc?GLO=true"); + checkLoggedOut(APP_SERVER_BASE_URL + "/sales-post-enc/"); + + } + public void testPostBadClientSignature() { + driver.navigate().to(APP_SERVER_BASE_URL + "/bad-client-sales-post-sig/"); + Assert.assertEquals(driver.getCurrentUrl(), AUTH_SERVER_URL + "/realms/demo/protocol/saml"); + Assert.assertEquals(driver.getTitle(), "We're sorry..."); + + } + public static interface CheckAuthError { + void check(WebDriver driver); + } + + public void testPostBadRealmSignature(CheckAuthError error) { + driver.navigate().to(APP_SERVER_BASE_URL + "/bad-realm-sales-post-sig/"); + Assert.assertEquals(driver.getCurrentUrl(), AUTH_SERVER_URL + "/realms/demo/protocol/saml"); + loginPage.login("bburke", "password"); + Assert.assertEquals(driver.getCurrentUrl(), APP_SERVER_BASE_URL + "/bad-realm-sales-post-sig/"); + System.out.println(driver.getPageSource()); + error.check(driver); + } + + private static String createToken(String AUTH_SERVER_URL, AbstractKeycloakRule keycloakRule) { + KeycloakSession session = keycloakRule.startSession(); + try { + RealmManager manager = new RealmManager(session); + + RealmModel adminRealm = manager.getRealm(Config.getAdminRealm()); + ClientModel adminConsole = adminRealm.getClientByClientId(Constants.ADMIN_CONSOLE_CLIENT_ID); + TokenManager tm = new TokenManager(); + UserModel admin = session.users().getUserByUsername("admin", adminRealm); + ClientSessionModel clientSession = session.sessions().createClientSession(adminRealm, adminConsole); + clientSession.setNote(OIDCLoginProtocol.ISSUER, AUTH_SERVER_URL + "/realms/master"); + UserSessionModel userSession = session.sessions().createUserSession(adminRealm, admin, "admin", null, "form", false, null, null); + AccessToken token = tm.createClientAccessToken(session, tm.getAccess(null, true, adminConsole, admin), adminRealm, adminConsole, admin, userSession, clientSession); + return tm.encodeToken(adminRealm, token); + } finally { + keycloakRule.stopSession(session, true); + } + } + + + public void testMetadataPostSignedLoginLogout() throws Exception { + + driver.navigate().to(APP_SERVER_BASE_URL + "/sales-metadata/"); + Assert.assertEquals(driver.getCurrentUrl(), AUTH_SERVER_URL + "/realms/demo/protocol/saml"); + loginPage.login("bburke", "password"); + Assert.assertEquals(driver.getCurrentUrl(), APP_SERVER_BASE_URL + "/sales-metadata/"); + String pageSource = driver.getPageSource(); + Assert.assertTrue(pageSource.contains("bburke")); + driver.navigate().to(APP_SERVER_BASE_URL + "/sales-metadata?GLO=true"); + checkLoggedOut(APP_SERVER_BASE_URL + "/sales-metadata/"); + + } + + public static void uploadSP(String AUTH_SERVER_URL, AbstractKeycloakRule keycloakRule) { + String token = createToken(AUTH_SERVER_URL, keycloakRule); + final String authHeader = "Bearer " + token; + ClientRequestFilter authFilter = new ClientRequestFilter() { + @Override + public void filter(ClientRequestContext requestContext) throws IOException { + requestContext.getHeaders().add(HttpHeaders.AUTHORIZATION, authHeader); + } + }; + Client client = ClientBuilder.newBuilder().register(authFilter).build(); + UriBuilder authBase = UriBuilder.fromUri(AUTH_SERVER_URL + ""); + WebTarget adminRealms = client.target(AdminRoot.realmsUrl(authBase)); + + + MultipartFormDataOutput formData = new MultipartFormDataOutput(); + InputStream is = SamlAdapterTestStrategy.class.getResourceAsStream("/keycloak-saml/sp-metadata.xml"); + Assert.assertNotNull(is); + formData.addFormData("file", is, MediaType.APPLICATION_XML_TYPE); + + WebTarget upload = adminRealms.path("demo/client-importers/saml2-entity-descriptor/upload"); + System.out.println(upload.getUri()); + Response response = upload.request().post(Entity.entity(formData, MediaType.MULTIPART_FORM_DATA)); + Assert.assertEquals(204, response.getStatus()); + response.close(); + client.close(); + } +} diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/keycloaksaml/SamlBindingTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/keycloaksaml/SamlBindingTest.java deleted file mode 100755 index f51c15a713..0000000000 --- a/testsuite/integration/src/test/java/org/keycloak/testsuite/keycloaksaml/SamlBindingTest.java +++ /dev/null @@ -1,450 +0,0 @@ -package org.keycloak.testsuite.keycloaksaml; - -import org.jboss.resteasy.plugins.providers.multipart.MultipartFormDataOutput; -import org.junit.Assert; -import org.junit.ClassRule; -import org.junit.Rule; -import org.junit.Test; -import org.keycloak.Config; -import org.keycloak.adapters.saml.SamlPrincipal; -import org.keycloak.models.ClientModel; -import org.keycloak.models.ClientSessionModel; -import org.keycloak.models.Constants; -import org.keycloak.models.KeycloakSession; -import org.keycloak.models.ProtocolMapperModel; -import org.keycloak.models.RealmModel; -import org.keycloak.models.UserModel; -import org.keycloak.models.UserSessionModel; -import org.keycloak.protocol.oidc.OIDCLoginProtocol; -import org.keycloak.protocol.oidc.TokenManager; -import org.keycloak.protocol.saml.mappers.AttributeStatementHelper; -import org.keycloak.protocol.saml.mappers.HardcodedAttributeMapper; -import org.keycloak.protocol.saml.mappers.HardcodedRole; -import org.keycloak.protocol.saml.mappers.RoleListMapper; -import org.keycloak.protocol.saml.mappers.RoleNameMapper; -import org.keycloak.representations.AccessToken; -import org.keycloak.saml.processing.core.saml.v2.constants.X500SAMLProfileConstants; -import org.keycloak.services.managers.RealmManager; -import org.keycloak.services.resources.admin.AdminRoot; -import org.keycloak.testsuite.pages.LoginPage; -import org.keycloak.testsuite.rule.KeycloakRule; -import org.keycloak.testsuite.rule.WebResource; -import org.keycloak.testsuite.rule.WebRule; -import org.openqa.selenium.WebDriver; - -import javax.servlet.ServletException; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import javax.ws.rs.client.Client; -import javax.ws.rs.client.ClientBuilder; -import javax.ws.rs.client.ClientRequestContext; -import javax.ws.rs.client.ClientRequestFilter; -import javax.ws.rs.client.Entity; -import javax.ws.rs.client.WebTarget; -import javax.ws.rs.core.HttpHeaders; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.Response; -import javax.ws.rs.core.UriBuilder; -import java.io.IOException; -import java.io.InputStream; -import java.util.LinkedList; -import java.util.List; - -/** - * @author Bill Burke - * @version $Revision: 1 $ - */ -public class SamlBindingTest { - - @ClassRule - public static SamlKeycloakRule keycloakRule = new SamlKeycloakRule() { - @Override - public void initWars() { - ClassLoader classLoader = SamlBindingTest.class.getClassLoader(); - - initializeSamlSecuredWar("/keycloak-saml/simple-post", "/sales-post", "post.war", classLoader); - initializeSamlSecuredWar("/keycloak-saml/signed-post", "/sales-post-sig", "post-sig.war", classLoader); - initializeSamlSecuredWar("/keycloak-saml/signed-post-email", "/sales-post-sig-email", "post-sig-email.war", classLoader); - initializeSamlSecuredWar("/keycloak-saml/signed-post-transient", "/sales-post-sig-transient", "post-sig-transient.war", classLoader); - initializeSamlSecuredWar("/keycloak-saml/signed-post-persistent", "/sales-post-sig-persistent", "post-sig-persistent.war", classLoader); - initializeSamlSecuredWar("/keycloak-saml/signed-metadata", "/sales-metadata", "post-metadata.war", classLoader); - initializeSamlSecuredWar("/keycloak-saml/signed-get", "/employee-sig", "employee-sig.war", classLoader); - initializeSamlSecuredWar("/keycloak-saml/mappers", "/employee2", "employee2.war", classLoader); - initializeSamlSecuredWar("/keycloak-saml/signed-front-get", "/employee-sig-front", "employee-sig-front.war", classLoader); - 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); - uploadSP(); - server.getServer().deploy(createDeploymentInfo("employee.war", "/employee", SamlSPFacade.class)); - - - - } - - @Override - public String getRealmJson() { - return "/keycloak-saml/testsaml.json"; - } - }; - - public static class SamlSPFacade extends HttpServlet { - public static String samlResponse; - public static String RELAY_STATE = "http://test.com/foo/bar"; - public static String sentRelayState; - - @Override - protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { - handler(req, resp); - } - - @Override - protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { - handler(req, resp); - } - - private void handler(HttpServletRequest req, HttpServletResponse resp) { - System.out.println("********* HERE ******"); - if (req.getParameterMap().isEmpty()) { - System.out.println("redirecting"); - resp.setStatus(302); - // Redirect - // UriBuilder builder = UriBuilder.fromUri("http://localhost:8081/auth/realms/demo/protocol/saml?SAMLRequest=jVLRTsIwFP2Vpe%2BjG4wxG0YyWYxL0BBAH3wx3XYnTbp29nYof%2B8YEvEBNOlD03vOveec2ynyWjYsae1WreC9BbTOZy0Vsr4Qk9YopjkKZIrXgMwWbJ08LNhw4LHGaKsLLcmRch3MEcFYoRVxktN1rhW2NZg1mJ0o4Gm1iMnW2oZRKnXB5VajZZEX%2BRTqRuo9ACVO2mkUih%2F4l9C8s0MNcFkjLaHW9KSUHlwR506bAnrPMam4RCBOlsYkS1%2BD3MvLcDJxAx9KN4jCkXszrG5cP%2BCVH4y8IM8PYFx2dsQOfuiILWQKLVc2JkPPH7te6HrRxh%2BzUdidwSSIXoiz%2FBZyK1Qp1Nv1yPIjCNn9ZrN0V1AKA4UlzjMY7N13IDKbHjyxXoA5291%2FtzH7I%2FApPet%2FHNawx65hli61FMXeSaTUH%2FMubtvlYU0LfcA1t5cl%2BAO%2FfxGlW%2FVQ1ipsoBCVgJLQ2XHo7385%2BwI%3D"); - UriBuilder builder = UriBuilder.fromUri("http://localhost:8081/auth/realms/demo/protocol/saml?SAMLRequest=jVJbT8IwFP4rS99HuwluNIwEIUYSLwugD76Y2h2kSdfOng7l31uGRn0ATfrQ9HznfJfTEYpaN3zS%2Bo1ZwGsL6KP3WhvkXaEgrTPcClTIjagBuZd8Obm55mmP8cZZb6XV5NByGiwQwXllDYkmX9epNdjW4JbgtkrC%2FeK6IBvvG06ptlLojUXPc5YnFOpG2x0AJdEsaFRG7PuPoUWwQx0IXSOtoLb0SynduyLRpXUSOs8FWQuNQKL5rCDz2VO%2FymEgIY2zlJ3H%2FSx9jkU%2BzOK0ys8yNmSSsUEAYxnsqC18tyO2MDfohfEFSVkyiNlZzM5XacrDSbJePug%2Fkqj8FHKhTKXMy%2BnIng8g5FerVRmXd8sViR7AYec8AMh4tPfDO3L3Y2%2F%2F3cT4j7BH9Mf8A1nDb8PA%2Bay0WsldNNHavk1D1D5k4V0LXbi18MclJL2ke1FVvO6gvDXYgFRrBRWh4wPp7z85%2FgA%3D"); - builder.queryParam("RelayState", RELAY_STATE); - resp.setHeader("Location", builder.build().toString()); - return; - } - System.out.println("received response"); - samlResponse = req.getParameter("SAMLResponse"); - sentRelayState = req.getParameter("RelayState"); - } - } - - @Rule - public WebRule webRule = new WebRule(this); - @WebResource - protected WebDriver driver; - @WebResource - protected LoginPage loginPage; - - protected void checkLoggedOut(String mainUrl) { - String pageSource = driver.getPageSource(); - System.out.println("*** logout pagesource ***"); - System.out.println(pageSource); - System.out.println("driver url: " + driver.getCurrentUrl()); - Assert.assertTrue(pageSource.contains("request-path: /logout.jsp")); - driver.navigate().to(mainUrl); - Assert.assertTrue(driver.getCurrentUrl().startsWith("http://localhost:8081/auth/realms/demo/protocol/saml")); - } - - //@Test - public void ideTesting() throws Exception { - Thread.sleep(100000000); - } - - @Test - public void testPostSimpleLoginLogout() { - driver.navigate().to("http://localhost:8081/sales-post/"); - Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/auth/realms/demo/protocol/saml"); - loginPage.login("bburke", "password"); - Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/sales-post/"); - System.out.println(driver.getPageSource()); - Assert.assertTrue(driver.getPageSource().contains("bburke")); - driver.navigate().to("http://localhost:8081/sales-post?GLO=true"); - checkLoggedOut("http://localhost:8081/sales-post/"); - } - @Test - public void testPostSimpleLoginLogoutIdpInitiated() { - driver.navigate().to("http://localhost:8081/auth/realms/demo/protocol/saml/clients/sales-post"); - loginPage.login("bburke", "password"); - Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/sales-post/"); - System.out.println(driver.getPageSource()); - Assert.assertTrue(driver.getPageSource().contains("bburke")); - driver.navigate().to("http://localhost:8081/sales-post?GLO=true"); - checkLoggedOut("http://localhost:8081/sales-post/"); - } - - @Test - public void testPostSignedLoginLogout() { - driver.navigate().to("http://localhost:8081/sales-post-sig/"); - Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/auth/realms/demo/protocol/saml"); - loginPage.login("bburke", "password"); - Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/sales-post-sig/"); - Assert.assertTrue(driver.getPageSource().contains("bburke")); - driver.navigate().to("http://localhost:8081/sales-post-sig?GLO=true"); - checkLoggedOut("http://localhost:8081/sales-post-sig/"); - - } - @Test - public void testPostSignedLoginLogoutTransientNameID() { - driver.navigate().to("http://localhost:8081/sales-post-sig-transient/"); - Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/auth/realms/demo/protocol/saml"); - loginPage.login("bburke", "password"); - Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/sales-post-sig-transient/"); - System.out.println(driver.getPageSource()); - Assert.assertFalse(driver.getPageSource().contains("bburke")); - Assert.assertTrue(driver.getPageSource().contains("principal=G-")); - driver.navigate().to("http://localhost:8081/sales-post-sig-transient?GLO=true"); - checkLoggedOut("http://localhost:8081/sales-post-sig-transient/"); - - } - @Test - public void testPostSignedLoginLogoutPersistentNameID() { - driver.navigate().to("http://localhost:8081/sales-post-sig-persistent/"); - Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/auth/realms/demo/protocol/saml"); - loginPage.login("bburke", "password"); - Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/sales-post-sig-persistent/"); - System.out.println(driver.getPageSource()); - Assert.assertFalse(driver.getPageSource().contains("bburke")); - Assert.assertTrue(driver.getPageSource().contains("principal=G-")); - driver.navigate().to("http://localhost:8081/sales-post-sig-persistent?GLO=true"); - checkLoggedOut("http://localhost:8081/sales-post-sig-persistent/"); - - } - @Test - public void testPostSignedLoginLogoutEmailNameID() { - driver.navigate().to("http://localhost:8081/sales-post-sig-email/"); - Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/auth/realms/demo/protocol/saml"); - loginPage.login("bburke", "password"); - Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/sales-post-sig-email/"); - System.out.println(driver.getPageSource()); - Assert.assertTrue(driver.getPageSource().contains("principal=bburke@redhat.com")); - driver.navigate().to("http://localhost:8081/sales-post-sig-email?GLO=true"); - checkLoggedOut("http://localhost:8081/sales-post-sig-email/"); - - } - - @Test - public void testRelayStateEncoding() throws Exception { - // this test has a hardcoded SAMLRequest and we hack a SP face servlet to get the SAMLResponse so we can look - // at the relay state - SamlSPFacade.samlResponse = null; - driver.navigate().to("http://localhost:8081/employee/"); - Assert.assertTrue(driver.getCurrentUrl().startsWith("http://localhost:8081/auth/realms/demo/protocol/saml")); - System.out.println(driver.getCurrentUrl()); - loginPage.login("bburke", "password"); - Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/employee/"); - Assert.assertEquals(SamlSPFacade.sentRelayState, SamlSPFacade.RELAY_STATE); - Assert.assertNotNull(SamlSPFacade.samlResponse); - - } - - @Test - public void testAttributes() throws Exception { - { - SamlKeycloakRule.SendUsernameServlet.sentPrincipal = null; - SamlKeycloakRule.SendUsernameServlet.checkRoles = null; - driver.navigate().to("http://localhost:8081/employee2/"); - Assert.assertTrue(driver.getCurrentUrl().startsWith("http://localhost:8081/auth/realms/demo/protocol/saml")); - List requiredRoles = new LinkedList<>(); - requiredRoles.add("manager"); - requiredRoles.add("employee"); - requiredRoles.add("user"); - SamlKeycloakRule.SendUsernameServlet.checkRoles = requiredRoles; - loginPage.login("bburke", "password"); - Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/employee2/"); - SamlKeycloakRule.SendUsernameServlet.checkRoles = null; - SamlPrincipal principal = (SamlPrincipal)SamlKeycloakRule.SendUsernameServlet.sentPrincipal; - Assert.assertNotNull(principal); - Assert.assertEquals("bburke@redhat.com", principal.getAttribute(X500SAMLProfileConstants.EMAIL.get())); - Assert.assertEquals("bburke@redhat.com", principal.getFriendlyAttribute("email")); - Assert.assertEquals("617", principal.getAttribute("phone")); - Assert.assertNull(principal.getFriendlyAttribute("phone")); - driver.navigate().to("http://localhost:8081/employee2/?GLO=true"); - checkLoggedOut("http://localhost:8081/employee2/"); - - } - keycloakRule.update(new KeycloakRule.KeycloakSetup() { - @Override - public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) { - ClientModel app = appRealm.getClientByClientId("http://localhost:8081/employee2/"); - for (ProtocolMapperModel mapper : app.getProtocolMappers()) { - if (mapper.getName().equals("role-list")) { - app.removeProtocolMapper(mapper); - mapper.setId(null); - mapper.getConfig().put(RoleListMapper.SINGLE_ROLE_ATTRIBUTE, "true"); - mapper.getConfig().put(AttributeStatementHelper.SAML_ATTRIBUTE_NAME, "memberOf"); - app.addProtocolMapper(mapper); - } - } - app.addProtocolMapper(HardcodedAttributeMapper.create("hardcoded-attribute", "hardcoded-attribute", "Basic", null, "hard", false, null)); - app.addProtocolMapper(HardcodedRole.create("hardcoded-role", "hardcoded-role")); - app.addProtocolMapper(RoleNameMapper.create("renamed-role", "manager", "el-jefe")); - app.addProtocolMapper(RoleNameMapper.create("renamed-employee-role", "http://localhost:8081/employee/.employee", "pee-on")); - } - }, "demo"); - - System.out.println(">>>>>>>>>> single role attribute <<<<<<<<"); - - { - SamlKeycloakRule.SendUsernameServlet.sentPrincipal = null; - SamlKeycloakRule.SendUsernameServlet.checkRoles = null; - driver.navigate().to("http://localhost:8081/employee2/"); - Assert.assertTrue(driver.getCurrentUrl().startsWith("http://localhost:8081/auth/realms/demo/protocol/saml")); - List requiredRoles = new LinkedList<>(); - requiredRoles.add("el-jefe"); - requiredRoles.add("user"); - requiredRoles.add("hardcoded-role"); - requiredRoles.add("pee-on"); - SamlKeycloakRule.SendUsernameServlet.checkRoles = requiredRoles; - SamlKeycloakRule.SendUsernameServlet.checkRoles = requiredRoles; - loginPage.login("bburke", "password"); - Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/employee2/"); - SamlKeycloakRule.SendUsernameServlet.checkRoles = null; - SamlPrincipal principal = (SamlPrincipal)SamlKeycloakRule.SendUsernameServlet.sentPrincipal; - Assert.assertNotNull(principal); - Assert.assertEquals("hard", principal.getAttribute("hardcoded-attribute")); - - - } - } - - @Test - public void testRedirectSignedLoginLogout() { - driver.navigate().to("http://localhost:8081/employee-sig/"); - Assert.assertTrue(driver.getCurrentUrl().startsWith("http://localhost:8081/auth/realms/demo/protocol/saml")); - loginPage.login("bburke", "password"); - Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/employee-sig/"); - Assert.assertTrue(driver.getPageSource().contains("bburke")); - driver.navigate().to("http://localhost:8081/employee-sig?GLO=true"); - checkLoggedOut("http://localhost:8081/employee-sig/"); - - } - - @Test - public void testRedirectSignedLoginLogoutFrontNoSSO() { - driver.navigate().to("http://localhost:8081/employee-sig-front/"); - Assert.assertTrue(driver.getCurrentUrl().startsWith("http://localhost:8081/auth/realms/demo/protocol/saml")); - loginPage.login("bburke", "password"); - Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/employee-sig-front/"); - Assert.assertTrue(driver.getPageSource().contains("bburke")); - driver.navigate().to("http://localhost:8081/employee-sig-front?GLO=true"); - checkLoggedOut("http://localhost:8081/employee-sig-front/"); - - } - - @Test - public void testRedirectSignedLoginLogoutFront() { - // visit 1st app an logg in - System.out.println("visit 1st app "); - driver.navigate().to("http://localhost:8081/employee-sig/"); - Assert.assertTrue(driver.getCurrentUrl().startsWith("http://localhost:8081/auth/realms/demo/protocol/saml")); - System.out.println("login to form"); - loginPage.login("bburke", "password"); - Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/employee-sig/"); - Assert.assertTrue(driver.getPageSource().contains("bburke")); - - // visit 2nd app - System.out.println("visit 2nd app "); - driver.navigate().to("http://localhost:8081/employee-sig-front/"); - Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/employee-sig-front/"); - Assert.assertTrue(driver.getPageSource().contains("bburke")); - - // visit 3rd app - System.out.println("visit 3rd app "); - driver.navigate().to("http://localhost:8081/sales-post-sig/"); - Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/sales-post-sig/"); - Assert.assertTrue(driver.getPageSource().contains("bburke")); - - // logout of first app - System.out.println("GLO"); - driver.navigate().to("http://localhost:8081/employee-sig?GLO=true"); - checkLoggedOut("http://localhost:8081/employee-sig/"); - driver.navigate().to("http://localhost:8081/employee-sig-front/"); - String currentUrl = driver.getCurrentUrl(); - Assert.assertTrue(currentUrl.startsWith("http://localhost:8081/auth/realms/demo/protocol/saml")); - driver.navigate().to("http://localhost:8081/sales-post-sig/"); - Assert.assertTrue(driver.getCurrentUrl().startsWith("http://localhost:8081/auth/realms/demo/protocol/saml")); - - } - - @Test - public void testPostEncryptedLoginLogout() { - driver.navigate().to("http://localhost:8081/sales-post-enc/"); - Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/auth/realms/demo/protocol/saml"); - loginPage.login("bburke", "password"); - Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/sales-post-enc/"); - Assert.assertTrue(driver.getPageSource().contains("bburke")); - driver.navigate().to("http://localhost:8081/sales-post-enc?GLO=true"); - checkLoggedOut("http://localhost:8081/sales-post-enc/"); - - } - @Test - public void testPostBadClientSignature() { - driver.navigate().to("http://localhost:8081/bad-client-sales-post-sig/"); - Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/auth/realms/demo/protocol/saml"); - Assert.assertEquals(driver.getTitle(), "We're sorry..."); - - } - - @Test - public void testPostBadRealmSignature() { - driver.navigate().to("http://localhost:8081/bad-realm-sales-post-sig/"); - Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/auth/realms/demo/protocol/saml"); - loginPage.login("bburke", "password"); - Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/bad-realm-sales-post-sig/"); - Assert.assertTrue(driver.getPageSource().contains("null")); - } - - private static String createToken() { - KeycloakSession session = keycloakRule.startSession(); - try { - RealmManager manager = new RealmManager(session); - - RealmModel adminRealm = manager.getRealm(Config.getAdminRealm()); - ClientModel adminConsole = adminRealm.getClientByClientId(Constants.ADMIN_CONSOLE_CLIENT_ID); - TokenManager tm = new TokenManager(); - UserModel admin = session.users().getUserByUsername("admin", adminRealm); - ClientSessionModel clientSession = session.sessions().createClientSession(adminRealm, adminConsole); - clientSession.setNote(OIDCLoginProtocol.ISSUER, "http://localhost:8081/auth/realms/master"); - UserSessionModel userSession = session.sessions().createUserSession(adminRealm, admin, "admin", null, "form", false, null, null); - AccessToken token = tm.createClientAccessToken(session, tm.getAccess(null, true, adminConsole, admin), adminRealm, adminConsole, admin, userSession, clientSession); - return tm.encodeToken(adminRealm, token); - } finally { - keycloakRule.stopSession(session, true); - } - } - - - @Test - public void testMetadataPostSignedLoginLogout() throws Exception { - - driver.navigate().to("http://localhost:8081/sales-metadata/"); - Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/auth/realms/demo/protocol/saml"); - loginPage.login("bburke", "password"); - Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/sales-metadata/"); - String pageSource = driver.getPageSource(); - Assert.assertTrue(pageSource.contains("bburke")); - driver.navigate().to("http://localhost:8081/sales-metadata?GLO=true"); - checkLoggedOut("http://localhost:8081/sales-metadata/"); - - } - - public static void uploadSP() { - String token = createToken(); - final String authHeader = "Bearer " + token; - ClientRequestFilter authFilter = new ClientRequestFilter() { - @Override - public void filter(ClientRequestContext requestContext) throws IOException { - requestContext.getHeaders().add(HttpHeaders.AUTHORIZATION, authHeader); - } - }; - Client client = ClientBuilder.newBuilder().register(authFilter).build(); - UriBuilder authBase = UriBuilder.fromUri("http://localhost:8081/auth"); - WebTarget adminRealms = client.target(AdminRoot.realmsUrl(authBase)); - - - MultipartFormDataOutput formData = new MultipartFormDataOutput(); - InputStream is = SamlBindingTest.class.getResourceAsStream("/keycloak-saml/sp-metadata.xml"); - Assert.assertNotNull(is); - formData.addFormData("file", is, MediaType.APPLICATION_XML_TYPE); - - WebTarget upload = adminRealms.path("demo/client-importers/saml2-entity-descriptor/upload"); - System.out.println(upload.getUri()); - Response response = upload.request().post(Entity.entity(formData, MediaType.MULTIPART_FORM_DATA)); - Assert.assertEquals(204, response.getStatus()); - response.close(); - client.close(); - } -} 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 e7889afc3d..34d17f0aff 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 @@ -12,20 +12,11 @@ import io.undertow.servlet.api.LoginConfig; import io.undertow.servlet.api.SecurityConstraint; import io.undertow.servlet.api.ServletInfo; import io.undertow.servlet.api.WebResourceCollection; -import org.junit.Assert; import org.keycloak.adapters.saml.undertow.SamlServletExtension; import org.keycloak.testsuite.rule.AbstractKeycloakRule; -import org.picketlink.identity.federation.bindings.wildfly.sp.SPServletExtension; -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.OutputStream; import java.net.URL; -import java.security.Principal; -import java.util.List; /** * @author Bill Burke @@ -33,61 +24,6 @@ import java.util.List; */ public abstract class SamlKeycloakRule extends AbstractKeycloakRule { - public static class SendUsernameServlet extends HttpServlet { - - public static Principal sentPrincipal; - public static List checkRoles; - - @Override - protected void doGet(final HttpServletRequest req, final HttpServletResponse resp) throws ServletException, IOException { - if (checkRoles != null) { - for (String role : checkRoles) { - System.out.println("check role: " + role); - Assert.assertTrue(req.isUserInRole(role)); - } - - } - resp.setContentType("text/plain"); - OutputStream stream = resp.getOutputStream(); - Principal principal = req.getUserPrincipal(); - stream.write("request-path: ".getBytes()); - stream.write(req.getPathInfo().getBytes()); - stream.write("\n".getBytes()); - stream.write("principal=".getBytes()); - if (principal == null) { - stream.write("null".getBytes()); - return; - } - String name = principal.getName(); - stream.write(name.getBytes()); - sentPrincipal = principal; - - } - @Override - protected void doPost(final HttpServletRequest req, final HttpServletResponse resp) throws ServletException, IOException { - if (checkRoles != null) { - for (String role : checkRoles) { - Assert.assertTrue(req.isUserInRole(role)); - } - - } - resp.setContentType("text/plain"); - OutputStream stream = resp.getOutputStream(); - Principal principal = req.getUserPrincipal(); - stream.write("request-path: ".getBytes()); - stream.write(req.getPathInfo().getBytes()); - stream.write("\n".getBytes()); - stream.write("principal=".getBytes()); - if (principal == null) { - stream.write("null".getBytes()); - return; - } - String name = principal.getName(); - stream.write(name.getBytes()); - sentPrincipal = principal; - } - } - public static class TestResourceManager implements ResourceManager { private final String basePath; diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/keycloaksaml/SamlSPFacade.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/keycloaksaml/SamlSPFacade.java new file mode 100755 index 0000000000..a03fb8f2d5 --- /dev/null +++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/keycloaksaml/SamlSPFacade.java @@ -0,0 +1,45 @@ +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 javax.ws.rs.core.UriBuilder; +import java.io.IOException; + +/** +* @author Bill Burke +* @version $Revision: 1 $ +*/ +public class SamlSPFacade extends HttpServlet { + public static String samlResponse; + public static String RELAY_STATE = "http://test.com/foo/bar"; + public static String sentRelayState; + + @Override + protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + handler(req, resp); + } + + @Override + protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + handler(req, resp); + } + + private void handler(HttpServletRequest req, HttpServletResponse resp) { + System.out.println("********* HERE ******"); + if (req.getParameterMap().isEmpty()) { + System.out.println("redirecting"); + resp.setStatus(302); + // Redirect + // UriBuilder builder = UriBuilder.fromUri("http://localhost:8081/auth/realms/demo/protocol/saml?SAMLRequest=jVLRTsIwFP2Vpe%2BjG4wxG0YyWYxL0BBAH3wx3XYnTbp29nYof%2B8YEvEBNOlD03vOveec2ynyWjYsae1WreC9BbTOZy0Vsr4Qk9YopjkKZIrXgMwWbJ08LNhw4LHGaKsLLcmRch3MEcFYoRVxktN1rhW2NZg1mJ0o4Gm1iMnW2oZRKnXB5VajZZEX%2BRTqRuo9ACVO2mkUih%2F4l9C8s0MNcFkjLaHW9KSUHlwR506bAnrPMam4RCBOlsYkS1%2BD3MvLcDJxAx9KN4jCkXszrG5cP%2BCVH4y8IM8PYFx2dsQOfuiILWQKLVc2JkPPH7te6HrRxh%2BzUdidwSSIXoiz%2FBZyK1Qp1Nv1yPIjCNn9ZrN0V1AKA4UlzjMY7N13IDKbHjyxXoA5291%2FtzH7I%2FApPet%2FHNawx65hli61FMXeSaTUH%2FMubtvlYU0LfcA1t5cl%2BAO%2FfxGlW%2FVQ1ipsoBCVgJLQ2XHo7385%2BwI%3D"); + UriBuilder builder = UriBuilder.fromUri("http://localhost:8081/auth/realms/demo/protocol/saml?SAMLRequest=jVJbT8IwFP4rS99HuwluNIwEIUYSLwugD76Y2h2kSdfOng7l31uGRn0ATfrQ9HznfJfTEYpaN3zS%2Bo1ZwGsL6KP3WhvkXaEgrTPcClTIjagBuZd8Obm55mmP8cZZb6XV5NByGiwQwXllDYkmX9epNdjW4JbgtkrC%2FeK6IBvvG06ptlLojUXPc5YnFOpG2x0AJdEsaFRG7PuPoUWwQx0IXSOtoLb0SynduyLRpXUSOs8FWQuNQKL5rCDz2VO%2FymEgIY2zlJ3H%2FSx9jkU%2BzOK0ys8yNmSSsUEAYxnsqC18tyO2MDfohfEFSVkyiNlZzM5XacrDSbJePug%2Fkqj8FHKhTKXMy%2BnIng8g5FerVRmXd8sViR7AYec8AMh4tPfDO3L3Y2%2F%2F3cT4j7BH9Mf8A1nDb8PA%2Bay0WsldNNHavk1D1D5k4V0LXbi18MclJL2ke1FVvO6gvDXYgFRrBRWh4wPp7z85%2FgA%3D"); + builder.queryParam("RelayState", RELAY_STATE); + resp.setHeader("Location", builder.build().toString()); + return; + } + System.out.println("received response"); + samlResponse = req.getParameter("SAMLResponse"); + sentRelayState = req.getParameter("RelayState"); + } +} diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/keycloaksaml/SendUsernameServlet.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/keycloaksaml/SendUsernameServlet.java new file mode 100755 index 0000000000..faa50146a9 --- /dev/null +++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/keycloaksaml/SendUsernameServlet.java @@ -0,0 +1,74 @@ +package org.keycloak.testsuite.keycloaksaml; + +import org.junit.Assert; + +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.OutputStream; +import java.security.Principal; +import java.util.List; + +/** +* @author Bill Burke +* @version $Revision: 1 $ +*/ +public class SendUsernameServlet extends HttpServlet { + + public static Principal sentPrincipal; + public static List checkRoles; + + @Override + protected void doGet(final HttpServletRequest req, final HttpServletResponse resp) throws ServletException, IOException { + System.out.println("In SendUsername Servlet doGet()"); + if (checkRoles != null) { + for (String role : checkRoles) { + System.out.println("check role: " + role); + Assert.assertTrue(req.isUserInRole(role)); + } + + } + resp.setContentType("text/plain"); + OutputStream stream = resp.getOutputStream(); + Principal principal = req.getUserPrincipal(); + stream.write("request-path: ".getBytes()); + stream.write(req.getPathInfo().getBytes()); + stream.write("\n".getBytes()); + stream.write("principal=".getBytes()); + if (principal == null) { + stream.write("null".getBytes()); + return; + } + String name = principal.getName(); + stream.write(name.getBytes()); + sentPrincipal = principal; + + } + @Override + protected void doPost(final HttpServletRequest req, final HttpServletResponse resp) throws ServletException, IOException { + System.out.println("In SendUsername Servlet doPost()"); + if (checkRoles != null) { + for (String role : checkRoles) { + System.out.println("check role: " + role); + Assert.assertTrue(req.isUserInRole(role)); + } + + } + resp.setContentType("text/plain"); + OutputStream stream = resp.getOutputStream(); + Principal principal = req.getUserPrincipal(); + stream.write("request-path: ".getBytes()); + stream.write(req.getPathInfo().getBytes()); + stream.write("\n".getBytes()); + stream.write("principal=".getBytes()); + if (principal == null) { + stream.write("null".getBytes()); + return; + } + String name = principal.getName(); + stream.write(name.getBytes()); + sentPrincipal = principal; + } +} diff --git a/testsuite/integration/src/test/resources/keycloak-saml/testsaml.json b/testsuite/integration/src/test/resources/keycloak-saml/testsaml.json index 5fafa8e7e1..8d5576e30f 100755 --- a/testsuite/integration/src/test/resources/keycloak-saml/testsaml.json +++ b/testsuite/integration/src/test/resources/keycloak-saml/testsaml.json @@ -21,7 +21,7 @@ "email" : "bburke@redhat.com", "credentials" : [ { "type" : "password", - "value" : "password" } + "value" : "password" } ], "attributes" : { "phone": "617" @@ -31,6 +31,15 @@ "http://localhost:8081/employee/": [ "employee" ], "http://localhost:8081/employee2/": [ "employee" ] } + }, + { + "username" : "unauthorized", + "enabled": true, + "email" : "unauthorized@redhat.com", + "credentials" : [ + { "type" : "password", + "value" : "password" } + ] } ], "applications": [ diff --git a/testsuite/tomcat6/pom.xml b/testsuite/tomcat6/pom.xml index 498c4d61e6..7d05f4d196 100755 --- a/testsuite/tomcat6/pom.xml +++ b/testsuite/tomcat6/pom.xml @@ -103,6 +103,24 @@ org.keycloak keycloak-tomcat6-adapter + + + org.keycloak + keycloak-tomcat6-saml-adapter + + + org.apache.tomcat + tomcat-servlet-api + + + org.apache.tomcat + tomcat-catalina + + + org.apache.tomcat + catalina + + io.undertow diff --git a/testsuite/tomcat6/src/test/java/org/keycloak/testsuite/TomcatSamlTest.java b/testsuite/tomcat6/src/test/java/org/keycloak/testsuite/TomcatSamlTest.java new file mode 100755 index 0000000000..98eec5a2f8 --- /dev/null +++ b/testsuite/tomcat6/src/test/java/org/keycloak/testsuite/TomcatSamlTest.java @@ -0,0 +1,193 @@ +/* + * JBoss, Home of Professional Open Source. + * Copyright 2012, Red Hat, Inc., and individual contributors + * as indicated by the @author tags. See the copyright.txt file in the + * distribution for a full listing of individual contributors. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.keycloak.testsuite; + +import org.junit.AfterClass; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.ClassRule; +import org.junit.Rule; +import org.junit.Test; +import org.keycloak.models.KeycloakSession; +import org.keycloak.models.RealmModel; +import org.keycloak.services.managers.RealmManager; +import org.keycloak.testsuite.adapter.AdapterTestStrategy; +import org.keycloak.testsuite.keycloaksaml.SamlAdapterTestStrategy; +import org.keycloak.testsuite.rule.AbstractKeycloakRule; +import org.openqa.selenium.WebDriver; + +import java.io.File; +import java.net.URL; +import java.util.regex.Matcher; + +/** + * @author Stian Thorgersen + */ +public class TomcatSamlTest { + @ClassRule + public static AbstractKeycloakRule keycloakRule = new AbstractKeycloakRule() { + @Override + protected void configure(KeycloakSession session, RealmManager manager, RealmModel adminRealm) { + SamlAdapterTestStrategy.baseAdapterTestInitialization(session, manager, adminRealm, getClass()); + } + }; + + static TomcatServer tomcat = null; + + @BeforeClass + public static void initTomcat() throws Exception { + URL dir = TomcatSamlTest.class.getResource("/keycloak-saml/testsaml.json"); + String baseDir = new File(dir.getFile()).getParentFile().toString(); + System.out.println("Tomcat basedir: " + baseDir); + tomcat = new TomcatServer(8082, baseDir); + System.setProperty("app.server.base.url", "http://localhost:8082"); + System.setProperty("my.host.name", "localhost"); + tomcat.deploySaml("/sales-post", "simple-post"); + tomcat.deploySaml("/sales-post-sig", "signed-post"); + tomcat.deploySaml("/sales-post-sig-email", "signed-post-email"); + tomcat.deploySaml("/sales-post-sig-transient", "signed-post-transient"); + tomcat.deploySaml("/sales-post-sig-persistent", "signed-post-persistent"); + tomcat.deploySaml("/sales-metadata", "signed-metadata"); + tomcat.deploySaml("/employee-sig", "signed-get"); + tomcat.deploySaml("/employee2", "mappers"); + tomcat.deploySaml("/employee-sig-front", "signed-front-get"); + tomcat.deploySaml("/bad-client-sales-post-sig", "bad-client-signed-post"); + tomcat.deploySaml("/bad-realm-sales-post-sig", "bad-realm-signed-post"); + tomcat.deploySaml("/sales-post-enc", "encrypted-post"); + SamlAdapterTestStrategy.uploadSP("http://localhost:8081/auth", keycloakRule); + + + tomcat.start(); + //tomcat.getServer().await(); + } + + @AfterClass + public static void shutdownTomcat() throws Exception { + tomcat.stop(); + } + + @Rule + public SamlAdapterTestStrategy testStrategy = new SamlAdapterTestStrategy("http://localhost:8081/auth", "http://localhost:8082", keycloakRule); + + @Test + public void testPostSimpleLoginLogout() { + testStrategy.testPostSimpleLoginLogout(); + } + + @Test + public void testPostSimpleLoginLogoutIdpInitiated() { + testStrategy.testPostSimpleLoginLogoutIdpInitiated(); + } + + @Test + public void testPostSignedLoginLogout() { + testStrategy.testPostSignedLoginLogout(); + } + + @Test + public void testPostSignedLoginLogoutTransientNameID() { + testStrategy.testPostSignedLoginLogoutTransientNameID(); + } + + @Test + public void testPostSignedLoginLogoutPersistentNameID() { + testStrategy.testPostSignedLoginLogoutPersistentNameID(); + } + + @Test + public void testPostSignedLoginLogoutEmailNameID() { + testStrategy.testPostSignedLoginLogoutEmailNameID(); + } + + @Test + public void testAttributes() throws Exception { + testStrategy.testAttributes(); + } + + @Test + public void testRedirectSignedLoginLogout() { + testStrategy.testRedirectSignedLoginLogout(); + } + + @Test + public void testRedirectSignedLoginLogoutFrontNoSSO() { + testStrategy.testRedirectSignedLoginLogoutFrontNoSSO(); + } + + @Test + public void testRedirectSignedLoginLogoutFront() { + testStrategy.testRedirectSignedLoginLogoutFront(); + } + + @Test + public void testPostEncryptedLoginLogout() { + testStrategy.testPostEncryptedLoginLogout(); + } + + @Test + public void testPostBadClientSignature() { + testStrategy.testPostBadClientSignature(); + } + + @Test + public void testPostBadRealmSignature() { + testStrategy.testPostBadRealmSignature( new SamlAdapterTestStrategy.CheckAuthError() { + @Override + public void check(WebDriver driver) { + Assert.assertEquals(driver.getPageSource(), ""); + } + }); + } + + @Test + public void testPostSimpleUnauthorized() { + testStrategy.testPostSimpleUnauthorized( new SamlAdapterTestStrategy.CheckAuthError() { + @Override + public void check(WebDriver driver) { + Assert.assertTrue(driver.getPageSource().contains("forbidden")); + } + }); + } + + //@Test + public void testMetadataPostSignedLoginLogout() throws Exception { + testStrategy.testMetadataPostSignedLoginLogout(); + } + + static String getBaseDirectory() { + String dirPath = null; + String relativeDirPath = "testsuite" + File.separator + "tomcat6" + File.separator + "target"; + + if (System.getProperties().containsKey("maven.home")) { + dirPath = System.getProperty("user.dir").replaceFirst("testsuite.tomcat6.*", Matcher.quoteReplacement(relativeDirPath)); + } else { + for (String c : System.getProperty("java.class.path").split(File.pathSeparator)) { + if (c.contains(File.separator + "testsuite" + File.separator + "tomcat6")) { + dirPath = c.replaceFirst("testsuite.tomcat6.*", Matcher.quoteReplacement(relativeDirPath)); + break; + } + } + } + String absolutePath = new File(dirPath).getAbsolutePath(); + return absolutePath; + } +} diff --git a/testsuite/tomcat6/src/test/java/org/keycloak/testsuite/TomcatServer.java b/testsuite/tomcat6/src/test/java/org/keycloak/testsuite/TomcatServer.java index a0ebb08547..df17d9b1be 100755 --- a/testsuite/tomcat6/src/test/java/org/keycloak/testsuite/TomcatServer.java +++ b/testsuite/tomcat6/src/test/java/org/keycloak/testsuite/TomcatServer.java @@ -7,6 +7,7 @@ import org.apache.catalina.connector.Connector; import org.apache.catalina.core.StandardContext; import org.apache.catalina.startup.Embedded; import org.jboss.logging.Logger; +import org.keycloak.adapters.saml.tomcat.SamlAuthenticatorValve; import org.keycloak.adapters.tomcat.KeycloakAuthenticatorValve; public class TomcatServer { @@ -40,7 +41,7 @@ public class TomcatServer { public TomcatServer(int port, String appBase) { this.port = port; - + Thread.currentThread().setContextClassLoader(getClass().getClassLoader()); server = new Embedded(); server.setName("TomcatEmbeddedServer"); server.setCatalinaBase(TomcatTest.getBaseDirectory()); @@ -64,6 +65,20 @@ public class TomcatServer { rootContext.setDefaultWebXml("web.xml"); host.addChild(rootContext); } + public void deploySaml(String contextPath, String appDir) { + if (contextPath == null) { + throw new IllegalArgumentException("Context path or appbase should not be null"); + } + if (!contextPath.startsWith("/")) { + contextPath = "/" + contextPath; + } + StandardContext rootContext = (StandardContext) server.createContext(contextPath, appDir); + SamlAuthenticatorValve valve = new SamlAuthenticatorValve(); + rootContext.addValve(valve); + //rootContext.addLifecycleListener(valve); + rootContext.setDefaultWebXml("web.xml"); + host.addChild(rootContext); + } /** * Start the tomcat embedded server diff --git a/testsuite/tomcat6/src/test/java/org/keycloak/testsuite/TomcatTest.java b/testsuite/tomcat6/src/test/java/org/keycloak/testsuite/TomcatTest.java index e28a2f6308..9e0101dccd 100755 --- a/testsuite/tomcat6/src/test/java/org/keycloak/testsuite/TomcatTest.java +++ b/testsuite/tomcat6/src/test/java/org/keycloak/testsuite/TomcatTest.java @@ -24,6 +24,7 @@ package org.keycloak.testsuite; import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.ClassRule; +import org.junit.Ignore; import org.junit.Rule; import org.junit.Test; import org.keycloak.models.KeycloakSession; @@ -39,6 +40,7 @@ import java.util.regex.Matcher; /** * @author Stian Thorgersen */ +//@Ignore public class TomcatTest { @ClassRule public static AbstractKeycloakRule keycloakRule = new AbstractKeycloakRule() { diff --git a/testsuite/tomcat6/src/test/resources/keycloak-saml/bad-client-signed-post/WEB-INF/keycloak-saml.xml b/testsuite/tomcat6/src/test/resources/keycloak-saml/bad-client-signed-post/WEB-INF/keycloak-saml.xml new file mode 100755 index 0000000000..fa1b2593d4 --- /dev/null +++ b/testsuite/tomcat6/src/test/resources/keycloak-saml/bad-client-signed-post/WEB-INF/keycloak-saml.xml @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/testsuite/tomcat6/src/test/resources/keycloak-saml/bad-client-signed-post/WEB-INF/keystore.jks b/testsuite/tomcat6/src/test/resources/keycloak-saml/bad-client-signed-post/WEB-INF/keystore.jks new file mode 100755 index 0000000000..6a3e3ba7d3 Binary files /dev/null and b/testsuite/tomcat6/src/test/resources/keycloak-saml/bad-client-signed-post/WEB-INF/keystore.jks differ diff --git a/testsuite/tomcat6/src/test/resources/keycloak-saml/bad-client-signed-post/WEB-INF/web.xml b/testsuite/tomcat6/src/test/resources/keycloak-saml/bad-client-signed-post/WEB-INF/web.xml new file mode 100755 index 0000000000..86db4a46a4 --- /dev/null +++ b/testsuite/tomcat6/src/test/resources/keycloak-saml/bad-client-signed-post/WEB-INF/web.xml @@ -0,0 +1,43 @@ + + + + adapter-test + + + SendUsernameServlet + org.keycloak.testsuite.keycloaksaml.SendUsernameServlet + + + SendUsernameServlet + /* + + + + + Users + /* + + + manager + + + + + BASIC + demo + + /error.html + /error.html + + + + + manager + + + el-jefe + + diff --git a/testsuite/tomcat6/src/test/resources/keycloak-saml/bad-realm-signed-post/WEB-INF/keycloak-saml.xml b/testsuite/tomcat6/src/test/resources/keycloak-saml/bad-realm-signed-post/WEB-INF/keycloak-saml.xml new file mode 100755 index 0000000000..8b1bf3d783 --- /dev/null +++ b/testsuite/tomcat6/src/test/resources/keycloak-saml/bad-realm-signed-post/WEB-INF/keycloak-saml.xml @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/testsuite/tomcat6/src/test/resources/keycloak-saml/bad-realm-signed-post/WEB-INF/keystore.jks b/testsuite/tomcat6/src/test/resources/keycloak-saml/bad-realm-signed-post/WEB-INF/keystore.jks new file mode 100755 index 0000000000..215384cdef Binary files /dev/null and b/testsuite/tomcat6/src/test/resources/keycloak-saml/bad-realm-signed-post/WEB-INF/keystore.jks differ diff --git a/testsuite/tomcat6/src/test/resources/keycloak-saml/bad-realm-signed-post/WEB-INF/web.xml b/testsuite/tomcat6/src/test/resources/keycloak-saml/bad-realm-signed-post/WEB-INF/web.xml new file mode 100755 index 0000000000..86db4a46a4 --- /dev/null +++ b/testsuite/tomcat6/src/test/resources/keycloak-saml/bad-realm-signed-post/WEB-INF/web.xml @@ -0,0 +1,43 @@ + + + + adapter-test + + + SendUsernameServlet + org.keycloak.testsuite.keycloaksaml.SendUsernameServlet + + + SendUsernameServlet + /* + + + + + Users + /* + + + manager + + + + + BASIC + demo + + /error.html + /error.html + + + + + manager + + + el-jefe + + diff --git a/testsuite/tomcat6/src/test/resources/keycloak-saml/context.xml b/testsuite/tomcat6/src/test/resources/keycloak-saml/context.xml new file mode 100755 index 0000000000..d16faafd19 --- /dev/null +++ b/testsuite/tomcat6/src/test/resources/keycloak-saml/context.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/testsuite/tomcat6/src/test/resources/keycloak-saml/encrypted-post/WEB-INF/keycloak-saml.xml b/testsuite/tomcat6/src/test/resources/keycloak-saml/encrypted-post/WEB-INF/keycloak-saml.xml new file mode 100755 index 0000000000..24bfb6454a --- /dev/null +++ b/testsuite/tomcat6/src/test/resources/keycloak-saml/encrypted-post/WEB-INF/keycloak-saml.xml @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/testsuite/tomcat6/src/test/resources/keycloak-saml/encrypted-post/WEB-INF/keystore.jks b/testsuite/tomcat6/src/test/resources/keycloak-saml/encrypted-post/WEB-INF/keystore.jks new file mode 100755 index 0000000000..822162ceaf Binary files /dev/null and b/testsuite/tomcat6/src/test/resources/keycloak-saml/encrypted-post/WEB-INF/keystore.jks differ diff --git a/testsuite/tomcat6/src/test/resources/keycloak-saml/encrypted-post/WEB-INF/web.xml b/testsuite/tomcat6/src/test/resources/keycloak-saml/encrypted-post/WEB-INF/web.xml new file mode 100755 index 0000000000..86db4a46a4 --- /dev/null +++ b/testsuite/tomcat6/src/test/resources/keycloak-saml/encrypted-post/WEB-INF/web.xml @@ -0,0 +1,43 @@ + + + + adapter-test + + + SendUsernameServlet + org.keycloak.testsuite.keycloaksaml.SendUsernameServlet + + + SendUsernameServlet + /* + + + + + Users + /* + + + manager + + + + + BASIC + demo + + /error.html + /error.html + + + + + manager + + + el-jefe + + diff --git a/testsuite/tomcat6/src/test/resources/keycloak-saml/mappers/WEB-INF/keycloak-saml.xml b/testsuite/tomcat6/src/test/resources/keycloak-saml/mappers/WEB-INF/keycloak-saml.xml new file mode 100755 index 0000000000..4fc1dfc640 --- /dev/null +++ b/testsuite/tomcat6/src/test/resources/keycloak-saml/mappers/WEB-INF/keycloak-saml.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/testsuite/tomcat6/src/test/resources/keycloak-saml/mappers/WEB-INF/web.xml b/testsuite/tomcat6/src/test/resources/keycloak-saml/mappers/WEB-INF/web.xml new file mode 100755 index 0000000000..0d92eb3cab --- /dev/null +++ b/testsuite/tomcat6/src/test/resources/keycloak-saml/mappers/WEB-INF/web.xml @@ -0,0 +1,56 @@ + + + + adapter-test + + + SendUsernameServlet + org.keycloak.testsuite.keycloaksaml.SendUsernameServlet + + + SendUsernameServlet + /* + + + + + Users + /* + + + manager + el-jefe + + + + + BASIC + demo + + /error.html + /error.html + + + + + manager + + + el-jefe + + + user + + + employee + + + pee-on + + + hardcoded-role + + diff --git a/testsuite/tomcat6/src/test/resources/keycloak-saml/signed-front-get/WEB-INF/keycloak-saml.xml b/testsuite/tomcat6/src/test/resources/keycloak-saml/signed-front-get/WEB-INF/keycloak-saml.xml new file mode 100755 index 0000000000..a8d84c17fe --- /dev/null +++ b/testsuite/tomcat6/src/test/resources/keycloak-saml/signed-front-get/WEB-INF/keycloak-saml.xml @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/testsuite/tomcat6/src/test/resources/keycloak-saml/signed-front-get/WEB-INF/keystore.jks b/testsuite/tomcat6/src/test/resources/keycloak-saml/signed-front-get/WEB-INF/keystore.jks new file mode 100755 index 0000000000..4daad218a3 Binary files /dev/null and b/testsuite/tomcat6/src/test/resources/keycloak-saml/signed-front-get/WEB-INF/keystore.jks differ diff --git a/testsuite/tomcat6/src/test/resources/keycloak-saml/signed-front-get/WEB-INF/web.xml b/testsuite/tomcat6/src/test/resources/keycloak-saml/signed-front-get/WEB-INF/web.xml new file mode 100755 index 0000000000..86db4a46a4 --- /dev/null +++ b/testsuite/tomcat6/src/test/resources/keycloak-saml/signed-front-get/WEB-INF/web.xml @@ -0,0 +1,43 @@ + + + + adapter-test + + + SendUsernameServlet + org.keycloak.testsuite.keycloaksaml.SendUsernameServlet + + + SendUsernameServlet + /* + + + + + Users + /* + + + manager + + + + + BASIC + demo + + /error.html + /error.html + + + + + manager + + + el-jefe + + diff --git a/testsuite/tomcat6/src/test/resources/keycloak-saml/signed-get/WEB-INF/keycloak-saml.xml b/testsuite/tomcat6/src/test/resources/keycloak-saml/signed-get/WEB-INF/keycloak-saml.xml new file mode 100755 index 0000000000..724919bd9b --- /dev/null +++ b/testsuite/tomcat6/src/test/resources/keycloak-saml/signed-get/WEB-INF/keycloak-saml.xml @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/testsuite/tomcat6/src/test/resources/keycloak-saml/signed-get/WEB-INF/keystore.jks b/testsuite/tomcat6/src/test/resources/keycloak-saml/signed-get/WEB-INF/keystore.jks new file mode 100755 index 0000000000..4daad218a3 Binary files /dev/null and b/testsuite/tomcat6/src/test/resources/keycloak-saml/signed-get/WEB-INF/keystore.jks differ diff --git a/testsuite/tomcat6/src/test/resources/keycloak-saml/signed-get/WEB-INF/web.xml b/testsuite/tomcat6/src/test/resources/keycloak-saml/signed-get/WEB-INF/web.xml new file mode 100755 index 0000000000..86db4a46a4 --- /dev/null +++ b/testsuite/tomcat6/src/test/resources/keycloak-saml/signed-get/WEB-INF/web.xml @@ -0,0 +1,43 @@ + + + + adapter-test + + + SendUsernameServlet + org.keycloak.testsuite.keycloaksaml.SendUsernameServlet + + + SendUsernameServlet + /* + + + + + Users + /* + + + manager + + + + + BASIC + demo + + /error.html + /error.html + + + + + manager + + + el-jefe + + diff --git a/testsuite/tomcat6/src/test/resources/keycloak-saml/signed-metadata/WEB-INF/keycloak-saml.xml b/testsuite/tomcat6/src/test/resources/keycloak-saml/signed-metadata/WEB-INF/keycloak-saml.xml new file mode 100755 index 0000000000..1ffeb1bdd3 --- /dev/null +++ b/testsuite/tomcat6/src/test/resources/keycloak-saml/signed-metadata/WEB-INF/keycloak-saml.xml @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/testsuite/tomcat6/src/test/resources/keycloak-saml/signed-metadata/WEB-INF/keystore.jks b/testsuite/tomcat6/src/test/resources/keycloak-saml/signed-metadata/WEB-INF/keystore.jks new file mode 100755 index 0000000000..144830bc77 Binary files /dev/null and b/testsuite/tomcat6/src/test/resources/keycloak-saml/signed-metadata/WEB-INF/keystore.jks differ diff --git a/testsuite/tomcat6/src/test/resources/keycloak-saml/signed-metadata/WEB-INF/web.xml b/testsuite/tomcat6/src/test/resources/keycloak-saml/signed-metadata/WEB-INF/web.xml new file mode 100755 index 0000000000..86db4a46a4 --- /dev/null +++ b/testsuite/tomcat6/src/test/resources/keycloak-saml/signed-metadata/WEB-INF/web.xml @@ -0,0 +1,43 @@ + + + + adapter-test + + + SendUsernameServlet + org.keycloak.testsuite.keycloaksaml.SendUsernameServlet + + + SendUsernameServlet + /* + + + + + Users + /* + + + manager + + + + + BASIC + demo + + /error.html + /error.html + + + + + manager + + + el-jefe + + diff --git a/testsuite/tomcat6/src/test/resources/keycloak-saml/signed-post-email/WEB-INF/keycloak-saml.xml b/testsuite/tomcat6/src/test/resources/keycloak-saml/signed-post-email/WEB-INF/keycloak-saml.xml new file mode 100755 index 0000000000..dbb9c31b6f --- /dev/null +++ b/testsuite/tomcat6/src/test/resources/keycloak-saml/signed-post-email/WEB-INF/keycloak-saml.xml @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/testsuite/tomcat6/src/test/resources/keycloak-saml/signed-post-email/WEB-INF/keystore.jks b/testsuite/tomcat6/src/test/resources/keycloak-saml/signed-post-email/WEB-INF/keystore.jks new file mode 100755 index 0000000000..144830bc77 Binary files /dev/null and b/testsuite/tomcat6/src/test/resources/keycloak-saml/signed-post-email/WEB-INF/keystore.jks differ diff --git a/testsuite/tomcat6/src/test/resources/keycloak-saml/signed-post-email/WEB-INF/web.xml b/testsuite/tomcat6/src/test/resources/keycloak-saml/signed-post-email/WEB-INF/web.xml new file mode 100755 index 0000000000..86db4a46a4 --- /dev/null +++ b/testsuite/tomcat6/src/test/resources/keycloak-saml/signed-post-email/WEB-INF/web.xml @@ -0,0 +1,43 @@ + + + + adapter-test + + + SendUsernameServlet + org.keycloak.testsuite.keycloaksaml.SendUsernameServlet + + + SendUsernameServlet + /* + + + + + Users + /* + + + manager + + + + + BASIC + demo + + /error.html + /error.html + + + + + manager + + + el-jefe + + diff --git a/testsuite/tomcat6/src/test/resources/keycloak-saml/signed-post-persistent/WEB-INF/keycloak-saml.xml b/testsuite/tomcat6/src/test/resources/keycloak-saml/signed-post-persistent/WEB-INF/keycloak-saml.xml new file mode 100755 index 0000000000..0415bb1dd1 --- /dev/null +++ b/testsuite/tomcat6/src/test/resources/keycloak-saml/signed-post-persistent/WEB-INF/keycloak-saml.xml @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/testsuite/tomcat6/src/test/resources/keycloak-saml/signed-post-persistent/WEB-INF/keystore.jks b/testsuite/tomcat6/src/test/resources/keycloak-saml/signed-post-persistent/WEB-INF/keystore.jks new file mode 100755 index 0000000000..144830bc77 Binary files /dev/null and b/testsuite/tomcat6/src/test/resources/keycloak-saml/signed-post-persistent/WEB-INF/keystore.jks differ diff --git a/testsuite/tomcat6/src/test/resources/keycloak-saml/signed-post-persistent/WEB-INF/web.xml b/testsuite/tomcat6/src/test/resources/keycloak-saml/signed-post-persistent/WEB-INF/web.xml new file mode 100755 index 0000000000..86db4a46a4 --- /dev/null +++ b/testsuite/tomcat6/src/test/resources/keycloak-saml/signed-post-persistent/WEB-INF/web.xml @@ -0,0 +1,43 @@ + + + + adapter-test + + + SendUsernameServlet + org.keycloak.testsuite.keycloaksaml.SendUsernameServlet + + + SendUsernameServlet + /* + + + + + Users + /* + + + manager + + + + + BASIC + demo + + /error.html + /error.html + + + + + manager + + + el-jefe + + diff --git a/testsuite/tomcat6/src/test/resources/keycloak-saml/signed-post-transient/WEB-INF/keycloak-saml.xml b/testsuite/tomcat6/src/test/resources/keycloak-saml/signed-post-transient/WEB-INF/keycloak-saml.xml new file mode 100755 index 0000000000..4b96159674 --- /dev/null +++ b/testsuite/tomcat6/src/test/resources/keycloak-saml/signed-post-transient/WEB-INF/keycloak-saml.xml @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/testsuite/tomcat6/src/test/resources/keycloak-saml/signed-post-transient/WEB-INF/keystore.jks b/testsuite/tomcat6/src/test/resources/keycloak-saml/signed-post-transient/WEB-INF/keystore.jks new file mode 100755 index 0000000000..144830bc77 Binary files /dev/null and b/testsuite/tomcat6/src/test/resources/keycloak-saml/signed-post-transient/WEB-INF/keystore.jks differ diff --git a/testsuite/tomcat6/src/test/resources/keycloak-saml/signed-post-transient/WEB-INF/web.xml b/testsuite/tomcat6/src/test/resources/keycloak-saml/signed-post-transient/WEB-INF/web.xml new file mode 100755 index 0000000000..86db4a46a4 --- /dev/null +++ b/testsuite/tomcat6/src/test/resources/keycloak-saml/signed-post-transient/WEB-INF/web.xml @@ -0,0 +1,43 @@ + + + + adapter-test + + + SendUsernameServlet + org.keycloak.testsuite.keycloaksaml.SendUsernameServlet + + + SendUsernameServlet + /* + + + + + Users + /* + + + manager + + + + + BASIC + demo + + /error.html + /error.html + + + + + manager + + + el-jefe + + diff --git a/testsuite/tomcat6/src/test/resources/keycloak-saml/signed-post/WEB-INF/keycloak-saml.xml b/testsuite/tomcat6/src/test/resources/keycloak-saml/signed-post/WEB-INF/keycloak-saml.xml new file mode 100755 index 0000000000..dcd6f5b0e4 --- /dev/null +++ b/testsuite/tomcat6/src/test/resources/keycloak-saml/signed-post/WEB-INF/keycloak-saml.xml @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/testsuite/tomcat6/src/test/resources/keycloak-saml/signed-post/WEB-INF/keystore.jks b/testsuite/tomcat6/src/test/resources/keycloak-saml/signed-post/WEB-INF/keystore.jks new file mode 100755 index 0000000000..144830bc77 Binary files /dev/null and b/testsuite/tomcat6/src/test/resources/keycloak-saml/signed-post/WEB-INF/keystore.jks differ diff --git a/testsuite/tomcat6/src/test/resources/keycloak-saml/signed-post/WEB-INF/web.xml b/testsuite/tomcat6/src/test/resources/keycloak-saml/signed-post/WEB-INF/web.xml new file mode 100755 index 0000000000..86db4a46a4 --- /dev/null +++ b/testsuite/tomcat6/src/test/resources/keycloak-saml/signed-post/WEB-INF/web.xml @@ -0,0 +1,43 @@ + + + + adapter-test + + + SendUsernameServlet + org.keycloak.testsuite.keycloaksaml.SendUsernameServlet + + + SendUsernameServlet + /* + + + + + Users + /* + + + manager + + + + + BASIC + demo + + /error.html + /error.html + + + + + manager + + + el-jefe + + diff --git a/testsuite/tomcat6/src/test/resources/keycloak-saml/simple-post/WEB-INF/keycloak-saml.xml b/testsuite/tomcat6/src/test/resources/keycloak-saml/simple-post/WEB-INF/keycloak-saml.xml new file mode 100755 index 0000000000..e831ff7e3f --- /dev/null +++ b/testsuite/tomcat6/src/test/resources/keycloak-saml/simple-post/WEB-INF/keycloak-saml.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/testsuite/tomcat6/src/test/resources/keycloak-saml/simple-post/WEB-INF/web.xml b/testsuite/tomcat6/src/test/resources/keycloak-saml/simple-post/WEB-INF/web.xml new file mode 100755 index 0000000000..86db4a46a4 --- /dev/null +++ b/testsuite/tomcat6/src/test/resources/keycloak-saml/simple-post/WEB-INF/web.xml @@ -0,0 +1,43 @@ + + + + adapter-test + + + SendUsernameServlet + org.keycloak.testsuite.keycloaksaml.SendUsernameServlet + + + SendUsernameServlet + /* + + + + + Users + /* + + + manager + + + + + BASIC + demo + + /error.html + /error.html + + + + + manager + + + el-jefe + + diff --git a/testsuite/tomcat6/src/test/resources/keycloak-saml/sp-metadata.xml b/testsuite/tomcat6/src/test/resources/keycloak-saml/sp-metadata.xml new file mode 100755 index 0000000000..8f143deb61 --- /dev/null +++ b/testsuite/tomcat6/src/test/resources/keycloak-saml/sp-metadata.xml @@ -0,0 +1,38 @@ + + + + + urn:oasis:names:tc:SAML:2.0:nameid-format:transient + + + + + + + + MIIB1DCCAT0CBgFJGP5dZDANBgkqhkiG9w0BAQsFADAwMS4wLAYDVQQDEyVodHRwOi8vbG9jYWxob3N0OjgwODAvc2FsZXMtcG9zdC1zaWcvMB4XDTE0MTAxNjEyNDQyM1oXDTI0MTAxNjEyNDYwM1owMDEuMCwGA1UEAxMlaHR0cDovL2xvY2FsaG9zdDo4MDgwL3NhbGVzLXBvc3Qtc2lnLzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA1RvGu8RjemSJA23nnMksoHA37MqY1DDTxOECY4rPAd9egr7GUNIXE0y1MokaR5R2crNpN8RIRwR8phQtQDjXL82c6W+NLQISxztarQJ7rdNJIYwHY0d5ri1XRpDP8zAuxubPYiMAVYcDkIcvlbBpwh/dRM5I2eElRK+eSiaMkCUCAwEAATANBgkqhkiG9w0BAQsFAAOBgQCLms6htnPaY69k1ntm9a5jgwSn/K61cdai8R8B0ccY7zvinn9AfRD7fiROQpFyY29wKn8WCLrJ86NBXfgFUGyR5nLNHVy3FghE36N2oHy53uichieMxffE6vhkKJ4P8ChfJMMOZlmCPsQPDvjoAghHt4mriFiQgRdPgIy/zDjSNw== + + + + + + + JBoss + JBoss by Red Hat + http://localhost:8080/sales-metadata/ + + + The + Admin + admin@mycompany.com + + + \ No newline at end of file diff --git a/testsuite/tomcat6/src/test/resources/keycloak-saml/testsaml.json b/testsuite/tomcat6/src/test/resources/keycloak-saml/testsaml.json new file mode 100755 index 0000000000..0b13fb9e9e --- /dev/null +++ b/testsuite/tomcat6/src/test/resources/keycloak-saml/testsaml.json @@ -0,0 +1,376 @@ +{ + "id": "demo", + "realm": "demo", + "enabled": true, + "sslRequired": "external", + "registrationAllowed": true, + "resetPasswordAllowed": true, + "privateKey": "MIICXAIBAAKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQABAoGAfmO8gVhyBxdqlxmIuglbz8bcjQbhXJLR2EoS8ngTXmN1bo2L90M0mUKSdc7qF10LgETBzqL8jYlQIbt+e6TH8fcEpKCjUlyq0Mf/vVbfZSNaVycY13nTzo27iPyWQHK5NLuJzn1xvxxrUeXI6A2WFpGEBLbHjwpx5WQG9A+2scECQQDvdn9NE75HPTVPxBqsEd2z10TKkl9CZxu10Qby3iQQmWLEJ9LNmy3acvKrE3gMiYNWb6xHPKiIqOR1as7L24aTAkEAtyvQOlCvr5kAjVqrEKXalj0Tzewjweuxc0pskvArTI2Oo070h65GpoIKLc9jf+UA69cRtquwP93aZKtW06U8dQJAF2Y44ks/mK5+eyDqik3koCI08qaC8HYq2wVl7G2QkJ6sbAaILtcvD92ToOvyGyeE0flvmDZxMYlvaZnaQ0lcSQJBAKZU6umJi3/xeEbkJqMfeLclD27XGEFoPeNrmdx0q10Azp4NfJAY+Z8KRyQCR2BEG+oNitBOZ+YXF9KCpH3cdmECQHEigJhYg+ykOvr1aiZUMFT72HU0jnmQe2FVekuG+LJUt2Tm7GtMjTFoGpf0JwrVuZN39fOYAlo+nTixgeW7X8Y=", + "publicKey": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB", + "requiredCredentials": [ "password" ], + "defaultRoles": [ "user" ], + "smtpServer": { + "from": "auto@keycloak.org", + "host": "localhost", + "port":"3025" + }, + "users" : [ + { + "username" : "bburke", + "enabled": true, + "email" : "bburke@redhat.com", + "credentials" : [ + { "type" : "password", + "value" : "password" } + ], + "attributes" : { + "phone": "617" + }, + "realmRoles": ["manager", "user"], + "applicationRoles": { + "http://localhost:8082/employee/": [ "employee" ], + "http://localhost:8082/employee2/": [ "employee" ] + } + } , + { + "username" : "unauthorized", + "enabled": true, + "email" : "unauthorized@redhat.com", + "credentials" : [ + { "type" : "password", + "value" : "password" } + ] + } + ], + "applications": [ + { + "name": "http://localhost:8082/sales-post/", + "enabled": true, + "fullScopeAllowed": true, + "protocol": "saml", + "baseUrl": "http://localhost:8082/sales-post", + "redirectUris": [ + "http://localhost:8082/sales-post/*" + ], + "attributes": { + "saml.authnstatement": "true", + "saml_assertion_consumer_url_post": "http://localhost:8082/sales-post/", + "saml_assertion_consumer_url_redirect": "http://localhost:8082/sales-post/", + "saml_single_logout_service_url_post": "http://localhost:8082/sales-post/", + "saml_single_logout_service_url_redirect": "http://localhost:8082/sales-post/", + "saml_idp_initiated_sso_url_name": "sales-post" + } + }, + { + "name": "http://localhost:8082/sales-post-sig/", + "enabled": true, + "protocol": "saml", + "fullScopeAllowed": true, + "baseUrl": "http://localhost:8082/sales-post-sig", + "redirectUris": [ + "http://localhost:8082/sales-post-sig/*" + ], + "attributes": { + "saml_assertion_consumer_url_post": "http://localhost:8082/sales-post-sig/", + "saml_assertion_consumer_url_redirect": "http://localhost:8082/sales-post-sig/", + "saml_single_logout_service_url_post": "http://localhost:8082/sales-post-sig/", + "saml_single_logout_service_url_redirect": "http://localhost:8082/sales-post-sig/", + "saml.server.signature": "true", + "saml.signature.algorithm": "RSA_SHA256", + "saml.client.signature": "true", + "saml.authnstatement": "true", + "saml.signing.certificate": "MIIB1DCCAT0CBgFJGP5dZDANBgkqhkiG9w0BAQsFADAwMS4wLAYDVQQDEyVodHRwOi8vbG9jYWxob3N0OjgwODAvc2FsZXMtcG9zdC1zaWcvMB4XDTE0MTAxNjEyNDQyM1oXDTI0MTAxNjEyNDYwM1owMDEuMCwGA1UEAxMlaHR0cDovL2xvY2FsaG9zdDo4MDgwL3NhbGVzLXBvc3Qtc2lnLzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA1RvGu8RjemSJA23nnMksoHA37MqY1DDTxOECY4rPAd9egr7GUNIXE0y1MokaR5R2crNpN8RIRwR8phQtQDjXL82c6W+NLQISxztarQJ7rdNJIYwHY0d5ri1XRpDP8zAuxubPYiMAVYcDkIcvlbBpwh/dRM5I2eElRK+eSiaMkCUCAwEAATANBgkqhkiG9w0BAQsFAAOBgQCLms6htnPaY69k1ntm9a5jgwSn/K61cdai8R8B0ccY7zvinn9AfRD7fiROQpFyY29wKn8WCLrJ86NBXfgFUGyR5nLNHVy3FghE36N2oHy53uichieMxffE6vhkKJ4P8ChfJMMOZlmCPsQPDvjoAghHt4mriFiQgRdPgIy/zDjSNw==" + } + }, + { + "name": "http://localhost:8082/sales-post-sig-transient/", + "enabled": true, + "protocol": "saml", + "fullScopeAllowed": true, + "baseUrl": "http://localhost:8082/sales-post-sig-transient", + "adminUrl": "http://localhost:8082/sales-post-sig-transient", + "redirectUris": [ + "http://localhost:8082/sales-post-sig-transient/*" + ], + "attributes": { + "saml_assertion_consumer_url_post": "http://localhost:8082/sales-post-sig-transient/", + "saml_assertion_consumer_url_redirect": "http://localhost:8082/sales-post-sig-transient/", + "saml_single_logout_service_url_post": "http://localhost:8082/sales-post-sig-transient/", + "saml_single_logout_service_url_redirect": "http://localhost:8082/sales-post-sig-transient/", + "saml.server.signature": "true", + "saml.signature.algorithm": "RSA_SHA256", + "saml.client.signature": "true", + "saml.authnstatement": "true", + "saml.signing.certificate": "MIIB1DCCAT0CBgFJGP5dZDANBgkqhkiG9w0BAQsFADAwMS4wLAYDVQQDEyVodHRwOi8vbG9jYWxob3N0OjgwODAvc2FsZXMtcG9zdC1zaWcvMB4XDTE0MTAxNjEyNDQyM1oXDTI0MTAxNjEyNDYwM1owMDEuMCwGA1UEAxMlaHR0cDovL2xvY2FsaG9zdDo4MDgwL3NhbGVzLXBvc3Qtc2lnLzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA1RvGu8RjemSJA23nnMksoHA37MqY1DDTxOECY4rPAd9egr7GUNIXE0y1MokaR5R2crNpN8RIRwR8phQtQDjXL82c6W+NLQISxztarQJ7rdNJIYwHY0d5ri1XRpDP8zAuxubPYiMAVYcDkIcvlbBpwh/dRM5I2eElRK+eSiaMkCUCAwEAATANBgkqhkiG9w0BAQsFAAOBgQCLms6htnPaY69k1ntm9a5jgwSn/K61cdai8R8B0ccY7zvinn9AfRD7fiROQpFyY29wKn8WCLrJ86NBXfgFUGyR5nLNHVy3FghE36N2oHy53uichieMxffE6vhkKJ4P8ChfJMMOZlmCPsQPDvjoAghHt4mriFiQgRdPgIy/zDjSNw==" + } + }, + { + "name": "http://localhost:8082/sales-post-sig-persistent/", + "enabled": true, + "protocol": "saml", + "fullScopeAllowed": true, + "baseUrl": "http://localhost:8082/sales-post-sig-persistent", + "redirectUris": [ + "http://localhost:8082/sales-post-sig-persistent/*" + ], + "attributes": { + "saml_assertion_consumer_url_post": "http://localhost:8082/sales-post-sig-persistent/", + "saml_assertion_consumer_url_redirect": "http://localhost:8082/sales-post-sig-persistent/", + "saml_single_logout_service_url_post": "http://localhost:8082/sales-post-sig-persistent/", + "saml_single_logout_service_url_redirect": "http://localhost:8082/sales-post-sig-persistent/", + "saml.server.signature": "true", + "saml.signature.algorithm": "RSA_SHA256", + "saml.client.signature": "true", + "saml.authnstatement": "true", + "saml.signing.certificate": "MIIB1DCCAT0CBgFJGP5dZDANBgkqhkiG9w0BAQsFADAwMS4wLAYDVQQDEyVodHRwOi8vbG9jYWxob3N0OjgwODAvc2FsZXMtcG9zdC1zaWcvMB4XDTE0MTAxNjEyNDQyM1oXDTI0MTAxNjEyNDYwM1owMDEuMCwGA1UEAxMlaHR0cDovL2xvY2FsaG9zdDo4MDgwL3NhbGVzLXBvc3Qtc2lnLzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA1RvGu8RjemSJA23nnMksoHA37MqY1DDTxOECY4rPAd9egr7GUNIXE0y1MokaR5R2crNpN8RIRwR8phQtQDjXL82c6W+NLQISxztarQJ7rdNJIYwHY0d5ri1XRpDP8zAuxubPYiMAVYcDkIcvlbBpwh/dRM5I2eElRK+eSiaMkCUCAwEAATANBgkqhkiG9w0BAQsFAAOBgQCLms6htnPaY69k1ntm9a5jgwSn/K61cdai8R8B0ccY7zvinn9AfRD7fiROQpFyY29wKn8WCLrJ86NBXfgFUGyR5nLNHVy3FghE36N2oHy53uichieMxffE6vhkKJ4P8ChfJMMOZlmCPsQPDvjoAghHt4mriFiQgRdPgIy/zDjSNw==" + } + }, + { + "name": "http://localhost:8082/sales-post-sig-email/", + "enabled": true, + "protocol": "saml", + "fullScopeAllowed": true, + "baseUrl": "http://localhost:8082/sales-post-sig-email", + "adminUrl": "http://localhost:8082/sales-post-sig-email", + "redirectUris": [ + "http://localhost:8082/sales-post-sig-email/*" + ], + "attributes": { + "saml_force_name_id_format": "true", + "saml_name_id_format": "email", + "saml_assertion_consumer_url_post": "http://localhost:8082/sales-post-sig-email/", + "saml_assertion_consumer_url_redirect": "http://localhost:8082/sales-post-sig-email/", + "saml_single_logout_service_url_post": "http://localhost:8082/sales-post-sig-email/", + "saml_single_logout_service_url_redirect": "http://localhost:8082/sales-post-sig-email/", + "saml.server.signature": "true", + "saml.signature.algorithm": "RSA_SHA256", + "saml.client.signature": "true", + "saml.authnstatement": "true", + "saml.signing.certificate": "MIIB1DCCAT0CBgFJGP5dZDANBgkqhkiG9w0BAQsFADAwMS4wLAYDVQQDEyVodHRwOi8vbG9jYWxob3N0OjgwODAvc2FsZXMtcG9zdC1zaWcvMB4XDTE0MTAxNjEyNDQyM1oXDTI0MTAxNjEyNDYwM1owMDEuMCwGA1UEAxMlaHR0cDovL2xvY2FsaG9zdDo4MDgwL3NhbGVzLXBvc3Qtc2lnLzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA1RvGu8RjemSJA23nnMksoHA37MqY1DDTxOECY4rPAd9egr7GUNIXE0y1MokaR5R2crNpN8RIRwR8phQtQDjXL82c6W+NLQISxztarQJ7rdNJIYwHY0d5ri1XRpDP8zAuxubPYiMAVYcDkIcvlbBpwh/dRM5I2eElRK+eSiaMkCUCAwEAATANBgkqhkiG9w0BAQsFAAOBgQCLms6htnPaY69k1ntm9a5jgwSn/K61cdai8R8B0ccY7zvinn9AfRD7fiROQpFyY29wKn8WCLrJ86NBXfgFUGyR5nLNHVy3FghE36N2oHy53uichieMxffE6vhkKJ4P8ChfJMMOZlmCPsQPDvjoAghHt4mriFiQgRdPgIy/zDjSNw==" + } + }, + { + "name": "http://localhost:8082/bad-realm-sales-post-sig/", + "enabled": true, + "protocol": "saml", + "fullScopeAllowed": true, + "baseUrl": "http://localhost:8082/bad-realm-sales-post-sig/", + "adminUrl": "http://localhost:8082/bad-realm-sales-post-sig/", + "redirectUris": [ + "http://localhost:8082/bad-realm-sales-post-sig/*" + ], + "attributes": { + "saml.server.signature": "true", + "saml.client.signature": "true", + "saml.authnstatement": "true", + "saml.signing.certificate": "MIIB1DCCAT0CBgFJGP5dZDANBgkqhkiG9w0BAQsFADAwMS4wLAYDVQQDEyVodHRwOi8vbG9jYWxob3N0OjgwODAvc2FsZXMtcG9zdC1zaWcvMB4XDTE0MTAxNjEyNDQyM1oXDTI0MTAxNjEyNDYwM1owMDEuMCwGA1UEAxMlaHR0cDovL2xvY2FsaG9zdDo4MDgwL3NhbGVzLXBvc3Qtc2lnLzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA1RvGu8RjemSJA23nnMksoHA37MqY1DDTxOECY4rPAd9egr7GUNIXE0y1MokaR5R2crNpN8RIRwR8phQtQDjXL82c6W+NLQISxztarQJ7rdNJIYwHY0d5ri1XRpDP8zAuxubPYiMAVYcDkIcvlbBpwh/dRM5I2eElRK+eSiaMkCUCAwEAATANBgkqhkiG9w0BAQsFAAOBgQCLms6htnPaY69k1ntm9a5jgwSn/K61cdai8R8B0ccY7zvinn9AfRD7fiROQpFyY29wKn8WCLrJ86NBXfgFUGyR5nLNHVy3FghE36N2oHy53uichieMxffE6vhkKJ4P8ChfJMMOZlmCPsQPDvjoAghHt4mriFiQgRdPgIy/zDjSNw==" + } + }, + { + "name": "http://localhost:8082/bad-client-sales-post-sig/", + "enabled": true, + "protocol": "saml", + "fullScopeAllowed": true, + "baseUrl": "http://localhost:8082/bad-client-sales-post-sig/", + "adminUrl": "http://localhost:8082/bad-client-sales-post-sig/", + "redirectUris": [ + "http://localhost:8082/bad-client-sales-post-sig/*" + ], + "attributes": { + "saml.server.signature": "true", + "saml.client.signature": "true", + "saml.authnstatement": "true", + "saml.signing.certificate": "MIIB1DCCAT0CBgFJGVacCDANBgkqhkiG9w0BAQsFADAwMS4wLAYDVQQDEyVodHRwOi8vbG9jYWxob3N0OjgwODAvc2FsZXMtcG9zdC1lbmMvMB4XDTE0MTAxNjE0MjA0NloXDTI0MTAxNjE0MjIyNlowMDEuMCwGA1UEAxMlaHR0cDovL2xvY2FsaG9zdDo4MDgwL3NhbGVzLXBvc3QtZW5jLzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA2+5MCT5BnVN+IYnKZcH6ev1pjXGi4feE0nOycq/VJ3aeaZMi4G9AxOxCBPupErOC7Kgm/Bw5AdJyw+Q12wSRXfJ9FhqCrLXpb7YOhbVSTJ8De5O8mW35DxAlh/cxe9FXjqPb286wKTUZ3LfGYR+X235UQeCTAPS/Ufi21EXaEikCAwEAATANBgkqhkiG9w0BAQsFAAOBgQBMrfGD9QFfx5v7ld/OAto5rjkTe3R1Qei8XRXfcs83vLaqEzjEtTuLGrJEi55kXuJgBpVmQpnwCCkkjSy0JxbqLDdVi9arfWUxEGmOr01ZHycELhDNaQcFqVMPr5kRHIHgktT8hK2IgCvd3Fy9/JCgUgCPxKfhwecyEOKxUc857g==" + } + }, + { + "name": "http://localhost:8082/sales-post-enc/", + "enabled": true, + "protocol": "saml", + "fullScopeAllowed": true, + "baseUrl": "http://localhost:8082/sales-post-enc", + "redirectUris": [ + "http://localhost:8082/sales-post-enc/*" + ], + "attributes": { + "saml_assertion_consumer_url_post": "http://localhost:8082/sales-post-enc/", + "saml_assertion_consumer_url_redirect": "http://localhost:8082/sales-post-enc/", + "saml_single_logout_service_url_post": "http://localhost:8082/sales-post-enc/", + "saml_single_logout_service_url_redirect": "http://localhost:8082/sales-post-enc/", + "saml.server.signature": "true", + "saml.signature.algorithm": "RSA_SHA512", + "saml.client.signature": "true", + "saml.encrypt": "true", + "saml.authnstatement": "true", + "saml.signing.certificate": "MIIB1DCCAT0CBgFJGVacCDANBgkqhkiG9w0BAQsFADAwMS4wLAYDVQQDEyVodHRwOi8vbG9jYWxob3N0OjgwODAvc2FsZXMtcG9zdC1lbmMvMB4XDTE0MTAxNjE0MjA0NloXDTI0MTAxNjE0MjIyNlowMDEuMCwGA1UEAxMlaHR0cDovL2xvY2FsaG9zdDo4MDgwL3NhbGVzLXBvc3QtZW5jLzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA2+5MCT5BnVN+IYnKZcH6ev1pjXGi4feE0nOycq/VJ3aeaZMi4G9AxOxCBPupErOC7Kgm/Bw5AdJyw+Q12wSRXfJ9FhqCrLXpb7YOhbVSTJ8De5O8mW35DxAlh/cxe9FXjqPb286wKTUZ3LfGYR+X235UQeCTAPS/Ufi21EXaEikCAwEAATANBgkqhkiG9w0BAQsFAAOBgQBMrfGD9QFfx5v7ld/OAto5rjkTe3R1Qei8XRXfcs83vLaqEzjEtTuLGrJEi55kXuJgBpVmQpnwCCkkjSy0JxbqLDdVi9arfWUxEGmOr01ZHycELhDNaQcFqVMPr5kRHIHgktT8hK2IgCvd3Fy9/JCgUgCPxKfhwecyEOKxUc857g==", + "saml.encryption.certificate": "MIIB1DCCAT0CBgFJGVacCDANBgkqhkiG9w0BAQsFADAwMS4wLAYDVQQDEyVodHRwOi8vbG9jYWxob3N0OjgwODAvc2FsZXMtcG9zdC1lbmMvMB4XDTE0MTAxNjE0MjA0NloXDTI0MTAxNjE0MjIyNlowMDEuMCwGA1UEAxMlaHR0cDovL2xvY2FsaG9zdDo4MDgwL3NhbGVzLXBvc3QtZW5jLzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA2+5MCT5BnVN+IYnKZcH6ev1pjXGi4feE0nOycq/VJ3aeaZMi4G9AxOxCBPupErOC7Kgm/Bw5AdJyw+Q12wSRXfJ9FhqCrLXpb7YOhbVSTJ8De5O8mW35DxAlh/cxe9FXjqPb286wKTUZ3LfGYR+X235UQeCTAPS/Ufi21EXaEikCAwEAATANBgkqhkiG9w0BAQsFAAOBgQBMrfGD9QFfx5v7ld/OAto5rjkTe3R1Qei8XRXfcs83vLaqEzjEtTuLGrJEi55kXuJgBpVmQpnwCCkkjSy0JxbqLDdVi9arfWUxEGmOr01ZHycELhDNaQcFqVMPr5kRHIHgktT8hK2IgCvd3Fy9/JCgUgCPxKfhwecyEOKxUc857g==" + } + }, + { + "name": "http://localhost:8082/employee-sig/", + "enabled": true, + "protocol": "saml", + "fullScopeAllowed": true, + "baseUrl": "http://localhost:8082/employee-sig", + "redirectUris": [ + "http://localhost:8082/employee-sig/*" + ], + "adminUrl": "http://localhost:8082/employee-sig/", + "attributes": { + "saml.server.signature": "true", + "saml.client.signature": "true", + "saml.signature.algorithm": "RSA_SHA256", + "saml.authnstatement": "true", + "saml.signing.certificate": "MIIB0DCCATkCBgFJH5u0EDANBgkqhkiG9w0BAQsFADAuMSwwKgYDVQQDEyNodHRwOi8vbG9jYWxob3N0OjgwODAvZW1wbG95ZWUtc2lnLzAeFw0xNDEwMTcxOTMzNThaFw0yNDEwMTcxOTM1MzhaMC4xLDAqBgNVBAMTI2h0dHA6Ly9sb2NhbGhvc3Q6ODA4MC9lbXBsb3llZS1zaWcvMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC+9kVgPFpshjS2aT2g52lqTv2lqb1jgvXZVk7iFF4LAO6SdCXKXRZI4SuzIRkVNpE1a42V1kQRlaozoFklgvX5sje8tkpa9ylq+bxGXM9RRycqRu2B+oWUV7Aqq7Bs0Xud0WeHQYRcEoCjqsFKGy65qkLRDdT70FTJgpSHts+gDwIDAQABMA0GCSqGSIb3DQEBCwUAA4GBACKyPLGqMX8GsIrCfJU8eVnpaqzTXMglLVo/nTcfAnWe9UAdVe8N3a2PXpDBvuqNA/DEAhVcQgxdlOTWnB6s8/yLTRuH0bZgb3qGdySif+lU+E7zZ/SiDzavAvn+ABqemnzHcHyhYO+hNRGHvUbW5OAii9Vdjhm8BI32YF1NwhKp" + } + }, + { + "name": "http://localhost:8082/employee/", + "enabled": true, + "protocol": "saml", + "fullScopeAllowed": true, + "baseUrl": "http://localhost:8082/employee/", + "redirectUris": [ + "http://localhost:8082/employee/*" + ], + "adminUrl": "http://localhost:8082/employee/", + "attributes": { + "saml.authnstatement": "true" + }, + "protocolMappers": [ + { + "name": "email", + "protocol": "saml", + "protocolMapper": "saml-user-property-mapper", + "consentRequired": false, + "config": { + "user.attribute": "email", + "friendly.name": "email", + "attribute.name": "urn:oid:1.2.840.113549.1.9.1", + "attribute.nameformat": "URI Reference" + } + }, + { + "name": "phone", + "protocol": "saml", + "protocolMapper": "saml-user-attribute-mapper", + "consentRequired": false, + "config": { + "user.attribute": "phone", + "attribute.name": "phone", + "attribute.nameformat": "Basic" + } + }, + { + "name": "role-list", + "protocol": "saml", + "protocolMapper": "saml-role-list-mapper", + "consentRequired": false, + "config": { + "attribute.name": "Role", + "attribute.nameformat": "Basic", + "single": "false" + } + } + ] + }, + { + "name": "http://localhost:8082/employee2/", + "enabled": true, + "protocol": "saml", + "fullScopeAllowed": true, + "baseUrl": "http://localhost:8082/employee2/", + "redirectUris": [ + "http://localhost:8082/employee2/*" + ], + "adminUrl": "http://localhost:8082/employee2/", + "attributes": { + "saml.authnstatement": "true" + }, + "protocolMappers": [ + { + "name": "email", + "protocol": "saml", + "protocolMapper": "saml-user-property-mapper", + "consentRequired": false, + "config": { + "user.attribute": "email", + "friendly.name": "email", + "attribute.name": "urn:oid:1.2.840.113549.1.9.1", + "attribute.nameformat": "URI Reference" + } + }, + { + "name": "phone", + "protocol": "saml", + "protocolMapper": "saml-user-attribute-mapper", + "consentRequired": false, + "config": { + "user.attribute": "phone", + "attribute.name": "phone", + "attribute.nameformat": "Basic" + } + }, + { + "name": "role-list", + "protocol": "saml", + "protocolMapper": "saml-role-list-mapper", + "consentRequired": false, + "config": { + "attribute.name": "Role", + "attribute.nameformat": "Basic", + "single": "false" + } + } + ] + }, + { + "name": "http://localhost:8082/employee-sig-front/", + "enabled": true, + "protocol": "saml", + "fullScopeAllowed": true, + "frontchannelLogout": true, + "baseUrl": "http://localhost:8082/employee-sig-front/", + "redirectUris": [ + "http://localhost:8082/employee-sig-front/*" + ], + "attributes": { + "saml_assertion_consumer_url_post": "http://localhost:8082/employee-sig-front/", + "saml_assertion_consumer_url_redirect": "http://localhost:8082/employee-sig-front/", + "saml_single_logout_service_url_post": "http://localhost:8082/employee-sig-front/", + "saml_single_logout_service_url_redirect": "http://localhost:8082/employee-sig-front/", + "saml.server.signature": "true", + "saml.client.signature": "true", + "saml.signature.algorithm": "RSA_SHA1", + "saml.authnstatement": "true", + "saml.signing.certificate": "MIIB0DCCATkCBgFJH5u0EDANBgkqhkiG9w0BAQsFADAuMSwwKgYDVQQDEyNodHRwOi8vbG9jYWxob3N0OjgwODAvZW1wbG95ZWUtc2lnLzAeFw0xNDEwMTcxOTMzNThaFw0yNDEwMTcxOTM1MzhaMC4xLDAqBgNVBAMTI2h0dHA6Ly9sb2NhbGhvc3Q6ODA4MC9lbXBsb3llZS1zaWcvMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC+9kVgPFpshjS2aT2g52lqTv2lqb1jgvXZVk7iFF4LAO6SdCXKXRZI4SuzIRkVNpE1a42V1kQRlaozoFklgvX5sje8tkpa9ylq+bxGXM9RRycqRu2B+oWUV7Aqq7Bs0Xud0WeHQYRcEoCjqsFKGy65qkLRDdT70FTJgpSHts+gDwIDAQABMA0GCSqGSIb3DQEBCwUAA4GBACKyPLGqMX8GsIrCfJU8eVnpaqzTXMglLVo/nTcfAnWe9UAdVe8N3a2PXpDBvuqNA/DEAhVcQgxdlOTWnB6s8/yLTRuH0bZgb3qGdySif+lU+E7zZ/SiDzavAvn+ABqemnzHcHyhYO+hNRGHvUbW5OAii9Vdjhm8BI32YF1NwhKp" + } + } + ], + "roles" : { + "realm" : [ + { + "name": "manager", + "description": "Have Manager privileges" + }, + { + "name": "user", + "description": "Have User privileges" + } + ], + "application" : { + "http://localhost:8082/employee/" : [ + { + "name": "employee", + "description": "Have Employee privileges" + } + ], + "http://localhost:8082/employee2/" : [ + { + "name": "employee", + "description": "Have Employee privileges" + } + ] + } + } +}