Added utils for testing Keycloak - includes a quick and easy way to start keycloak, a mail server and a google authenticator simulator

This commit is contained in:
Stian Thorgersen 2013-10-01 14:51:35 +01:00
parent cd9bb6b9d9
commit 453834e807
12 changed files with 458 additions and 144 deletions

View file

@ -9,7 +9,7 @@
keycloak.init({ keycloak.init({
clientId : 'test-app', clientId : 'test-app',
clientSecret : 'password', clientSecret : 'password',
baseUrl : 'http://localhost:8081/auth', baseUrl : 'http://localhost:8081/auth-server',
realm : 'test' realm : 'test'
}); });

59
examples/js/testrealm.json Executable file
View file

@ -0,0 +1,59 @@
{
"id": "test",
"realm": "test",
"enabled": true,
"tokenLifespan": 300,
"accessCodeLifespan": 10,
"accessCodeLifespanUserAction": 600,
"sslNotRequired": true,
"cookieLoginAllowed": true,
"registrationAllowed": true,
"resetPasswordAllowed": true,
"privateKey": "MIICXAIBAAKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQABAoGAfmO8gVhyBxdqlxmIuglbz8bcjQbhXJLR2EoS8ngTXmN1bo2L90M0mUKSdc7qF10LgETBzqL8jYlQIbt+e6TH8fcEpKCjUlyq0Mf/vVbfZSNaVycY13nTzo27iPyWQHK5NLuJzn1xvxxrUeXI6A2WFpGEBLbHjwpx5WQG9A+2scECQQDvdn9NE75HPTVPxBqsEd2z10TKkl9CZxu10Qby3iQQmWLEJ9LNmy3acvKrE3gMiYNWb6xHPKiIqOR1as7L24aTAkEAtyvQOlCvr5kAjVqrEKXalj0Tzewjweuxc0pskvArTI2Oo070h65GpoIKLc9jf+UA69cRtquwP93aZKtW06U8dQJAF2Y44ks/mK5+eyDqik3koCI08qaC8HYq2wVl7G2QkJ6sbAaILtcvD92ToOvyGyeE0flvmDZxMYlvaZnaQ0lcSQJBAKZU6umJi3/xeEbkJqMfeLclD27XGEFoPeNrmdx0q10Azp4NfJAY+Z8KRyQCR2BEG+oNitBOZ+YXF9KCpH3cdmECQHEigJhYg+ykOvr1aiZUMFT72HU0jnmQe2FVekuG+LJUt2Tm7GtMjTFoGpf0JwrVuZN39fOYAlo+nTixgeW7X8Y=",
"publicKey": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
"requiredCredentials": [ "password" ],
"requiredApplicationCredentials": [ "password" ],
"requiredOAuthClientCredentials": [ "password" ],
"defaultRoles": [ "user" ],
"users" : [
{
"username" : "test-user@localhost",
"enabled": true,
"email" : "test-user@localhost",
"credentials" : [
{ "type" : "password",
"value" : "password" }
]
}
],
"roles": [
{
"name": "user",
"description": "Have User privileges"
},
{
"name": "admin",
"description": "Have Administrator privileges"
}
],
"roleMappings": [
{
"username": "test-user@localhost",
"roles": ["user"]
}
],
"applications": [
{
"name": "test-app",
"enabled": true,
"adminUrl": "http://localhost:8081/app/logout",
"useRealmMappings": true,
"credentials": [
{
"type": "password",
"value": "password"
}
]
}
]
}

View file

@ -1,14 +0,0 @@
import org.picketlink.common.util.Base32;
import org.picketlink.idm.credential.util.TimeBasedOTP;
public class TotpUtil {
public static void main(String[] args) {
String google = "PJBX GURY NZIT C2JX I44T S3D2 JBKD G6SB";
google = google.replace(" ", "");
google = new String(Base32.decode(google));
TimeBasedOTP otp = new TimeBasedOTP();
System.out.println(otp.generate(google));
}
}

View file

@ -6,4 +6,49 @@ Browser
The testsuite uses Sellenium. By default it uses the HtmlUnit WebDriver, but can also be executed with Chrome or Firefox. The testsuite uses Sellenium. By default it uses the HtmlUnit WebDriver, but can also be executed with Chrome or Firefox.
To run the tests with Firefox add `-Dbrowser=firefox` or for Chrome add `-Dbrowser=chrome` To run the tests with Firefox add `-Dbrowser=firefox` or for Chrome add `-Dbrowser=chrome`
Test utils
==========
Keycloak server
---------------
To start a basic Keycloak server for testing run:
mvn exec:java -Dexec.mainClass=org.keycloak.testutils.KeycloakServer
or just run KeycloakServer from your favourite IDE!
When starting the server it can also import a realm from a json file:
mvn exec:java -Dexec.mainClass=org.keycloak.testutils.KeycloakServer -Dexec.args="-import testrealm.json"
You can also change the host and port the server is bound to:
mvn exec:java -Dexec.mainClass=org.keycloak.testutils.KeycloakServer -Dexec.args="-b host -p 8080"
TOTP codes
----------
To generate totp codes without Google authenticator run:
mvn exec:java -Dexec.mainClass=org.keycloak.testutils.TotpGenerator -Dexec.args="PJBX GURY NZIT C2JX I44T S3D2 JBKD G6SB"
or just run TotpGenerator from your favourite IDE!
Replace value of -Dexec.args with the secret from the totp configuration page
Mail server
-----------
To start a test mail server for testing email sending run:
mvn exec:java -Dexec.mainClass=org.keycloak.testutils.MailServer
or just run MailServer from your favourite IDE!
To configure Keycloak to use the above server add:
-Dkeycloak.mail.smtp.from=auto@keycloak.org -Dkeycloak.mail.smtp.host=localhost -Dkeycloak.mail.smtp.port=3025

View file

@ -26,7 +26,6 @@
<dependency> <dependency>
<groupId>org.bouncycastle</groupId> <groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk16</artifactId> <artifactId>bcprov-jdk16</artifactId>
<scope>provided</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.keycloak</groupId> <groupId>org.keycloak</groupId>
@ -38,6 +37,11 @@
<artifactId>keycloak-services</artifactId> <artifactId>keycloak-services</artifactId>
<version>${project.version}</version> <version>${project.version}</version>
</dependency> </dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-server</artifactId>
<version>${project.version}</version>
</dependency>
<dependency> <dependency>
<groupId>org.keycloak</groupId> <groupId>org.keycloak</groupId>
<artifactId>keycloak-social-core</artifactId> <artifactId>keycloak-social-core</artifactId>
@ -67,37 +71,30 @@
<dependency> <dependency>
<groupId>org.jboss.logging</groupId> <groupId>org.jboss.logging</groupId>
<artifactId>jboss-logging</artifactId> <artifactId>jboss-logging</artifactId>
<scope>provided</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.picketlink</groupId> <groupId>org.picketlink</groupId>
<artifactId>picketlink-idm-api</artifactId> <artifactId>picketlink-idm-api</artifactId>
<scope>provided</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.picketlink</groupId> <groupId>org.picketlink</groupId>
<artifactId>picketlink-common</artifactId> <artifactId>picketlink-common</artifactId>
<scope>provided</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.picketlink</groupId> <groupId>org.picketlink</groupId>
<artifactId>picketlink-idm-impl</artifactId> <artifactId>picketlink-idm-impl</artifactId>
<scope>provided</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.picketlink</groupId> <groupId>org.picketlink</groupId>
<artifactId>picketlink-idm-simple-schema</artifactId> <artifactId>picketlink-idm-simple-schema</artifactId>
<scope>provided</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.picketlink</groupId> <groupId>org.picketlink</groupId>
<artifactId>picketlink-config</artifactId> <artifactId>picketlink-config</artifactId>
<scope>provided</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.jboss.resteasy</groupId> <groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-jaxrs</artifactId> <artifactId>resteasy-jaxrs</artifactId>
<scope>provided</scope>
<exclusions> <exclusions>
<exclusion> <exclusion>
<groupId>log4j</groupId> <groupId>log4j</groupId>
@ -116,89 +113,72 @@
<dependency> <dependency>
<groupId>org.jboss.resteasy</groupId> <groupId>org.jboss.resteasy</groupId>
<artifactId>jaxrs-api</artifactId> <artifactId>jaxrs-api</artifactId>
<scope>provided</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.jboss.resteasy</groupId> <groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-client</artifactId> <artifactId>resteasy-client</artifactId>
<scope>provided</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.jboss.resteasy</groupId> <groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-crypto</artifactId> <artifactId>resteasy-crypto</artifactId>
<scope>provided</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.jboss.resteasy</groupId> <groupId>org.jboss.resteasy</groupId>
<artifactId>jose-jwt</artifactId> <artifactId>jose-jwt</artifactId>
<scope>provided</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.jboss.resteasy</groupId> <groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-undertow</artifactId> <artifactId>resteasy-undertow</artifactId>
<scope>test</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>io.undertow</groupId> <groupId>io.undertow</groupId>
<artifactId>undertow-servlet</artifactId> <artifactId>undertow-servlet</artifactId>
<scope>test</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>io.undertow</groupId> <groupId>io.undertow</groupId>
<artifactId>undertow-core</artifactId> <artifactId>undertow-core</artifactId>
<scope>test</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.codehaus.jackson</groupId> <groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-core-asl</artifactId> <artifactId>jackson-core-asl</artifactId>
<scope>provided</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.codehaus.jackson</groupId> <groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-mapper-asl</artifactId> <artifactId>jackson-mapper-asl</artifactId>
<scope>provided</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.jboss.spec.javax.servlet</groupId> <groupId>org.jboss.spec.javax.servlet</groupId>
<artifactId>jboss-servlet-api_3.0_spec</artifactId> <artifactId>jboss-servlet-api_3.0_spec</artifactId>
<scope>provided</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.codehaus.jackson</groupId> <groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-xc</artifactId> <artifactId>jackson-xc</artifactId>
<scope>provided</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>junit</groupId> <groupId>junit</groupId>
<artifactId>junit</artifactId> <artifactId>junit</artifactId>
<scope>test</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.hibernate.javax.persistence</groupId> <groupId>org.hibernate.javax.persistence</groupId>
<artifactId>hibernate-jpa-2.0-api</artifactId> <artifactId>hibernate-jpa-2.0-api</artifactId>
<scope>provided</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.h2database</groupId> <groupId>com.h2database</groupId>
<artifactId>h2</artifactId> <artifactId>h2</artifactId>
<version>1.3.161</version> <version>1.3.161</version>
<scope>test</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.hibernate</groupId> <groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId> <artifactId>hibernate-entitymanager</artifactId>
<version>3.6.6.Final</version> <version>3.6.6.Final</version>
<scope>test</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.icegreen</groupId> <groupId>com.icegreen</groupId>
<artifactId>greenmail</artifactId> <artifactId>greenmail</artifactId>
<scope>test</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.seleniumhq.selenium</groupId> <groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId> <artifactId>selenium-java</artifactId>
<scope>test</scope>
</dependency> </dependency>
</dependencies> </dependencies>
<build> <build>

View file

@ -0,0 +1,264 @@
/*
* JBoss, Home of Professional Open Source.
* Copyright 2012, Red Hat, Inc., and individual contributors
* as indicated by the @author tags. See the copyright.txt file in the
* distribution for a full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.keycloak.testutils;
import io.undertow.Undertow;
import io.undertow.Undertow.Builder;
import io.undertow.server.handlers.resource.ClassPathResourceManager;
import io.undertow.servlet.Servlets;
import io.undertow.servlet.api.DeploymentInfo;
import io.undertow.servlet.api.FilterInfo;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import javax.servlet.DispatcherType;
import org.jboss.resteasy.jwt.JsonSerialization;
import org.jboss.resteasy.logging.Logger;
import org.jboss.resteasy.plugins.server.undertow.UndertowJaxrsServer;
import org.jboss.resteasy.spi.ResteasyDeployment;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.KeycloakSessionFactory;
import org.keycloak.models.RealmModel;
import org.keycloak.models.RoleModel;
import org.keycloak.models.UserModel;
import org.keycloak.representations.idm.CredentialRepresentation;
import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.services.FormService;
import org.keycloak.services.filters.KeycloakSessionServletFilter;
import org.keycloak.services.managers.RealmManager;
import org.keycloak.services.resources.KeycloakApplication;
import org.keycloak.services.resources.SaasService;
/**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
*/
public class KeycloakServer {
private static final Logger log = Logger.getLogger(KeycloakServer.class);
private boolean sysout = false;
public static class KeycloakServerConfig {
private String host = "localhost";
private int port = 8081;
public String getHost() {
return host;
}
public int getPort() {
return port;
}
public void setHost(String host) {
this.host = host;
}
public void setPort(int port) {
this.port = port;
}
}
private static <T> T loadJson(InputStream is, Class<T> type) {
try {
ByteArrayOutputStream os = new ByteArrayOutputStream();
int c;
while ((c = is.read()) != -1) {
os.write(c);
}
byte[] bytes = os.toByteArray();
return JsonSerialization.fromBytes(type, bytes);
} catch (IOException e) {
throw new RuntimeException("Failed to parse json", e);
}
}
public static void main(String[] args) throws Throwable {
KeycloakServerConfig config = new KeycloakServerConfig();
for (int i = 0; i < args.length; i++) {
if (args[i].equals("-b")) {
config.setHost(args[++i]);
}
if (args[i].equals("-p")) {
config.setPort(Integer.valueOf(args[++i]));
}
}
final KeycloakServer keycloak = new KeycloakServer(config);
keycloak.sysout = true;
keycloak.start();
for (int i = 0; i < args.length; i++) {
if (args[i].equals("-import")) {
keycloak.importRealm(new FileInputStream(args[++i]));
}
}
Runtime.getRuntime().addShutdownHook(new Thread() {
@Override
public void run() {
keycloak.stop();
}
});
}
private KeycloakServerConfig config;
private KeycloakSessionFactory factory;
private UndertowJaxrsServer server;
public KeycloakServer() {
this(new KeycloakServerConfig());
}
public KeycloakServer(KeycloakServerConfig config) {
this.config = config;
}
public KeycloakSessionFactory getKeycloakSessionFactory() {
return factory;
}
public UndertowJaxrsServer getServer() {
return server;
}
public void importRealm(InputStream realm) {
RealmRepresentation rep = loadJson(realm, RealmRepresentation.class);
importRealm(rep);
}
public void importRealm(RealmRepresentation rep) {
KeycloakSession session = factory.createSession();
session.getTransaction().begin();
try {
RealmManager manager = new RealmManager(session);
if (rep.getId() == null) {
throw new RuntimeException("Realm id not specified");
}
if (manager.getRealm(rep.getId()) != null) {
info("Not importing realm " + rep.getRealm() + " realm already exists");
return;
}
RealmModel realm = manager.createRealm(rep.getId(), rep.getRealm());
manager.importRealm(rep, realm);
info("Imported realm " + realm.getName());
session.getTransaction().commit();
} finally {
session.close();
}
}
protected void setupDefaultRealm() {
KeycloakSession session = factory.createSession();
session.getTransaction().begin();
try {
RealmManager manager = new RealmManager(session);
if (manager.getRealm(RealmModel.DEFAULT_REALM) != null) {
return;
}
RealmModel defaultRealm = manager.createRealm(RealmModel.DEFAULT_REALM, RealmModel.DEFAULT_REALM);
manager.generateRealmKeys(defaultRealm);
defaultRealm.setEnabled(true);
defaultRealm.setTokenLifespan(300);
defaultRealm.setAccessCodeLifespan(60);
defaultRealm.setAccessCodeLifespanUserAction(600);
defaultRealm.setSslNotRequired(false);
defaultRealm.setCookieLoginAllowed(true);
defaultRealm.setRegistrationAllowed(true);
defaultRealm.setAutomaticRegistrationAfterSocialLogin(false);
defaultRealm.setVerifyEmail(false);
defaultRealm.addRequiredCredential(CredentialRepresentation.PASSWORD);
RoleModel role = defaultRealm.addRole(SaasService.REALM_CREATOR_ROLE);
UserModel admin = defaultRealm.addUser("admin");
defaultRealm.grantRole(admin, role);
session.getTransaction().commit();
} finally {
session.close();
}
}
public void start() throws Throwable {
long start = System.currentTimeMillis();
ResteasyDeployment deployment = new ResteasyDeployment();
deployment.setApplicationClass(KeycloakApplication.class.getName());
Builder builder = Undertow.builder().addListener(config.getPort(), config.getHost());
server = new UndertowJaxrsServer().start(builder);
DeploymentInfo di = server.undertowDeployment(deployment, "rest");
di.setClassLoader(getClass().getClassLoader());
di.setContextPath("/auth-server");
di.setDeploymentName("Keycloak");
di.setResourceManager(new ClassPathResourceManager(FormService.class.getClassLoader(), "META-INF/resources"));
FilterInfo filter = Servlets.filter("SessionFilter", KeycloakSessionServletFilter.class);
di.addFilter(filter);
di.addFilterUrlMapping("SessionFilter", "/rest/*", DispatcherType.REQUEST);
server.deploy(di);
factory = KeycloakApplication.buildSessionFactory();
setupDefaultRealm();
info("Started Keycloak (http://" + config.getHost() + ":" + config.getPort() + "/auth-server) in "
+ (System.currentTimeMillis() - start) + " ms\n");
}
private void info(String message) {
if (sysout) {
System.out.println(message);
} else {
log.info(message);
}
}
public void stop() {
factory.close();
server.stop();
info("Stopped Keycloak");
}
}

View file

@ -0,0 +1,30 @@
package org.keycloak.testutils;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMessage.RecipientType;
import com.icegreen.greenmail.util.GreenMail;
import com.icegreen.greenmail.util.ServerSetup;
public class MailServer {
public static void main(String[] args) throws Exception {
ServerSetup setup = new ServerSetup(3025, "localhost", "smtp");
GreenMail greenMail = new GreenMail(setup);
greenMail.start();
while (true) {
int c = greenMail.getReceivedMessages().length;
if (greenMail.waitForIncomingEmail(Long.MAX_VALUE, c + 1)) {
MimeMessage message = greenMail.getReceivedMessages()[c++];
System.out.println("Received mail to " + message.getRecipients(RecipientType.TO)[0]);
System.out.println();
System.out.println(message.getContent());
System.out.println("-------------------------------------------------------");
}
}
}
}

View file

@ -0,0 +1,31 @@
package org.keycloak.testutils;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.TimeUnit;
import org.picketlink.common.util.Base32;
import org.picketlink.idm.credential.util.TimeBasedOTP;
public class TotpGenerator {
public static void main(String[] args) {
String totp = "";
for (String a : args) {
totp += a.trim();
}
totp = totp.replace(" ", "");
final String google = new String(Base32.decode(totp));
final TimeBasedOTP otp = new TimeBasedOTP();
Timer t = new Timer();
t.schedule(new TimerTask() {
@Override
public void run() {
System.out.println(otp.generate(google));
}
}, 0, TimeUnit.SECONDS.toMillis(TimeBasedOTP.DEFAULT_INTERVAL_SECONDS));
}
}

View file

@ -56,7 +56,7 @@ public class OAuthClient {
private WebDriver driver; private WebDriver driver;
private String baseUrl = "http://localhost:8081/auth-server/rest"; private String baseUrl = Constants.AUTH_SERVER_ROOT + "/rest";
private String realm = "test"; private String realm = "test";

View file

@ -21,81 +21,45 @@
*/ */
package org.keycloak.testsuite.rule; package org.keycloak.testsuite.rule;
import io.undertow.server.handlers.resource.ClassPathResourceManager;
import io.undertow.servlet.Servlets;
import io.undertow.servlet.api.DeploymentInfo; import io.undertow.servlet.api.DeploymentInfo;
import io.undertow.servlet.api.FilterInfo;
import io.undertow.servlet.api.ServletInfo; import io.undertow.servlet.api.ServletInfo;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import javax.servlet.DispatcherType;
import javax.servlet.Servlet; import javax.servlet.Servlet;
import org.jboss.resteasy.jwt.JsonSerialization; import org.jboss.resteasy.jwt.JsonSerialization;
import org.jboss.resteasy.plugins.server.undertow.UndertowJaxrsServer;
import org.jboss.resteasy.spi.ResteasyDeployment;
import org.junit.rules.ExternalResource; import org.junit.rules.ExternalResource;
import org.keycloak.representations.idm.CredentialRepresentation;
import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.services.filters.KeycloakSessionServletFilter;
import org.keycloak.services.managers.RealmManager;
import org.keycloak.models.KeycloakSession; import org.keycloak.models.KeycloakSession;
import org.keycloak.models.KeycloakSessionFactory;
import org.keycloak.models.RealmModel; import org.keycloak.models.RealmModel;
import org.keycloak.models.RoleModel; import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.models.UserModel; import org.keycloak.services.managers.RealmManager;
import org.keycloak.services.resources.KeycloakApplication;
import org.keycloak.services.resources.SaasService;
import org.keycloak.testsuite.ApplicationServlet; import org.keycloak.testsuite.ApplicationServlet;
import org.keycloak.testutils.KeycloakServer;
/** /**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a> * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
*/ */
public class KeycloakRule extends ExternalResource { public class KeycloakRule extends ExternalResource {
private String testRealm = "testrealm.json"; private KeycloakServer server;
private UndertowJaxrsServer server;
private KeycloakSessionFactory factory;
private KeycloakSetup setup; private KeycloakSetup setup;
public KeycloakRule() { public KeycloakRule() {
} }
public KeycloakRule(String testRealm) {
this.testRealm = testRealm;
}
public KeycloakRule(KeycloakSetup setup) { public KeycloakRule(KeycloakSetup setup) {
this.setup = setup; this.setup = setup;
} }
protected void before() throws Throwable { protected void before() throws Throwable {
ResteasyDeployment deployment = new ResteasyDeployment(); server = new KeycloakServer();
deployment.setApplicationClass(KeycloakApplication.class.getName()); server.start();
server = new UndertowJaxrsServer().start();
DeploymentInfo di = server.undertowDeployment(deployment, "rest"); server.importRealm(getClass().getResourceAsStream("/testrealm.json"));
di.setClassLoader(getClass().getClassLoader());
di.setContextPath("/auth-server");
di.setDeploymentName("Keycloak");
di.setResourceManager(new ClassPathResourceManager(getClass().getClassLoader(), "META-INF/resources"));
FilterInfo filter = Servlets.filter("SessionFilter", KeycloakSessionServletFilter.class);
di.addFilter(filter);
di.addFilterUrlMapping("SessionFilter", "/rest/*", DispatcherType.REQUEST);
server.deploy(di);
factory = KeycloakApplication.buildSessionFactory();
setupDefaultRealm();
importRealm(testRealm);
if (setup != null) { if (setup != null) {
configure(setup); configure(setup);
@ -114,12 +78,11 @@ public class KeycloakRule extends ExternalResource {
servlet.addMapping("/*"); servlet.addMapping("/*");
deploymentInfo.addServlet(servlet); deploymentInfo.addServlet(servlet);
server.deploy(deploymentInfo); server.getServer().deploy(deploymentInfo);
} }
@Override @Override
protected void after() { protected void after() {
factory.close();
server.stop(); server.stop();
} }
@ -134,73 +97,28 @@ public class KeycloakRule extends ExternalResource {
return JsonSerialization.fromBytes(RealmRepresentation.class, bytes); return JsonSerialization.fromBytes(RealmRepresentation.class, bytes);
} }
public void setupDefaultRealm() {
KeycloakSession session = createSession();
session.getTransaction().begin();
RealmManager manager = new RealmManager(session);
RealmModel defaultRealm = manager.createRealm(RealmModel.DEFAULT_REALM, RealmModel.DEFAULT_REALM);
defaultRealm.setName(RealmModel.DEFAULT_REALM);
defaultRealm.setEnabled(true);
defaultRealm.setTokenLifespan(300);
defaultRealm.setAccessCodeLifespan(60);
defaultRealm.setAccessCodeLifespanUserAction(600);
defaultRealm.setSslNotRequired(false);
defaultRealm.setCookieLoginAllowed(true);
defaultRealm.setRegistrationAllowed(true);
defaultRealm.setAutomaticRegistrationAfterSocialLogin(false);
manager.generateRealmKeys(defaultRealm);
defaultRealm.addRequiredCredential(CredentialRepresentation.PASSWORD);
RoleModel role = defaultRealm.addRole(SaasService.REALM_CREATOR_ROLE);
UserModel admin = defaultRealm.addUser("admin");
defaultRealm.grantRole(admin, role);
session.getTransaction().commit();
session.close();
}
public void importRealm(String name) throws IOException {
KeycloakSession session = createSession();
session.getTransaction().begin();
RealmManager manager = new RealmManager(session);
RealmModel defaultRealm = manager.getRealm(RealmModel.DEFAULT_REALM);
UserModel admin = defaultRealm.getUser("admin");
RealmRepresentation rep = loadJson(name);
RealmModel realm = manager.createRealm("test", rep.getRealm());
manager.importRealm(rep, realm);
realm.addRealmAdmin(admin);
session.getTransaction().commit();
session.close();
}
public void configure(KeycloakSetup configurer) { public void configure(KeycloakSetup configurer) {
KeycloakSession session = createSession(); KeycloakSession session = server.getKeycloakSessionFactory().createSession();
session.getTransaction().begin(); session.getTransaction().begin();
RealmManager manager = new RealmManager(session); try {
RealmManager manager = new RealmManager(session);
RealmModel defaultRealm = manager.getRealm(RealmModel.DEFAULT_REALM); RealmModel defaultRealm = manager.getRealm(RealmModel.DEFAULT_REALM);
RealmModel appRealm = manager.getRealm("test"); RealmModel appRealm = manager.getRealm("test");
configurer.config(manager, defaultRealm, appRealm); configurer.config(manager, defaultRealm, appRealm);
session.getTransaction().commit(); session.getTransaction().commit();
session.close(); } finally {
session.close();
}
} }
public KeycloakSession createSession() {
return factory.createSession();
}
public interface KeycloakSetup { public interface KeycloakSetup {
void config(RealmManager manager, RealmModel defaultRealm, RealmModel appRealm); void config(RealmManager manager, RealmModel defaultRealm, RealmModel appRealm);
} }
} }

View file

@ -1,4 +1,5 @@
{ {
"id": "test",
"realm": "test", "realm": "test",
"enabled": true, "enabled": true,
"tokenLifespan": 300, "tokenLifespan": 300,