Merge remote-tracking branch 'upstream/master'
This commit is contained in:
commit
548c0db0ae
21 changed files with 773 additions and 686 deletions
|
@ -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
|
||||
|
|
|
@ -1,73 +1,73 @@
|
|||
package org.keycloak.representations.idm;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class RequiredActionProviderRepresentation {
|
||||
|
||||
private String alias;
|
||||
private String name;
|
||||
private String providerId;
|
||||
private boolean enabled;
|
||||
private boolean defaultAction;
|
||||
private Map<String, String> config = new HashMap<String, String>();
|
||||
|
||||
|
||||
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<String, String> getConfig() {
|
||||
return config;
|
||||
}
|
||||
|
||||
public void setConfig(Map<String, String> config) {
|
||||
this.config = config;
|
||||
}
|
||||
}
|
||||
package org.keycloak.representations.idm;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class RequiredActionProviderRepresentation {
|
||||
|
||||
private String alias;
|
||||
private String name;
|
||||
private String providerId;
|
||||
private boolean enabled;
|
||||
private boolean defaultAction;
|
||||
private Map<String, String> config = new HashMap<String, String>();
|
||||
|
||||
|
||||
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<String, String> getConfig() {
|
||||
return config;
|
||||
}
|
||||
|
||||
public void setConfig(Map<String, String> config) {
|
||||
this.config = config;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,4 +27,10 @@
|
|||
<outputDirectory>modules</outputDirectory>
|
||||
</fileSet>
|
||||
</fileSets>
|
||||
<files>
|
||||
<file>
|
||||
<source>../../shared-cli/adapter-install.cli</source>
|
||||
<outputDirectory>bin</outputDirectory>
|
||||
</file>
|
||||
</files>
|
||||
</assembly>
|
||||
|
|
|
@ -27,4 +27,10 @@
|
|||
<outputDirectory>modules/system/layers/base</outputDirectory>
|
||||
</fileSet>
|
||||
</fileSets>
|
||||
<files>
|
||||
<file>
|
||||
<source>../../shared-cli/adapter-install.cli</source>
|
||||
<outputDirectory>bin</outputDirectory>
|
||||
</file>
|
||||
</files>
|
||||
</assembly>
|
||||
|
|
4
distribution/adapters/shared-cli/adapter-install.cli
Normal file
4
distribution/adapters/shared-cli/adapter-install.cli
Normal file
|
@ -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
|
|
@ -28,4 +28,10 @@
|
|||
<outputDirectory>modules/system/layers/base</outputDirectory>
|
||||
</fileSet>
|
||||
</fileSets>
|
||||
<files>
|
||||
<file>
|
||||
<source>../../shared-cli/adapter-install.cli</source>
|
||||
<outputDirectory>bin</outputDirectory>
|
||||
</file>
|
||||
</files>
|
||||
</assembly>
|
||||
|
|
|
@ -27,4 +27,10 @@
|
|||
<outputDirectory>modules/system/layers/base</outputDirectory>
|
||||
</fileSet>
|
||||
</fileSets>
|
||||
<files>
|
||||
<file>
|
||||
<source>../../shared-cli/adapter-install.cli</source>
|
||||
<outputDirectory>bin</outputDirectory>
|
||||
</file>
|
||||
</files>
|
||||
</assembly>
|
||||
|
|
|
@ -40,6 +40,14 @@
|
|||
<source>src/main/providers/README.txt</source>
|
||||
<outputDirectory>standalone/configuration/providers</outputDirectory>
|
||||
</file>
|
||||
<file>
|
||||
<source>cli/keycloak-prepare.cli</source>
|
||||
<outputDirectory>bin</outputDirectory>
|
||||
</file>
|
||||
<file>
|
||||
<source>cli/keycloak-install.cli</source>
|
||||
<outputDirectory>bin</outputDirectory>
|
||||
</file>
|
||||
</files>
|
||||
|
||||
</assembly>
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
/extension=org.keycloak.keycloak-server-subsystem/:add(module=org.keycloak.keycloak-server-subsystem)
|
||||
/subsystem=keycloak-server:add(web-context=auth)
|
|
@ -0,0 +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)
|
|
@ -44,22 +44,6 @@
|
|||
</xsl:copy>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template match="//sec:security-domains">
|
||||
<xsl:copy>
|
||||
<xsl:apply-templates select="node()[name(.)='security-domain']"/>
|
||||
<security-domain name="keycloak">
|
||||
<authentication>
|
||||
<login-module code="org.keycloak.adapters.jboss.KeycloakLoginModule" flag="required"/>
|
||||
</authentication>
|
||||
</security-domain>
|
||||
<security-domain name="sp" cache-type="default">
|
||||
<authentication>
|
||||
<login-module code="org.picketlink.identity.federation.bindings.wildfly.SAML2LoginModule" flag="required"/>
|
||||
</authentication>
|
||||
</security-domain>
|
||||
</xsl:copy>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template match="//*[local-name()='subsystem' and starts-with(namespace-uri(), $log)]">
|
||||
<xsl:copy>
|
||||
<xsl:apply-templates select="node()|@*"/>
|
||||
|
|
|
@ -62,6 +62,10 @@
|
|||
<source>${project.build.directory}/unpacked/keycloak-${project.version}/standalone/configuration/keycloak-server.json</source>
|
||||
<outputDirectory>standalone/configuration</outputDirectory>
|
||||
</file>
|
||||
<file>
|
||||
<source>cli/keycloak-install.cli</source>
|
||||
<outputDirectory>bin</outputDirectory>
|
||||
</file>
|
||||
</files>
|
||||
|
||||
</assembly>
|
||||
|
|
|
@ -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)
|
|
@ -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:
|
||||
<literal>domain.xml</literal> or <literal>standalone.xml</literal>.
|
||||
</para>
|
||||
<para>
|
||||
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:
|
||||
<programlisting>
|
||||
$ cd $JBOSS_HOME/bin
|
||||
$ jboss-cli.sh -c --file=adapter-install.cli
|
||||
</programlisting>
|
||||
The script will add the extension, subsystem, and optional security-domain as described below.
|
||||
</para>
|
||||
<para>
|
||||
<programlisting><![CDATA[
|
||||
<server xmlns="urn:jboss:domain:1.4">
|
||||
|
@ -65,8 +74,7 @@ $ unzip keycloak-as7-adapter-dist.zip
|
|||
</programlisting>
|
||||
</para>
|
||||
<para>
|
||||
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.
|
||||
</para>
|
||||
|
|
|
@ -49,9 +49,9 @@
|
|||
<literal>keycloak-overlay-&project.version;.zip</literal> or <literal>keycloak-overlay-&project.version;.tar.gz</literal>.
|
||||
Once downloaded extract into the root directory of your WildFly installation. To start WildFly with Keycloak
|
||||
run:
|
||||
<programlisting>keycloak-&project.version;/bin/standalone.sh --server-config=standalone-keycloak.xml</programlisting>
|
||||
<programlisting><WILDFLY_HOME>/bin/standalone.sh --server-config=standalone-keycloak.xml</programlisting>
|
||||
or:
|
||||
<programlisting>keycloak-&project.version;/bin/standalone.bat --server-config=standalone-keycloak.xml</programlisting>
|
||||
<programlisting><WILDFLY_HOME>/bin/standalone.bat --server-config=standalone-keycloak.xml</programlisting>
|
||||
</para>
|
||||
<para>
|
||||
Once the server is started log into the admin console at
|
||||
|
@ -60,15 +60,9 @@
|
|||
enter in a new password.
|
||||
</para>
|
||||
<para>
|
||||
To add Keycloak to other sever configurations (standalone.xml, standalone-ha.xml, etc.) open
|
||||
<literal>standalone/configuration/standalone-keycloak.xml</literal> and the configuration you want to add it
|
||||
to, for example <literal>standalone/configuration/standalone.xml</literal>. From <literal>standalone-keycloak.xml</literal>
|
||||
you need to copy 3 elements:
|
||||
<itemizedlist>
|
||||
<listitem><literal><extension module="org.keycloak.keycloak-server-subsystem"/></literal></listitem>
|
||||
<listitem><literal><datasource jndi-name="java:jboss/datasources/KeycloakDS" ...></literal></listitem>
|
||||
<listitem><literal><subsystem xmlns="urn:jboss:domain:keycloak-server:1.1" ...></literal></listitem>
|
||||
</itemizedlist>
|
||||
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:
|
||||
<programlisting><WILDFLY_HOME>/bin/jboss-cli.sh -c --file=keycloak-install.cli</programlisting>
|
||||
</para>
|
||||
</section>
|
||||
<section>
|
||||
|
@ -76,6 +70,19 @@
|
|||
<para>
|
||||
Same procedure as WildFly 9.0.0.Final, but download <literal>keycloak-overlay-eap6-&project.version;.zip</literal> or <literal>keycloak-overlay-eap6-&project.version;.tar.gz</literal>.
|
||||
</para>
|
||||
<para>
|
||||
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:
|
||||
<orderedlist>
|
||||
<listitem>
|
||||
<programlisting><EAP_HOME>/bin/jboss-cli.sh -c --file=keycloak-prepare.cli</programlisting>
|
||||
</listitem>
|
||||
<listitem>Restart the server with the same server-config.</listitem>
|
||||
<listitem>
|
||||
<programlisting><EAP_HOME>/bin/jboss-cli.sh -c --file=keycloak-install.cli</programlisting>
|
||||
</listitem>
|
||||
</orderedlist>
|
||||
</para>
|
||||
</section>
|
||||
<section>
|
||||
<title id="demo_install">Install Development Bundle</title>
|
||||
|
|
|
@ -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
|
||||
* <code>WEB-INF/keycloak.json</code> file generated by Keycloak.
|
||||
* <code>keycloak.json</code> resource file.
|
||||
*
|
||||
* @author <a href="mailto:srossillo@smartling.com">Scott Rossillo</a>
|
||||
* @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.
|
||||
*
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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 <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @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 <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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("-------------------------------------------------------");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||
*/
|
||||
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 <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||
*/
|
||||
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();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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 <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||
*/
|
||||
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 <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||
*/
|
||||
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());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue