Merge remote-tracking branch 'upstream/master'
This commit is contained in:
commit
0d20e3c7ff
35 changed files with 1141 additions and 253 deletions
|
@ -1,18 +1,5 @@
|
||||||
package org.keycloak.connections.jpa;
|
package org.keycloak.connections.jpa;
|
||||||
|
|
||||||
import org.hibernate.ejb.AvailableSettings;
|
|
||||||
import org.jboss.logging.Logger;
|
|
||||||
import org.keycloak.Config;
|
|
||||||
import org.keycloak.connections.jpa.updater.JpaUpdaterProvider;
|
|
||||||
import org.keycloak.connections.jpa.util.JpaUtils;
|
|
||||||
import org.keycloak.models.KeycloakSession;
|
|
||||||
import org.keycloak.models.KeycloakSessionFactory;
|
|
||||||
|
|
||||||
import javax.naming.InitialContext;
|
|
||||||
import javax.persistence.EntityManager;
|
|
||||||
import javax.persistence.EntityManagerFactory;
|
|
||||||
import javax.persistence.Persistence;
|
|
||||||
import javax.sql.DataSource;
|
|
||||||
import java.sql.Connection;
|
import java.sql.Connection;
|
||||||
import java.sql.DatabaseMetaData;
|
import java.sql.DatabaseMetaData;
|
||||||
import java.sql.DriverManager;
|
import java.sql.DriverManager;
|
||||||
|
@ -22,10 +9,25 @@ import java.util.HashMap;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
import javax.naming.InitialContext;
|
||||||
|
import javax.persistence.EntityManager;
|
||||||
|
import javax.persistence.EntityManagerFactory;
|
||||||
|
import javax.persistence.Persistence;
|
||||||
|
import javax.sql.DataSource;
|
||||||
|
|
||||||
|
import org.hibernate.ejb.AvailableSettings;
|
||||||
|
import org.jboss.logging.Logger;
|
||||||
|
import org.keycloak.Config;
|
||||||
|
import org.keycloak.connections.jpa.updater.JpaUpdaterProvider;
|
||||||
|
import org.keycloak.connections.jpa.util.JpaUtils;
|
||||||
|
import org.keycloak.models.KeycloakSession;
|
||||||
|
import org.keycloak.models.KeycloakSessionFactory;
|
||||||
|
import org.keycloak.provider.ServerInfoAwareProviderFactory;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||||
*/
|
*/
|
||||||
public class DefaultJpaConnectionProviderFactory implements JpaConnectionProviderFactory {
|
public class DefaultJpaConnectionProviderFactory implements JpaConnectionProviderFactory, ServerInfoAwareProviderFactory {
|
||||||
|
|
||||||
private static final Logger logger = Logger.getLogger(DefaultJpaConnectionProviderFactory.class);
|
private static final Logger logger = Logger.getLogger(DefaultJpaConnectionProviderFactory.class);
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
package org.keycloak.connections.jpa;
|
package org.keycloak.connections.jpa;
|
||||||
|
|
||||||
import org.keycloak.provider.ServerInfoAwareProviderFactory;
|
import org.keycloak.provider.ProviderFactory;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||||
*/
|
*/
|
||||||
public interface JpaConnectionProviderFactory extends ServerInfoAwareProviderFactory<JpaConnectionProvider> {
|
public interface JpaConnectionProviderFactory extends ProviderFactory<JpaConnectionProvider> {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
package org.keycloak.connections.mongo;
|
package org.keycloak.connections.mongo;
|
||||||
|
|
||||||
import com.mongodb.DB;
|
import java.lang.reflect.Method;
|
||||||
import com.mongodb.MongoClient;
|
import java.net.UnknownHostException;
|
||||||
import com.mongodb.MongoClientOptions;
|
import java.util.Collections;
|
||||||
import com.mongodb.MongoClientURI;
|
import java.util.LinkedHashMap;
|
||||||
import com.mongodb.MongoCredential;
|
import java.util.Map;
|
||||||
import com.mongodb.ServerAddress;
|
|
||||||
|
import javax.net.ssl.SSLSocketFactory;
|
||||||
|
|
||||||
import org.jboss.logging.Logger;
|
import org.jboss.logging.Logger;
|
||||||
import org.keycloak.Config;
|
import org.keycloak.Config;
|
||||||
|
@ -15,18 +16,19 @@ import org.keycloak.connections.mongo.impl.context.TransactionMongoStoreInvocati
|
||||||
import org.keycloak.connections.mongo.updater.MongoUpdaterProvider;
|
import org.keycloak.connections.mongo.updater.MongoUpdaterProvider;
|
||||||
import org.keycloak.models.KeycloakSession;
|
import org.keycloak.models.KeycloakSession;
|
||||||
import org.keycloak.models.KeycloakSessionFactory;
|
import org.keycloak.models.KeycloakSessionFactory;
|
||||||
|
import org.keycloak.provider.ServerInfoAwareProviderFactory;
|
||||||
|
|
||||||
import javax.net.ssl.SSLSocketFactory;
|
import com.mongodb.DB;
|
||||||
import java.lang.reflect.Method;
|
import com.mongodb.MongoClient;
|
||||||
import java.net.UnknownHostException;
|
import com.mongodb.MongoClientOptions;
|
||||||
import java.util.Collections;
|
import com.mongodb.MongoClientURI;
|
||||||
import java.util.LinkedHashMap;
|
import com.mongodb.MongoCredential;
|
||||||
import java.util.Map;
|
import com.mongodb.ServerAddress;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||||
*/
|
*/
|
||||||
public class DefaultMongoConnectionFactoryProvider implements MongoConnectionProviderFactory {
|
public class DefaultMongoConnectionFactoryProvider implements MongoConnectionProviderFactory, ServerInfoAwareProviderFactory {
|
||||||
|
|
||||||
// TODO Make it dynamic
|
// TODO Make it dynamic
|
||||||
private String[] entities = new String[]{
|
private String[] entities = new String[]{
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
package org.keycloak.connections.mongo;
|
package org.keycloak.connections.mongo;
|
||||||
|
|
||||||
import org.keycloak.provider.ServerInfoAwareProviderFactory;
|
import org.keycloak.provider.ProviderFactory;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||||
*/
|
*/
|
||||||
public interface MongoConnectionProviderFactory extends ServerInfoAwareProviderFactory<MongoConnectionProvider> {
|
public interface MongoConnectionProviderFactory extends ProviderFactory<MongoConnectionProvider> {
|
||||||
}
|
}
|
||||||
|
|
|
@ -114,6 +114,10 @@
|
||||||
<name>picketlink.version</name>
|
<name>picketlink.version</name>
|
||||||
<value>${picketlink.version}</value>
|
<value>${picketlink.version}</value>
|
||||||
</injection>
|
</injection>
|
||||||
|
<injection>
|
||||||
|
<name>wildfly.version</name>
|
||||||
|
<value>${wildfly.version}</value>
|
||||||
|
</injection>
|
||||||
</injections>
|
</injections>
|
||||||
<options>
|
<options>
|
||||||
<xmlTransformerType>saxon</xmlTransformerType>
|
<xmlTransformerType>saxon</xmlTransformerType>
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
</para>
|
</para>
|
||||||
<para>
|
<para>
|
||||||
For example to implement the Event Listener SPI you start by implementing EventListenerProviderFactory:
|
For example to implement the Event Listener SPI you start by implementing EventListenerProviderFactory:
|
||||||
<programlisting><![CDATA[{
|
<programlisting><![CDATA[
|
||||||
package org.acme.provider;
|
package org.acme.provider;
|
||||||
|
|
||||||
import ...
|
import ...
|
||||||
|
@ -43,7 +43,7 @@ public class MyEventListenerProviderFactory implements EventListenerProviderFact
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}]]></programlisting>
|
]]></programlisting>
|
||||||
The example uses an imagined MaxList which has a maximum size and is concurrency safe. When the maximum size is reached
|
The example uses an imagined MaxList which has a maximum size and is concurrency safe. When the maximum size is reached
|
||||||
and new entries are added the oldest entry is removed. Keycloak creates a single instance of
|
and new entries are added the oldest entry is removed. Keycloak creates a single instance of
|
||||||
EventListenerProviderFactory which makes it possible to store state for multiple requests. EventListenerProvider
|
EventListenerProviderFactory which makes it possible to store state for multiple requests. EventListenerProvider
|
||||||
|
@ -51,7 +51,7 @@ public class MyEventListenerProviderFactory implements EventListenerProviderFact
|
||||||
</para>
|
</para>
|
||||||
<para>
|
<para>
|
||||||
Next you would implement EventListenerProvider:
|
Next you would implement EventListenerProvider:
|
||||||
<programlisting><![CDATA[{
|
<programlisting><![CDATA[
|
||||||
package org.acme.provider;
|
package org.acme.provider;
|
||||||
|
|
||||||
import ...
|
import ...
|
||||||
|
@ -75,13 +75,61 @@ public class MyEventListenerProvider implements EventListenerProvider {
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}]]></programlisting>
|
]]></programlisting>
|
||||||
</para>
|
</para>
|
||||||
<para>
|
<para>
|
||||||
The file <literal>META-INF/services/org.keycloak.events.EventListenerProviderFactory</literal> should
|
The file <literal>META-INF/services/org.keycloak.events.EventListenerProviderFactory</literal> should
|
||||||
contain the full name of your ProviderFactory implementation:
|
contain the full name of your ProviderFactory implementation:
|
||||||
<programlisting><![CDATA[org.acme.provider.MyEventListenerProviderFactory]]></programlisting>
|
<programlisting><![CDATA[org.acme.provider.MyEventListenerProviderFactory]]></programlisting>
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<title>Show info from you SPI implementation in Keycloak admin console</title>
|
||||||
|
<para>
|
||||||
|
Sometimes it is useful to show additional info about your Provider to a Keycloak administrator.
|
||||||
|
You can show provider build time informations (eg. version of custom provider currently installed),
|
||||||
|
current configuration of the provider (eg. url of remote system your provider talks to) or some operational
|
||||||
|
info (average time of response from remote system your provider talks to).
|
||||||
|
Keycloak admin console provides Server Info page to show this kind of information.
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
To show info from your provider it is enough to implement
|
||||||
|
<literal>org.keycloak.provider.ServerInfoAwareProviderFactory</literal> interface in your ProviderFactory.
|
||||||
|
Example implementation for MyEventListenerProviderFactory from previous example:
|
||||||
|
<programlisting><![CDATA[
|
||||||
|
package org.acme.provider;
|
||||||
|
|
||||||
|
import ...
|
||||||
|
|
||||||
|
public class MyEventListenerProviderFactory implements EventListenerProviderFactory, ServerInfoAwareProviderFactory {
|
||||||
|
|
||||||
|
private List<Event> events;
|
||||||
|
private int max;
|
||||||
|
|
||||||
|
...
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void init(Config.Scope config) {
|
||||||
|
max = config.getInt("max");
|
||||||
|
events = new MaxList(max);
|
||||||
|
}
|
||||||
|
|
||||||
|
...
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<String, String> getOperationalInfo() {
|
||||||
|
Map<String, String> ret = new LinkedHashMap<>();
|
||||||
|
ret.put("version", "1.0");
|
||||||
|
ret.put("listSizeMax", max + "");
|
||||||
|
ret.put("listSizeCurrent", events.size() + "");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
]]></programlisting>
|
||||||
|
|
||||||
|
</para>
|
||||||
|
</section>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section>
|
<section>
|
||||||
|
@ -98,13 +146,13 @@ public class MyEventListenerProvider implements EventListenerProvider {
|
||||||
To register a provider using Modules first create a module. To do this you can either use the jboss-cli
|
To register a provider using Modules first create a module. To do this you can either use the jboss-cli
|
||||||
script or manually create a folder inside KEYCLOAK_HOME/modules and add your jar and a <literal>module.xml</literal>.
|
script or manually create a folder inside KEYCLOAK_HOME/modules and add your jar and a <literal>module.xml</literal>.
|
||||||
For example to add the event listener sysout example provider using the jboss-cli script execute:
|
For example to add the event listener sysout example provider using the jboss-cli script execute:
|
||||||
<programlisting><![CDATA[{
|
<programlisting><![CDATA[
|
||||||
KEYCLOAK_HOME/bin/jboss-cli.sh --command="module add --name=org.keycloak.examples.event-sysout --resources=target/event-listener-sysout-example.jar --dependencies=org.keycloak.keycloak-core,org.keycloak.keycloak-model-api,org.keycloak.keycloak-events-api"
|
KEYCLOAK_HOME/bin/jboss-cli.sh --command="module add --name=org.keycloak.examples.event-sysout --resources=target/event-listener-sysout-example.jar --dependencies=org.keycloak.keycloak-core,org.keycloak.keycloak-model-api,org.keycloak.keycloak-events-api"
|
||||||
}]]></programlisting>
|
]]></programlisting>
|
||||||
Or to manually create it start by creating the folder <literal>KEYCLOAK_HOME/modules/org/keycloak/examples/event-sysout/main</literal>.
|
Or to manually create it start by creating the folder <literal>KEYCLOAK_HOME/modules/org/keycloak/examples/event-sysout/main</literal>.
|
||||||
Then copy <literal>event-listener-sysout-example.jar</literal> to this folder and create <literal>module.xml</literal>
|
Then copy <literal>event-listener-sysout-example.jar</literal> to this folder and create <literal>module.xml</literal>
|
||||||
with the following content:
|
with the following content:
|
||||||
<programlisting><![CDATA[{
|
<programlisting><![CDATA[
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<module xmlns="urn:jboss:module:1.1" name="org.keycloak.examples.event-sysout">
|
<module xmlns="urn:jboss:module:1.1" name="org.keycloak.examples.event-sysout">
|
||||||
<resources>
|
<resources>
|
||||||
|
@ -116,7 +164,7 @@ public class MyEventListenerProvider implements EventListenerProvider {
|
||||||
<module name="org.keycloak.keycloak-events-api"/>
|
<module name="org.keycloak.keycloak-events-api"/>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
</module>
|
</module>
|
||||||
}]]></programlisting>
|
]]></programlisting>
|
||||||
</para>
|
</para>
|
||||||
<para>
|
<para>
|
||||||
Once you've created the module you need to register this module with Keycloak. This is done by editing
|
Once you've created the module you need to register this module with Keycloak. This is done by editing
|
||||||
|
|
|
@ -43,9 +43,9 @@
|
||||||
|
|
||||||
|
|
||||||
<section id="overlay_install">
|
<section id="overlay_install">
|
||||||
<title>Install on existing WildFly 9.0.1.Final</title>
|
<title>Install on existing WildFly &wildfly.version;</title>
|
||||||
<para>
|
<para>
|
||||||
Keycloak can be installed into an existing WildFly 9.0.0.Final server. To do this download
|
Keycloak can be installed into an existing WildFly &wildfly.version; server. To do this download
|
||||||
<literal>keycloak-overlay-&project.version;.zip</literal> or <literal>keycloak-overlay-&project.version;.tar.gz</literal>.
|
<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
|
Once downloaded extract into the root directory of your WildFly installation. To start WildFly with Keycloak
|
||||||
run:
|
run:
|
||||||
|
@ -62,11 +62,15 @@
|
||||||
<para>
|
<para>
|
||||||
To add Keycloak to other sever configurations (standalone.xml, standalone-ha.xml, etc.) start the server with
|
To add Keycloak to other sever configurations (standalone.xml, standalone-ha.xml, etc.) start the server with
|
||||||
the desired server-config. If you are running the server in standalone mode run:
|
the desired server-config. If you are running the server in standalone mode run:
|
||||||
<programlisting>cd <WILDFLY_HOME>/bin
|
<programlisting>
|
||||||
./jboss-cli.sh -c --file=keycloak-install.cli</programlisting>
|
cd <WILDFLY_HOME>/bin
|
||||||
|
./jboss-cli.sh -c --file=keycloak-install.cli
|
||||||
|
</programlisting>
|
||||||
Or if you are running in clustering (HA) mode (by having used -c standalone-ha.xml) then run:
|
Or if you are running in clustering (HA) mode (by having used -c standalone-ha.xml) then run:
|
||||||
<programlisting>cd <WILDFLY_HOME>/bin
|
<programlisting>
|
||||||
./jboss-cli.sh -c --file=keycloak-install-ha.cli</programlisting>
|
cd <WILDFLY_HOME>/bin
|
||||||
|
./jboss-cli.sh -c --file=keycloak-install-ha.cli
|
||||||
|
</programlisting>
|
||||||
You may see exceptions in the server log, but after restarting the server they should be gone.
|
You may see exceptions in the server log, but after restarting the server they should be gone.
|
||||||
You can restart the server with:
|
You can restart the server with:
|
||||||
<programlisting><WILDFLY_HOME>/bin/jboss-cli.sh -c :reload</programlisting>
|
<programlisting><WILDFLY_HOME>/bin/jboss-cli.sh -c :reload</programlisting>
|
||||||
|
@ -75,7 +79,7 @@
|
||||||
<section>
|
<section>
|
||||||
<title>Install on existing JBoss EAP 6.4.0.GA</title>
|
<title>Install on existing JBoss EAP 6.4.0.GA</title>
|
||||||
<para>
|
<para>
|
||||||
Same procedure as WildFly 9.0.1.Final, but download <literal>keycloak-overlay-eap6-&project.version;.zip</literal> or <literal>keycloak-overlay-eap6-&project.version;.tar.gz</literal>.
|
Same procedure as WildFly &wildfly.version;, but download <literal>keycloak-overlay-eap6-&project.version;.zip</literal> or <literal>keycloak-overlay-eap6-&project.version;.tar.gz</literal>.
|
||||||
</para>
|
</para>
|
||||||
</section>
|
</section>
|
||||||
<section>
|
<section>
|
||||||
|
@ -85,7 +89,7 @@
|
||||||
To install it first download <literal>keycloak-demo-&project.version;.zip</literal> or
|
To install it first download <literal>keycloak-demo-&project.version;.zip</literal> or
|
||||||
<literal>keycloak-demo-&project.version;.tar.gz</literal>. Once downloaded extract it inside
|
<literal>keycloak-demo-&project.version;.tar.gz</literal>. Once downloaded extract it inside
|
||||||
<literal>keycloak-demo-&project.version;</literal> you'll find <literal>keycloak</literal> which contains
|
<literal>keycloak-demo-&project.version;</literal> you'll find <literal>keycloak</literal> which contains
|
||||||
a full WildFly 9.0.0.Final server with Keycloak Server and Adapters included. You'll also find <literal>docs</literal>
|
a full WildFly &wildfly.version; server with Keycloak Server and Adapters included. You'll also find <literal>docs</literal>
|
||||||
and <literal>examples</literal> which contains everything you need to get started developing applications that use Keycloak.
|
and <literal>examples</literal> which contains everything you need to get started developing applications that use Keycloak.
|
||||||
</para>
|
</para>
|
||||||
<para>
|
<para>
|
||||||
|
@ -437,12 +441,12 @@ All configuration options are optional. Default value for directory is <literal>
|
||||||
settings you can specify before boot time. This is configured in the
|
settings you can specify before boot time. This is configured in the
|
||||||
<literal>standalone/configuration/keycloak-server.json</literal>.
|
<literal>standalone/configuration/keycloak-server.json</literal>.
|
||||||
By default the setting is like this:
|
By default the setting is like this:
|
||||||
<programlisting><![CDATA[
|
<programlisting><![CDATA[
|
||||||
"connectionsHttpClient": {
|
"connectionsHttpClient": {
|
||||||
"default": {
|
"default": {
|
||||||
"disable-trust-manager": true
|
"disable-trust-manager": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
]]></programlisting>
|
]]></programlisting>
|
||||||
Possible configuration options are:
|
Possible configuration options are:
|
||||||
<variablelist>
|
<variablelist>
|
||||||
|
@ -659,25 +663,25 @@ All configuration options are optional. Default value for directory is <literal>
|
||||||
to do with the <literal>keytool</literal> utility that comes with the Java jdk.
|
to do with the <literal>keytool</literal> utility that comes with the Java jdk.
|
||||||
</para>
|
</para>
|
||||||
<para>
|
<para>
|
||||||
<programlisting>
|
<programlisting>
|
||||||
$ keytool -genkey -alias localhost -keyalg RSA -keystore keycloak.jks -validity 10950
|
$ keytool -genkey -alias localhost -keyalg RSA -keystore keycloak.jks -validity 10950
|
||||||
Enter keystore password: secret
|
Enter keystore password: secret
|
||||||
Re-enter new password: secret
|
Re-enter new password: secret
|
||||||
What is your first and last name?
|
What is your first and last name?
|
||||||
[Unknown]: localhost
|
[Unknown]: localhost
|
||||||
What is the name of your organizational unit?
|
What is the name of your organizational unit?
|
||||||
[Unknown]: Keycloak
|
[Unknown]: Keycloak
|
||||||
What is the name of your organization?
|
What is the name of your organization?
|
||||||
[Unknown]: Red Hat
|
[Unknown]: Red Hat
|
||||||
What is the name of your City or Locality?
|
What is the name of your City or Locality?
|
||||||
[Unknown]: Westford
|
[Unknown]: Westford
|
||||||
What is the name of your State or Province?
|
What is the name of your State or Province?
|
||||||
[Unknown]: MA
|
[Unknown]: MA
|
||||||
What is the two-letter country code for this unit?
|
What is the two-letter country code for this unit?
|
||||||
[Unknown]: US
|
[Unknown]: US
|
||||||
Is CN=localhost, OU=Keycloak, O=Test, L=Westford, ST=MA, C=US correct?
|
Is CN=localhost, OU=Keycloak, O=Test, L=Westford, ST=MA, C=US correct?
|
||||||
[no]: yes
|
[no]: yes
|
||||||
</programlisting>
|
</programlisting>
|
||||||
</para>
|
</para>
|
||||||
<para>
|
<para>
|
||||||
You should answer <literal>What is your first and last name ?</literal> question with
|
You should answer <literal>What is your first and last name ?</literal> question with
|
||||||
|
@ -693,44 +697,44 @@ All configuration options are optional. Default value for directory is <literal>
|
||||||
</para>
|
</para>
|
||||||
<para>
|
<para>
|
||||||
The first thing to do is generate a Certificate Request:
|
The first thing to do is generate a Certificate Request:
|
||||||
<programlisting>
|
<programlisting>
|
||||||
$ keytool -certreq -alias yourdomain -keystore keycloak.jks > keycloak.careq
|
$ keytool -certreq -alias yourdomain -keystore keycloak.jks > keycloak.careq
|
||||||
</programlisting>
|
</programlisting>
|
||||||
</para>
|
</para>
|
||||||
<para>
|
<para>
|
||||||
Where <literal>yourdomain</literal> is a DNS name for which this certificate is generated for.
|
Where <literal>yourdomain</literal> is a DNS name for which this certificate is generated for.
|
||||||
Keytool generates the request:
|
Keytool generates the request:
|
||||||
<programlisting>
|
<programlisting>
|
||||||
-----BEGIN NEW CERTIFICATE REQUEST-----
|
-----BEGIN NEW CERTIFICATE REQUEST-----
|
||||||
MIIC2jCCAcICAQAwZTELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAk1BMREwDwYDVQQHEwhXZXN0Zm9y
|
MIIC2jCCAcICAQAwZTELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAk1BMREwDwYDVQQHEwhXZXN0Zm9y
|
||||||
ZDEQMA4GA1UEChMHUmVkIEhhdDEQMA4GA1UECxMHUmVkIEhhdDESMBAGA1UEAxMJbG9jYWxob3N0
|
ZDEQMA4GA1UEChMHUmVkIEhhdDEQMA4GA1UECxMHUmVkIEhhdDESMBAGA1UEAxMJbG9jYWxob3N0
|
||||||
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAr7kck2TaavlEOGbcpi9c0rncY4HhdzmY
|
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAr7kck2TaavlEOGbcpi9c0rncY4HhdzmY
|
||||||
Ax2nZfq1eZEaIPqI5aTxwQZzzLDK9qbeAd8Ji79HzSqnRDxNYaZu7mAYhFKHgixsolE3o5Yfzbw1
|
Ax2nZfq1eZEaIPqI5aTxwQZzzLDK9qbeAd8Ji79HzSqnRDxNYaZu7mAYhFKHgixsolE3o5Yfzbw1
|
||||||
29Rvy+eUVe+WZxv5oo9wolVVpdSINIMEL2LaFhtX/c1dqiqYVpfnvFshZQaIg2nL8juzZcBjj4as
|
29Rvy+eUVe+WZxv5oo9wolVVpdSINIMEL2LaFhtX/c1dqiqYVpfnvFshZQaIg2nL8juzZcBjj4as
|
||||||
H98gIS7khql/dkZKsw9NLvyxgJvp7PaXurX29fNf3ihG+oFrL22oFyV54BWWxXCKU/GPn61EGZGw
|
H98gIS7khql/dkZKsw9NLvyxgJvp7PaXurX29fNf3ihG+oFrL22oFyV54BWWxXCKU/GPn61EGZGw
|
||||||
Ft2qSIGLdctpMD1aJR2bcnlhEjZKDksjQZoQ5YMXaAGkcYkG6QkgrocDE2YXDbi7GIdf9MegVJ35
|
Ft2qSIGLdctpMD1aJR2bcnlhEjZKDksjQZoQ5YMXaAGkcYkG6QkgrocDE2YXDbi7GIdf9MegVJ35
|
||||||
2DQMpwIDAQABoDAwLgYJKoZIhvcNAQkOMSEwHzAdBgNVHQ4EFgQUQwlZJBA+fjiDdiVzaO9vrE/i
|
2DQMpwIDAQABoDAwLgYJKoZIhvcNAQkOMSEwHzAdBgNVHQ4EFgQUQwlZJBA+fjiDdiVzaO9vrE/i
|
||||||
n2swDQYJKoZIhvcNAQELBQADggEBAC5FRvMkhal3q86tHPBYWBuTtmcSjs4qUm6V6f63frhveWHf
|
n2swDQYJKoZIhvcNAQELBQADggEBAC5FRvMkhal3q86tHPBYWBuTtmcSjs4qUm6V6f63frhveWHf
|
||||||
PzRrI1xH272XUIeBk0gtzWo0nNZnf0mMCtUBbHhhDcG82xolikfqibZijoQZCiGiedVjHJFtniDQ
|
PzRrI1xH272XUIeBk0gtzWo0nNZnf0mMCtUBbHhhDcG82xolikfqibZijoQZCiGiedVjHJFtniDQ
|
||||||
9bMDUOXEMQ7gHZg5q6mJfNG9MbMpQaUVEEFvfGEQQxbiFK7hRWU8S23/d80e8nExgQxdJWJ6vd0X
|
9bMDUOXEMQ7gHZg5q6mJfNG9MbMpQaUVEEFvfGEQQxbiFK7hRWU8S23/d80e8nExgQxdJWJ6vd0X
|
||||||
MzzFK6j4Dj55bJVuM7GFmfdNC52pNOD5vYe47Aqh8oajHX9XTycVtPXl45rrWAH33ftbrS8SrZ2S
|
MzzFK6j4Dj55bJVuM7GFmfdNC52pNOD5vYe47Aqh8oajHX9XTycVtPXl45rrWAH33ftbrS8SrZ2S
|
||||||
vqIFQeuLL3BaHwpl3t7j2lMWcK1p80laAxEASib/fAwrRHpLHBXRcq6uALUOZl4Alt8=
|
vqIFQeuLL3BaHwpl3t7j2lMWcK1p80laAxEASib/fAwrRHpLHBXRcq6uALUOZl4Alt8=
|
||||||
-----END NEW CERTIFICATE REQUEST-----
|
-----END NEW CERTIFICATE REQUEST-----
|
||||||
</programlisting>
|
</programlisting>
|
||||||
</para>
|
</para>
|
||||||
<para>
|
<para>
|
||||||
Send this ca request to your CA. The CA will issue you a signed certificate and send it to you.
|
Send this ca request to your CA. The CA will issue you a signed certificate and send it to you.
|
||||||
Before you import your new cert, you must obtain and import the root certificate of the CA.
|
Before you import your new cert, you must obtain and import the root certificate of the CA.
|
||||||
You can download the cert from CA (ie.: root.crt) and import as follows:
|
You can download the cert from CA (ie.: root.crt) and import as follows:
|
||||||
<programlisting>
|
<programlisting>
|
||||||
$ keytool -import -keystore keycloak.jks -file root.crt -alias root
|
$ keytool -import -keystore keycloak.jks -file root.crt -alias root
|
||||||
</programlisting>
|
</programlisting>
|
||||||
</para>
|
</para>
|
||||||
<para>
|
<para>
|
||||||
Last step is import your new CA generated certificate to your keystore:
|
Last step is import your new CA generated certificate to your keystore:
|
||||||
<programlisting>
|
<programlisting>
|
||||||
$ keytool -import -alias yourdomain -keystore keycloak.jks -file your-certificate.cer
|
$ keytool -import -alias yourdomain -keystore keycloak.jks -file your-certificate.cer
|
||||||
</programlisting>
|
</programlisting>
|
||||||
</para>
|
</para>
|
||||||
</section>
|
</section>
|
||||||
</section>
|
</section>
|
||||||
|
@ -744,18 +748,19 @@ All configuration options are optional. Default value for directory is <literal>
|
||||||
</para>
|
</para>
|
||||||
<para>
|
<para>
|
||||||
To the <literal>security-realms</literal> element add:
|
To the <literal>security-realms</literal> element add:
|
||||||
<programlisting><![CDATA[<security-realm name="UndertowRealm">
|
<programlisting><![CDATA[
|
||||||
<server-identities>
|
<security-realm name="UndertowRealm">
|
||||||
<ssl>
|
<server-identities>
|
||||||
<keystore path="keycloak.jks" relative-to="jboss.server.config.dir" keystore-password="secret" />
|
<ssl>
|
||||||
</ssl>
|
<keystore path="keycloak.jks" relative-to="jboss.server.config.dir" keystore-password="secret" />
|
||||||
</server-identities>
|
</ssl>
|
||||||
</security-realm>]]></programlisting>
|
</server-identities>
|
||||||
|
</security-realm>
|
||||||
|
]]></programlisting>
|
||||||
</para>
|
</para>
|
||||||
<para>
|
<para>
|
||||||
Find the element <literal><server name="default-server"></literal> (it's a child element of <literal><subsystem xmlns="urn:jboss:domain:undertow:1.0"></literal>) and add:
|
Find the element <literal><server name="default-server"></literal> (it's a child element of <literal><subsystem xmlns="urn:jboss:domain:undertow:1.0"></literal>) and add:
|
||||||
<programlisting><![CDATA[<https-listener name="https" socket-binding="https" security-realm="UndertowRealm"/>
|
<programlisting><![CDATA[<https-listener name="https" socket-binding="https" security-realm="UndertowRealm"/>]]></programlisting>
|
||||||
]]></programlisting>
|
|
||||||
</para>
|
</para>
|
||||||
<para>
|
<para>
|
||||||
Check the <ulink url="https://docs.jboss.org/author/display/WFLY8/Undertow+(web)+subsystem+configuration">Wildfly Undertow</ulink> documentation for more information on fine tuning the socket connections.
|
Check the <ulink url="https://docs.jboss.org/author/display/WFLY8/Undertow+(web)+subsystem+configuration">Wildfly Undertow</ulink> documentation for more information on fine tuning the socket connections.
|
||||||
|
@ -865,12 +870,12 @@ All configuration options are optional. Default value for directory is <literal>
|
||||||
</para>
|
</para>
|
||||||
<para>
|
<para>
|
||||||
To do this, add the <literal>default-web-module</literal> attribute in the Undertow subystem in standalone.xml.
|
To do this, add the <literal>default-web-module</literal> attribute in the Undertow subystem in standalone.xml.
|
||||||
<programlisting><![CDATA[
|
<programlisting><![CDATA[
|
||||||
<subsystem xmlns="urn:jboss:domain:undertow:2.0">
|
<subsystem xmlns="urn:jboss:domain:undertow:2.0">
|
||||||
<server name="default-server">
|
<server name="default-server">
|
||||||
<host name="default-host" alias="localhost" default-web-module="keycloak-server.war">
|
<host name="default-host" alias="localhost" default-web-module="keycloak-server.war">
|
||||||
<location name="/" handler="welcome-content"/>
|
<location name="/" handler="welcome-content"/>
|
||||||
</host>
|
</host>
|
||||||
]]></programlisting>
|
]]></programlisting>
|
||||||
</para>
|
</para>
|
||||||
<para>
|
<para>
|
||||||
|
|
|
@ -877,7 +877,7 @@ module.controller('ClientDetailCtrl', function($scope, realm, client, $route, se
|
||||||
$scope.viewImportDetails = function() {
|
$scope.viewImportDetails = function() {
|
||||||
$modal.open({
|
$modal.open({
|
||||||
templateUrl: resourceUrl + '/partials/modal/view-object.html',
|
templateUrl: resourceUrl + '/partials/modal/view-object.html',
|
||||||
controller: 'JsonModalCtrl',
|
controller: 'ObjectModalCtrl',
|
||||||
resolve: {
|
resolve: {
|
||||||
object: function () {
|
object: function () {
|
||||||
return $scope.client;
|
return $scope.client;
|
||||||
|
|
|
@ -37,7 +37,7 @@
|
||||||
<td>{{mapper.name}}</td>
|
<td>{{mapper.name}}</td>
|
||||||
<td>{{mapperTypes[mapper.protocolMapper].category}}</td>
|
<td>{{mapperTypes[mapper.protocolMapper].category}}</td>
|
||||||
<td>{{mapperTypes[mapper.protocolMapper].name}}</td>
|
<td>{{mapperTypes[mapper.protocolMapper].name}}</td>
|
||||||
<td><input type="checkbox" ng-model="mapper.isChecked"></td>
|
<td><input type="checkbox" ng-model="mapper.isChecked" id="{{mapper.protocolMapper}}"></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr data-ng-show="mappers.length == 0">
|
<tr data-ng-show="mappers.length == 0">
|
||||||
<td>{{:: 'no-mappers-available' | translate}}</td>
|
<td>{{:: 'no-mappers-available' | translate}}</td>
|
||||||
|
|
|
@ -54,7 +54,7 @@
|
||||||
<div class="form-group" data-ng-show="realm.otpPolicyType == 'hotp'">
|
<div class="form-group" data-ng-show="realm.otpPolicyType == 'hotp'">
|
||||||
<label class="col-md-2 control-label" for="counter">Initial Counter</label>
|
<label class="col-md-2 control-label" for="counter">Initial Counter</label>
|
||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
<input class="form-control" type="text" id="counter" name="counter" data-ng-model="realm.otpPolicyInitialCounter" autofocus>
|
<input class="form-control" type="number" required min="1" max="120" id="counter" name="counter" data-ng-model="realm.otpPolicyInitialCounter" autofocus>
|
||||||
</div>
|
</div>
|
||||||
<kc-tooltip>What should the initial counter value be?</kc-tooltip>
|
<kc-tooltip>What should the initial counter value be?</kc-tooltip>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -20,8 +20,8 @@
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr ng-repeat="requiredAction in requiredActions" data-ng-show="requiredActions.length > 0">
|
<tr ng-repeat="requiredAction in requiredActions" data-ng-show="requiredActions.length > 0">
|
||||||
<td>{{requiredAction.name}}</td>
|
<td>{{requiredAction.name}}</td>
|
||||||
<td><input type="checkbox" ng-model="requiredAction.enabled" ng-change="updateRequiredAction(requiredAction)"></td>
|
<td><input type="checkbox" ng-model="requiredAction.enabled" ng-change="updateRequiredAction(requiredAction)" id="{{requiredAction.alias}}.enabled"></td>
|
||||||
<td><input type="checkbox" ng-model="requiredAction.defaultAction" ng-change="updateRequiredAction(requiredAction)"></td>
|
<td><input type="checkbox" ng-model="requiredAction.defaultAction" ng-change="updateRequiredAction(requiredAction)" id="{{requiredAction.alias}}.defaultAction"></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr data-ng-show="requiredActions.length == 0">
|
<tr data-ng-show="requiredActions.length == 0">
|
||||||
<td>No required actions configured</td>
|
<td>No required actions configured</td>
|
||||||
|
|
|
@ -43,21 +43,21 @@
|
||||||
<groupId>org.eclipse.jetty</groupId>
|
<groupId>org.eclipse.jetty</groupId>
|
||||||
<artifactId>jetty-server</artifactId>
|
<artifactId>jetty-server</artifactId>
|
||||||
<version>${jetty9.version}</version>
|
<version>${jetty9.version}</version>
|
||||||
<scope>compile</scope>
|
<scope>provided</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.eclipse.jetty</groupId>
|
<groupId>org.eclipse.jetty</groupId>
|
||||||
<artifactId>jetty-util</artifactId>
|
<artifactId>jetty-util</artifactId>
|
||||||
<version>${jetty9.version}</version>
|
<version>${jetty9.version}</version>
|
||||||
<scope>compile</scope>
|
<scope>provided</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.eclipse.jetty</groupId>
|
<groupId>org.eclipse.jetty</groupId>
|
||||||
<artifactId>jetty-security</artifactId>
|
<artifactId>jetty-security</artifactId>
|
||||||
<version>${jetty9.version}</version>
|
<version>${jetty9.version}</version>
|
||||||
<scope>compile</scope>
|
<scope>provided</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
|
|
|
@ -153,23 +153,23 @@
|
||||||
+ '&response_type=code';
|
+ '&response_type=code';
|
||||||
|
|
||||||
if (options && options.prompt) {
|
if (options && options.prompt) {
|
||||||
url += '&prompt=' + options.prompt;
|
url += '&prompt=' + encodeURIComponent(options.prompt);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (options && options.loginHint) {
|
if (options && options.loginHint) {
|
||||||
url += '&login_hint=' + options.loginHint;
|
url += '&login_hint=' + encodeURIComponent(options.loginHint);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (options && options.idpHint) {
|
if (options && options.idpHint) {
|
||||||
url += '&kc_idp_hint=' + options.idpHint;
|
url += '&kc_idp_hint=' + encodeURIComponent(options.idpHint);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (options && options.scope) {
|
if (options && options.scope) {
|
||||||
url += '&scope=' + options.scope;
|
url += '&scope=' + encodeURIComponent(options.scope);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (options && options.locale) {
|
if (options && options.locale) {
|
||||||
url += '&ui_locales=' + options.locale;
|
url += '&ui_locales=' + encodeURIComponent(options.locale);
|
||||||
}
|
}
|
||||||
|
|
||||||
return url;
|
return url;
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
package org.keycloak.adapters.osgi;
|
package org.keycloak.adapters.osgi;
|
||||||
|
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
|
import java.security.SecureRandom;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Random;
|
|
||||||
|
|
||||||
import org.eclipse.jetty.security.ConstraintMapping;
|
import org.eclipse.jetty.security.ConstraintMapping;
|
||||||
import org.eclipse.jetty.util.security.Constraint;
|
import org.eclipse.jetty.util.security.Constraint;
|
||||||
|
@ -133,7 +133,8 @@ public class PaxWebIntegrationService {
|
||||||
Constraint constraint = constraintMapping.getConstraint();
|
Constraint constraint = constraintMapping.getConstraint();
|
||||||
String[] roles = constraint.getRoles();
|
String[] roles = constraint.getRoles();
|
||||||
// name property is unavailable on constraint object :/
|
// name property is unavailable on constraint object :/
|
||||||
String name = "Constraint-" + new Random().nextInt();
|
|
||||||
|
String name = "Constraint-" + new SecureRandom().nextInt(Integer.MAX_VALUE);
|
||||||
|
|
||||||
int dataConstraint = constraint.getDataConstraint();
|
int dataConstraint = constraint.getDataConstraint();
|
||||||
String dataConstraintStr;
|
String dataConstraintStr;
|
||||||
|
|
|
@ -3,15 +3,15 @@ package org.keycloak.provider;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Marker interface for ProviderFactory of Provider which wants to show some info on "Server Info" page in Admin console.
|
* Marker interface for {@link ProviderFactory} of Provider which wants to show some info on "Server Info" page in Admin console.
|
||||||
*
|
*
|
||||||
* @author Vlastimil Elias (velias at redhat dot com)
|
* @author Vlastimil Elias (velias at redhat dot com)
|
||||||
*/
|
*/
|
||||||
public interface ServerInfoAwareProviderFactory<T extends Provider> extends ProviderFactory<T> {
|
public interface ServerInfoAwareProviderFactory {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get operational info about given provider. This info contains informations about providers configuration and operational conditions (eg. errors in connection to remote systems etc) which is
|
* Return actual info about the provider. This info contains informations about providers configuration and operational conditions (eg. errors in connection to remote systems etc) which is
|
||||||
* shown on "Server Info" page.
|
* shown on "Server Info" page then.
|
||||||
*
|
*
|
||||||
* @return Map with keys describing value and relevant values itself
|
* @return Map with keys describing value and relevant values itself
|
||||||
*/
|
*/
|
||||||
|
|
4
pom.xml
4
pom.xml
|
@ -48,8 +48,8 @@
|
||||||
<dom4j.version>1.6.1</dom4j.version>
|
<dom4j.version>1.6.1</dom4j.version>
|
||||||
<xml-apis.version>1.4.01</xml-apis.version>
|
<xml-apis.version>1.4.01</xml-apis.version>
|
||||||
<slf4j.version>1.7.7</slf4j.version>
|
<slf4j.version>1.7.7</slf4j.version>
|
||||||
<wildfly.version>9.0.1.Final</wildfly.version>
|
<wildfly.version>9.0.2.Final</wildfly.version>
|
||||||
<wildfly.core.version>1.0.1.Final</wildfly.core.version>
|
<wildfly.core.version>1.0.2.Final</wildfly.core.version>
|
||||||
<wildfly.build-tools.version>1.0.0.Final</wildfly.build-tools.version>
|
<wildfly.build-tools.version>1.0.0.Final</wildfly.build-tools.version>
|
||||||
|
|
||||||
<!-- this is EAP 6.4 alpha, publicly available -->
|
<!-- this is EAP 6.4 alpha, publicly available -->
|
||||||
|
|
|
@ -1,5 +1,17 @@
|
||||||
package org.keycloak.services.resources.admin.info;
|
package org.keycloak.services.resources.admin.info;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.ServiceLoader;
|
||||||
|
|
||||||
|
import javax.ws.rs.GET;
|
||||||
|
import javax.ws.rs.core.Context;
|
||||||
|
|
||||||
import org.keycloak.broker.provider.IdentityProvider;
|
import org.keycloak.broker.provider.IdentityProvider;
|
||||||
import org.keycloak.broker.provider.IdentityProviderFactory;
|
import org.keycloak.broker.provider.IdentityProviderFactory;
|
||||||
import org.keycloak.events.EventType;
|
import org.keycloak.events.EventType;
|
||||||
|
@ -21,10 +33,6 @@ import org.keycloak.representations.idm.ProtocolMapperRepresentation;
|
||||||
import org.keycloak.representations.idm.ProtocolMapperTypeRepresentation;
|
import org.keycloak.representations.idm.ProtocolMapperTypeRepresentation;
|
||||||
import org.keycloak.social.SocialIdentityProvider;
|
import org.keycloak.social.SocialIdentityProvider;
|
||||||
|
|
||||||
import javax.ws.rs.GET;
|
|
||||||
import javax.ws.rs.core.Context;
|
|
||||||
import java.util.*;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||||
*/
|
*/
|
||||||
|
@ -73,7 +81,6 @@ public class ServerInfoAdminResource {
|
||||||
for (Spi spi : spis) {
|
for (Spi spi : spis) {
|
||||||
SpiInfoRepresentation spiRep = new SpiInfoRepresentation();
|
SpiInfoRepresentation spiRep = new SpiInfoRepresentation();
|
||||||
spiRep.setInternal(spi.isInternal());
|
spiRep.setInternal(spi.isInternal());
|
||||||
spiRep.setSystemInfo(ServerInfoAwareProviderFactory.class.isAssignableFrom(spi.getProviderFactoryClass()));
|
|
||||||
|
|
||||||
List<String> providerIds = new LinkedList<>(session.listProviderIds(spi.getProviderClass()));
|
List<String> providerIds = new LinkedList<>(session.listProviderIds(spi.getProviderClass()));
|
||||||
Collections.sort(providerIds);
|
Collections.sort(providerIds);
|
||||||
|
@ -83,8 +90,9 @@ public class ServerInfoAdminResource {
|
||||||
if (providerIds != null) {
|
if (providerIds != null) {
|
||||||
for (String name : providerIds) {
|
for (String name : providerIds) {
|
||||||
ProviderRepresentation provider = new ProviderRepresentation();
|
ProviderRepresentation provider = new ProviderRepresentation();
|
||||||
if (spiRep.isSystemInfo()) {
|
ProviderFactory<?> pi = session.getKeycloakSessionFactory().getProviderFactory(spi.getProviderClass(), name);
|
||||||
provider.setOperationalInfo(((ServerInfoAwareProviderFactory) session.getKeycloakSessionFactory().getProviderFactory(spi.getProviderClass(), name)).getOperationalInfo());
|
if (ServerInfoAwareProviderFactory.class.isAssignableFrom(pi.getClass())) {
|
||||||
|
provider.setOperationalInfo(((ServerInfoAwareProviderFactory) pi).getOperationalInfo());
|
||||||
}
|
}
|
||||||
providers.put(name, provider);
|
providers.put(name, provider);
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,6 @@ import java.util.Map;
|
||||||
public class SpiInfoRepresentation {
|
public class SpiInfoRepresentation {
|
||||||
|
|
||||||
private boolean internal;
|
private boolean internal;
|
||||||
private boolean systemInfo;
|
|
||||||
|
|
||||||
private Map<String, ProviderRepresentation> providers;
|
private Map<String, ProviderRepresentation> providers;
|
||||||
|
|
||||||
|
@ -20,14 +19,6 @@ public class SpiInfoRepresentation {
|
||||||
this.internal = internal;
|
this.internal = internal;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isSystemInfo() {
|
|
||||||
return systemInfo;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setSystemInfo(boolean systemInfo) {
|
|
||||||
this.systemInfo = systemInfo;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Map<String, ProviderRepresentation> getProviders() {
|
public Map<String, ProviderRepresentation> getProviders() {
|
||||||
return providers;
|
return providers;
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,18 @@
|
||||||
<exclude.console>-</exclude.console>
|
<exclude.console>-</exclude.console>
|
||||||
<exclude.account>-</exclude.account>
|
<exclude.account>-</exclude.account>
|
||||||
</properties>
|
</properties>
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.keycloak</groupId>
|
||||||
|
<artifactId>keycloak-util-embedded-ldap</artifactId>
|
||||||
|
<exclusions>
|
||||||
|
<exclusion>
|
||||||
|
<groupId>bouncycastle</groupId>
|
||||||
|
<artifactId>bcprov-jdk15</artifactId>
|
||||||
|
</exclusion>
|
||||||
|
</exclusions>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
<build>
|
<build>
|
||||||
<plugins>
|
<plugins>
|
||||||
<plugin>
|
<plugin>
|
||||||
|
|
|
@ -57,7 +57,7 @@ public class AdminConsoleRealm extends AdminConsoleRealmsRoot {
|
||||||
private WebElement rolesLink;
|
private WebElement rolesLink;
|
||||||
@FindBy(partialLinkText = "Identity Providers")
|
@FindBy(partialLinkText = "Identity Providers")
|
||||||
private WebElement identityProvidersLink;
|
private WebElement identityProvidersLink;
|
||||||
@FindBy(partialLinkText = "User Feferation")
|
@FindBy(partialLinkText = "User Federation")
|
||||||
private WebElement userFederationLink;
|
private WebElement userFederationLink;
|
||||||
@FindBy(partialLinkText = "Authentication")
|
@FindBy(partialLinkText = "Authentication")
|
||||||
private WebElement authenticationLink;
|
private WebElement authenticationLink;
|
||||||
|
|
|
@ -3,7 +3,7 @@ package org.keycloak.testsuite.console.page.authentication;
|
||||||
import org.keycloak.testsuite.console.page.AdminConsoleRealm;
|
import org.keycloak.testsuite.console.page.AdminConsoleRealm;
|
||||||
import org.openqa.selenium.WebElement;
|
import org.openqa.selenium.WebElement;
|
||||||
import org.openqa.selenium.support.FindBy;
|
import org.openqa.selenium.support.FindBy;
|
||||||
import static org.keycloak.testsuite.util.WaitUtils.waitAjaxForElement;
|
import static org.keycloak.testsuite.util.WaitUtils.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author tkyjovsk
|
* @author tkyjovsk
|
||||||
|
@ -20,6 +20,9 @@ public class Authentication extends AdminConsoleRealm {
|
||||||
@FindBy(xpath = "//div[contains(@class, 'alert-success')]")
|
@FindBy(xpath = "//div[contains(@class, 'alert-success')]")
|
||||||
private WebElement success;
|
private WebElement success;
|
||||||
|
|
||||||
|
@FindBy(xpath = "//button[@class='close']/span")
|
||||||
|
private WebElement close;
|
||||||
|
|
||||||
public String getSuccessMessage() {
|
public String getSuccessMessage() {
|
||||||
waitAjaxForElement(success);
|
waitAjaxForElement(success);
|
||||||
return success.getText();
|
return success.getText();
|
||||||
|
@ -30,6 +33,13 @@ public class Authentication extends AdminConsoleRealm {
|
||||||
return error.getText();
|
return error.getText();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void closeNotification() {
|
||||||
|
if (close.isDisplayed()) {
|
||||||
|
close.click();
|
||||||
|
}
|
||||||
|
waitAjaxForElementNotVisible(close);
|
||||||
|
}
|
||||||
|
|
||||||
public AuthenticationTabs tabs() {
|
public AuthenticationTabs tabs() {
|
||||||
return authenticationTabs;
|
return authenticationTabs;
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,11 +7,17 @@ import org.openqa.selenium.support.FindBy;
|
||||||
/**
|
/**
|
||||||
* @author tkyjovsk
|
* @author tkyjovsk
|
||||||
* @author mhajas
|
* @author mhajas
|
||||||
|
* @author Vaclav Muzikar <vmuzikar@redhat.com>
|
||||||
*/
|
*/
|
||||||
public class RequiredActions extends Authentication {
|
public class RequiredActions extends Authentication {
|
||||||
|
|
||||||
public final static String ENABLED = "enabled";
|
public final static String ENABLED = ".enabled";
|
||||||
public final static String DEFAULT_ACTION = "defaultAction";
|
public final static String DEFAULT = ".defaultAction";
|
||||||
|
public final static String CONFIGURE_TOTP = "CONFIGURE_TOTP";
|
||||||
|
public final static String UPDATE_PROFILE = "UPDATE_PROFILE";
|
||||||
|
public final static String TERMS_AND_CONDITIONS = "terms_and_conditions";
|
||||||
|
public final static String UPDATE_PASSWORD = "UPDATE_PASSWORD";
|
||||||
|
public final static String VERIFY_EMAIL = "VERIFY_EMAIL";
|
||||||
|
|
||||||
@FindBy(tagName = "table")
|
@FindBy(tagName = "table")
|
||||||
private WebElement requiredActionTable;
|
private WebElement requiredActionTable;
|
||||||
|
@ -21,51 +27,59 @@ public class RequiredActions extends Authentication {
|
||||||
return super.getUriFragment() + "/required-actions";
|
return super.getUriFragment() + "/required-actions";
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setRequiredActionValue(String row, String column, boolean value) {
|
private void setRequiredActionValue(String id, boolean value) {
|
||||||
WebElement checkbox = requiredActionTable.findElement(By.xpath("//td[text()='" + row + "']/..//input[@ng-model='requiredAction." + column + "']"));
|
WebElement checkbox = requiredActionTable.findElement(By.id(id));
|
||||||
|
|
||||||
if (checkbox.isSelected() != value) {
|
if (checkbox.isSelected() != value) {
|
||||||
checkbox.click();
|
checkbox.click();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void setRequiredActionEnabledValue(String id, boolean value) {
|
||||||
|
setRequiredActionValue(id + ENABLED, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setRequiredActionDefaultValue(String id, boolean value) {
|
||||||
|
setRequiredActionValue(id + DEFAULT, value);
|
||||||
|
}
|
||||||
|
|
||||||
public void setTermsAndConditionEnabled(boolean value) {
|
public void setTermsAndConditionEnabled(boolean value) {
|
||||||
setRequiredActionValue("Terms and Conditions", ENABLED, value);
|
setRequiredActionEnabledValue(TERMS_AND_CONDITIONS, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setTermsAndConditionDefaultAction(boolean value) {
|
public void setTermsAndConditionDefaultAction(boolean value) {
|
||||||
setRequiredActionValue("Terms and Conditions", DEFAULT_ACTION, value);
|
setRequiredActionDefaultValue(TERMS_AND_CONDITIONS, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setVerifyEmailEnabled(boolean value) {
|
public void setVerifyEmailEnabled(boolean value) {
|
||||||
setRequiredActionValue("Verify Email", ENABLED, value);
|
setRequiredActionEnabledValue(VERIFY_EMAIL, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setVerifyEmailDefaultAction(boolean value) {
|
public void setVerifyEmailDefaultAction(boolean value) {
|
||||||
setRequiredActionValue("Verify Email", DEFAULT_ACTION, value);
|
setRequiredActionDefaultValue(VERIFY_EMAIL, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setUpdatePasswordEnabled(boolean value) {
|
public void setUpdatePasswordEnabled(boolean value) {
|
||||||
setRequiredActionValue("Update Password", ENABLED, value);
|
setRequiredActionEnabledValue(UPDATE_PASSWORD, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setUpdatePasswordDefaultAction(boolean value) {
|
public void setUpdatePasswordDefaultAction(boolean value) {
|
||||||
setRequiredActionValue("Update Password", DEFAULT_ACTION, value);
|
setRequiredActionDefaultValue(UPDATE_PASSWORD, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setConfigureTotpEnabled(boolean value) {
|
public void setConfigureTotpEnabled(boolean value) {
|
||||||
setRequiredActionValue("Configure Totp", ENABLED, value);
|
setRequiredActionEnabledValue(CONFIGURE_TOTP, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setConfigureTotpDefaultAction(boolean value) {
|
public void setConfigureTotpDefaultAction(boolean value) {
|
||||||
setRequiredActionValue("Configure Totp", DEFAULT_ACTION, value);
|
setRequiredActionDefaultValue(CONFIGURE_TOTP, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setUpdateProfileEnabled(boolean value) {
|
public void setUpdateProfileEnabled(boolean value) {
|
||||||
setRequiredActionValue("Update Profile", ENABLED, value);
|
setRequiredActionEnabledValue(UPDATE_PROFILE, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setUpdateProfileDefaultAction(boolean value) {
|
public void setUpdateProfileDefaultAction(boolean value) {
|
||||||
setRequiredActionValue("Update Profile", DEFAULT_ACTION, value);
|
setRequiredActionDefaultValue(UPDATE_PROFILE, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,14 +1,112 @@
|
||||||
package org.keycloak.testsuite.console.page.clients;
|
package org.keycloak.testsuite.console.page.clients;
|
||||||
|
|
||||||
|
import org.keycloak.representations.idm.ProtocolMapperRepresentation;
|
||||||
|
import org.keycloak.testsuite.console.page.fragment.DataTable;
|
||||||
|
import org.openqa.selenium.By;
|
||||||
|
import org.openqa.selenium.WebElement;
|
||||||
|
import org.openqa.selenium.support.FindBy;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @author tkyjovsk
|
* @author tkyjovsk
|
||||||
|
* @author Vaclav Muzikar <vmuzikar@redhat.com>
|
||||||
*/
|
*/
|
||||||
public class ClientMappers extends Client {
|
public class ClientMappers extends Client {
|
||||||
|
|
||||||
|
public static final String ADD_BUILTIN = "Add Builtin";
|
||||||
|
|
||||||
|
@FindBy(tagName = "table")
|
||||||
|
private ClientMapperTable table;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getUriFragment() {
|
public String getUriFragment() {
|
||||||
return super.getUriFragment() + "/mappers";
|
return super.getUriFragment() + "/mappers";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ClientMapperTable mapperTable() {
|
||||||
|
return table;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ClientMapperTable extends DataTable {
|
||||||
|
|
||||||
|
public List<ProtocolMapperRepresentation> searchMappings(String searchPattern) {
|
||||||
|
search(searchPattern);
|
||||||
|
return getMappingsFromRows();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void createMapper() {
|
||||||
|
waitAjaxForBody();
|
||||||
|
clickHeaderLink(CREATE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addBuiltin() {
|
||||||
|
waitAjaxForBody();
|
||||||
|
clickHeaderLink(ADD_BUILTIN);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void clickMapper(String mapperName) {
|
||||||
|
waitAjaxForBody();
|
||||||
|
body().findElement(By.linkText(mapperName)).click();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void clickMapper(ProtocolMapperRepresentation mapper) {
|
||||||
|
clickMapper(mapper.getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void clickMapperActionButton(String mapperName, String buttonText) {
|
||||||
|
waitAjaxForBody();
|
||||||
|
clickRowActionButton(getRowByLinkText(mapperName), buttonText);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void clickMapperActionButton(ProtocolMapperRepresentation mapper, String buttonName) {
|
||||||
|
clickMapperActionButton(mapper.getName(), buttonName);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void editMapper(String mapperName) {
|
||||||
|
clickMapperActionButton(mapperName, EDIT);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void editMapper(ProtocolMapperRepresentation mapper) {
|
||||||
|
clickMapperActionButton(mapper, EDIT);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void deleteMapper(String mapperName) {
|
||||||
|
clickMapperActionButton(mapperName, DELETE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void deleteMapper(ProtocolMapperRepresentation mapper) {
|
||||||
|
clickMapperActionButton(mapper, DELETE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ProtocolMapperRepresentation getMappingFromRow(WebElement row) {
|
||||||
|
if (!row.isDisplayed()) {return null;} // Is that necessary?
|
||||||
|
|
||||||
|
ProtocolMapperRepresentation mappingsRepresentation = new ProtocolMapperRepresentation();
|
||||||
|
List<WebElement> cols = row.findElements(By.tagName("td"));
|
||||||
|
|
||||||
|
|
||||||
|
mappingsRepresentation.setName(cols.get(0).getText());
|
||||||
|
//mappingsRepresentation.setProtocol(cols.get(1).getText());
|
||||||
|
mappingsRepresentation.setProtocolMapper(cols.get(2).getText());
|
||||||
|
|
||||||
|
return mappingsRepresentation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<ProtocolMapperRepresentation> getMappingsFromRows() {
|
||||||
|
List<ProtocolMapperRepresentation> mappings = new ArrayList<ProtocolMapperRepresentation>();
|
||||||
|
|
||||||
|
for (WebElement row : rows()) {
|
||||||
|
ProtocolMapperRepresentation mapperRepresentation = getMappingFromRow(row);
|
||||||
|
if (mapperRepresentation != null) {
|
||||||
|
mappings.add(mapperRepresentation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return mappings;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
package org.keycloak.testsuite.console.page.clients;
|
||||||
|
|
||||||
|
import org.jboss.arquillian.graphene.page.Page;
|
||||||
|
import org.keycloak.testsuite.console.page.AdminConsoleCreate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Vaclav Muzikar <vmuzikar@redhat.com>
|
||||||
|
*/
|
||||||
|
public class CreateClientMappers extends AdminConsoleCreate {
|
||||||
|
|
||||||
|
@Page
|
||||||
|
private CreateClientMappersForm form;
|
||||||
|
|
||||||
|
public CreateClientMappers() {
|
||||||
|
setEntity("mappers");
|
||||||
|
}
|
||||||
|
|
||||||
|
public CreateClientMappersForm form() {
|
||||||
|
return form;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,187 @@
|
||||||
|
package org.keycloak.testsuite.console.page.clients;
|
||||||
|
|
||||||
|
import org.jboss.arquillian.test.api.ArquillianResource;
|
||||||
|
import org.keycloak.testsuite.console.page.fragment.OnOffSwitch;
|
||||||
|
import org.keycloak.testsuite.page.Form;
|
||||||
|
import org.openqa.selenium.By;
|
||||||
|
import org.openqa.selenium.WebElement;
|
||||||
|
import org.openqa.selenium.interactions.Actions;
|
||||||
|
import org.openqa.selenium.support.FindBy;
|
||||||
|
import org.openqa.selenium.support.ui.Select;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Vaclav Muzikar <vmuzikar@redhat.com>
|
||||||
|
*
|
||||||
|
* TODO: SAML
|
||||||
|
*/
|
||||||
|
public class CreateClientMappersForm extends Form {
|
||||||
|
|
||||||
|
// Mappers types
|
||||||
|
public static final String HARDCODED_ROLE = "Hardcoded Role";
|
||||||
|
public static final String HARDCODED_CLAIM = "Hardcoded claim";
|
||||||
|
public static final String USER_SESSION_NOTE = "User Session Note";
|
||||||
|
public static final String ROLE_NAME_MAPPER = "Role Name Mapper";
|
||||||
|
public static final String USER_ADDRESS = "User Address";
|
||||||
|
public static final String USERS_FULL_NAME = "User's full name";
|
||||||
|
public static final String USER_ATTRIBUTE = "User Attribute";
|
||||||
|
public static final String USER_PROPERTY = "User Property";
|
||||||
|
|
||||||
|
@FindBy(id = "name")
|
||||||
|
private WebElement nameElement;
|
||||||
|
|
||||||
|
@FindBy(xpath = ".//div[@class='onoffswitch' and ./input[@id='consentRequired']]")
|
||||||
|
private OnOffSwitch consentRequiredSwitch;
|
||||||
|
|
||||||
|
@FindBy(id = "consentText")
|
||||||
|
private WebElement consentTextElement;
|
||||||
|
|
||||||
|
@FindBy(id = "mapperTypeCreate")
|
||||||
|
private Select mapperTypeSelect;
|
||||||
|
|
||||||
|
@FindBy(xpath = ".//div[@properties='mapperType.properties']//label[text()='Property']//following-sibling::node()//input[@type='text']")
|
||||||
|
private WebElement propertyInput;
|
||||||
|
|
||||||
|
@FindBy(xpath = ".//div[@properties='mapperType.properties']//label[text()='User Attribute']//following-sibling::node()//input[@type='text']")
|
||||||
|
private WebElement userAttributeInput;
|
||||||
|
|
||||||
|
@FindBy(xpath = ".//div[@properties='mapperType.properties']//label[text()='User Session Note']//following-sibling::node()//input[@type='text']")
|
||||||
|
private WebElement userSessionNoteInput;
|
||||||
|
|
||||||
|
@FindBy(xpath = ".//div[@properties='mapperType.properties']//label[text()='Multivalued']//following-sibling::node()//div[@class='onoffswitch']")
|
||||||
|
private OnOffSwitch multivaluedInput;
|
||||||
|
|
||||||
|
@FindBy(xpath = ".//div[@properties='mapperType.properties']//label[text()='Role']//following-sibling::node()//input[@type='text']")
|
||||||
|
private WebElement roleInput;
|
||||||
|
|
||||||
|
@FindBy(xpath = ".//div[@properties='mapperType.properties']//label[text()='New Role Name']//following-sibling::node()//input[@type='text']")
|
||||||
|
private WebElement newRoleInput;
|
||||||
|
|
||||||
|
@FindBy(xpath = ".//div[@properties='mapperType.properties']//label[text()='Token Claim Name']//following-sibling::node()//input[@type='text']")
|
||||||
|
private WebElement tokenClaimNameInput;
|
||||||
|
|
||||||
|
@FindBy(xpath = ".//div[@properties='mapperType.properties']//label[text()='Claim value']//following-sibling::node()//input[@type='text']")
|
||||||
|
private WebElement tokenClaimValueInput;
|
||||||
|
|
||||||
|
@FindBy(xpath = ".//div[@properties='mapperType.properties']//label[text()='Claim JSON Type']//following-sibling::node()//select")
|
||||||
|
private Select claimJSONTypeInput;
|
||||||
|
|
||||||
|
@FindBy(xpath = ".//div[@properties='mapperType.properties']//label[text()='Add to ID token']//following-sibling::node()//div[@class='onoffswitch']")
|
||||||
|
private OnOffSwitch addToIDTokenInput;
|
||||||
|
|
||||||
|
@FindBy(xpath = ".//div[@properties='mapperType.properties']//label[text()='Add to access token']//following-sibling::node()//div[@class='onoffswitch']")
|
||||||
|
private OnOffSwitch addToAccessTokenInput;
|
||||||
|
|
||||||
|
public boolean isConsentRequired() {
|
||||||
|
return consentRequiredSwitch.isOn();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setConsentRequired(boolean consentRequired) {
|
||||||
|
consentRequiredSwitch.setOn(consentRequired);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getConsentText() {
|
||||||
|
return getInputValue(consentTextElement);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setConsentText(String consentText) {
|
||||||
|
setInputValue(consentTextElement, consentText);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getMapperType() {
|
||||||
|
return mapperTypeSelect.getFirstSelectedOption().getText();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMapperType(String type) {
|
||||||
|
mapperTypeSelect.selectByVisibleText(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getProperty() {
|
||||||
|
return getInputValue(propertyInput);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setProperty(String value) {
|
||||||
|
setInputValue(propertyInput, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUserAttribute() {
|
||||||
|
return getInputValue(userAttributeInput);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUserAttribute(String value) {
|
||||||
|
setInputValue(userAttributeInput, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUserSessionNote() {
|
||||||
|
return getInputValue(userSessionNoteInput);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUserSessionNote(String value) {
|
||||||
|
setInputValue(userSessionNoteInput, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isMultivalued() {
|
||||||
|
return multivaluedInput.isOn();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMultivalued(boolean value) {
|
||||||
|
multivaluedInput.setOn(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getRole() {
|
||||||
|
return getInputValue(roleInput);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRole(String value) {
|
||||||
|
setInputValue(roleInput, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getNewRole() {
|
||||||
|
return getInputValue(newRoleInput);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNewRole(String value) {
|
||||||
|
setInputValue(newRoleInput, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTokenClaimName() {
|
||||||
|
return getInputValue(tokenClaimNameInput);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTokenClaimName(String value) {
|
||||||
|
setInputValue(tokenClaimNameInput, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTokenClaimValue() {
|
||||||
|
return getInputValue(tokenClaimValueInput);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTokenClaimValue(String value) {
|
||||||
|
setInputValue(tokenClaimValueInput, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getClaimJSONType() {
|
||||||
|
return claimJSONTypeInput.getFirstSelectedOption().getText();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setClaimJSONType(String value) {
|
||||||
|
claimJSONTypeInput.selectByVisibleText(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isAddToIDToken() {
|
||||||
|
return addToIDTokenInput.isOn();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAddToIDToken(boolean value) {
|
||||||
|
addToIDTokenInput.setOn(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isAddToAccessToken() {
|
||||||
|
return addToAccessTokenInput.isOn();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAddToAccessToken(boolean value) {
|
||||||
|
addToAccessTokenInput.setOn(value);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,28 @@
|
||||||
|
package org.keycloak.testsuite.console.page.federation;
|
||||||
|
|
||||||
|
import org.jboss.arquillian.graphene.page.Page;
|
||||||
|
import org.keycloak.testsuite.console.page.AdminConsoleCreate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author pdrozd
|
||||||
|
*/
|
||||||
|
public class CreateKerberosUserProvider extends AdminConsoleCreate {
|
||||||
|
|
||||||
|
@Page
|
||||||
|
private KerberosUserProviderForm form;
|
||||||
|
|
||||||
|
public CreateKerberosUserProvider() {
|
||||||
|
setEntity("user-federation");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getUriFragment() {
|
||||||
|
return super.getUriFragment() + "/providers/kerberos";
|
||||||
|
}
|
||||||
|
|
||||||
|
public KerberosUserProviderForm form() {
|
||||||
|
return form;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,5 +1,6 @@
|
||||||
package org.keycloak.testsuite.console.page.federation;
|
package org.keycloak.testsuite.console.page.federation;
|
||||||
|
|
||||||
|
import org.jboss.arquillian.graphene.page.Page;
|
||||||
import org.keycloak.testsuite.console.page.AdminConsoleCreate;
|
import org.keycloak.testsuite.console.page.AdminConsoleCreate;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -8,6 +9,9 @@ import org.keycloak.testsuite.console.page.AdminConsoleCreate;
|
||||||
*/
|
*/
|
||||||
public class CreateLdapUserProvider extends AdminConsoleCreate {
|
public class CreateLdapUserProvider extends AdminConsoleCreate {
|
||||||
|
|
||||||
|
@Page
|
||||||
|
private LdapUserProviderForm form;
|
||||||
|
|
||||||
public CreateLdapUserProvider() {
|
public CreateLdapUserProvider() {
|
||||||
setEntity("user-federation");
|
setEntity("user-federation");
|
||||||
}
|
}
|
||||||
|
@ -17,4 +21,7 @@ public class CreateLdapUserProvider extends AdminConsoleCreate {
|
||||||
return super.getUriFragment() + "/providers/ldap";
|
return super.getUriFragment() + "/providers/ldap";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public LdapUserProviderForm form() {
|
||||||
|
return form;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,81 @@
|
||||||
|
package org.keycloak.testsuite.console.page.federation;
|
||||||
|
|
||||||
|
import static org.keycloak.testsuite.util.WaitUtils.waitGuiForElement;
|
||||||
|
|
||||||
|
import org.keycloak.testsuite.console.page.fragment.OnOffSwitch;
|
||||||
|
import org.keycloak.testsuite.page.Form;
|
||||||
|
import org.openqa.selenium.By;
|
||||||
|
import org.openqa.selenium.WebElement;
|
||||||
|
import org.openqa.selenium.support.FindBy;
|
||||||
|
import org.openqa.selenium.support.ui.Select;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author pdrozd
|
||||||
|
*/
|
||||||
|
public class KerberosUserProviderForm extends Form {
|
||||||
|
|
||||||
|
@FindBy(id = "consoleDisplayName")
|
||||||
|
private WebElement consoleDisplayNameInput;
|
||||||
|
|
||||||
|
@FindBy(id = "priority")
|
||||||
|
private WebElement priorityInput;
|
||||||
|
|
||||||
|
@FindBy(id = "kerberosRealm")
|
||||||
|
private WebElement kerberosRealmInput;
|
||||||
|
|
||||||
|
@FindBy(id = "serverPrincipal")
|
||||||
|
private WebElement serverPrincipalInput;
|
||||||
|
|
||||||
|
@FindBy(id = "keyTab")
|
||||||
|
private WebElement keyTabInput;
|
||||||
|
|
||||||
|
@FindBy(xpath = ".//div[contains(@class,'onoffswitch') and ./input[@id='debug']]")
|
||||||
|
private OnOffSwitch debug;
|
||||||
|
|
||||||
|
@FindBy(xpath = ".//div[contains(@class,'onoffswitch') and ./input[@id='allowPasswordAuthentication']]")
|
||||||
|
private OnOffSwitch allowPwdAuth;
|
||||||
|
|
||||||
|
@FindBy(id = "editMode")
|
||||||
|
private Select editModeSelect;
|
||||||
|
|
||||||
|
@FindBy(xpath = ".//div[contains(@class,'onoffswitch') and ./input[@id='updateProfileFirstLogin']]")
|
||||||
|
private OnOffSwitch updateProfileFirstLogin;
|
||||||
|
|
||||||
|
public void setConsoleDisplayNameInput(String name) {
|
||||||
|
setInputValue(consoleDisplayNameInput, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPriorityInput(Integer priority) {
|
||||||
|
setInputValue(priorityInput, String.valueOf(priority));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setKerberosRealmInput(String kerberosRealm) {
|
||||||
|
waitGuiForElement(By.id("kerberosRealm"));
|
||||||
|
setInputValue(kerberosRealmInput, kerberosRealm);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setServerPrincipalInput(String serverPrincipal) {
|
||||||
|
setInputValue(serverPrincipalInput, serverPrincipal);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setKeyTabInput(String keyTab) {
|
||||||
|
setInputValue(keyTabInput, keyTab);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDebugEnabled(boolean debugEnabled) {
|
||||||
|
this.debug.setOn(debugEnabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAllowPasswordAuthentication(boolean enabled) {
|
||||||
|
allowPwdAuth.setOn(enabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void selectEditMode(String mode) {
|
||||||
|
waitGuiForElement(By.id("editMode"));
|
||||||
|
editModeSelect.selectByVisibleText(mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUpdateProfileFirstLogin(boolean enabled) {
|
||||||
|
updateProfileFirstLogin.setOn(enabled);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,5 +1,8 @@
|
||||||
package org.keycloak.testsuite.console.page.federation;
|
package org.keycloak.testsuite.console.page.federation;
|
||||||
|
|
||||||
|
import static org.keycloak.testsuite.util.WaitUtils.waitAjaxForElement;
|
||||||
|
import static org.keycloak.testsuite.util.WaitUtils.waitGuiForElement;
|
||||||
|
|
||||||
import org.jboss.arquillian.graphene.findby.FindByJQuery;
|
import org.jboss.arquillian.graphene.findby.FindByJQuery;
|
||||||
import org.keycloak.testsuite.console.page.fragment.OnOffSwitch;
|
import org.keycloak.testsuite.console.page.fragment.OnOffSwitch;
|
||||||
import org.keycloak.testsuite.page.Form;
|
import org.keycloak.testsuite.page.Form;
|
||||||
|
@ -8,10 +11,8 @@ import org.openqa.selenium.WebElement;
|
||||||
import org.openqa.selenium.support.FindBy;
|
import org.openqa.selenium.support.FindBy;
|
||||||
import org.openqa.selenium.support.ui.Select;
|
import org.openqa.selenium.support.ui.Select;
|
||||||
|
|
||||||
import static org.keycloak.testsuite.util.WaitUtils.waitGuiForElement;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by fkiss.
|
* @author fkiss, pdrozd
|
||||||
*/
|
*/
|
||||||
public class LdapUserProviderForm extends Form {
|
public class LdapUserProviderForm extends Form {
|
||||||
|
|
||||||
|
@ -24,24 +25,33 @@ public class LdapUserProviderForm extends Form {
|
||||||
@FindBy(id = "usernameLDAPAttribute")
|
@FindBy(id = "usernameLDAPAttribute")
|
||||||
private WebElement usernameLDAPAttributeInput;
|
private WebElement usernameLDAPAttributeInput;
|
||||||
|
|
||||||
|
@FindBy(id = "rdnLDAPAttribute")
|
||||||
|
private WebElement rdnLDAPAttributeInput;
|
||||||
|
|
||||||
|
@FindBy(id = "uuidLDAPAttribute")
|
||||||
|
private WebElement uuidLDAPAttributeInput;
|
||||||
|
|
||||||
@FindBy(id = "userObjectClasses")
|
@FindBy(id = "userObjectClasses")
|
||||||
private WebElement userObjectClassesInput;
|
private WebElement userObjectClassesInput;
|
||||||
|
|
||||||
@FindBy(id = "ldapConnectionUrl")
|
@FindBy(id = "ldapConnectionUrl")
|
||||||
private WebElement ldapConnectionUrlInput;
|
private WebElement ldapConnectionUrlInput;
|
||||||
|
|
||||||
@FindBy(id = "ldapBaseDn")
|
|
||||||
private WebElement ldapBaseDnInput;
|
|
||||||
|
|
||||||
@FindBy(id = "ldapUsersDn")
|
@FindBy(id = "ldapUsersDn")
|
||||||
private WebElement ldapUserDnInput;
|
private WebElement ldapUserDnInput;
|
||||||
|
|
||||||
|
@FindBy(id = "authType")
|
||||||
|
private Select authTypeSelect;
|
||||||
|
|
||||||
@FindBy(id = "ldapBindDn")
|
@FindBy(id = "ldapBindDn")
|
||||||
private WebElement ldapBindDnInput;
|
private WebElement ldapBindDnInput;
|
||||||
|
|
||||||
@FindBy(id = "ldapBindCredential")
|
@FindBy(id = "ldapBindCredential")
|
||||||
private WebElement ldapBindCredentialInput;
|
private WebElement ldapBindCredentialInput;
|
||||||
|
|
||||||
|
@FindBy(id = "searchScope")
|
||||||
|
private Select searchScopeSelect;
|
||||||
|
|
||||||
@FindBy(id = "kerberosRealm")
|
@FindBy(id = "kerberosRealm")
|
||||||
private WebElement kerberosRealmInput;
|
private WebElement kerberosRealmInput;
|
||||||
|
|
||||||
|
@ -72,59 +82,173 @@ public class LdapUserProviderForm extends Form {
|
||||||
@FindByJQuery("a:contains('Test authentication')")
|
@FindByJQuery("a:contains('Test authentication')")
|
||||||
private WebElement testAuthenticationButton;
|
private WebElement testAuthenticationButton;
|
||||||
|
|
||||||
@FindByJQuery("div[class='onoffswitch']:eq(0)")
|
@FindByJQuery("a:contains('Synchronize changed users')")
|
||||||
|
private WebElement synchronizeChangedUsersButton;
|
||||||
|
|
||||||
|
@FindByJQuery("button:contains('Synchronize all users')")
|
||||||
|
private WebElement synchronizeAllUsersButton;
|
||||||
|
|
||||||
|
@FindBy(xpath = ".//div[contains(@class,'onoffswitch') and ./input[@id='syncRegistrations']]")
|
||||||
private OnOffSwitch syncRegistrations;
|
private OnOffSwitch syncRegistrations;
|
||||||
|
|
||||||
@FindByJQuery("div[class='onoffswitch']:eq(1)")
|
@FindBy(xpath = ".//div[contains(@class,'onoffswitch') and ./input[@id='connectionPooling']]")
|
||||||
private OnOffSwitch connectionPooling;
|
private OnOffSwitch connectionPooling;
|
||||||
|
|
||||||
@FindByJQuery("div[class='onoffswitch']:eq(2)")
|
@FindBy(xpath = ".//div[contains(@class,'onoffswitch') and ./input[@id='pagination']]")
|
||||||
private OnOffSwitch pagination;
|
private OnOffSwitch pagination;
|
||||||
|
|
||||||
@FindByJQuery("div[class='onoffswitch']:eq(3)")
|
@FindBy(xpath = ".//div[contains(@class,'onoffswitch') and ./input[@id='userAccountControlsAfterPasswordUpdate']]")
|
||||||
|
private OnOffSwitch enableAccountAfterPasswordUpdate;
|
||||||
|
|
||||||
|
@FindBy(xpath = "//div[contains(@class,'onoffswitch') and ./input[@id='allowKerberosAuthentication']]")
|
||||||
private OnOffSwitch allowKerberosAuth;
|
private OnOffSwitch allowKerberosAuth;
|
||||||
|
|
||||||
@FindByJQuery("div[class='onoffswitch']:eq(4)")
|
@FindBy(xpath = ".//div[contains(@class,'onoffswitch') and ./input[@id='debug']]")
|
||||||
private OnOffSwitch debug;
|
private OnOffSwitch debug;
|
||||||
|
|
||||||
@FindByJQuery("div[class='onoffswitch']:eq(5)")
|
@FindBy(xpath = ".//div[contains(@class,'onoffswitch') and ./input[@id='useKerberosForPasswordAuthentication']]")
|
||||||
private OnOffSwitch useKerberosForPwdAuth;
|
private OnOffSwitch useKerberosForPwdAuth;
|
||||||
|
|
||||||
@FindByJQuery("div[class='onoffswitch']:eq(6)")
|
@FindBy(xpath = ".//div[contains(@class,'onoffswitch') and ./input[@id='compositeSwitch']]")
|
||||||
private OnOffSwitch periodicFullSync;
|
private OnOffSwitch periodicFullSync;
|
||||||
|
|
||||||
@FindByJQuery("div[class='onoffswitch']:eq(7)")
|
@FindBy(xpath = ".//div[contains(@class,'onoffswitch') and ./input[@id='changedSyncEnabled']]")
|
||||||
private OnOffSwitch periodicChangedUsersSync;
|
private OnOffSwitch periodicChangedUsersSync;
|
||||||
|
|
||||||
@FindByJQuery("button:contains('Save')")
|
public void setConsoleDisplayNameInput(String name) {
|
||||||
private WebElement saveButton;
|
setInputValue(consoleDisplayNameInput, name);
|
||||||
|
}
|
||||||
|
|
||||||
public void selectEditMode(String mode){
|
public void setPriorityInput(Integer priority) {
|
||||||
|
setInputValue(priorityInput, String.valueOf(priority));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUsernameLDAPAttributeInput(String usernameLDAPAttribute) {
|
||||||
|
setInputValue(usernameLDAPAttributeInput, usernameLDAPAttribute);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRdnLDAPAttributeInput(String rdnLDAPAttribute) {
|
||||||
|
setInputValue(rdnLDAPAttributeInput, rdnLDAPAttribute);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUuidLDAPAttributeInput(String uuidLDAPAttribute) {
|
||||||
|
setInputValue(uuidLDAPAttributeInput, uuidLDAPAttribute);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUserObjectClassesInput(String userObjectClasses) {
|
||||||
|
setInputValue(userObjectClassesInput, userObjectClasses);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLdapConnectionUrlInput(String ldapConnectionUrl) {
|
||||||
|
setInputValue(ldapConnectionUrlInput, ldapConnectionUrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLdapUserDnInput(String ldapUserDn) {
|
||||||
|
setInputValue(ldapUserDnInput, ldapUserDn);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLdapBindDnInput(String ldapBindDn) {
|
||||||
|
setInputValue(ldapBindDnInput, ldapBindDn);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLdapBindCredentialInput(String ldapBindCredential) {
|
||||||
|
setInputValue(ldapBindCredentialInput, ldapBindCredential);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setKerberosRealmInput(String kerberosRealm) {
|
||||||
|
waitAjaxForElement(kerberosRealmInput);
|
||||||
|
setInputValue(kerberosRealmInput, kerberosRealm);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setServerPrincipalInput(String serverPrincipal) {
|
||||||
|
waitAjaxForElement(serverPrincipalInput);
|
||||||
|
setInputValue(serverPrincipalInput, serverPrincipal);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setKeyTabInput(String keyTab) {
|
||||||
|
waitAjaxForElement(keyTabInput);
|
||||||
|
setInputValue(keyTabInput, keyTab);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBatchSizeForSyncInput(String batchSizeForSync) {
|
||||||
|
setInputValue(batchSizeForSyncInput, batchSizeForSync);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void selectEditMode(String mode) {
|
||||||
waitGuiForElement(By.id("editMode"));
|
waitGuiForElement(By.id("editMode"));
|
||||||
editModeSelect.selectByVisibleText(mode);
|
editModeSelect.selectByVisibleText(mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void selectVendor(String vendor){
|
public void selectVendor(String vendor) {
|
||||||
waitGuiForElement(By.id("editMode"));
|
waitGuiForElement(By.id("vendor"));
|
||||||
vendorSelect.selectByVisibleText(vendor);
|
vendorSelect.selectByVisibleText(vendor);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void configureLdap(String displayName, String editMode, String vendor, String connectionUrl, String userDN, String ldapBindDn, String ldapBindCredential){
|
public void selectAuthenticationType(String authenticationType) {
|
||||||
consoleDisplayNameInput.sendKeys(displayName);
|
waitGuiForElement(By.id("authType"));
|
||||||
editModeSelect.selectByVisibleText(editMode);
|
authTypeSelect.selectByVisibleText(authenticationType);
|
||||||
selectVendor(vendor);
|
|
||||||
ldapConnectionUrlInput.sendKeys(connectionUrl);
|
|
||||||
ldapUserDnInput.sendKeys(userDN);
|
|
||||||
ldapBindDnInput.sendKeys(ldapBindDn);
|
|
||||||
ldapBindCredentialInput.sendKeys(ldapBindCredential);
|
|
||||||
saveButton.click();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testConnection(){
|
public void selectSearchScope(String searchScope) {
|
||||||
|
waitGuiForElement(By.id("searchScope"));
|
||||||
|
searchScopeSelect.selectByVisibleText(searchScope);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSyncRegistrationsEnabled(boolean syncRegistrationsEnabled) {
|
||||||
|
this.syncRegistrations.setOn(syncRegistrationsEnabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setConnectionPoolingEnabled(boolean connectionPoolingEnabled) {
|
||||||
|
this.connectionPooling.setOn(connectionPoolingEnabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPaginationEnabled(boolean paginationEnabled) {
|
||||||
|
this.pagination.setOn(paginationEnabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAccountAfterPasswordUpdateEnabled(boolean enabled) {
|
||||||
|
if ((!enableAccountAfterPasswordUpdate.isOn() && enabled)
|
||||||
|
|| !enabled && enableAccountAfterPasswordUpdate.isOn()) {
|
||||||
|
driver.findElement(By
|
||||||
|
.xpath("//div[contains(@class,'onoffswitch') and ./input[@id='userAccountControlsAfterPasswordUpdate']]"))
|
||||||
|
.findElements(By.tagName("span")).get(0).click();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAllowKerberosAuthEnabled(boolean enabled) {
|
||||||
|
if ((!allowKerberosAuth.isOn() && enabled) || !enabled && allowKerberosAuth.isOn()) {
|
||||||
|
driver.findElement(
|
||||||
|
By.xpath("//div[contains(@class,'onoffswitch') and ./input[@id='allowKerberosAuthentication']]"))
|
||||||
|
.findElements(By.tagName("span")).get(0).click();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDebugEnabled(boolean debugEnabled) {
|
||||||
|
this.debug.setOn(debugEnabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUseKerberosForPwdAuthEnabled(boolean useKerberosForPwdAuthEnabled) {
|
||||||
|
this.useKerberosForPwdAuth.setOn(useKerberosForPwdAuthEnabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPeriodicFullSyncEnabled(boolean periodicFullSyncEnabled) {
|
||||||
|
this.periodicFullSync.setOn(periodicFullSyncEnabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPeriodicChangedUsersSyncEnabled(boolean periodicChangedUsersSyncEnabled) {
|
||||||
|
this.periodicChangedUsersSync.setOn(periodicChangedUsersSyncEnabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testConnection() {
|
||||||
testConnectionButton.click();
|
testConnectionButton.click();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testAuthentication(){
|
public void testAuthentication() {
|
||||||
testAuthenticationButton.click();
|
testAuthenticationButton.click();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void synchronizeAllUsers() {
|
||||||
|
waitAjaxForElement(synchronizeAllUsersButton);
|
||||||
|
synchronizeAllUsersButton.click();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,6 +36,14 @@ public class OnOffSwitch {
|
||||||
@ArquillianResource
|
@ArquillianResource
|
||||||
private Actions actions;
|
private Actions actions;
|
||||||
|
|
||||||
|
public OnOffSwitch() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public OnOffSwitch(WebElement root, Actions actions) {
|
||||||
|
this.root = root;
|
||||||
|
this.actions = actions;
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isOn() {
|
public boolean isOn() {
|
||||||
waitAjaxForElement(root);
|
waitAjaxForElement(root);
|
||||||
return root.findElement(By.tagName("input")).isSelected();
|
return root.findElement(By.tagName("input")).isSelected();
|
||||||
|
|
|
@ -41,6 +41,11 @@ public final class WaitUtils {
|
||||||
.element(element).is().not().present();
|
.element(element).is().not().present();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void waitAjaxForElementNotVisible(WebElement element) {
|
||||||
|
waitAjax().until()
|
||||||
|
.element(element).is().not().visible();
|
||||||
|
}
|
||||||
|
|
||||||
public static void waitGuiForElement(By element, String message) {
|
public static void waitGuiForElement(By element, String message) {
|
||||||
waitGui().until(message)
|
waitGui().until(message)
|
||||||
.element(element).is().present();
|
.element(element).is().present();
|
||||||
|
|
|
@ -24,6 +24,7 @@ package org.keycloak.testsuite.console.authentication;
|
||||||
import org.jboss.arquillian.graphene.page.Page;
|
import org.jboss.arquillian.graphene.page.Page;
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.*;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
|
import org.junit.Ignore;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.keycloak.representations.idm.RealmRepresentation;
|
import org.keycloak.representations.idm.RealmRepresentation;
|
||||||
import org.keycloak.testsuite.console.AbstractConsoleTest;
|
import org.keycloak.testsuite.console.AbstractConsoleTest;
|
||||||
|
@ -66,42 +67,58 @@ public class OTPPolicyTest extends AbstractConsoleTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@Ignore //KEYCLOAK-2051 when you close notification, it is not displayed again
|
||||||
public void invalidValuesTest() {
|
public void invalidValuesTest() {
|
||||||
otpPolicyPage.form().setValues(OTPType.TIME_BASED, OTPHashAlg.SHA1, Digits.EMPTY, "", "30");
|
otpPolicyPage.form().setValues(OTPType.TIME_BASED, OTPHashAlg.SHA1, Digits.EMPTY, "", "30");
|
||||||
assertEquals("Error! Missing or invalid field(s). Please verify the fields in red.", otpPolicyPage.getErrorMessage());
|
assertEquals("Error! Missing or invalid field(s). Please verify the fields in red.", otpPolicyPage.getErrorMessage());
|
||||||
|
otpPolicyPage.closeNotification();
|
||||||
|
otpPolicyPage.navigateTo();// workaround: input.clear() doesn't work when <input type="number" ...
|
||||||
|
|
||||||
otpPolicyPage.form().setValues(OTPType.TIME_BASED, OTPHashAlg.SHA1, Digits.EMPTY, " ", "30");
|
otpPolicyPage.form().setValues(OTPType.TIME_BASED, OTPHashAlg.SHA1, Digits.EMPTY, " ", "30");
|
||||||
assertEquals("Error! Missing or invalid field(s). Please verify the fields in red.", otpPolicyPage.getErrorMessage());
|
assertEquals("Error! Missing or invalid field(s). Please verify the fields in red.", otpPolicyPage.getErrorMessage());
|
||||||
|
otpPolicyPage.closeNotification();
|
||||||
|
otpPolicyPage.navigateTo();
|
||||||
|
|
||||||
otpPolicyPage.form().setValues(OTPType.TIME_BASED, OTPHashAlg.SHA1, Digits.EMPTY, "no number", "30");
|
otpPolicyPage.form().setValues(OTPType.TIME_BASED, OTPHashAlg.SHA1, Digits.EMPTY, "no number", "30");
|
||||||
assertEquals("Error! Missing or invalid field(s). Please verify the fields in red.", otpPolicyPage.getErrorMessage());
|
assertEquals("Error! Missing or invalid field(s). Please verify the fields in red.", otpPolicyPage.getErrorMessage());
|
||||||
|
otpPolicyPage.closeNotification();
|
||||||
|
otpPolicyPage.navigateTo();
|
||||||
|
|
||||||
RealmRepresentation realm = testRealmResource().toRepresentation();
|
RealmRepresentation realm = testRealmResource().toRepresentation();
|
||||||
assertEquals(Integer.valueOf(1), realm.getOtpPolicyLookAheadWindow());
|
assertEquals(Integer.valueOf(1), realm.getOtpPolicyLookAheadWindow());
|
||||||
|
|
||||||
otpPolicyPage.form().setValues(OTPType.TIME_BASED, OTPHashAlg.SHA1, Digits.EMPTY, "1", "");
|
otpPolicyPage.form().setValues(OTPType.TIME_BASED, OTPHashAlg.SHA1, Digits.EMPTY, "1", "");
|
||||||
assertEquals("Error! Missing or invalid field(s). Please verify the fields in red.", otpPolicyPage.getErrorMessage());
|
assertEquals("Error! Missing or invalid field(s). Please verify the fields in red.", otpPolicyPage.getErrorMessage());
|
||||||
|
otpPolicyPage.closeNotification();
|
||||||
|
otpPolicyPage.navigateTo();
|
||||||
|
|
||||||
otpPolicyPage.form().setValues(OTPType.TIME_BASED, OTPHashAlg.SHA1, Digits.EMPTY, "1", " ");
|
otpPolicyPage.form().setValues(OTPType.TIME_BASED, OTPHashAlg.SHA1, Digits.EMPTY, "1", " ");
|
||||||
assertEquals("Error! Missing or invalid field(s). Please verify the fields in red.", otpPolicyPage.getErrorMessage());
|
assertEquals("Error! Missing or invalid field(s). Please verify the fields in red.", otpPolicyPage.getErrorMessage());
|
||||||
|
otpPolicyPage.closeNotification();
|
||||||
|
otpPolicyPage.navigateTo();
|
||||||
|
|
||||||
otpPolicyPage.form().setValues(OTPType.TIME_BASED, OTPHashAlg.SHA1, Digits.EMPTY, "1", "no number");
|
otpPolicyPage.form().setValues(OTPType.TIME_BASED, OTPHashAlg.SHA1, Digits.EMPTY, "1", "no number");
|
||||||
assertEquals("Error! Missing or invalid field(s). Please verify the fields in red.", otpPolicyPage.getErrorMessage());
|
assertEquals("Error! Missing or invalid field(s). Please verify the fields in red.", otpPolicyPage.getErrorMessage());
|
||||||
|
otpPolicyPage.closeNotification();
|
||||||
|
otpPolicyPage.navigateTo();
|
||||||
|
|
||||||
realm = testRealmResource().toRepresentation();
|
realm = testRealmResource().toRepresentation();
|
||||||
assertEquals(Integer.valueOf(30), realm.getOtpPolicyPeriod());
|
assertEquals(Integer.valueOf(30), realm.getOtpPolicyPeriod());
|
||||||
|
|
||||||
otpPolicyPage.form().setValues(OTPType.COUNTER_BASED, OTPHashAlg.SHA1, Digits.EMPTY, "1", "");
|
otpPolicyPage.form().setValues(OTPType.COUNTER_BASED, OTPHashAlg.SHA1, Digits.EMPTY, "1", "");
|
||||||
assertEquals("Error! Missing or invalid field(s). Please verify the fields in red.", otpPolicyPage.getErrorMessage());
|
assertEquals("Error! Missing or invalid field(s). Please verify the fields in red.", otpPolicyPage.getErrorMessage());
|
||||||
|
otpPolicyPage.closeNotification();
|
||||||
|
otpPolicyPage.navigateTo();
|
||||||
|
|
||||||
otpPolicyPage.form().setValues(OTPType.COUNTER_BASED, OTPHashAlg.SHA1, Digits.EMPTY, "1", " ");
|
otpPolicyPage.form().setValues(OTPType.COUNTER_BASED, OTPHashAlg.SHA1, Digits.EMPTY, "1", " ");
|
||||||
assertEquals("Error! Missing or invalid field(s). Please verify the fields in red.", otpPolicyPage.getErrorMessage());
|
assertEquals("Error! Missing or invalid field(s). Please verify the fields in red.", otpPolicyPage.getErrorMessage());
|
||||||
|
otpPolicyPage.closeNotification();
|
||||||
|
otpPolicyPage.navigateTo();
|
||||||
|
|
||||||
otpPolicyPage.form().setValues(OTPType.COUNTER_BASED, OTPHashAlg.SHA1, Digits.EMPTY, "1", "no number");
|
otpPolicyPage.form().setValues(OTPType.COUNTER_BASED, OTPHashAlg.SHA1, Digits.EMPTY, "1", "no number");
|
||||||
assertEquals("Error! Missing or invalid field(s). Please verify the fields in red.", otpPolicyPage.getErrorMessage());
|
assertEquals("Error! Missing or invalid field(s). Please verify the fields in red.", otpPolicyPage.getErrorMessage());
|
||||||
|
otpPolicyPage.closeNotification();
|
||||||
otpPolicyPage.form().setValues(OTPType.COUNTER_BASED, OTPHashAlg.SHA1, Digits.EMPTY, "1", "1 2");
|
otpPolicyPage.navigateTo();
|
||||||
assertEquals("Error! Missing or invalid field(s). Please verify the fields in red.", otpPolicyPage.getErrorMessage());
|
|
||||||
|
|
||||||
realm = testRealmResource().toRepresentation();
|
realm = testRealmResource().toRepresentation();
|
||||||
assertEquals(Integer.valueOf(0), realm.getOtpPolicyInitialCounter());
|
assertEquals(Integer.valueOf(0), realm.getOtpPolicyInitialCounter());
|
||||||
|
|
|
@ -0,0 +1,75 @@
|
||||||
|
package org.keycloak.testsuite.console.federation;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
|
import org.jboss.arquillian.graphene.page.Page;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.keycloak.representations.idm.RealmRepresentation;
|
||||||
|
import org.keycloak.representations.idm.UserFederationProviderRepresentation;
|
||||||
|
import org.keycloak.testsuite.console.AbstractConsoleTest;
|
||||||
|
import org.keycloak.testsuite.console.page.federation.CreateKerberosUserProvider;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author pdrozd
|
||||||
|
*/
|
||||||
|
public class KerberosUserFederationTest extends AbstractConsoleTest {
|
||||||
|
|
||||||
|
private static final String UNSYNCED = "UNSYNCED";
|
||||||
|
|
||||||
|
private static final String READ_ONLY = "READ_ONLY";
|
||||||
|
|
||||||
|
@Page
|
||||||
|
private CreateKerberosUserProvider createKerberosUserProvider;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void configureKerberosProvider() {
|
||||||
|
createKerberosUserProvider.navigateTo();
|
||||||
|
createKerberosUserProvider.form().setConsoleDisplayNameInput("kerberos");
|
||||||
|
createKerberosUserProvider.form().setKerberosRealmInput("KEYCLOAK.ORG");
|
||||||
|
createKerberosUserProvider.form().setServerPrincipalInput("HTTP/localhost@KEYCLOAK.ORG");
|
||||||
|
createKerberosUserProvider.form().setKeyTabInput("http.keytab");
|
||||||
|
createKerberosUserProvider.form().setDebugEnabled(true);
|
||||||
|
createKerberosUserProvider.form().setAllowPasswordAuthentication(true);
|
||||||
|
createKerberosUserProvider.form().selectEditMode(READ_ONLY);
|
||||||
|
createKerberosUserProvider.form().setUpdateProfileFirstLogin(true);
|
||||||
|
createKerberosUserProvider.form().save();
|
||||||
|
assertFlashMessageSuccess();
|
||||||
|
RealmRepresentation realm = testRealmResource().toRepresentation();
|
||||||
|
UserFederationProviderRepresentation ufpr = realm.getUserFederationProviders().get(0);
|
||||||
|
assertKerberosSetings(ufpr, "KEYCLOAK.ORG", "HTTP/localhost@KEYCLOAK.ORG", "http.keytab", "true", "true", "true");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void invalidSettingsTest() {
|
||||||
|
createKerberosUserProvider.navigateTo();
|
||||||
|
createKerberosUserProvider.form().setConsoleDisplayNameInput("kerberos");
|
||||||
|
createKerberosUserProvider.form().setServerPrincipalInput("HTTP/localhost@KEYCLOAK.ORG");
|
||||||
|
createKerberosUserProvider.form().setKeyTabInput("http.keytab");
|
||||||
|
createKerberosUserProvider.form().setDebugEnabled(true);
|
||||||
|
createKerberosUserProvider.form().setAllowPasswordAuthentication(true);
|
||||||
|
createKerberosUserProvider.form().selectEditMode(UNSYNCED);
|
||||||
|
createKerberosUserProvider.form().setUpdateProfileFirstLogin(true);
|
||||||
|
createKerberosUserProvider.form().save();
|
||||||
|
assertFlashMessageDanger();
|
||||||
|
createKerberosUserProvider.form().setServerPrincipalInput("");
|
||||||
|
createKerberosUserProvider.form().setKerberosRealmInput("KEYCLOAK.ORG");;
|
||||||
|
createKerberosUserProvider.form().save();
|
||||||
|
assertFlashMessageDanger();
|
||||||
|
createKerberosUserProvider.form().setServerPrincipalInput("HTTP/localhost@KEYCLOAK.ORG");;
|
||||||
|
createKerberosUserProvider.form().setKeyTabInput("");
|
||||||
|
createKerberosUserProvider.form().save();
|
||||||
|
assertFlashMessageDanger();
|
||||||
|
createKerberosUserProvider.form().setKeyTabInput("http.keytab");;
|
||||||
|
createKerberosUserProvider.form().save();
|
||||||
|
assertFlashMessageSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void assertKerberosSetings(UserFederationProviderRepresentation ufpr, String kerberosRealm, String serverPrincipal, String keyTab, String debug, String useKerberosForPasswordAuthentication, String updateProfileFirstLogin) {
|
||||||
|
assertEquals(kerberosRealm, ufpr.getConfig().get("kerberosRealm"));
|
||||||
|
assertEquals(serverPrincipal, ufpr.getConfig().get("serverPrincipal"));
|
||||||
|
assertEquals(keyTab, ufpr.getConfig().get("keyTab"));
|
||||||
|
assertEquals(debug, ufpr.getConfig().get("debug"));
|
||||||
|
assertEquals(useKerberosForPasswordAuthentication, ufpr.getConfig().get("allowKerberosAuthentication"));
|
||||||
|
assertEquals(updateProfileFirstLogin, ufpr.getConfig().get("updateProfileFirstLogin"));
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,71 +1,192 @@
|
||||||
package org.keycloak.testsuite.console.federation;
|
package org.keycloak.testsuite.console.federation;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
|
import java.util.Properties;
|
||||||
|
|
||||||
import org.jboss.arquillian.graphene.page.Page;
|
import org.jboss.arquillian.graphene.page.Page;
|
||||||
import org.junit.*;
|
import org.junit.Test;
|
||||||
import org.keycloak.models.LDAPConstants;
|
import org.keycloak.representations.idm.RealmRepresentation;
|
||||||
|
import org.keycloak.representations.idm.UserFederationProviderRepresentation;
|
||||||
import org.keycloak.representations.idm.UserRepresentation;
|
|
||||||
import org.keycloak.testsuite.console.AbstractConsoleTest;
|
import org.keycloak.testsuite.console.AbstractConsoleTest;
|
||||||
import org.keycloak.testsuite.console.page.federation.LdapUserProviderForm;
|
import org.keycloak.testsuite.console.page.federation.CreateLdapUserProvider;
|
||||||
import org.keycloak.testsuite.console.page.federation.UserFederation;
|
import org.keycloak.util.ldap.LDAPEmbeddedServer;
|
||||||
import org.keycloak.testsuite.console.page.users.Users;
|
|
||||||
import org.keycloak.testsuite.util.LDAPTestConfiguration;
|
|
||||||
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import static org.junit.Assert.assertTrue;
|
|
||||||
import static org.keycloak.representations.idm.CredentialRepresentation.PASSWORD;
|
|
||||||
import static org.keycloak.testsuite.admin.Users.setPasswordFor;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by fkiss.
|
* @author fkiss, pdrozd
|
||||||
*/
|
*/
|
||||||
public class LdapUserFederationTest extends AbstractConsoleTest {
|
public class LdapUserFederationTest extends AbstractConsoleTest {
|
||||||
|
|
||||||
@Page
|
private static final String UNSYNCED = "UNSYNCED";
|
||||||
private LdapUserProviderForm ldapUserProviderForm;
|
|
||||||
|
private static final String READ_ONLY = "READ_ONLY";
|
||||||
|
|
||||||
|
private static final String RED_HAT_DIRECTORY_SERVER = "Red Hat Directory Server";
|
||||||
|
|
||||||
|
private static final String WRITABLE = "WRITABLE";
|
||||||
|
|
||||||
|
private static final String ACTIVE_DIRECTORY = "Active Directory";
|
||||||
|
|
||||||
@Page
|
@Page
|
||||||
private UserFederation userFederationPage;
|
private CreateLdapUserProvider createLdapUserProvider;
|
||||||
|
|
||||||
@Page
|
@Test
|
||||||
private Users usersPage;
|
public void configureAdProvider() {
|
||||||
|
createLdapUserProvider.navigateTo();
|
||||||
|
createLdapUserProvider.form().selectVendor(ACTIVE_DIRECTORY);
|
||||||
|
createLdapUserProvider.form().setConsoleDisplayNameInput("ldap");
|
||||||
|
createLdapUserProvider.form().selectEditMode(WRITABLE);
|
||||||
|
createLdapUserProvider.form().setLdapConnectionUrlInput("ldap://localhost:389");
|
||||||
|
createLdapUserProvider.form().setLdapBindDnInput("KEYCLOAK/Administrator");
|
||||||
|
createLdapUserProvider.form().setLdapUserDnInput("ou=People,dc=keycloak,dc=org");
|
||||||
|
createLdapUserProvider.form().setLdapBindCredentialInput("secret");
|
||||||
|
createLdapUserProvider.form().setAccountAfterPasswordUpdateEnabled(false);
|
||||||
|
// enable kerberos
|
||||||
|
createLdapUserProvider.form().setAllowKerberosAuthEnabled(true);
|
||||||
|
createLdapUserProvider.form().setKerberosRealmInput("KEYCLOAK.ORG");
|
||||||
|
createLdapUserProvider.form().setServerPrincipalInput("HTTP/localhost@KEYCLOAK.ORG");
|
||||||
|
createLdapUserProvider.form().setKeyTabInput("http.keytab");
|
||||||
|
createLdapUserProvider.form().setDebugEnabled(true);
|
||||||
|
createLdapUserProvider.form().save();
|
||||||
|
assertFlashMessageSuccess();
|
||||||
|
|
||||||
@Before
|
RealmRepresentation realm = testRealmResource().toRepresentation();
|
||||||
public void beforeTestLdapUserFederation() {
|
UserFederationProviderRepresentation ufpr = realm.getUserFederationProviders().get(0);
|
||||||
//configure().userFederation();
|
assertLdapProviderSetting(ufpr, "ldap", 0, WRITABLE, "false", "ad", "1", "true", "true", "false");
|
||||||
|
assertLdapBasicMapping(ufpr, "cn", "cn", "objectGUID", "person, organizationalPerson, user",
|
||||||
|
"ou=People,dc=keycloak,dc=org");
|
||||||
|
assertLdapSyncSetings(ufpr, "1000", 0, 0);
|
||||||
|
assertLdapKerberosSetings(ufpr, "KEYCLOAK.ORG", "HTTP/localhost@KEYCLOAK.ORG", "http.keytab", "true", "false");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Ignore
|
|
||||||
@Test
|
@Test
|
||||||
public void addAndConfigureProvider() {
|
public void configureRhdsProvider() {
|
||||||
adminConsolePage.navigateTo();
|
createLdapUserProvider.navigateTo();
|
||||||
testRealmLoginPage.form().login(testUser);
|
createLdapUserProvider.form().selectVendor(RED_HAT_DIRECTORY_SERVER);
|
||||||
|
createLdapUserProvider.form().setConsoleDisplayNameInput("ldap");
|
||||||
|
createLdapUserProvider.form().selectEditMode(READ_ONLY);
|
||||||
|
createLdapUserProvider.form().setLdapConnectionUrlInput("ldap://localhost:389");
|
||||||
|
createLdapUserProvider.form().setLdapBindDnInput("uid=admin,ou=system");
|
||||||
|
createLdapUserProvider.form().setLdapUserDnInput("ou=People,dc=keycloak,dc=org");
|
||||||
|
createLdapUserProvider.form().setLdapBindCredentialInput("secret");
|
||||||
|
createLdapUserProvider.form().save();
|
||||||
|
assertFlashMessageSuccess();
|
||||||
|
|
||||||
String name = "ldapname";
|
RealmRepresentation realm = testRealmResource().toRepresentation();
|
||||||
|
UserFederationProviderRepresentation ufpr = realm.getUserFederationProviders().get(0);
|
||||||
String LDAP_CONNECTION_PROPERTIES_LOCATION = "ldap/ldap-connection.properties";
|
assertLdapProviderSetting(ufpr, "ldap", 0, READ_ONLY, "false", "rhds", "1", "true", "true", "true");
|
||||||
LDAPTestConfiguration ldapTestConfiguration = LDAPTestConfiguration.readConfiguration(LDAP_CONNECTION_PROPERTIES_LOCATION);
|
assertLdapBasicMapping(ufpr, "uid", "uid", "nsuniqueid", "inetOrgPerson, organizationalPerson",
|
||||||
|
"ou=People,dc=keycloak,dc=org");
|
||||||
UserRepresentation newUser = new UserRepresentation();
|
assertLdapSyncSetings(ufpr, "1000", 0, 0);
|
||||||
String testUsername = "defaultrole tester";
|
|
||||||
newUser.setUsername(testUsername);
|
|
||||||
setPasswordFor(newUser, PASSWORD);
|
|
||||||
|
|
||||||
Map<String,String> ldapConfig = ldapTestConfiguration.getLDAPConfig();
|
|
||||||
|
|
||||||
//addLdapProviderTest
|
|
||||||
configure().userFederation();
|
|
||||||
userFederationPage.addProvider("ldap");
|
|
||||||
ldapUserProviderForm.configureLdap(ldapConfig.get(LDAPConstants.LDAP_PROVIDER), ldapConfig.get(LDAPConstants.EDIT_MODE), ldapConfig.get(LDAPConstants.VENDOR), ldapConfig.get(LDAPConstants.CONNECTION_URL), ldapConfig.get(LDAPConstants.USERS_DN), ldapConfig.get(LDAPConstants.BIND_DN), ldapConfig.get(LDAPConstants.BIND_CREDENTIAL));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Ignore
|
|
||||||
@Test
|
@Test
|
||||||
public void caseSensitiveSearch() {
|
public void invalidSettingsTest() {
|
||||||
// This should fail for now due to case-sensitivity
|
createLdapUserProvider.navigateTo();
|
||||||
adminConsolePage.navigateTo();
|
createLdapUserProvider.form().selectVendor(ACTIVE_DIRECTORY);
|
||||||
testRealmLoginPage.form().login("johnKeycloak", "Password1");
|
createLdapUserProvider.form().setConsoleDisplayNameInput("ldap");
|
||||||
assertTrue(flashMessage.getText(), flashMessage.isDanger());
|
createLdapUserProvider.form().selectEditMode(UNSYNCED);
|
||||||
|
createLdapUserProvider.form().setLdapBindDnInput("uid=admin,ou=system");
|
||||||
|
createLdapUserProvider.form().setLdapUserDnInput("ou=People,dc=keycloak,dc=org");
|
||||||
|
createLdapUserProvider.form().setLdapBindCredentialInput("secret");
|
||||||
|
createLdapUserProvider.form().save();
|
||||||
|
assertFlashMessageDanger();
|
||||||
|
createLdapUserProvider.form().setLdapUserDnInput("");
|
||||||
|
createLdapUserProvider.form().setLdapConnectionUrlInput("ldap://localhost:389");
|
||||||
|
createLdapUserProvider.form().save();
|
||||||
|
assertFlashMessageDanger();
|
||||||
|
createLdapUserProvider.form().setLdapUserDnInput("ou=People,dc=keycloak,dc=org");
|
||||||
|
createLdapUserProvider.form().setLdapBindDnInput("");
|
||||||
|
createLdapUserProvider.form().save();
|
||||||
|
assertFlashMessageDanger();
|
||||||
|
createLdapUserProvider.form().setLdapBindDnInput("uid=admin,ou=system");
|
||||||
|
createLdapUserProvider.form().setLdapBindCredentialInput("");
|
||||||
|
createLdapUserProvider.form().save();
|
||||||
|
assertFlashMessageDanger();
|
||||||
|
createLdapUserProvider.form().setLdapBindCredentialInput("secret");
|
||||||
|
createLdapUserProvider.form().save();
|
||||||
|
assertFlashMessageSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testConnection() throws Exception {
|
||||||
|
createLdapUserProvider.navigateTo();
|
||||||
|
createLdapUserProvider.form().selectVendor("Other");
|
||||||
|
createLdapUserProvider.form().setConsoleDisplayNameInput("ldap");
|
||||||
|
createLdapUserProvider.form().selectEditMode(WRITABLE);
|
||||||
|
createLdapUserProvider.form().setLdapConnectionUrlInput("ldap://localhost:10389");
|
||||||
|
createLdapUserProvider.form().setLdapBindDnInput("uid=admin,ou=system");
|
||||||
|
createLdapUserProvider.form().setLdapUserDnInput("ou=People,dc=keycloak,dc=org");
|
||||||
|
createLdapUserProvider.form().setLdapBindCredentialInput("secret");
|
||||||
|
createLdapUserProvider.form().setAccountAfterPasswordUpdateEnabled(true);
|
||||||
|
createLdapUserProvider.form().save();
|
||||||
|
assertFlashMessageSuccess();
|
||||||
|
LDAPEmbeddedServer ldapServer = null;
|
||||||
|
try {
|
||||||
|
ldapServer = startEmbeddedLdapServer();
|
||||||
|
createLdapUserProvider.form().testConnection();
|
||||||
|
assertFlashMessageSuccess();
|
||||||
|
createLdapUserProvider.form().testAuthentication();
|
||||||
|
assertFlashMessageSuccess();
|
||||||
|
createLdapUserProvider.form().synchronizeAllUsers();
|
||||||
|
assertFlashMessageSuccess();
|
||||||
|
createLdapUserProvider.form().setLdapBindCredentialInput("secret1");
|
||||||
|
createLdapUserProvider.form().testAuthentication();
|
||||||
|
assertFlashMessageDanger();
|
||||||
|
} finally {
|
||||||
|
if (ldapServer != null) {
|
||||||
|
ldapServer.stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void assertLdapProviderSetting(UserFederationProviderRepresentation ufpr, String name, int priority,
|
||||||
|
String editMode, String syncRegistrations, String vendor, String searchScope, String connectionPooling,
|
||||||
|
String pagination, String enableAccountAfterPasswordUpdate) {
|
||||||
|
assertEquals(name, ufpr.getDisplayName());
|
||||||
|
assertEquals(priority, ufpr.getPriority());
|
||||||
|
assertEquals(editMode, ufpr.getConfig().get("editMode"));
|
||||||
|
assertEquals(syncRegistrations, ufpr.getConfig().get("syncRegistrations"));
|
||||||
|
assertEquals(vendor, ufpr.getConfig().get("vendor"));
|
||||||
|
assertEquals(searchScope, ufpr.getConfig().get("searchScope"));
|
||||||
|
assertEquals(connectionPooling, ufpr.getConfig().get("connectionPooling"));
|
||||||
|
assertEquals(pagination, ufpr.getConfig().get("pagination"));
|
||||||
|
assertEquals(enableAccountAfterPasswordUpdate, ufpr.getConfig().get("userAccountControlsAfterPasswordUpdate"));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void assertLdapBasicMapping(UserFederationProviderRepresentation ufpr, String usernameLdapAttribute,
|
||||||
|
String rdnLdapAttr, String uuidLdapAttr, String userObjectClasses, String userDN) {
|
||||||
|
assertEquals(usernameLdapAttribute, ufpr.getConfig().get("usernameLDAPAttribute"));
|
||||||
|
assertEquals(rdnLdapAttr, ufpr.getConfig().get("rdnLDAPAttribute"));
|
||||||
|
assertEquals(uuidLdapAttr, ufpr.getConfig().get("uuidLDAPAttribute"));
|
||||||
|
assertEquals(userObjectClasses, ufpr.getConfig().get("userObjectClasses"));
|
||||||
|
assertEquals(userDN, ufpr.getConfig().get("usersDn"));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void assertLdapKerberosSetings(UserFederationProviderRepresentation ufpr, String kerberosRealm,
|
||||||
|
String serverPrincipal, String keyTab, String debug, String useKerberosForPasswordAuthentication) {
|
||||||
|
assertEquals(kerberosRealm, ufpr.getConfig().get("kerberosRealm"));
|
||||||
|
assertEquals(serverPrincipal, ufpr.getConfig().get("serverPrincipal"));
|
||||||
|
assertEquals(keyTab, ufpr.getConfig().get("keyTab"));
|
||||||
|
assertEquals(debug, ufpr.getConfig().get("debug"));
|
||||||
|
assertEquals(useKerberosForPasswordAuthentication,
|
||||||
|
ufpr.getConfig().get("useKerberosForPasswordAuthentication"));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void assertLdapSyncSetings(UserFederationProviderRepresentation ufpr, String batchSize,
|
||||||
|
int periodicFullSync, int periodicChangedUsersSync) {
|
||||||
|
assertEquals(batchSize, ufpr.getConfig().get("batchSizeForSync"));
|
||||||
|
assertEquals(periodicFullSync, ufpr.getFullSyncPeriod());
|
||||||
|
assertEquals(periodicChangedUsersSync, ufpr.getChangedSyncPeriod());
|
||||||
|
}
|
||||||
|
|
||||||
|
private LDAPEmbeddedServer startEmbeddedLdapServer() throws Exception {
|
||||||
|
Properties defaultProperties = new Properties();
|
||||||
|
defaultProperties.setProperty(LDAPEmbeddedServer.PROPERTY_DSF, LDAPEmbeddedServer.DSF_INMEMORY);
|
||||||
|
defaultProperties.setProperty(LDAPEmbeddedServer.PROPERTY_LDIF_FILE, "classpath:ldap/users.ldif");
|
||||||
|
LDAPEmbeddedServer ldapEmbeddedServer = new LDAPEmbeddedServer(defaultProperties);
|
||||||
|
ldapEmbeddedServer.init();
|
||||||
|
ldapEmbeddedServer.start();
|
||||||
|
return ldapEmbeddedServer;
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
dn: dc=keycloak,dc=org
|
||||||
|
objectclass: dcObject
|
||||||
|
objectclass: organization
|
||||||
|
o: Keycloak
|
||||||
|
dc: Keycloak
|
||||||
|
|
||||||
|
dn: ou=People,dc=keycloak,dc=org
|
||||||
|
objectclass: top
|
||||||
|
objectclass: organizationalUnit
|
||||||
|
ou: People
|
||||||
|
|
||||||
|
dn: ou=RealmRoles,dc=keycloak,dc=org
|
||||||
|
objectclass: top
|
||||||
|
objectclass: organizationalUnit
|
||||||
|
ou: RealmRoles
|
||||||
|
|
||||||
|
dn: ou=FinanceRoles,dc=keycloak,dc=org
|
||||||
|
objectclass: top
|
||||||
|
objectclass: organizationalUnit
|
||||||
|
ou: FinanceRoles
|
Loading…
Reference in a new issue