From 092562fb9442ff5328455f1065d32e5a1bc95c00 Mon Sep 17 00:00:00 2001 From: Stan Silvert Date: Fri, 17 Jul 2015 12:23:10 -0400 Subject: [PATCH 1/8] KEYCLOAK-1414 Add CLI script for installing JBoss/WildFly/EAP adapters. --- .../as7-eap6-adapter/as7-adapter-zip/assembly.xml | 6 ++++++ .../as7-eap6-adapter/eap6-adapter-zip/assembly.xml | 6 ++++++ distribution/adapters/shared-cli/adapter-install.cli | 4 ++++ .../wf8-adapter/wf8-adapter-zip/assembly.xml | 6 ++++++ .../wf9-adapter/wf9-adapter-zip/assembly.xml | 6 ++++++ docbook/reference/en/en-US/modules/jboss-adapter.xml | 12 ++++++++++-- 6 files changed, 38 insertions(+), 2 deletions(-) create mode 100644 distribution/adapters/shared-cli/adapter-install.cli diff --git a/distribution/adapters/as7-eap6-adapter/as7-adapter-zip/assembly.xml b/distribution/adapters/as7-eap6-adapter/as7-adapter-zip/assembly.xml index 094e4268d4..59ae243e0c 100755 --- a/distribution/adapters/as7-eap6-adapter/as7-adapter-zip/assembly.xml +++ b/distribution/adapters/as7-eap6-adapter/as7-adapter-zip/assembly.xml @@ -27,4 +27,10 @@ modules + + + ../../shared-cli/adapter-install.cli + bin + + diff --git a/distribution/adapters/as7-eap6-adapter/eap6-adapter-zip/assembly.xml b/distribution/adapters/as7-eap6-adapter/eap6-adapter-zip/assembly.xml index 4e29b1b9c3..0f6c462771 100755 --- a/distribution/adapters/as7-eap6-adapter/eap6-adapter-zip/assembly.xml +++ b/distribution/adapters/as7-eap6-adapter/eap6-adapter-zip/assembly.xml @@ -27,4 +27,10 @@ modules/system/layers/base + + + ../../shared-cli/adapter-install.cli + bin + + diff --git a/distribution/adapters/shared-cli/adapter-install.cli b/distribution/adapters/shared-cli/adapter-install.cli new file mode 100644 index 0000000000..b4a396ba7a --- /dev/null +++ b/distribution/adapters/shared-cli/adapter-install.cli @@ -0,0 +1,4 @@ +/subsystem=security/security-domain=keycloak/:add +/subsystem=security/security-domain=keycloak/authentication=classic/:add(login-modules=[{ "code" => "org.keycloak.adapters.jboss.KeycloakLoginModule","flag" => "required"}]) +/extension=org.keycloak.keycloak-adapter-subsystem/:add(module=org.keycloak.keycloak-adapter-subsystem) +/subsystem=keycloak:add \ No newline at end of file diff --git a/distribution/adapters/wf8-adapter/wf8-adapter-zip/assembly.xml b/distribution/adapters/wf8-adapter/wf8-adapter-zip/assembly.xml index 3f5d8878d9..da4e127bc4 100755 --- a/distribution/adapters/wf8-adapter/wf8-adapter-zip/assembly.xml +++ b/distribution/adapters/wf8-adapter/wf8-adapter-zip/assembly.xml @@ -28,4 +28,10 @@ modules/system/layers/base + + + ../../shared-cli/adapter-install.cli + bin + + diff --git a/distribution/adapters/wf9-adapter/wf9-adapter-zip/assembly.xml b/distribution/adapters/wf9-adapter/wf9-adapter-zip/assembly.xml index e81d4e4e0f..764b76dbba 100755 --- a/distribution/adapters/wf9-adapter/wf9-adapter-zip/assembly.xml +++ b/distribution/adapters/wf9-adapter/wf9-adapter-zip/assembly.xml @@ -27,4 +27,10 @@ modules/system/layers/base + + + ../../shared-cli/adapter-install.cli + bin + + diff --git a/docbook/reference/en/en-US/modules/jboss-adapter.xml b/docbook/reference/en/en-US/modules/jboss-adapter.xml index 08949b4ca5..e3b1c913d1 100755 --- a/docbook/reference/en/en-US/modules/jboss-adapter.xml +++ b/docbook/reference/en/en-US/modules/jboss-adapter.xml @@ -48,6 +48,15 @@ $ unzip keycloak-as7-adapter-dist.zip After adding the Keycloak modules, you must then enable the Keycloak Subsystem within your app server's server configuration: domain.xml or standalone.xml. + + There is a CLI script that will help you modify your server configuration. Start the server and run the script + from the server's bin directory: + +$ cd $JBOSS_HOME/bin +$ jboss-cli.sh -c --file=adapter-install.cli + + The script will add the extension, subsystem, and optional security-domain as described below. + @@ -65,8 +74,7 @@ $ unzip keycloak-as7-adapter-dist.zip - Finally, you must specify a shared keycloak security domain. - This security domain should be used with EJBs and other components when you need the security context created + The keycloak security domain should be used with EJBs and other components when you need the security context created in the secured web tier to be propagated to the EJBs (other EE component) you are invoking. Otherwise this configuration is optional. From ef49bd685e4eec2e1c457862aa505ca5005911ef Mon Sep 17 00:00:00 2001 From: Stan Silvert Date: Thu, 16 Jul 2015 15:36:24 -0400 Subject: [PATCH 2/8] KEYCLOAK-1415 Add CLI scripts to WildFly and EAP overlay bundles. --- .../eap6/eap6-server-overlay/assembly.xml | 8 +++++ .../cli/keycloak-install.cli | 2 ++ .../cli/keycloak-prepare.cli | 8 +++++ .../wf9-server-overlay/assembly.xml | 4 +++ .../cli/keycloak-install.cli | 3 ++ .../en/en-US/modules/server-installation.xml | 29 ++++++++++++------- 6 files changed, 43 insertions(+), 11 deletions(-) create mode 100644 distribution/server-overlay/eap6/eap6-server-overlay/cli/keycloak-install.cli create mode 100644 distribution/server-overlay/eap6/eap6-server-overlay/cli/keycloak-prepare.cli create mode 100644 distribution/server-overlay/wf9-server-overlay/cli/keycloak-install.cli diff --git a/distribution/server-overlay/eap6/eap6-server-overlay/assembly.xml b/distribution/server-overlay/eap6/eap6-server-overlay/assembly.xml index 1ead8b9e8e..1d978dde84 100755 --- a/distribution/server-overlay/eap6/eap6-server-overlay/assembly.xml +++ b/distribution/server-overlay/eap6/eap6-server-overlay/assembly.xml @@ -40,6 +40,14 @@ src/main/providers/README.txt standalone/configuration/providers + + cli/keycloak-prepare.cli + bin + + + cli/keycloak-install.cli + bin + diff --git a/distribution/server-overlay/eap6/eap6-server-overlay/cli/keycloak-install.cli b/distribution/server-overlay/eap6/eap6-server-overlay/cli/keycloak-install.cli new file mode 100644 index 0000000000..cc594313f9 --- /dev/null +++ b/distribution/server-overlay/eap6/eap6-server-overlay/cli/keycloak-install.cli @@ -0,0 +1,2 @@ +/extension=org.keycloak.keycloak-server-subsystem/:add(module=org.keycloak.keycloak-server-subsystem) +/subsystem=keycloak-server:add(web-context=auth) \ No newline at end of file diff --git a/distribution/server-overlay/eap6/eap6-server-overlay/cli/keycloak-prepare.cli b/distribution/server-overlay/eap6/eap6-server-overlay/cli/keycloak-prepare.cli new file mode 100644 index 0000000000..6315805a64 --- /dev/null +++ b/distribution/server-overlay/eap6/eap6-server-overlay/cli/keycloak-prepare.cli @@ -0,0 +1,8 @@ +/subsystem=datasources/data-source=KeycloakDS/:add(connection-url="jdbc:h2:${jboss.server.data.dir}/keycloak;AUTO_SERVER=TRUE",driver-name=h2,jndi-name=java:jboss/datasources/KeycloakDS,password=sa,user-name=sa,use-java-context=true,enabled=true) +/subsystem=logging/logger=org.jboss.resteasy.resteasy_jaxrs.i18n/:add(level=ERROR) +/subsystem=security/security-domain=keycloak/:add +/subsystem=security/security-domain=keycloak/authentication=classic:add +/subsystem=security/security-domain=keycloak/authentication=classic/login-module=keycloak/:add(flag=required,code=org.keycloak.adapters.jboss.KeycloakLoginModule) +/subsystem=security/security-domain=sp/:add(cache-type=default) +/subsystem=security/security-domain=sp/authentication=classic:add +/subsystem=security/security-domain=sp/authentication=classic/login-module=saml/:add(flag=required,code=org.picketlink.identity.federation.bindings.wildfly.SAML2LoginModule) \ No newline at end of file diff --git a/distribution/server-overlay/wf9-server-overlay/assembly.xml b/distribution/server-overlay/wf9-server-overlay/assembly.xml index 4d87e6912e..e7fcb1b112 100755 --- a/distribution/server-overlay/wf9-server-overlay/assembly.xml +++ b/distribution/server-overlay/wf9-server-overlay/assembly.xml @@ -62,6 +62,10 @@ ${project.build.directory}/unpacked/keycloak-${project.version}/standalone/configuration/keycloak-server.json standalone/configuration + + cli/keycloak-install.cli + bin + diff --git a/distribution/server-overlay/wf9-server-overlay/cli/keycloak-install.cli b/distribution/server-overlay/wf9-server-overlay/cli/keycloak-install.cli new file mode 100644 index 0000000000..ac5ca0b81c --- /dev/null +++ b/distribution/server-overlay/wf9-server-overlay/cli/keycloak-install.cli @@ -0,0 +1,3 @@ +/subsystem=datasources/data-source=KeycloakDS/:add(connection-url="jdbc:h2:${jboss.server.data.dir}/keycloak;AUTO_SERVER=TRUE",driver-name=h2,jndi-name=java:jboss/datasources/KeycloakDS,password=sa,user-name=sa,use-java-context=true) +/extension=org.keycloak.keycloak-server-subsystem/:add(module=org.keycloak.keycloak-server-subsystem) +/subsystem=keycloak-server:add(web-context=auth) \ No newline at end of file diff --git a/docbook/reference/en/en-US/modules/server-installation.xml b/docbook/reference/en/en-US/modules/server-installation.xml index 9584852177..6b39bf664f 100755 --- a/docbook/reference/en/en-US/modules/server-installation.xml +++ b/docbook/reference/en/en-US/modules/server-installation.xml @@ -49,9 +49,9 @@ keycloak-overlay-&project.version;.zip or keycloak-overlay-&project.version;.tar.gz. Once downloaded extract into the root directory of your WildFly installation. To start WildFly with Keycloak run: - keycloak-&project.version;/bin/standalone.sh --server-config=standalone-keycloak.xml + <WILDFLY_HOME>/bin/standalone.sh --server-config=standalone-keycloak.xml or: - keycloak-&project.version;/bin/standalone.bat --server-config=standalone-keycloak.xml + <WILDFLY_HOME>/bin/standalone.bat --server-config=standalone-keycloak.xml Once the server is started log into the admin console at @@ -60,15 +60,9 @@ enter in a new password. - To add Keycloak to other sever configurations (standalone.xml, standalone-ha.xml, etc.) open - standalone/configuration/standalone-keycloak.xml and the configuration you want to add it - to, for example standalone/configuration/standalone.xml. From standalone-keycloak.xml - you need to copy 3 elements: - - <extension module="org.keycloak.keycloak-server-subsystem"/> - <datasource jndi-name="java:jboss/datasources/KeycloakDS" ...> - <subsystem xmlns="urn:jboss:domain:keycloak-server:1.1" ...> - + To add Keycloak to other sever configurations (standalone.xml, standalone-ha.xml, etc.) start the server with + the desired server-config. Then execute the following CLI script: + <WILDFLY_HOME>/bin/jboss-cli.sh -c --file=keycloak-install.cli
@@ -76,6 +70,19 @@ Same procedure as WildFly 9.0.0.Final, but download keycloak-overlay-eap6-&project.version;.zip or keycloak-overlay-eap6-&project.version;.tar.gz. + + However, for EAP, adding Keycloak to other sever configurations (standalone.xml, standalone-ha.xml, etc.) requires two CLI scripts. Start the server with + the desired server-config. Then execute the following CLI scripts with a restart in between: + + + <EAP_HOME>/bin/jboss-cli.sh -c --file=keycloak-prepare.cli + + Restart the server with the same server-config. + + <EAP_HOME>/bin/jboss-cli.sh -c --file=keycloak-install.cli + + +
Install Development Bundle From 5bcf334bc548ff69acc31780e3591804606f5b5a Mon Sep 17 00:00:00 2001 From: Stan Silvert Date: Fri, 17 Jul 2015 12:48:32 -0400 Subject: [PATCH 3/8] Don't add security-domain to server. --- .../eap6-server-overlay/cli/keycloak-prepare.cli | 8 +------- .../src/main/xslt/standalone.xsl | 16 ---------------- 2 files changed, 1 insertion(+), 23 deletions(-) diff --git a/distribution/server-overlay/eap6/eap6-server-overlay/cli/keycloak-prepare.cli b/distribution/server-overlay/eap6/eap6-server-overlay/cli/keycloak-prepare.cli index 6315805a64..000cbfa3d8 100644 --- a/distribution/server-overlay/eap6/eap6-server-overlay/cli/keycloak-prepare.cli +++ b/distribution/server-overlay/eap6/eap6-server-overlay/cli/keycloak-prepare.cli @@ -1,8 +1,2 @@ /subsystem=datasources/data-source=KeycloakDS/:add(connection-url="jdbc:h2:${jboss.server.data.dir}/keycloak;AUTO_SERVER=TRUE",driver-name=h2,jndi-name=java:jboss/datasources/KeycloakDS,password=sa,user-name=sa,use-java-context=true,enabled=true) -/subsystem=logging/logger=org.jboss.resteasy.resteasy_jaxrs.i18n/:add(level=ERROR) -/subsystem=security/security-domain=keycloak/:add -/subsystem=security/security-domain=keycloak/authentication=classic:add -/subsystem=security/security-domain=keycloak/authentication=classic/login-module=keycloak/:add(flag=required,code=org.keycloak.adapters.jboss.KeycloakLoginModule) -/subsystem=security/security-domain=sp/:add(cache-type=default) -/subsystem=security/security-domain=sp/authentication=classic:add -/subsystem=security/security-domain=sp/authentication=classic/login-module=saml/:add(flag=required,code=org.picketlink.identity.federation.bindings.wildfly.SAML2LoginModule) \ No newline at end of file +/subsystem=logging/logger=org.jboss.resteasy.resteasy_jaxrs.i18n/:add(level=ERROR) \ No newline at end of file diff --git a/distribution/server-overlay/eap6/eap6-server-overlay/src/main/xslt/standalone.xsl b/distribution/server-overlay/eap6/eap6-server-overlay/src/main/xslt/standalone.xsl index 69ea1c1f00..519b4a71b6 100755 --- a/distribution/server-overlay/eap6/eap6-server-overlay/src/main/xslt/standalone.xsl +++ b/distribution/server-overlay/eap6/eap6-server-overlay/src/main/xslt/standalone.xsl @@ -44,22 +44,6 @@ - - - - - - - - - - - - - - - - From 1839b24b901ec190ca86a806344c236f16986cbe Mon Sep 17 00:00:00 2001 From: Scott Rossillo Date: Mon, 22 Jun 2015 14:54:07 -0400 Subject: [PATCH 4/8] Support for loading keycloak.json from the classpath Spring Boot and non-web based applications don't have a WEB-INF directory. Support loading Spring Security adapter's keycloak.json from the class path. --- .../AdapterDeploymentContextBean.java | 28 +++++++++++++++---- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/integration/spring-security/src/main/java/org/keycloak/adapters/springsecurity/AdapterDeploymentContextBean.java b/integration/spring-security/src/main/java/org/keycloak/adapters/springsecurity/AdapterDeploymentContextBean.java index 29433ef7c5..60d413c4ad 100644 --- a/integration/spring-security/src/main/java/org/keycloak/adapters/springsecurity/AdapterDeploymentContextBean.java +++ b/integration/spring-security/src/main/java/org/keycloak/adapters/springsecurity/AdapterDeploymentContextBean.java @@ -9,30 +9,48 @@ import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.core.io.Resource; -import java.io.InputStream; +import java.io.FileNotFoundException; +import java.io.IOException; /** * Bean holding the {@link KeycloakDeployment} and {@link AdapterDeploymentContext} for this * Spring application context. The Keycloak deployment is loaded from the required - * WEB-INF/keycloak.json file generated by Keycloak. + * keycloak.json resource file. * * @author Scott Rossillo * @version $Revision: 1 $ */ public class AdapterDeploymentContextBean implements ApplicationContextAware, InitializingBean { + private static final String KEYCLOAK_CONFIG_FILE = "keycloak.json"; + private static final String KEYCLOAK_CONFIG_WEB_RESOURCE = "WEB-INF/" + KEYCLOAK_CONFIG_FILE; + private static final String KEYCLOAK_CONFIG_CLASSPATH_RESOURCE = "classpath:" + KEYCLOAK_CONFIG_FILE; + private ApplicationContext applicationContext; private AdapterDeploymentContext deploymentContext; private KeycloakDeployment deployment; @Override public void afterPropertiesSet() throws Exception { - Resource resource = applicationContext.getResource("WEB-INF/keycloak.json"); - InputStream is = resource.getInputStream(); - this.deployment = KeycloakDeploymentBuilder.build(is); + this.deployment = loadKeycloakDeployment(); this.deploymentContext = new AdapterDeploymentContext(deployment); } + private KeycloakDeployment loadKeycloakDeployment() throws IOException { + + Resource resource = applicationContext.getResource(KEYCLOAK_CONFIG_WEB_RESOURCE); + + if (!resource.isReadable()) { + resource= applicationContext.getResource(KEYCLOAK_CONFIG_CLASSPATH_RESOURCE); + } + + if (!resource.isReadable()) { + throw new FileNotFoundException(String.format("Unable to locate Keycloak from %s or %s", KEYCLOAK_CONFIG_WEB_RESOURCE, KEYCLOAK_CONFIG_CLASSPATH_RESOURCE)); + } + + return KeycloakDeploymentBuilder.build(resource.getInputStream()); + } + /** * Returns the Keycloak {@link AdapterDeploymentContext} for this application context. * From 66a2b916f241be3c74eace43d20d9224472f05ec Mon Sep 17 00:00:00 2001 From: Stian Thorgersen Date: Mon, 20 Jul 2015 07:48:02 +0200 Subject: [PATCH 5/8] Fix CRLF with LF --- .../RequiredActionProviderRepresentation.java | 146 ++--- .../org/keycloak/utils/CredentialHelper.java | 116 ++-- .../actions/RequiredActionTotpSetupTest.java | 446 ++++++------- .../composites/CompositeRoleTest.java | 592 +++++++++--------- 4 files changed, 650 insertions(+), 650 deletions(-) diff --git a/core/src/main/java/org/keycloak/representations/idm/RequiredActionProviderRepresentation.java b/core/src/main/java/org/keycloak/representations/idm/RequiredActionProviderRepresentation.java index e145818cc2..d94fe5b735 100755 --- a/core/src/main/java/org/keycloak/representations/idm/RequiredActionProviderRepresentation.java +++ b/core/src/main/java/org/keycloak/representations/idm/RequiredActionProviderRepresentation.java @@ -1,73 +1,73 @@ -package org.keycloak.representations.idm; - -import java.util.HashMap; -import java.util.Map; - -/** -* @author Bill Burke -* @version $Revision: 1 $ -*/ -public class RequiredActionProviderRepresentation { - - private String alias; - private String name; - private String providerId; - private boolean enabled; - private boolean defaultAction; - private Map config = new HashMap(); - - - public String getAlias() { - return alias; - } - - public void setAlias(String alias) { - this.alias = alias; - } - - /** - * Used for display purposes. Probably should clean this code up and make alias and name the same, but - * the old code references an Enum and the admin console creates a "friendly" name for each enum. - * - * @return - */ - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public boolean isEnabled() { - return enabled; - } - - public void setEnabled(boolean enabled) { - this.enabled = enabled; - } - - public boolean isDefaultAction() { - return defaultAction; - } - - public void setDefaultAction(boolean defaultAction) { - this.defaultAction = defaultAction; - } - - public String getProviderId() { - return providerId; - } - - public void setProviderId(String providerId) { - this.providerId = providerId; - } - - public Map getConfig() { - return config; - } - - public void setConfig(Map config) { - this.config = config; - } -} +package org.keycloak.representations.idm; + +import java.util.HashMap; +import java.util.Map; + +/** +* @author Bill Burke +* @version $Revision: 1 $ +*/ +public class RequiredActionProviderRepresentation { + + private String alias; + private String name; + private String providerId; + private boolean enabled; + private boolean defaultAction; + private Map config = new HashMap(); + + + public String getAlias() { + return alias; + } + + public void setAlias(String alias) { + this.alias = alias; + } + + /** + * Used for display purposes. Probably should clean this code up and make alias and name the same, but + * the old code references an Enum and the admin console creates a "friendly" name for each enum. + * + * @return + */ + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public boolean isEnabled() { + return enabled; + } + + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } + + public boolean isDefaultAction() { + return defaultAction; + } + + public void setDefaultAction(boolean defaultAction) { + this.defaultAction = defaultAction; + } + + public String getProviderId() { + return providerId; + } + + public void setProviderId(String providerId) { + this.providerId = providerId; + } + + public Map getConfig() { + return config; + } + + public void setConfig(Map config) { + this.config = config; + } +} diff --git a/services/src/main/java/org/keycloak/utils/CredentialHelper.java b/services/src/main/java/org/keycloak/utils/CredentialHelper.java index c40656b46e..9b3af31618 100755 --- a/services/src/main/java/org/keycloak/utils/CredentialHelper.java +++ b/services/src/main/java/org/keycloak/utils/CredentialHelper.java @@ -1,58 +1,58 @@ -package org.keycloak.utils; - -import org.keycloak.authentication.Authenticator; -import org.keycloak.authentication.AuthenticatorFactory; -import org.keycloak.authentication.ConfigurableAuthenticatorFactory; -import org.keycloak.authentication.FormAction; -import org.keycloak.authentication.FormActionFactory; -import org.keycloak.authentication.authenticators.OTPFormAuthenticatorFactory; -import org.keycloak.authentication.authenticators.SpnegoAuthenticatorFactory; -import org.keycloak.authentication.authenticators.UsernamePasswordFormFactory; -import org.keycloak.models.AuthenticationExecutionModel; -import org.keycloak.models.AuthenticationFlowModel; -import org.keycloak.models.KeycloakSession; -import org.keycloak.models.RealmModel; -import org.keycloak.models.UserCredentialModel; -import org.keycloak.models.utils.DefaultAuthenticationFlows; -import org.keycloak.representations.idm.CredentialRepresentation; - -/** - * used to set an execution a state based on type. - * - * @author Bill Burke - * @version $Revision: 1 $ - */ -public class CredentialHelper { - - public static void setRequiredCredential(KeycloakSession session, String type, RealmModel realm) { - AuthenticationExecutionModel.Requirement requirement = AuthenticationExecutionModel.Requirement.REQUIRED; - authenticationRequirement(session, realm, type, requirement); - } - - public static void setAlternativeCredential(KeycloakSession session, String type, RealmModel realm) { - AuthenticationExecutionModel.Requirement requirement = AuthenticationExecutionModel.Requirement.ALTERNATIVE; - authenticationRequirement(session, realm, type, requirement); - } - - public static void authenticationRequirement(KeycloakSession session, RealmModel realm, String type, AuthenticationExecutionModel.Requirement requirement) { - for (AuthenticationFlowModel flow : realm.getAuthenticationFlows()) { - for (AuthenticationExecutionModel execution : realm.getAuthenticationExecutions(flow.getId())) { - String providerId = execution.getAuthenticator(); - ConfigurableAuthenticatorFactory factory = getConfigurableAuthenticatorFactory(session, providerId); - if (factory == null) continue; - if (type.equals(factory.getReferenceCategory())) { - execution.setRequirement(requirement); - realm.updateAuthenticatorExecution(execution); - } - } - } - } - - public static ConfigurableAuthenticatorFactory getConfigurableAuthenticatorFactory(KeycloakSession session, String providerId) { - ConfigurableAuthenticatorFactory factory = (AuthenticatorFactory)session.getKeycloakSessionFactory().getProviderFactory(Authenticator.class, providerId); - if (factory == null) { - factory = (FormActionFactory)session.getKeycloakSessionFactory().getProviderFactory(FormAction.class, providerId); - } - return factory; - } -} +package org.keycloak.utils; + +import org.keycloak.authentication.Authenticator; +import org.keycloak.authentication.AuthenticatorFactory; +import org.keycloak.authentication.ConfigurableAuthenticatorFactory; +import org.keycloak.authentication.FormAction; +import org.keycloak.authentication.FormActionFactory; +import org.keycloak.authentication.authenticators.OTPFormAuthenticatorFactory; +import org.keycloak.authentication.authenticators.SpnegoAuthenticatorFactory; +import org.keycloak.authentication.authenticators.UsernamePasswordFormFactory; +import org.keycloak.models.AuthenticationExecutionModel; +import org.keycloak.models.AuthenticationFlowModel; +import org.keycloak.models.KeycloakSession; +import org.keycloak.models.RealmModel; +import org.keycloak.models.UserCredentialModel; +import org.keycloak.models.utils.DefaultAuthenticationFlows; +import org.keycloak.representations.idm.CredentialRepresentation; + +/** + * used to set an execution a state based on type. + * + * @author Bill Burke + * @version $Revision: 1 $ + */ +public class CredentialHelper { + + public static void setRequiredCredential(KeycloakSession session, String type, RealmModel realm) { + AuthenticationExecutionModel.Requirement requirement = AuthenticationExecutionModel.Requirement.REQUIRED; + authenticationRequirement(session, realm, type, requirement); + } + + public static void setAlternativeCredential(KeycloakSession session, String type, RealmModel realm) { + AuthenticationExecutionModel.Requirement requirement = AuthenticationExecutionModel.Requirement.ALTERNATIVE; + authenticationRequirement(session, realm, type, requirement); + } + + public static void authenticationRequirement(KeycloakSession session, RealmModel realm, String type, AuthenticationExecutionModel.Requirement requirement) { + for (AuthenticationFlowModel flow : realm.getAuthenticationFlows()) { + for (AuthenticationExecutionModel execution : realm.getAuthenticationExecutions(flow.getId())) { + String providerId = execution.getAuthenticator(); + ConfigurableAuthenticatorFactory factory = getConfigurableAuthenticatorFactory(session, providerId); + if (factory == null) continue; + if (type.equals(factory.getReferenceCategory())) { + execution.setRequirement(requirement); + realm.updateAuthenticatorExecution(execution); + } + } + } + } + + public static ConfigurableAuthenticatorFactory getConfigurableAuthenticatorFactory(KeycloakSession session, String providerId) { + ConfigurableAuthenticatorFactory factory = (AuthenticatorFactory)session.getKeycloakSessionFactory().getProviderFactory(Authenticator.class, providerId); + if (factory == null) { + factory = (FormActionFactory)session.getKeycloakSessionFactory().getProviderFactory(FormAction.class, providerId); + } + return factory; + } +} diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/actions/RequiredActionTotpSetupTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/actions/RequiredActionTotpSetupTest.java index 56adc8961b..c448a927ea 100755 --- a/testsuite/integration/src/test/java/org/keycloak/testsuite/actions/RequiredActionTotpSetupTest.java +++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/actions/RequiredActionTotpSetupTest.java @@ -1,223 +1,223 @@ -/* - * 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.actions; - -import org.junit.Assert; -import org.junit.ClassRule; -import org.junit.Rule; -import org.junit.Test; -import org.keycloak.authentication.requiredactions.UpdateTotp; -import org.keycloak.events.Details; -import org.keycloak.events.Event; -import org.keycloak.events.EventType; -import org.keycloak.models.RealmModel; -import org.keycloak.models.RequiredActionProviderModel; -import org.keycloak.models.UserModel; -import org.keycloak.models.utils.TimeBasedOTP; -import org.keycloak.representations.idm.CredentialRepresentation; -import org.keycloak.services.managers.RealmManager; -import org.keycloak.testsuite.AssertEvents; -import org.keycloak.testsuite.OAuthClient; -import org.keycloak.testsuite.pages.AccountTotpPage; -import org.keycloak.testsuite.pages.AppPage; -import org.keycloak.testsuite.pages.AppPage.RequestType; -import org.keycloak.testsuite.pages.LoginConfigTotpPage; -import org.keycloak.testsuite.pages.LoginPage; -import org.keycloak.testsuite.pages.LoginTotpPage; -import org.keycloak.testsuite.pages.RegisterPage; -import org.keycloak.testsuite.rule.KeycloakRule; -import org.keycloak.testsuite.rule.KeycloakRule.KeycloakSetup; -import org.keycloak.testsuite.rule.WebResource; -import org.keycloak.testsuite.rule.WebRule; -import org.keycloak.utils.CredentialHelper; -import org.openqa.selenium.WebDriver; - -/** - * @author Stian Thorgersen - */ -public class RequiredActionTotpSetupTest { - - @ClassRule - public static KeycloakRule keycloakRule = new KeycloakRule(new KeycloakSetup() { - - @Override - public void config(RealmManager manager, RealmModel defaultRealm, RealmModel appRealm) { - CredentialHelper.setRequiredCredential(manager.getSession(), CredentialRepresentation.TOTP, appRealm); - //appRealm.addRequiredCredential(CredentialRepresentation.TOTP); - RequiredActionProviderModel requiredAction = appRealm.getRequiredActionProviderByAlias(UserModel.RequiredAction.CONFIGURE_TOTP.name()); - requiredAction.setDefaultAction(true); - appRealm.updateRequiredActionProvider(requiredAction); - appRealm.setResetPasswordAllowed(true); - } - - }); - - @Rule - public AssertEvents events = new AssertEvents(keycloakRule); - - @Rule - public WebRule webRule = new WebRule(this); - - @WebResource - protected WebDriver driver; - - @WebResource - protected AppPage appPage; - - @WebResource - protected LoginPage loginPage; - - @WebResource - protected LoginTotpPage loginTotpPage; - - @WebResource - protected LoginConfigTotpPage totpPage; - - @WebResource - protected AccountTotpPage accountTotpPage; - - @WebResource - protected OAuthClient oauth; - - @WebResource - protected RegisterPage registerPage; - - protected TimeBasedOTP totp = new TimeBasedOTP(); - - @Test - public void setupTotpRegister() { - loginPage.open(); - loginPage.clickRegister(); - registerPage.register("firstName", "lastName", "email@mail.com", "setupTotp", "password", "password"); - - String userId = events.expectRegister("setupTotp", "email@mail.com").assertEvent().getUserId(); - - totpPage.assertCurrent(); - - totpPage.configure(totp.generate(totpPage.getTotpSecret())); - - String sessionId = events.expectRequiredAction(EventType.UPDATE_TOTP).user(userId).detail(Details.USERNAME, "setuptotp").assertEvent().getSessionId(); - - Assert.assertEquals(RequestType.AUTH_RESPONSE, appPage.getRequestType()); - - events.expectLogin().user(userId).session(sessionId).detail(Details.USERNAME, "setuptotp").assertEvent(); - } - - @Test - public void setupTotpExisting() { - loginPage.open(); - loginPage.login("test-user@localhost", "password"); - - totpPage.assertCurrent(); - - String totpSecret = totpPage.getTotpSecret(); - - totpPage.configure(totp.generate(totpSecret)); - - String sessionId = events.expectRequiredAction(EventType.UPDATE_TOTP).assertEvent().getSessionId(); - - Assert.assertEquals(RequestType.AUTH_RESPONSE, appPage.getRequestType()); - - Event loginEvent = events.expectLogin().session(sessionId).assertEvent(); - - oauth.openLogout(); - - events.expectLogout(loginEvent.getSessionId()).assertEvent(); - - loginPage.open(); - loginPage.login("test-user@localhost", "password"); - String src = driver.getPageSource(); - loginTotpPage.login(totp.generate(totpSecret)); - - Assert.assertEquals(RequestType.AUTH_RESPONSE, appPage.getRequestType()); - - events.expectLogin().assertEvent(); - } - - @Test - public void setupTotpRegisteredAfterTotpRemoval() { - // Register new user - loginPage.open(); - loginPage.clickRegister(); - registerPage.register("firstName2", "lastName2", "email2@mail.com", "setupTotp2", "password2", "password2"); - - String userId = events.expectRegister("setupTotp2", "email2@mail.com").assertEvent().getUserId(); - - // Configure totp - totpPage.assertCurrent(); - - String totpCode = totpPage.getTotpSecret(); - totpPage.configure(totp.generate(totpCode)); - - // After totp config, user should be on the app page - Assert.assertEquals(RequestType.AUTH_RESPONSE, appPage.getRequestType()); - - events.expectRequiredAction(EventType.UPDATE_TOTP).user(userId).detail(Details.USERNAME, "setuptotp2").assertEvent(); - - Event loginEvent = events.expectLogin().user(userId).detail(Details.USERNAME, "setuptotp2").assertEvent(); - - // Logout - oauth.openLogout(); - events.expectLogout(loginEvent.getSessionId()).user(userId).assertEvent(); - - // Try to login after logout - loginPage.open(); - loginPage.login("setupTotp2", "password2"); - - // Totp is already configured, thus one-time password is needed, login page should be loaded - Assert.assertTrue(loginPage.isCurrent()); - Assert.assertFalse(totpPage.isCurrent()); - - // Login with one-time password - loginTotpPage.login(totp.generate(totpCode)); - - loginEvent = events.expectLogin().user(userId).detail(Details.USERNAME, "setuptotp2").assertEvent(); - - // Open account page - accountTotpPage.open(); - accountTotpPage.assertCurrent(); - - // Remove google authentificator - accountTotpPage.removeTotp(); - - events.expectAccount(EventType.REMOVE_TOTP).user(userId).assertEvent(); - - // Logout - oauth.openLogout(); - events.expectLogout(loginEvent.getSessionId()).user(userId).assertEvent(); - - // Try to login - loginPage.open(); - loginPage.login("setupTotp2", "password2"); - - // Since the authentificator was removed, it has to be set up again - totpPage.assertCurrent(); - totpPage.configure(totp.generate(totpPage.getTotpSecret())); - - String sessionId = events.expectRequiredAction(EventType.UPDATE_TOTP).user(userId).detail(Details.USERNAME, "setuptotp2").assertEvent().getSessionId(); - - Assert.assertEquals(RequestType.AUTH_RESPONSE, appPage.getRequestType()); - - events.expectLogin().user(userId).session(sessionId).detail(Details.USERNAME, "setuptotp2").assertEvent(); - } - -} +/* + * 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.actions; + +import org.junit.Assert; +import org.junit.ClassRule; +import org.junit.Rule; +import org.junit.Test; +import org.keycloak.authentication.requiredactions.UpdateTotp; +import org.keycloak.events.Details; +import org.keycloak.events.Event; +import org.keycloak.events.EventType; +import org.keycloak.models.RealmModel; +import org.keycloak.models.RequiredActionProviderModel; +import org.keycloak.models.UserModel; +import org.keycloak.models.utils.TimeBasedOTP; +import org.keycloak.representations.idm.CredentialRepresentation; +import org.keycloak.services.managers.RealmManager; +import org.keycloak.testsuite.AssertEvents; +import org.keycloak.testsuite.OAuthClient; +import org.keycloak.testsuite.pages.AccountTotpPage; +import org.keycloak.testsuite.pages.AppPage; +import org.keycloak.testsuite.pages.AppPage.RequestType; +import org.keycloak.testsuite.pages.LoginConfigTotpPage; +import org.keycloak.testsuite.pages.LoginPage; +import org.keycloak.testsuite.pages.LoginTotpPage; +import org.keycloak.testsuite.pages.RegisterPage; +import org.keycloak.testsuite.rule.KeycloakRule; +import org.keycloak.testsuite.rule.KeycloakRule.KeycloakSetup; +import org.keycloak.testsuite.rule.WebResource; +import org.keycloak.testsuite.rule.WebRule; +import org.keycloak.utils.CredentialHelper; +import org.openqa.selenium.WebDriver; + +/** + * @author Stian Thorgersen + */ +public class RequiredActionTotpSetupTest { + + @ClassRule + public static KeycloakRule keycloakRule = new KeycloakRule(new KeycloakSetup() { + + @Override + public void config(RealmManager manager, RealmModel defaultRealm, RealmModel appRealm) { + CredentialHelper.setRequiredCredential(manager.getSession(), CredentialRepresentation.TOTP, appRealm); + //appRealm.addRequiredCredential(CredentialRepresentation.TOTP); + RequiredActionProviderModel requiredAction = appRealm.getRequiredActionProviderByAlias(UserModel.RequiredAction.CONFIGURE_TOTP.name()); + requiredAction.setDefaultAction(true); + appRealm.updateRequiredActionProvider(requiredAction); + appRealm.setResetPasswordAllowed(true); + } + + }); + + @Rule + public AssertEvents events = new AssertEvents(keycloakRule); + + @Rule + public WebRule webRule = new WebRule(this); + + @WebResource + protected WebDriver driver; + + @WebResource + protected AppPage appPage; + + @WebResource + protected LoginPage loginPage; + + @WebResource + protected LoginTotpPage loginTotpPage; + + @WebResource + protected LoginConfigTotpPage totpPage; + + @WebResource + protected AccountTotpPage accountTotpPage; + + @WebResource + protected OAuthClient oauth; + + @WebResource + protected RegisterPage registerPage; + + protected TimeBasedOTP totp = new TimeBasedOTP(); + + @Test + public void setupTotpRegister() { + loginPage.open(); + loginPage.clickRegister(); + registerPage.register("firstName", "lastName", "email@mail.com", "setupTotp", "password", "password"); + + String userId = events.expectRegister("setupTotp", "email@mail.com").assertEvent().getUserId(); + + totpPage.assertCurrent(); + + totpPage.configure(totp.generate(totpPage.getTotpSecret())); + + String sessionId = events.expectRequiredAction(EventType.UPDATE_TOTP).user(userId).detail(Details.USERNAME, "setuptotp").assertEvent().getSessionId(); + + Assert.assertEquals(RequestType.AUTH_RESPONSE, appPage.getRequestType()); + + events.expectLogin().user(userId).session(sessionId).detail(Details.USERNAME, "setuptotp").assertEvent(); + } + + @Test + public void setupTotpExisting() { + loginPage.open(); + loginPage.login("test-user@localhost", "password"); + + totpPage.assertCurrent(); + + String totpSecret = totpPage.getTotpSecret(); + + totpPage.configure(totp.generate(totpSecret)); + + String sessionId = events.expectRequiredAction(EventType.UPDATE_TOTP).assertEvent().getSessionId(); + + Assert.assertEquals(RequestType.AUTH_RESPONSE, appPage.getRequestType()); + + Event loginEvent = events.expectLogin().session(sessionId).assertEvent(); + + oauth.openLogout(); + + events.expectLogout(loginEvent.getSessionId()).assertEvent(); + + loginPage.open(); + loginPage.login("test-user@localhost", "password"); + String src = driver.getPageSource(); + loginTotpPage.login(totp.generate(totpSecret)); + + Assert.assertEquals(RequestType.AUTH_RESPONSE, appPage.getRequestType()); + + events.expectLogin().assertEvent(); + } + + @Test + public void setupTotpRegisteredAfterTotpRemoval() { + // Register new user + loginPage.open(); + loginPage.clickRegister(); + registerPage.register("firstName2", "lastName2", "email2@mail.com", "setupTotp2", "password2", "password2"); + + String userId = events.expectRegister("setupTotp2", "email2@mail.com").assertEvent().getUserId(); + + // Configure totp + totpPage.assertCurrent(); + + String totpCode = totpPage.getTotpSecret(); + totpPage.configure(totp.generate(totpCode)); + + // After totp config, user should be on the app page + Assert.assertEquals(RequestType.AUTH_RESPONSE, appPage.getRequestType()); + + events.expectRequiredAction(EventType.UPDATE_TOTP).user(userId).detail(Details.USERNAME, "setuptotp2").assertEvent(); + + Event loginEvent = events.expectLogin().user(userId).detail(Details.USERNAME, "setuptotp2").assertEvent(); + + // Logout + oauth.openLogout(); + events.expectLogout(loginEvent.getSessionId()).user(userId).assertEvent(); + + // Try to login after logout + loginPage.open(); + loginPage.login("setupTotp2", "password2"); + + // Totp is already configured, thus one-time password is needed, login page should be loaded + Assert.assertTrue(loginPage.isCurrent()); + Assert.assertFalse(totpPage.isCurrent()); + + // Login with one-time password + loginTotpPage.login(totp.generate(totpCode)); + + loginEvent = events.expectLogin().user(userId).detail(Details.USERNAME, "setuptotp2").assertEvent(); + + // Open account page + accountTotpPage.open(); + accountTotpPage.assertCurrent(); + + // Remove google authentificator + accountTotpPage.removeTotp(); + + events.expectAccount(EventType.REMOVE_TOTP).user(userId).assertEvent(); + + // Logout + oauth.openLogout(); + events.expectLogout(loginEvent.getSessionId()).user(userId).assertEvent(); + + // Try to login + loginPage.open(); + loginPage.login("setupTotp2", "password2"); + + // Since the authentificator was removed, it has to be set up again + totpPage.assertCurrent(); + totpPage.configure(totp.generate(totpPage.getTotpSecret())); + + String sessionId = events.expectRequiredAction(EventType.UPDATE_TOTP).user(userId).detail(Details.USERNAME, "setuptotp2").assertEvent().getSessionId(); + + Assert.assertEquals(RequestType.AUTH_RESPONSE, appPage.getRequestType()); + + events.expectLogin().user(userId).session(sessionId).detail(Details.USERNAME, "setuptotp2").assertEvent(); + } + +} diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/composites/CompositeRoleTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/composites/CompositeRoleTest.java index bf47e0c5ed..7178f1de10 100755 --- a/testsuite/integration/src/test/java/org/keycloak/testsuite/composites/CompositeRoleTest.java +++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/composites/CompositeRoleTest.java @@ -1,296 +1,296 @@ -/* - * 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.composites; - -import org.junit.Assert; -import org.junit.ClassRule; -import org.junit.Rule; -import org.junit.Test; -import org.keycloak.OAuth2Constants; -import org.keycloak.enums.SslRequired; -import org.keycloak.models.ClientModel; -import org.keycloak.models.KeycloakSession; -import org.keycloak.models.RealmModel; -import org.keycloak.models.RoleModel; -import org.keycloak.models.UserCredentialModel; -import org.keycloak.models.UserModel; -import org.keycloak.models.utils.KeycloakModelUtils; -import org.keycloak.representations.AccessToken; -import org.keycloak.services.managers.ClientManager; -import org.keycloak.services.managers.RealmManager; -import org.keycloak.testsuite.ApplicationServlet; -import org.keycloak.testsuite.OAuthClient; -import org.keycloak.testsuite.OAuthClient.AccessTokenResponse; -import org.keycloak.testsuite.pages.LoginPage; -import org.keycloak.testsuite.rule.AbstractKeycloakRule; -import org.keycloak.testsuite.rule.WebResource; -import org.keycloak.testsuite.rule.WebRule; -import org.openqa.selenium.WebDriver; - -import java.security.PublicKey; - -/** - * @author Stian Thorgersen - */ -public class CompositeRoleTest { - - public static PublicKey realmPublicKey; - @ClassRule - public static AbstractKeycloakRule keycloakRule = new AbstractKeycloakRule(){ - @Override - protected void configure(KeycloakSession session, RealmManager manager, RealmModel adminRealm) { - RealmModel realm = manager.createRealm("test"); - KeycloakModelUtils.generateRealmKeys(realm); - realmPublicKey = realm.getPublicKey(); - realm.setSsoSessionIdleTimeout(3000); - realm.setAccessTokenLifespan(10000); - realm.setSsoSessionMaxLifespan(10000); - realm.setAccessCodeLifespanUserAction(1000); - realm.setAccessCodeLifespan(1000); - realm.setSslRequired(SslRequired.EXTERNAL); - realm.setEnabled(true); - realm.addRequiredCredential(UserCredentialModel.PASSWORD); - final RoleModel realmRole1 = realm.addRole("REALM_ROLE_1"); - final RoleModel realmRole2 = realm.addRole("REALM_ROLE_2"); - final RoleModel realmRole3 = realm.addRole("REALM_ROLE_3"); - final RoleModel realmComposite1 = realm.addRole("REALM_COMPOSITE_1"); - realmComposite1.addCompositeRole(realmRole1); - - final UserModel realmComposite1User = session.users().addUser(realm, "REALM_COMPOSITE_1_USER"); - realmComposite1User.setEnabled(true); - realmComposite1User.updateCredential(UserCredentialModel.password("password")); - realmComposite1User.grantRole(realmComposite1); - - final UserModel realmRole1User = session.users().addUser(realm, "REALM_ROLE_1_USER"); - realmRole1User.setEnabled(true); - realmRole1User.updateCredential(UserCredentialModel.password("password")); - realmRole1User.grantRole(realmRole1); - - final ClientModel realmComposite1Application = new ClientManager(manager).createClient(realm, "REALM_COMPOSITE_1_APPLICATION"); - realmComposite1Application.setFullScopeAllowed(false); - realmComposite1Application.setEnabled(true); - realmComposite1Application.addScopeMapping(realmComposite1); - realmComposite1Application.addRedirectUri("http://localhost:8081/app/*"); - realmComposite1Application.setBaseUrl("http://localhost:8081/app"); - realmComposite1Application.setManagementUrl("http://localhost:8081/app/logout"); - realmComposite1Application.setSecret("password"); - - final ClientModel realmRole1Application = new ClientManager(manager).createClient(realm, "REALM_ROLE_1_APPLICATION"); - realmRole1Application.setFullScopeAllowed(false); - realmRole1Application.setEnabled(true); - realmRole1Application.addScopeMapping(realmRole1); - realmRole1Application.addRedirectUri("http://localhost:8081/app/*"); - realmRole1Application.setBaseUrl("http://localhost:8081/app"); - realmRole1Application.setManagementUrl("http://localhost:8081/app/logout"); - realmRole1Application.setSecret("password"); - - - final ClientModel appRoleApplication = new ClientManager(manager).createClient(realm, "APP_ROLE_APPLICATION"); - appRoleApplication.setFullScopeAllowed(false); - appRoleApplication.setEnabled(true); - appRoleApplication.addRedirectUri("http://localhost:8081/app/*"); - appRoleApplication.setBaseUrl("http://localhost:8081/app"); - appRoleApplication.setManagementUrl("http://localhost:8081/app/logout"); - appRoleApplication.setSecret("password"); - final RoleModel appRole1 = appRoleApplication.addRole("APP_ROLE_1"); - final RoleModel appRole2 = appRoleApplication.addRole("APP_ROLE_2"); - - final RoleModel realmAppCompositeRole = realm.addRole("REALM_APP_COMPOSITE_ROLE"); - realmAppCompositeRole.addCompositeRole(appRole1); - - final UserModel realmAppCompositeUser = session.users().addUser(realm, "REALM_APP_COMPOSITE_USER"); - realmAppCompositeUser.setEnabled(true); - realmAppCompositeUser.updateCredential(UserCredentialModel.password("password")); - realmAppCompositeUser.grantRole(realmAppCompositeRole); - - final UserModel realmAppRoleUser = session.users().addUser(realm, "REALM_APP_ROLE_USER"); - realmAppRoleUser.setEnabled(true); - realmAppRoleUser.updateCredential(UserCredentialModel.password("password")); - realmAppRoleUser.grantRole(appRole2); - - final ClientModel appCompositeApplication = new ClientManager(manager).createClient(realm, "APP_COMPOSITE_APPLICATION"); - appCompositeApplication.setFullScopeAllowed(false); - appCompositeApplication.setEnabled(true); - appCompositeApplication.addRedirectUri("http://localhost:8081/app/*"); - appCompositeApplication.setBaseUrl("http://localhost:8081/app"); - appCompositeApplication.setManagementUrl("http://localhost:8081/app/logout"); - appCompositeApplication.setSecret("password"); - final RoleModel appCompositeRole = appCompositeApplication.addRole("APP_COMPOSITE_ROLE"); - appCompositeApplication.addScopeMapping(appRole2); - appCompositeRole.addCompositeRole(realmRole1); - appCompositeRole.addCompositeRole(realmRole2); - appCompositeRole.addCompositeRole(realmRole3); - appCompositeRole.addCompositeRole(appRole1); - - final UserModel appCompositeUser = session.users().addUser(realm, "APP_COMPOSITE_USER"); - appCompositeUser.setEnabled(true); - appCompositeUser.updateCredential(UserCredentialModel.password("password")); - appCompositeUser.grantRole(realmAppCompositeRole); - appCompositeUser.grantRole(realmComposite1); - - deployServlet("app", "/app", ApplicationServlet.class); - - } - }; - - @Rule - public WebRule webRule = new WebRule(this); - - @WebResource - protected WebDriver driver; - - @WebResource - protected OAuthClient oauth; - - @WebResource - protected LoginPage loginPage; - - @Test - public void testAppCompositeUser() throws Exception { - oauth.realm("test"); - oauth.realmPublicKey(realmPublicKey); - oauth.clientId("APP_COMPOSITE_APPLICATION"); - oauth.doLogin("APP_COMPOSITE_USER", "password"); - - String code = oauth.getCurrentQuery().get(OAuth2Constants.CODE); - AccessTokenResponse response = oauth.doAccessTokenRequest(code, "password"); - - Assert.assertEquals(200, response.getStatusCode()); - - Assert.assertEquals("bearer", response.getTokenType()); - - AccessToken token = oauth.verifyToken(response.getAccessToken()); - - Assert.assertEquals(keycloakRule.getUser("test", "APP_COMPOSITE_USER").getId(), token.getSubject()); - - Assert.assertEquals(1, token.getResourceAccess("APP_ROLE_APPLICATION").getRoles().size()); - Assert.assertEquals(1, token.getRealmAccess().getRoles().size()); - Assert.assertTrue(token.getResourceAccess("APP_ROLE_APPLICATION").isUserInRole("APP_ROLE_1")); - Assert.assertTrue(token.getRealmAccess().isUserInRole("REALM_ROLE_1")); - - AccessTokenResponse refreshResponse = oauth.doRefreshTokenRequest(response.getRefreshToken(), "password"); - Assert.assertEquals(200, refreshResponse.getStatusCode()); - } - - - @Test - public void testRealmAppCompositeUser() throws Exception { - oauth.realm("test"); - oauth.realmPublicKey(realmPublicKey); - oauth.clientId("APP_ROLE_APPLICATION"); - oauth.doLogin("REALM_APP_COMPOSITE_USER", "password"); - - String code = oauth.getCurrentQuery().get(OAuth2Constants.CODE); - AccessTokenResponse response = oauth.doAccessTokenRequest(code, "password"); - - Assert.assertEquals(200, response.getStatusCode()); - - Assert.assertEquals("bearer", response.getTokenType()); - - AccessToken token = oauth.verifyToken(response.getAccessToken()); - - Assert.assertEquals(keycloakRule.getUser("test", "REALM_APP_COMPOSITE_USER").getId(), token.getSubject()); - - Assert.assertEquals(1, token.getResourceAccess("APP_ROLE_APPLICATION").getRoles().size()); - Assert.assertTrue(token.getResourceAccess("APP_ROLE_APPLICATION").isUserInRole("APP_ROLE_1")); - - AccessTokenResponse refreshResponse = oauth.doRefreshTokenRequest(response.getRefreshToken(), "password"); - Assert.assertEquals(200, refreshResponse.getStatusCode()); - } - - @Test - public void testRealmOnlyWithUserCompositeAppComposite() throws Exception { - oauth.realm("test"); - oauth.realmPublicKey(realmPublicKey); - oauth.clientId("REALM_COMPOSITE_1_APPLICATION"); - oauth.doLogin("REALM_COMPOSITE_1_USER", "password"); - - String code = oauth.getCurrentQuery().get(OAuth2Constants.CODE); - AccessTokenResponse response = oauth.doAccessTokenRequest(code, "password"); - - Assert.assertEquals(200, response.getStatusCode()); - - Assert.assertEquals("bearer", response.getTokenType()); - - AccessToken token = oauth.verifyToken(response.getAccessToken()); - - Assert.assertEquals(keycloakRule.getUser("test", "REALM_COMPOSITE_1_USER").getId(), token.getSubject()); - - Assert.assertEquals(2, token.getRealmAccess().getRoles().size()); - Assert.assertTrue(token.getRealmAccess().isUserInRole("REALM_COMPOSITE_1")); - Assert.assertTrue(token.getRealmAccess().isUserInRole("REALM_ROLE_1")); - - AccessTokenResponse refreshResponse = oauth.doRefreshTokenRequest(response.getRefreshToken(), "password"); - Assert.assertEquals(200, refreshResponse.getStatusCode()); - } - - @Test - public void testRealmOnlyWithUserCompositeAppRole() throws Exception { - oauth.realm("test"); - oauth.realmPublicKey(realmPublicKey); - oauth.clientId("REALM_ROLE_1_APPLICATION"); - oauth.doLogin("REALM_COMPOSITE_1_USER", "password"); - - String code = oauth.getCurrentQuery().get(OAuth2Constants.CODE); - AccessTokenResponse response = oauth.doAccessTokenRequest(code, "password"); - - Assert.assertEquals(200, response.getStatusCode()); - - Assert.assertEquals("bearer", response.getTokenType()); - - AccessToken token = oauth.verifyToken(response.getAccessToken()); - - Assert.assertEquals(keycloakRule.getUser("test", "REALM_COMPOSITE_1_USER").getId(), token.getSubject()); - - Assert.assertEquals(1, token.getRealmAccess().getRoles().size()); - Assert.assertTrue(token.getRealmAccess().isUserInRole("REALM_ROLE_1")); - - AccessTokenResponse refreshResponse = oauth.doRefreshTokenRequest(response.getRefreshToken(), "password"); - Assert.assertEquals(200, refreshResponse.getStatusCode()); - } - - @Test - public void testRealmOnlyWithUserRoleAppComposite() throws Exception { - oauth.realm("test"); - oauth.realmPublicKey(realmPublicKey); - oauth.clientId("REALM_COMPOSITE_1_APPLICATION"); - oauth.doLogin("REALM_ROLE_1_USER", "password"); - - String code = oauth.getCurrentQuery().get(OAuth2Constants.CODE); - AccessTokenResponse response = oauth.doAccessTokenRequest(code, "password"); - - Assert.assertEquals(200, response.getStatusCode()); - - Assert.assertEquals("bearer", response.getTokenType()); - - AccessToken token = oauth.verifyToken(response.getAccessToken()); - - Assert.assertEquals(keycloakRule.getUser("test", "REALM_ROLE_1_USER").getId(), token.getSubject()); - - Assert.assertEquals(1, token.getRealmAccess().getRoles().size()); - Assert.assertTrue(token.getRealmAccess().isUserInRole("REALM_ROLE_1")); - - AccessTokenResponse refreshResponse = oauth.doRefreshTokenRequest(response.getRefreshToken(), "password"); - Assert.assertEquals(200, refreshResponse.getStatusCode()); - } - -} +/* + * 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.composites; + +import org.junit.Assert; +import org.junit.ClassRule; +import org.junit.Rule; +import org.junit.Test; +import org.keycloak.OAuth2Constants; +import org.keycloak.enums.SslRequired; +import org.keycloak.models.ClientModel; +import org.keycloak.models.KeycloakSession; +import org.keycloak.models.RealmModel; +import org.keycloak.models.RoleModel; +import org.keycloak.models.UserCredentialModel; +import org.keycloak.models.UserModel; +import org.keycloak.models.utils.KeycloakModelUtils; +import org.keycloak.representations.AccessToken; +import org.keycloak.services.managers.ClientManager; +import org.keycloak.services.managers.RealmManager; +import org.keycloak.testsuite.ApplicationServlet; +import org.keycloak.testsuite.OAuthClient; +import org.keycloak.testsuite.OAuthClient.AccessTokenResponse; +import org.keycloak.testsuite.pages.LoginPage; +import org.keycloak.testsuite.rule.AbstractKeycloakRule; +import org.keycloak.testsuite.rule.WebResource; +import org.keycloak.testsuite.rule.WebRule; +import org.openqa.selenium.WebDriver; + +import java.security.PublicKey; + +/** + * @author Stian Thorgersen + */ +public class CompositeRoleTest { + + public static PublicKey realmPublicKey; + @ClassRule + public static AbstractKeycloakRule keycloakRule = new AbstractKeycloakRule(){ + @Override + protected void configure(KeycloakSession session, RealmManager manager, RealmModel adminRealm) { + RealmModel realm = manager.createRealm("test"); + KeycloakModelUtils.generateRealmKeys(realm); + realmPublicKey = realm.getPublicKey(); + realm.setSsoSessionIdleTimeout(3000); + realm.setAccessTokenLifespan(10000); + realm.setSsoSessionMaxLifespan(10000); + realm.setAccessCodeLifespanUserAction(1000); + realm.setAccessCodeLifespan(1000); + realm.setSslRequired(SslRequired.EXTERNAL); + realm.setEnabled(true); + realm.addRequiredCredential(UserCredentialModel.PASSWORD); + final RoleModel realmRole1 = realm.addRole("REALM_ROLE_1"); + final RoleModel realmRole2 = realm.addRole("REALM_ROLE_2"); + final RoleModel realmRole3 = realm.addRole("REALM_ROLE_3"); + final RoleModel realmComposite1 = realm.addRole("REALM_COMPOSITE_1"); + realmComposite1.addCompositeRole(realmRole1); + + final UserModel realmComposite1User = session.users().addUser(realm, "REALM_COMPOSITE_1_USER"); + realmComposite1User.setEnabled(true); + realmComposite1User.updateCredential(UserCredentialModel.password("password")); + realmComposite1User.grantRole(realmComposite1); + + final UserModel realmRole1User = session.users().addUser(realm, "REALM_ROLE_1_USER"); + realmRole1User.setEnabled(true); + realmRole1User.updateCredential(UserCredentialModel.password("password")); + realmRole1User.grantRole(realmRole1); + + final ClientModel realmComposite1Application = new ClientManager(manager).createClient(realm, "REALM_COMPOSITE_1_APPLICATION"); + realmComposite1Application.setFullScopeAllowed(false); + realmComposite1Application.setEnabled(true); + realmComposite1Application.addScopeMapping(realmComposite1); + realmComposite1Application.addRedirectUri("http://localhost:8081/app/*"); + realmComposite1Application.setBaseUrl("http://localhost:8081/app"); + realmComposite1Application.setManagementUrl("http://localhost:8081/app/logout"); + realmComposite1Application.setSecret("password"); + + final ClientModel realmRole1Application = new ClientManager(manager).createClient(realm, "REALM_ROLE_1_APPLICATION"); + realmRole1Application.setFullScopeAllowed(false); + realmRole1Application.setEnabled(true); + realmRole1Application.addScopeMapping(realmRole1); + realmRole1Application.addRedirectUri("http://localhost:8081/app/*"); + realmRole1Application.setBaseUrl("http://localhost:8081/app"); + realmRole1Application.setManagementUrl("http://localhost:8081/app/logout"); + realmRole1Application.setSecret("password"); + + + final ClientModel appRoleApplication = new ClientManager(manager).createClient(realm, "APP_ROLE_APPLICATION"); + appRoleApplication.setFullScopeAllowed(false); + appRoleApplication.setEnabled(true); + appRoleApplication.addRedirectUri("http://localhost:8081/app/*"); + appRoleApplication.setBaseUrl("http://localhost:8081/app"); + appRoleApplication.setManagementUrl("http://localhost:8081/app/logout"); + appRoleApplication.setSecret("password"); + final RoleModel appRole1 = appRoleApplication.addRole("APP_ROLE_1"); + final RoleModel appRole2 = appRoleApplication.addRole("APP_ROLE_2"); + + final RoleModel realmAppCompositeRole = realm.addRole("REALM_APP_COMPOSITE_ROLE"); + realmAppCompositeRole.addCompositeRole(appRole1); + + final UserModel realmAppCompositeUser = session.users().addUser(realm, "REALM_APP_COMPOSITE_USER"); + realmAppCompositeUser.setEnabled(true); + realmAppCompositeUser.updateCredential(UserCredentialModel.password("password")); + realmAppCompositeUser.grantRole(realmAppCompositeRole); + + final UserModel realmAppRoleUser = session.users().addUser(realm, "REALM_APP_ROLE_USER"); + realmAppRoleUser.setEnabled(true); + realmAppRoleUser.updateCredential(UserCredentialModel.password("password")); + realmAppRoleUser.grantRole(appRole2); + + final ClientModel appCompositeApplication = new ClientManager(manager).createClient(realm, "APP_COMPOSITE_APPLICATION"); + appCompositeApplication.setFullScopeAllowed(false); + appCompositeApplication.setEnabled(true); + appCompositeApplication.addRedirectUri("http://localhost:8081/app/*"); + appCompositeApplication.setBaseUrl("http://localhost:8081/app"); + appCompositeApplication.setManagementUrl("http://localhost:8081/app/logout"); + appCompositeApplication.setSecret("password"); + final RoleModel appCompositeRole = appCompositeApplication.addRole("APP_COMPOSITE_ROLE"); + appCompositeApplication.addScopeMapping(appRole2); + appCompositeRole.addCompositeRole(realmRole1); + appCompositeRole.addCompositeRole(realmRole2); + appCompositeRole.addCompositeRole(realmRole3); + appCompositeRole.addCompositeRole(appRole1); + + final UserModel appCompositeUser = session.users().addUser(realm, "APP_COMPOSITE_USER"); + appCompositeUser.setEnabled(true); + appCompositeUser.updateCredential(UserCredentialModel.password("password")); + appCompositeUser.grantRole(realmAppCompositeRole); + appCompositeUser.grantRole(realmComposite1); + + deployServlet("app", "/app", ApplicationServlet.class); + + } + }; + + @Rule + public WebRule webRule = new WebRule(this); + + @WebResource + protected WebDriver driver; + + @WebResource + protected OAuthClient oauth; + + @WebResource + protected LoginPage loginPage; + + @Test + public void testAppCompositeUser() throws Exception { + oauth.realm("test"); + oauth.realmPublicKey(realmPublicKey); + oauth.clientId("APP_COMPOSITE_APPLICATION"); + oauth.doLogin("APP_COMPOSITE_USER", "password"); + + String code = oauth.getCurrentQuery().get(OAuth2Constants.CODE); + AccessTokenResponse response = oauth.doAccessTokenRequest(code, "password"); + + Assert.assertEquals(200, response.getStatusCode()); + + Assert.assertEquals("bearer", response.getTokenType()); + + AccessToken token = oauth.verifyToken(response.getAccessToken()); + + Assert.assertEquals(keycloakRule.getUser("test", "APP_COMPOSITE_USER").getId(), token.getSubject()); + + Assert.assertEquals(1, token.getResourceAccess("APP_ROLE_APPLICATION").getRoles().size()); + Assert.assertEquals(1, token.getRealmAccess().getRoles().size()); + Assert.assertTrue(token.getResourceAccess("APP_ROLE_APPLICATION").isUserInRole("APP_ROLE_1")); + Assert.assertTrue(token.getRealmAccess().isUserInRole("REALM_ROLE_1")); + + AccessTokenResponse refreshResponse = oauth.doRefreshTokenRequest(response.getRefreshToken(), "password"); + Assert.assertEquals(200, refreshResponse.getStatusCode()); + } + + + @Test + public void testRealmAppCompositeUser() throws Exception { + oauth.realm("test"); + oauth.realmPublicKey(realmPublicKey); + oauth.clientId("APP_ROLE_APPLICATION"); + oauth.doLogin("REALM_APP_COMPOSITE_USER", "password"); + + String code = oauth.getCurrentQuery().get(OAuth2Constants.CODE); + AccessTokenResponse response = oauth.doAccessTokenRequest(code, "password"); + + Assert.assertEquals(200, response.getStatusCode()); + + Assert.assertEquals("bearer", response.getTokenType()); + + AccessToken token = oauth.verifyToken(response.getAccessToken()); + + Assert.assertEquals(keycloakRule.getUser("test", "REALM_APP_COMPOSITE_USER").getId(), token.getSubject()); + + Assert.assertEquals(1, token.getResourceAccess("APP_ROLE_APPLICATION").getRoles().size()); + Assert.assertTrue(token.getResourceAccess("APP_ROLE_APPLICATION").isUserInRole("APP_ROLE_1")); + + AccessTokenResponse refreshResponse = oauth.doRefreshTokenRequest(response.getRefreshToken(), "password"); + Assert.assertEquals(200, refreshResponse.getStatusCode()); + } + + @Test + public void testRealmOnlyWithUserCompositeAppComposite() throws Exception { + oauth.realm("test"); + oauth.realmPublicKey(realmPublicKey); + oauth.clientId("REALM_COMPOSITE_1_APPLICATION"); + oauth.doLogin("REALM_COMPOSITE_1_USER", "password"); + + String code = oauth.getCurrentQuery().get(OAuth2Constants.CODE); + AccessTokenResponse response = oauth.doAccessTokenRequest(code, "password"); + + Assert.assertEquals(200, response.getStatusCode()); + + Assert.assertEquals("bearer", response.getTokenType()); + + AccessToken token = oauth.verifyToken(response.getAccessToken()); + + Assert.assertEquals(keycloakRule.getUser("test", "REALM_COMPOSITE_1_USER").getId(), token.getSubject()); + + Assert.assertEquals(2, token.getRealmAccess().getRoles().size()); + Assert.assertTrue(token.getRealmAccess().isUserInRole("REALM_COMPOSITE_1")); + Assert.assertTrue(token.getRealmAccess().isUserInRole("REALM_ROLE_1")); + + AccessTokenResponse refreshResponse = oauth.doRefreshTokenRequest(response.getRefreshToken(), "password"); + Assert.assertEquals(200, refreshResponse.getStatusCode()); + } + + @Test + public void testRealmOnlyWithUserCompositeAppRole() throws Exception { + oauth.realm("test"); + oauth.realmPublicKey(realmPublicKey); + oauth.clientId("REALM_ROLE_1_APPLICATION"); + oauth.doLogin("REALM_COMPOSITE_1_USER", "password"); + + String code = oauth.getCurrentQuery().get(OAuth2Constants.CODE); + AccessTokenResponse response = oauth.doAccessTokenRequest(code, "password"); + + Assert.assertEquals(200, response.getStatusCode()); + + Assert.assertEquals("bearer", response.getTokenType()); + + AccessToken token = oauth.verifyToken(response.getAccessToken()); + + Assert.assertEquals(keycloakRule.getUser("test", "REALM_COMPOSITE_1_USER").getId(), token.getSubject()); + + Assert.assertEquals(1, token.getRealmAccess().getRoles().size()); + Assert.assertTrue(token.getRealmAccess().isUserInRole("REALM_ROLE_1")); + + AccessTokenResponse refreshResponse = oauth.doRefreshTokenRequest(response.getRefreshToken(), "password"); + Assert.assertEquals(200, refreshResponse.getStatusCode()); + } + + @Test + public void testRealmOnlyWithUserRoleAppComposite() throws Exception { + oauth.realm("test"); + oauth.realmPublicKey(realmPublicKey); + oauth.clientId("REALM_COMPOSITE_1_APPLICATION"); + oauth.doLogin("REALM_ROLE_1_USER", "password"); + + String code = oauth.getCurrentQuery().get(OAuth2Constants.CODE); + AccessTokenResponse response = oauth.doAccessTokenRequest(code, "password"); + + Assert.assertEquals(200, response.getStatusCode()); + + Assert.assertEquals("bearer", response.getTokenType()); + + AccessToken token = oauth.verifyToken(response.getAccessToken()); + + Assert.assertEquals(keycloakRule.getUser("test", "REALM_ROLE_1_USER").getId(), token.getSubject()); + + Assert.assertEquals(1, token.getRealmAccess().getRoles().size()); + Assert.assertTrue(token.getRealmAccess().isUserInRole("REALM_ROLE_1")); + + AccessTokenResponse refreshResponse = oauth.doRefreshTokenRequest(response.getRefreshToken(), "password"); + Assert.assertEquals(200, refreshResponse.getStatusCode()); + } + +} From 422b7ed5ef17f2e62dd4ff0b246248a4583be1b1 Mon Sep 17 00:00:00 2001 From: Stian Thorgersen Date: Mon, 20 Jul 2015 10:38:52 +0200 Subject: [PATCH 6/8] Enabled testsuite/integration-arquillian on Travis --- .travis.yml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.travis.yml b/.travis.yml index 8275e00333..8146d6e1ed 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,8 @@ language: java +jdk: + - oraclejdk8 + cache: directories: - $HOME/.m2 @@ -7,4 +10,10 @@ cache: before_cache: - rm -rf $HOME/.m2/repository/org/keycloak +install: mvn install -Pdistribution -DskipTests=true -B -V + +script: + - mvn test -B + - mvn -file testsuite/integration-arquillian test -B + sudo: false From f2dee1a470661725e40569e40207aa8923fbcae6 Mon Sep 17 00:00:00 2001 From: Stian Thorgersen Date: Mon, 20 Jul 2015 13:35:33 +0200 Subject: [PATCH 7/8] Add support for multi-part to MailServer util --- .../java/org/keycloak/testsuite/MailServer.java | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/MailServer.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/MailServer.java index 1acaafb2a9..f56f0aaaa3 100755 --- a/testsuite/integration/src/test/java/org/keycloak/testsuite/MailServer.java +++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/MailServer.java @@ -5,6 +5,7 @@ import com.icegreen.greenmail.util.ServerSetup; import javax.mail.internet.MimeMessage; import javax.mail.internet.MimeMessage.RecipientType; +import javax.mail.internet.MimeMultipart; public class MailServer { @@ -22,9 +23,20 @@ public class MailServer { if (greenMail.waitForIncomingEmail(Long.MAX_VALUE, c + 1)) { MimeMessage message = greenMail.getReceivedMessages()[c++]; + System.out.println("-------------------------------------------------------"); System.out.println("Received mail to " + message.getRecipients(RecipientType.TO)[0]); - System.out.println(); - System.out.println(message.getContent()); + if (message.getContent() instanceof MimeMultipart) { + MimeMultipart mimeMultipart = (MimeMultipart) message.getContent(); + for (int i = 0; i < mimeMultipart.getCount(); i++) { + System.out.println("----"); + System.out.println(mimeMultipart.getBodyPart(i).getContentType() + ":"); + System.out.println(); + System.out.println(mimeMultipart.getBodyPart(i).getContent()); + } + } else { + System.out.println(); + System.out.println(message.getContent()); + } System.out.println("-------------------------------------------------------"); } } From f884aed25e45a0e676786a7ede4c790330982ff1 Mon Sep 17 00:00:00 2001 From: Stian Thorgersen Date: Mon, 20 Jul 2015 13:35:56 +0200 Subject: [PATCH 8/8] KEYCLOAK-1576 --- .../org/keycloak/services/resources/LoginActionsService.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/services/src/main/java/org/keycloak/services/resources/LoginActionsService.java b/services/src/main/java/org/keycloak/services/resources/LoginActionsService.java index 79d20d5011..55ddb9b50b 100755 --- a/services/src/main/java/org/keycloak/services/resources/LoginActionsService.java +++ b/services/src/main/java/org/keycloak/services/resources/LoginActionsService.java @@ -623,6 +623,7 @@ public class LoginActionsService { if (clientSession.getAction().equals(ClientSessionModel.Action.RECOVER_PASSWORD.name())) { String actionCookieValue = getActionCookie(); if (actionCookieValue == null || !actionCookieValue.equals(userSession.getId())) { + session.sessions().removeClientSession(realm, clientSession); return session.getProvider(LoginFormsProvider.class) .setSuccess(Messages.ACCOUNT_PASSWORD_UPDATED) .createInfoPage(); @@ -657,6 +658,7 @@ public class LoginActionsService { String actionCookieValue = getActionCookie(); if (actionCookieValue == null || !actionCookieValue.equals(userSession.getId())) { + session.sessions().removeClientSession(realm, clientSession); return session.getProvider(LoginFormsProvider.class) .setSuccess(Messages.EMAIL_VERIFIED) .createInfoPage();