keycloak-memoizeit
Changes
bundled-war-example/pom.xml 285(+285 -0)
bundled-war-example/README.md 16(+16 -0)
bundled-war-example/src/main/webapp/WEB-INF/web.xml 144(+144 -0)
integration/adapter-core/src/main/java/org/keycloak/adapters/AdapterDeploymentContext.java 26(+26 -0)
integration/adapter-core/src/main/java/org/keycloak/adapters/KeycloakDeploymentBuilder.java 2(+1 -1)
integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/AuthenticatedActionsValve.java 9(+5 -4)
integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/KeycloakAuthenticatorValve.java 25(+19 -6)
pom.xml 1(+1 -0)
Details
bundled-war-example/pom.xml 285(+285 -0)
diff --git a/bundled-war-example/pom.xml b/bundled-war-example/pom.xml
new file mode 100755
index 0000000..751e7ab
--- /dev/null
+++ b/bundled-war-example/pom.xml
@@ -0,0 +1,285 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <parent>
+ <artifactId>keycloak-parent</artifactId>
+ <groupId>org.keycloak</groupId>
+ <version>1.0-beta-1-SNAPSHOT</version>
+ </parent>
+
+ <modelVersion>4.0.0</modelVersion>
+ <artifactId>app-bundle</artifactId>
+ <packaging>war</packaging>
+ <name>Keycloak Server and App Bundle EAP 6.x</name>
+ <description/>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.bouncycastle</groupId>
+ <artifactId>bcprov-jdk16</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.keycloak</groupId>
+ <artifactId>keycloak-core</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.keycloak</groupId>
+ <artifactId>keycloak-adapter-core</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.keycloak</groupId>
+ <artifactId>keycloak-jboss-adapter-core</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.keycloak</groupId>
+ <artifactId>keycloak-as7-adapter</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>net.iharder</groupId>
+ <artifactId>base64</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.keycloak</groupId>
+ <artifactId>keycloak-core-jaxrs</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.keycloak</groupId>
+ <artifactId>keycloak-services</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>com.google.zxing</groupId>
+ <artifactId>javase</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.keycloak</groupId>
+ <artifactId>keycloak-model-api</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.keycloak</groupId>
+ <artifactId>keycloak-model-jpa</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.keycloak</groupId>
+ <artifactId>keycloak-audit-api</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.keycloak</groupId>
+ <artifactId>keycloak-audit-jpa</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.keycloak</groupId>
+ <artifactId>keycloak-audit-jboss-logging</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <!-- social -->
+ <dependency>
+ <groupId>org.keycloak</groupId>
+ <artifactId>keycloak-social-core</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.json</groupId>
+ <artifactId>json</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.keycloak</groupId>
+ <artifactId>keycloak-social-github</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.keycloak</groupId>
+ <artifactId>keycloak-social-google</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.keycloak</groupId>
+ <artifactId>keycloak-social-twitter</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.twitter4j</groupId>
+ <artifactId>twitter4j-core</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.keycloak</groupId>
+ <artifactId>keycloak-social-facebook</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <!-- forms -->
+ <dependency>
+ <groupId>org.keycloak</groupId>
+ <artifactId>keycloak-forms-common-freemarker</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.freemarker</groupId>
+ <artifactId>freemarker</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.keycloak</groupId>
+ <artifactId>keycloak-forms-common-themes</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.keycloak</groupId>
+ <artifactId>keycloak-account-api</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.keycloak</groupId>
+ <artifactId>keycloak-account-freemarker</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.keycloak</groupId>
+ <artifactId>keycloak-login-api</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.keycloak</groupId>
+ <artifactId>keycloak-login-freemarker</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.keycloak</groupId>
+ <artifactId>keycloak-admin-ui</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.keycloak</groupId>
+ <artifactId>keycloak-js-adapter</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <!-- authentication api -->
+ <dependency>
+ <groupId>org.keycloak</groupId>
+ <artifactId>keycloak-authentication-api</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.keycloak</groupId>
+ <artifactId>keycloak-authentication-model</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.keycloak</groupId>
+ <artifactId>keycloak-authentication-picketlink</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.picketlink</groupId>
+ <artifactId>picketlink-common</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.picketlink</groupId>
+ <artifactId>picketlink-idm-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.picketlink</groupId>
+ <artifactId>picketlink-idm-impl</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.picketlink</groupId>
+ <artifactId>picketlink-idm-simple-schema</artifactId>
+ </dependency>
+
+ <!-- timer -->
+ <dependency>
+ <groupId>org.keycloak</groupId>
+ <artifactId>keycloak-timer-api</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.keycloak</groupId>
+ <artifactId>keycloak-timer-basic</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+
+ <!-- picketlink -->
+ <dependency>
+ <groupId>org.keycloak</groupId>
+ <artifactId>keycloak-picketlink-api</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.keycloak</groupId>
+ <artifactId>keycloak-picketlink-realm</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.jboss.spec.javax.servlet</groupId>
+ <artifactId>jboss-servlet-api_3.0_spec</artifactId>
+ <scope>provided</scope>
+ </dependency>
+ <!-- resteasy -->
+ <dependency>
+ <groupId>org.jboss.resteasy</groupId>
+ <artifactId>resteasy-jaxrs</artifactId>
+ <version>${resteasy.version}</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.jboss.resteasy</groupId>
+ <artifactId>resteasy-multipart-provider</artifactId>
+ <version>${resteasy.version}</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.jboss.resteasy</groupId>
+ <artifactId>async-http-servlet-3.0</artifactId>
+ <version>${resteasy.version}</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.jboss.resteasy</groupId>
+ <artifactId>jaxrs-api</artifactId>
+ <version>${resteasy.version}</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.jboss.resteasy</groupId>
+ <artifactId>resteasy-jackson-provider</artifactId>
+ <version>${resteasy.version}</version>
+ <scope>provided</scope>
+ </dependency>
+
+
+ </dependencies>
+
+ <build>
+ <finalName>app-bundle</finalName>
+ <plugins>
+ <plugin>
+ <groupId>org.jboss.as.plugins</groupId>
+ <artifactId>jboss-as-maven-plugin</artifactId>
+ <version>7.5.Final</version>
+ </plugin>
+
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-deploy-plugin</artifactId>
+ <configuration>
+ <skip>true</skip>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <configuration>
+ <source>${maven.compiler.source}</source>
+ <target>${maven.compiler.target}</target>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+</project>
bundled-war-example/README.md 16(+16 -0)
diff --git a/bundled-war-example/README.md b/bundled-war-example/README.md
new file mode 100755
index 0000000..269f159
--- /dev/null
+++ b/bundled-war-example/README.md
@@ -0,0 +1,16 @@
+Self Bootstrapping Keycloak Server and Bundled Application
+==========================================================
+
+This is an example of bundling the Keycloak server with an app within the same WAR in an EAP 6.x environment.
+
+* On bootup, a default realm is imported from WEB-INF/testrealm.json if it doesn't exist yet.
+* On bootup, the adapter config is created on the fly and configured with the testrealm imported.
+* The application is secured with keycloak (see jboss-web.xml)
+* web.xml security constraints are set for the secured URLs that are secured by keycloak
+* Because of weirdness with Resteasy 2.3.x, any secured JAX-RS urls from the application must have a security
+constraint that denies all as they will be reachable in two places. Under the Keycloak REST url "/rest" and under the
+application's REST url "/database".
+* Adapter config can be modified on the fly by getting the AdapterDeploymentContext from a servlet context attribute.
+* You must specify a host-port context param so that the auth url for AdapterConfig can be set correctly.
+
+* Run this demo by going to http://localhost:8080/app-bundle. Then click on the url.
\ No newline at end of file
diff --git a/bundled-war-example/src/main/java/org/keycloak/example/CustomerDatabaseClient.java b/bundled-war-example/src/main/java/org/keycloak/example/CustomerDatabaseClient.java
new file mode 100755
index 0000000..79bbeb8
--- /dev/null
+++ b/bundled-war-example/src/main/java/org/keycloak/example/CustomerDatabaseClient.java
@@ -0,0 +1,72 @@
+package org.keycloak.example;
+
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpResponse;
+import org.apache.http.client.HttpClient;
+import org.apache.http.client.methods.HttpGet;
+import org.keycloak.KeycloakSecurityContext;
+import org.keycloak.adapters.HttpClientBuilder;
+import org.keycloak.representations.IDToken;
+import org.keycloak.util.JsonSerialization;
+
+import javax.servlet.http.HttpServletRequest;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class CustomerDatabaseClient {
+
+ static class TypedList extends ArrayList<String> {
+ }
+
+ public static class Failure extends Exception {
+ private int status;
+
+ public Failure(int status) {
+ this.status = status;
+ }
+
+ public int getStatus() {
+ return status;
+ }
+ }
+
+ public static IDToken getIDToken(HttpServletRequest req) {
+ KeycloakSecurityContext session = (KeycloakSecurityContext) req.getAttribute(KeycloakSecurityContext.class.getName());
+ return session.getIdToken();
+
+ }
+
+ public static List<String> getCustomers(HttpServletRequest req) throws Failure {
+ KeycloakSecurityContext session = (KeycloakSecurityContext) req.getAttribute(KeycloakSecurityContext.class.getName());
+
+ HttpClient client = new HttpClientBuilder()
+ .disableTrustManager().build();
+ try {
+ HttpGet get = new HttpGet("http://localhost:8080/app-bundle/database/customers");
+ get.addHeader("Authorization", "Bearer " + session.getTokenString());
+ try {
+ HttpResponse response = client.execute(get);
+ if (response.getStatusLine().getStatusCode() != 200) {
+ throw new Failure(response.getStatusLine().getStatusCode());
+ }
+ HttpEntity entity = response.getEntity();
+ InputStream is = entity.getContent();
+ try {
+ return JsonSerialization.readValue(is, TypedList.class);
+ } finally {
+ is.close();
+ }
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ } finally {
+ client.getConnectionManager().shutdown();
+ }
+ }
+}
diff --git a/bundled-war-example/src/main/java/org/keycloak/example/oauth/CustomerService.java b/bundled-war-example/src/main/java/org/keycloak/example/oauth/CustomerService.java
new file mode 100755
index 0000000..8f5f5b1
--- /dev/null
+++ b/bundled-war-example/src/main/java/org/keycloak/example/oauth/CustomerService.java
@@ -0,0 +1,31 @@
+package org.keycloak.example.oauth;
+
+import org.jboss.resteasy.annotations.cache.NoCache;
+
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+@Path("customers")
+public class CustomerService {
+ @GET
+ @Produces("application/json")
+ @NoCache
+ public List<String> getCustomers() {
+ ArrayList<String> rtn = new ArrayList<String>();
+ rtn.add("Bill Burke");
+ rtn.add("Stian Thorgersen");
+ rtn.add("Stan Silvert");
+ rtn.add("Gabriel Cardoso");
+ rtn.add("Viliam Rockai");
+ rtn.add("Marek Posolda");
+ rtn.add("Boleslaw Dawidowicz");
+ return rtn;
+ }
+}
diff --git a/bundled-war-example/src/main/java/org/keycloak/example/oauth/DataApplication.java b/bundled-war-example/src/main/java/org/keycloak/example/oauth/DataApplication.java
new file mode 100755
index 0000000..10590ac
--- /dev/null
+++ b/bundled-war-example/src/main/java/org/keycloak/example/oauth/DataApplication.java
@@ -0,0 +1,25 @@
+package org.keycloak.example.oauth;
+
+import javax.ws.rs.core.Application;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class DataApplication extends Application
+{
+ @Override
+ public Set<Class<?>> getClasses() {
+ HashSet<Class<?>> set = new HashSet<Class<?>>();
+ set.add(CustomerService.class);
+ set.add(ProductService.class);
+ return set;
+ }
+
+ @Override
+ public Set<Object> getSingletons() {
+ return super.getSingletons(); //To change body of overridden methods use File | Settings | File Templates.
+ }
+}
diff --git a/bundled-war-example/src/main/java/org/keycloak/example/oauth/ProductService.java b/bundled-war-example/src/main/java/org/keycloak/example/oauth/ProductService.java
new file mode 100755
index 0000000..10fd5d7
--- /dev/null
+++ b/bundled-war-example/src/main/java/org/keycloak/example/oauth/ProductService.java
@@ -0,0 +1,27 @@
+package org.keycloak.example.oauth;
+
+import org.jboss.resteasy.annotations.cache.NoCache;
+
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+@Path("products")
+public class ProductService {
+ @GET
+ @Produces("application/json")
+ @NoCache
+ public List<String> getProducts() {
+ ArrayList<String> rtn = new ArrayList<String>();
+ rtn.add("iphone");
+ rtn.add("ipad");
+ rtn.add("ipod");
+ return rtn;
+ }
+}
diff --git a/bundled-war-example/src/main/java/org/keycloak/server/KeycloakServerApplication.java b/bundled-war-example/src/main/java/org/keycloak/server/KeycloakServerApplication.java
new file mode 100755
index 0000000..1b14058
--- /dev/null
+++ b/bundled-war-example/src/main/java/org/keycloak/server/KeycloakServerApplication.java
@@ -0,0 +1,84 @@
+package org.keycloak.server;
+
+import org.jboss.resteasy.core.Dispatcher;
+import org.jboss.resteasy.logging.Logger;
+import org.keycloak.adapters.AdapterDeploymentContext;
+import org.keycloak.models.Config;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.RealmModel;
+import org.keycloak.representations.adapters.config.AdapterConfig;
+import org.keycloak.representations.idm.CredentialRepresentation;
+import org.keycloak.representations.idm.RealmRepresentation;
+import org.keycloak.services.managers.RealmManager;
+import org.keycloak.services.resources.KeycloakApplication;
+import org.keycloak.util.JsonSerialization;
+import org.keycloak.util.KeycloakUriBuilder;
+
+import javax.servlet.ServletContext;
+import javax.ws.rs.core.Context;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.HashMap;
+import java.util.Map;
+
+public class KeycloakServerApplication extends KeycloakApplication {
+
+ private static final Logger log = Logger.getLogger(KeycloakServerApplication.class);
+
+ public KeycloakServerApplication(@Context ServletContext servletContext,@Context Dispatcher dispatcher) throws FileNotFoundException {
+ super(servletContext, dispatcher);
+ KeycloakSession session = factory.createSession();
+ session.getTransaction().begin();
+ try {
+ InputStream is = servletContext.getResourceAsStream("/WEB-INF/testrealm.json");
+ RealmRepresentation rep = loadJson(is, RealmRepresentation.class);
+ RealmModel realm = importRealm(session, rep);
+ AdapterDeploymentContext deploymentContext = (AdapterDeploymentContext)servletContext.getAttribute(AdapterDeploymentContext.class.getName());
+ AdapterConfig adapterConfig = new AdapterConfig();
+ String host = (String)servletContext.getInitParameter("host-port");
+ String uri = KeycloakUriBuilder.fromUri("http://" + host).path(servletContext.getContextPath()).build().toString();
+ log.info("**** auth server url: " + uri);
+ adapterConfig.setRealm("demo");
+ adapterConfig.setResource("customer-portal");
+ adapterConfig.setRealmKey(realm.getPublicKeyPem());
+ Map<String, String> creds = new HashMap<String, String>();
+ creds.put(CredentialRepresentation.SECRET, "password");
+ adapterConfig.setCredentials(creds);
+ adapterConfig.setAuthServerUrl(uri);
+ adapterConfig.setSslNotRequired(true);
+ deploymentContext.updateDeployment(adapterConfig);
+ session.getTransaction().commit();
+ } finally {
+ session.close();
+ }
+
+ }
+
+ public RealmModel importRealm(KeycloakSession session, RealmRepresentation rep) {
+ RealmManager manager = new RealmManager(session);
+
+ RealmModel realm = manager.getRealmByName(rep.getRealm());
+ if (realm != null) {
+ log.info("Not importing realm " + rep.getRealm() + " realm already exists");
+ return realm;
+ }
+
+ realm = manager.createRealm(rep.getId(), rep.getRealm());
+ manager.importRealm(rep, realm);
+
+ log.info("Imported realm " + realm.getName());
+ return realm;
+ }
+
+ private static <T> T loadJson(InputStream is, Class<T> type) {
+ try {
+ return JsonSerialization.readValue(is, type);
+ } catch (IOException e) {
+ throw new RuntimeException("Failed to parse json", e);
+ }
+ }
+
+}
diff --git a/bundled-war-example/src/main/resources/META-INF/persistence.xml b/bundled-war-example/src/main/resources/META-INF/persistence.xml
new file mode 100755
index 0000000..b9dbe7b
--- /dev/null
+++ b/bundled-war-example/src/main/resources/META-INF/persistence.xml
@@ -0,0 +1,39 @@
+<persistence xmlns="http://java.sun.com/xml/ns/persistence"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd"
+ version="1.0">
+ <persistence-unit name="jpa-keycloak-identity-store" transaction-type="RESOURCE_LOCAL">
+ <jta-data-source>java:jboss/datasources/ExampleDS</jta-data-source>
+ <class>org.keycloak.models.jpa.entities.ApplicationEntity</class>
+ <class>org.keycloak.models.jpa.entities.CredentialEntity</class>
+ <class>org.keycloak.models.jpa.entities.OAuthClientEntity</class>
+ <class>org.keycloak.models.jpa.entities.RealmEntity</class>
+ <class>org.keycloak.models.jpa.entities.RequiredCredentialEntity</class>
+ <class>org.keycloak.models.jpa.entities.AuthenticationProviderEntity</class>
+ <class>org.keycloak.models.jpa.entities.ApplicationRoleEntity</class>
+ <class>org.keycloak.models.jpa.entities.RealmRoleEntity</class>
+ <class>org.keycloak.models.jpa.entities.SocialLinkEntity</class>
+ <class>org.keycloak.models.jpa.entities.AuthenticationLinkEntity</class>
+ <class>org.keycloak.models.jpa.entities.UserEntity</class>
+ <class>org.keycloak.models.jpa.entities.UserRoleMappingEntity</class>
+ <class>org.keycloak.models.jpa.entities.ScopeMappingEntity</class>
+
+ <exclude-unlisted-classes>true</exclude-unlisted-classes>
+
+ <properties>
+ <property name="hibernate.hbm2ddl.auto" value="update" />
+ </properties>
+ </persistence-unit>
+
+ <persistence-unit name="jpa-keycloak-audit-store" transaction-type="RESOURCE_LOCAL">
+ <jta-data-source>java:jboss/datasources/ExampleDS</jta-data-source>
+ <class>org.keycloak.audit.jpa.EventEntity</class>
+
+ <exclude-unlisted-classes>true</exclude-unlisted-classes>
+
+ <properties>
+ <property name="hibernate.hbm2ddl.auto" value="update" />
+ </properties>
+ </persistence-unit>
+
+</persistence>
diff --git a/bundled-war-example/src/main/webapp/customers/view.jsp b/bundled-war-example/src/main/webapp/customers/view.jsp
new file mode 100755
index 0000000..5b7aba6
--- /dev/null
+++ b/bundled-war-example/src/main/webapp/customers/view.jsp
@@ -0,0 +1,47 @@
+<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
+ pageEncoding="ISO-8859-1" %>
+<%@ page import="org.keycloak.example.CustomerDatabaseClient" %>
+<%@ page import="org.keycloak.util.KeycloakUriBuilder" %>
+<%@ page import="org.keycloak.representations.IDToken" %>
+<html>
+<head>
+ <title>Customer View Page</title>
+</head>
+<body bgcolor="#E3F6CE">
+<%
+ String logoutUri = KeycloakUriBuilder.fromUri("http://localhost:8080/app-bundle/rest/realms/demo/tokens/logout")
+ .queryParam("redirect_uri", "http://localhost:8080/app-bundle").build().toString();
+ String acctUri = "http://localhost:8080/app-bundle/rest/realms/demo/account?referrer=customer-portal";
+ IDToken idToken = CustomerDatabaseClient.getIDToken(request);
+%>
+<p><a href="<%=logoutUri%>">logout</a> | <a
+ href="<%=acctUri%>">manage acct</a></p>
+Servlet User Principal <b><%=request.getUserPrincipal().getName()%>
+</b> made this request.
+<p><b>Caller IDToken values</b> (<i>You can specify what is returned in IDToken in the customer-portal claims page in the admin console</i>:</p>
+<p>Username: <%=idToken.getPreferredUsername()%></p>
+<p>Email: <%=idToken.getEmail()%></p>
+<p>Full Name: <%=idToken.getName()%></p>
+<p>First: <%=idToken.getGivenName()%></p>
+<p>Last: <%=idToken.getFamilyName()%></p>
+<h2>Customer Listing</h2>
+<%
+ java.util.List<String> list = null;
+ try {
+ list = CustomerDatabaseClient.getCustomers(request);
+ } catch (CustomerDatabaseClient.Failure failure) {
+ out.println("There was a failure processing request. You either didn't configure Keycloak properly, or maybe" +
+ "you just forgot to secure the database service?");
+ out.println("Status from database service invocation was: " + failure.getStatus());
+ return;
+ }
+ for (String cust : list) {
+ out.print("<p>");
+ out.print(cust);
+ out.println("</p>");
+
+ }
+%>
+<br><br>
+</body>
+</html>
\ No newline at end of file
diff --git a/bundled-war-example/src/main/webapp/index.html b/bundled-war-example/src/main/webapp/index.html
new file mode 100755
index 0000000..681fa08
--- /dev/null
+++ b/bundled-war-example/src/main/webapp/index.html
@@ -0,0 +1,13 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+ "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<head>
+ <title></title>
+</head>
+<body bgcolor="#E3F6CE">
+<h1>Customer Portal</h1>
+
+<p><a href="customers/view.jsp">Customer Listing</a></p>
+
+</body>
+</html>
\ No newline at end of file
diff --git a/bundled-war-example/src/main/webapp/WEB-INF/jboss-deployment-structure.xml b/bundled-war-example/src/main/webapp/WEB-INF/jboss-deployment-structure.xml
new file mode 100755
index 0000000..5457fd5
--- /dev/null
+++ b/bundled-war-example/src/main/webapp/WEB-INF/jboss-deployment-structure.xml
@@ -0,0 +1,36 @@
+<jboss-deployment-structure>
+ <deployment>
+ <dependencies>
+ <module name="org.apache.httpcomponents"/>
+ <module name="org.codehaus.jackson.jackson-core-asl"/>
+ <module name="org.codehaus.jackson.jackson-mapper-asl"/>
+ </dependencies>
+ <exclusions>
+
+ <!-- Exclude keycloak modules -->
+ <module name="org.keycloak.keycloak-core" />
+ <module name="org.keycloak.keycloak-adapter-core" />
+ <module name="org.keycloak.keycloak-undertow-adapter" />
+ <module name="org.keycloak.keycloak-as7-adapter" />
+
+ <!--
+ <module name="org.apache.cxf" />
+ <module name="javaee.api" />
+ <module name="javax.ws.rs.api"/>
+ <module name="org.codehaus.jackson.jackson-core-asl" />
+ <module name="org.jboss.resteasy.resteasy-atom-provider" />
+ <module name="org.jboss.resteasy.resteasy-cdi" />
+ <module name="org.jboss.resteasy.resteasy-crypto" />
+ <module name="org.jboss.resteasy.resteasy-jackson-provider" />
+ <module name="org.jboss.resteasy.resteasy-jaxb-provider" />
+ <module name="org.jboss.resteasy.resteasy-jaxrs" />
+ <module name="org.jboss.resteasy.resteasy-jettison-provider" />
+ <module name="org.jboss.resteasy.resteasy-jsapi" />
+ <module name="org.jboss.resteasy.resteasy-json-p-provider" />
+ <module name="org.jboss.resteasy.resteasy-multipart-provider" />
+ <module name="org.jboss.resteasy.resteasy-validator-provider-11" />
+ <module name="org.jboss.resteasy.resteasy-yaml-provider" />
+ -->
+ </exclusions>
+ </deployment>
+</jboss-deployment-structure>
\ No newline at end of file
diff --git a/bundled-war-example/src/main/webapp/WEB-INF/jboss-web.xml b/bundled-war-example/src/main/webapp/WEB-INF/jboss-web.xml
new file mode 100755
index 0000000..2f94ba4
--- /dev/null
+++ b/bundled-war-example/src/main/webapp/WEB-INF/jboss-web.xml
@@ -0,0 +1,5 @@
+<jboss-web>
+ <valve>
+ <class-name>org.keycloak.adapters.as7.KeycloakAuthenticatorValve</class-name>
+ </valve>
+</jboss-web>
\ No newline at end of file
diff --git a/bundled-war-example/src/main/webapp/WEB-INF/testrealm.json b/bundled-war-example/src/main/webapp/WEB-INF/testrealm.json
new file mode 100755
index 0000000..35ae9ad
--- /dev/null
+++ b/bundled-war-example/src/main/webapp/WEB-INF/testrealm.json
@@ -0,0 +1,70 @@
+{
+ "realm": "demo",
+ "enabled": true,
+ "accessTokenLifespan": 3000,
+ "accessCodeLifespan": 10,
+ "accessCodeLifespanUserAction": 6000,
+ "sslNotRequired": true,
+ "registrationAllowed": false,
+ "social": false,
+ "updateProfileOnInitialSocialLogin": false,
+ "requiredCredentials": [ "password" ],
+ "users" : [
+ {
+ "username" : "bburke@redhat.com",
+ "enabled": true,
+ "email" : "bburke@redhat.com",
+ "firstName": "Bill",
+ "lastName": "Burke",
+ "credentials" : [
+ { "type" : "password",
+ "value" : "password" }
+ ]
+ }
+ ],
+ "roles" : {
+ "realm" : [
+ {
+ "name": "user",
+ "description": "User privileges"
+ },
+ {
+ "name": "admin",
+ "description": "Administrator privileges"
+ }
+ ]
+ },
+ "roleMappings": [
+ {
+ "username": "bburke@redhat.com",
+ "roles": ["user"]
+ }
+ ],
+ "scopeMappings": [
+ {
+ "client": "customer-portal",
+ "roles": ["user"]
+ }
+ ],
+ "applications": [
+ {
+ "name": "customer-portal",
+ "enabled": true,
+ "adminUrl": "http://localhost:8080/app-bundle",
+ "baseUrl": "http://localhost:8080/app-bundle",
+ "redirectUris": [
+ "http://localhost:8080/app-bundle/*"
+ ],
+ "secret": "password"
+ }
+ ],
+ "applicationRoleMappings": {
+ "account": [
+ {
+ "username": "bburke@redhat.com",
+ "roles": ["manage-account"]
+ }
+ ]
+ }
+
+}
bundled-war-example/src/main/webapp/WEB-INF/web.xml 144(+144 -0)
diff --git a/bundled-war-example/src/main/webapp/WEB-INF/web.xml b/bundled-war-example/src/main/webapp/WEB-INF/web.xml
new file mode 100755
index 0000000..5d17437
--- /dev/null
+++ b/bundled-war-example/src/main/webapp/WEB-INF/web.xml
@@ -0,0 +1,144 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<web-app xmlns="http://java.sun.com/xml/ns/javaee"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
+ version="3.0">
+
+ <module-name>app-bundle</module-name>
+ <context-param>
+ <param-name>host-port</param-name>
+ <param-value>localhost:8080</param-value>
+ </context-param>
+
+ <servlet>
+ <servlet-name>Keycloak REST Interface</servlet-name>
+ <servlet-class>org.jboss.resteasy.plugins.server.servlet.HttpServlet30Dispatcher</servlet-class>
+ <init-param>
+ <param-name>javax.ws.rs.Application</param-name>
+ <param-value>org.keycloak.server.KeycloakServerApplication</param-value>
+ </init-param>
+ <init-param>
+ <param-name>resteasy.servlet.mapping.prefix</param-name>
+ <param-value>/rest</param-value>
+ </init-param>
+ <load-on-startup>1</load-on-startup>
+ <async-supported>true</async-supported>
+ </servlet>
+
+ <servlet>
+ <servlet-name>Customer REST Interface</servlet-name>
+ <servlet-class>org.jboss.resteasy.plugins.server.servlet.HttpServlet30Dispatcher</servlet-class>
+ <init-param>
+ <param-name>javax.ws.rs.Application</param-name>
+ <param-value>org.keycloak.example.oauth.DataApplication</param-value>
+ </init-param>
+ <init-param>
+ <param-name>resteasy.servlet.mapping.prefix</param-name>
+ <param-value>/database</param-value>
+ </init-param>
+ <load-on-startup>2</load-on-startup>
+ <async-supported>true</async-supported>
+ </servlet>
+
+ <servlet>
+ <servlet-name>TmpAdminRedirectServlet</servlet-name>
+ <servlet-class>org.keycloak.services.tmp.TmpAdminRedirectServlet</servlet-class>
+ </servlet>
+
+ <listener>
+ <listener-class>org.keycloak.services.listeners.KeycloakSessionDestroyListener</listener-class>
+ </listener>
+
+ <welcome-file-list>
+ <welcome-file>index.html</welcome-file>
+ </welcome-file-list>
+
+ <filter>
+ <filter-name>Keycloak Client Connection Filter</filter-name>
+ <filter-class>org.keycloak.services.filters.ClientConnectionFilter</filter-class>
+ </filter>
+
+ <filter>
+ <filter-name>Keycloak Session Management</filter-name>
+ <filter-class>org.keycloak.services.filters.KeycloakSessionServletFilter</filter-class>
+ </filter>
+
+ <filter-mapping>
+ <filter-name>Keycloak Session Management</filter-name>
+ <url-pattern>/rest/*</url-pattern>
+ </filter-mapping>
+
+ <filter-mapping>
+ <filter-name>Keycloak Client Connection Filter</filter-name>
+ <url-pattern>/rest/*</url-pattern>
+ </filter-mapping>
+
+ <servlet-mapping>
+ <servlet-name>Keycloak REST Interface</servlet-name>
+ <url-pattern>/rest/*</url-pattern>
+ </servlet-mapping>
+
+ <servlet-mapping>
+ <servlet-name>Customer REST Interface</servlet-name>
+ <url-pattern>/database/*</url-pattern>
+ </servlet-mapping>
+
+ <servlet-mapping>
+ <servlet-name>TmpAdminRedirectServlet</servlet-name>
+ <url-pattern>/admin</url-pattern>
+ <url-pattern>/admin/</url-pattern>
+ </servlet-mapping>
+
+ <!--
+
+ <security-constraint>
+ <web-resource-collection>
+ <url-pattern>/*</url-pattern>
+ </web-resource-collection>
+ <user-data-constraint>
+ <transport-guarantee>CONFIDENTIAL</transport-guarantee>
+ </user-data-constraint>
+ </security-constraint>
+ -->
+
+ <security-constraint>
+ <web-resource-collection>
+ <web-resource-name>Customers</web-resource-name>
+ <url-pattern>/customers/*</url-pattern>
+ </web-resource-collection>
+ <auth-constraint>
+ <role-name>user</role-name>
+ </auth-constraint>
+ </security-constraint>
+
+ <security-constraint>
+ <web-resource-collection>
+ <web-resource-name>Database</web-resource-name>
+ <url-pattern>/database/*</url-pattern>
+ </web-resource-collection>
+ <auth-constraint>
+ <role-name>user</role-name>
+ </auth-constraint>
+ </security-constraint>
+ <security-constraint>
+ <web-resource-collection>
+ <web-resource-name>deny</web-resource-name>
+ <url-pattern>/rest/customers/*</url-pattern>
+ </web-resource-collection>
+ <auth-constraint/>
+ </security-constraint>
+
+ <login-config>
+ <auth-method>BASIC</auth-method>
+ <realm-name>demo</realm-name>
+ </login-config>
+
+ <security-role>
+ <role-name>admin</role-name>
+ </security-role>
+ <security-role>
+ <role-name>user</role-name>
+ </security-role>
+
+
+</web-app>
diff --git a/integration/adapter-core/src/main/java/org/keycloak/adapters/AdapterDeploymentContext.java b/integration/adapter-core/src/main/java/org/keycloak/adapters/AdapterDeploymentContext.java
new file mode 100755
index 0000000..3dfce8e
--- /dev/null
+++ b/integration/adapter-core/src/main/java/org/keycloak/adapters/AdapterDeploymentContext.java
@@ -0,0 +1,26 @@
+package org.keycloak.adapters;
+
+import org.keycloak.representations.adapters.config.AdapterConfig;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class AdapterDeploymentContext {
+ protected KeycloakDeployment deployment;
+
+ public AdapterDeploymentContext() {
+ }
+
+ public AdapterDeploymentContext(KeycloakDeployment deployment) {
+ this.deployment = deployment;
+ }
+
+ public KeycloakDeployment getDeployment() {
+ return deployment;
+ }
+
+ public void updateDeployment(AdapterConfig config) {
+ deployment = KeycloakDeploymentBuilder.build(config);
+ }
+}
diff --git a/integration/adapter-core/src/main/java/org/keycloak/adapters/KeycloakDeployment.java b/integration/adapter-core/src/main/java/org/keycloak/adapters/KeycloakDeployment.java
index bd2eabc..722c40f 100755
--- a/integration/adapter-core/src/main/java/org/keycloak/adapters/KeycloakDeployment.java
+++ b/integration/adapter-core/src/main/java/org/keycloak/adapters/KeycloakDeployment.java
@@ -12,6 +12,7 @@ import java.util.Map;
* @version $Revision: 1 $
*/
public class KeycloakDeployment {
+ protected boolean configured;
protected String realm;
protected PublicKey realmKey;
protected KeycloakUriBuilder authUrl;
@@ -37,6 +38,14 @@ public class KeycloakDeployment {
protected boolean exposeToken;
protected volatile int notBefore;
+ public boolean isConfigured() {
+ return configured;
+ }
+
+ public void setConfigured(boolean configured) {
+ this.configured = configured;
+ }
+
public String getResourceName() {
return resourceName;
}
diff --git a/integration/adapter-core/src/main/java/org/keycloak/adapters/KeycloakDeploymentBuilder.java b/integration/adapter-core/src/main/java/org/keycloak/adapters/KeycloakDeploymentBuilder.java
index fc09bbe..04f8c15 100755
--- a/integration/adapter-core/src/main/java/org/keycloak/adapters/KeycloakDeploymentBuilder.java
+++ b/integration/adapter-core/src/main/java/org/keycloak/adapters/KeycloakDeploymentBuilder.java
@@ -27,7 +27,7 @@ public class KeycloakDeploymentBuilder {
protected KeycloakDeployment internalBuild(AdapterConfig adapterConfig) {
-
+ deployment.setConfigured(true);
if (adapterConfig.getRealm() == null) throw new RuntimeException("Must set 'realm' in config");
deployment.setRealm(adapterConfig.getRealm());
String resource = adapterConfig.getResource();
diff --git a/integration/adapter-core/src/main/java/org/keycloak/adapters/PreAuthActionsHandler.java b/integration/adapter-core/src/main/java/org/keycloak/adapters/PreAuthActionsHandler.java
index 370b313..c937809 100755
--- a/integration/adapter-core/src/main/java/org/keycloak/adapters/PreAuthActionsHandler.java
+++ b/integration/adapter-core/src/main/java/org/keycloak/adapters/PreAuthActionsHandler.java
@@ -35,6 +35,7 @@ public class PreAuthActionsHandler {
}
public boolean handleRequest() {
+ if (!deployment.isConfigured()) return false;
String requestUri = facade.getRequest().getURI();
log.debugv("adminRequest {0}", requestUri);
if (preflightCors()) {
diff --git a/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/AuthenticatedActionsValve.java b/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/AuthenticatedActionsValve.java
index 84f5ab6..4d78076 100755
--- a/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/AuthenticatedActionsValve.java
+++ b/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/AuthenticatedActionsValve.java
@@ -9,6 +9,7 @@ import org.apache.catalina.valves.ValveBase;
import org.jboss.logging.Logger;
import org.keycloak.KeycloakSecurityContext;
import org.keycloak.adapters.AdapterConstants;
+import org.keycloak.adapters.AdapterDeploymentContext;
import org.keycloak.adapters.AuthenticatedActionsHandler;
import org.keycloak.adapters.KeycloakDeployment;
import org.keycloak.representations.AccessToken;
@@ -33,10 +34,10 @@ import java.util.Set;
*/
public class AuthenticatedActionsValve extends ValveBase {
private static final Logger log = Logger.getLogger(AuthenticatedActionsValve.class);
- protected KeycloakDeployment deployment;
+ protected AdapterDeploymentContext deploymentContext;
- public AuthenticatedActionsValve(KeycloakDeployment deployment, Valve next, Container container, ObjectName controller) {
- this.deployment = deployment;
+ public AuthenticatedActionsValve(AdapterDeploymentContext deploymentContext, Valve next, Container container, ObjectName controller) {
+ this.deploymentContext = deploymentContext;
if (next == null) throw new RuntimeException("WTF is next null?!");
setNext(next);
setContainer(container);
@@ -47,7 +48,7 @@ public class AuthenticatedActionsValve extends ValveBase {
@Override
public void invoke(Request request, Response response) throws IOException, ServletException {
log.debugv("AuthenticatedActionsValve.invoke {0}", request.getRequestURI());
- AuthenticatedActionsHandler handler = new AuthenticatedActionsHandler(deployment, new CatalinaHttpFacade(request, response));
+ AuthenticatedActionsHandler handler = new AuthenticatedActionsHandler(deploymentContext.getDeployment(), new CatalinaHttpFacade(request, response));
if (handler.handledRequest()) {
return;
}
diff --git a/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/KeycloakAuthenticatorValve.java b/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/KeycloakAuthenticatorValve.java
index 74050be..291eb5f 100755
--- a/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/KeycloakAuthenticatorValve.java
+++ b/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/KeycloakAuthenticatorValve.java
@@ -13,6 +13,7 @@ import org.apache.catalina.deploy.LoginConfig;
import org.jboss.logging.Logger;
import org.keycloak.KeycloakSecurityContext;
import org.keycloak.adapters.AdapterConstants;
+import org.keycloak.adapters.AdapterDeploymentContext;
import org.keycloak.adapters.AuthChallenge;
import org.keycloak.adapters.AuthOutcome;
import org.keycloak.adapters.KeycloakDeployment;
@@ -55,7 +56,7 @@ import java.util.Map;
public class KeycloakAuthenticatorValve extends FormAuthenticator implements LifecycleListener {
private static final Logger log = Logger.getLogger(KeycloakAuthenticatorValve.class);
protected CatalinaUserSessionManagement userSessionManagement = new CatalinaUserSessionManagement();
- protected KeycloakDeployment deployment;
+ protected AdapterDeploymentContext deploymentContext;
@Override
@@ -100,15 +101,26 @@ public class KeycloakAuthenticatorValve extends FormAuthenticator implements Lif
protected void init() {
- this.deployment = KeycloakDeploymentBuilder.build(getConfigInputStream(context));
- AuthenticatedActionsValve actions = new AuthenticatedActionsValve(deployment, getNext(), getContainer(), getController());
+ InputStream configInputStream = getConfigInputStream(context);
+ KeycloakDeployment kd = null;
+ if (configInputStream == null) {
+ log.warn("No adapter configuration. Keycloak is unconfigured and will deny all requests.");
+ kd = new KeycloakDeployment();
+ kd.setConfigured(false);
+
+ } else {
+ kd = KeycloakDeploymentBuilder.build(configInputStream);
+ }
+ deploymentContext = new AdapterDeploymentContext(kd);
+ context.getServletContext().setAttribute(AdapterDeploymentContext.class.getName(), deploymentContext);
+ AuthenticatedActionsValve actions = new AuthenticatedActionsValve(deploymentContext, getNext(), getContainer(), getController());
setNext(actions);
}
@Override
public void invoke(Request request, Response response) throws IOException, ServletException {
try {
- PreAuthActionsHandler handler = new PreAuthActionsHandler(userSessionManagement, deployment, new CatalinaHttpFacade(request, response));
+ PreAuthActionsHandler handler = new PreAuthActionsHandler(userSessionManagement, deploymentContext.getDeployment(), new CatalinaHttpFacade(request, response));
if (handler.handleRequest()) {
return;
}
@@ -120,8 +132,9 @@ public class KeycloakAuthenticatorValve extends FormAuthenticator implements Lif
@Override
public boolean authenticate(Request request, HttpServletResponse response, LoginConfig config) throws IOException {
+ if (!deploymentContext.getDeployment().isConfigured()) return false;
CatalinaHttpFacade facade = new CatalinaHttpFacade(request, response);
- CatalinaRequestAuthenticator authenticator = new CatalinaRequestAuthenticator(deployment, this, userSessionManagement, facade, request);
+ CatalinaRequestAuthenticator authenticator = new CatalinaRequestAuthenticator(deploymentContext.getDeployment(), this, userSessionManagement, facade, request);
AuthOutcome outcome = authenticator.authenticate();
if (outcome == AuthOutcome.AUTHENTICATED) {
if (facade.isEnded()) {
@@ -146,7 +159,7 @@ public class KeycloakAuthenticatorValve extends FormAuthenticator implements Lif
RefreshableKeycloakSecurityContext session = (RefreshableKeycloakSecurityContext)request.getSessionInternal().getNote(KeycloakSecurityContext.class.getName());
if (session == null) return;
// just in case session got serialized
- session.setDeployment(deployment);
+ session.setDeployment(deploymentContext.getDeployment());
if (session.isActive()) return;
// FYI: A refresh requires same scope, so same roles will be set. Otherwise, refresh will fail and token will
pom.xml 1(+1 -0)
diff --git a/pom.xml b/pom.xml
index c600c6b..31ae93b 100755
--- a/pom.xml
+++ b/pom.xml
@@ -102,6 +102,7 @@
<module>testsuite</module>
<module>server</module>
<module>timer</module>
+ <module>bundled-war-example</module>
</modules>
<dependencyManagement>
diff --git a/server/src/main/java/org/keycloak/server/KeycloakServerApplication.java b/server/src/main/java/org/keycloak/server/KeycloakServerApplication.java
index 262bf60..823b44b 100755
--- a/server/src/main/java/org/keycloak/server/KeycloakServerApplication.java
+++ b/server/src/main/java/org/keycloak/server/KeycloakServerApplication.java
@@ -1,5 +1,6 @@
package org.keycloak.server;
+import org.jboss.resteasy.core.Dispatcher;
import org.jboss.resteasy.logging.Logger;
import org.keycloak.models.Config;
import org.keycloak.models.KeycloakSession;
@@ -21,8 +22,8 @@ public class KeycloakServerApplication extends KeycloakApplication {
private static final Logger log = Logger.getLogger(KeycloakServerApplication.class);
- public KeycloakServerApplication(@Context ServletContext servletContext) throws FileNotFoundException {
- super(servletContext);
+ public KeycloakServerApplication(@Context ServletContext servletContext, @Context Dispatcher dispatcher) throws FileNotFoundException {
+ super(servletContext, dispatcher);
String importRealm = System.getProperty("keycloak.import");
if (importRealm != null) {
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/ApplicationResource.java b/services/src/main/java/org/keycloak/services/resources/admin/ApplicationResource.java
index e0aedb0..0fb20a9 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/ApplicationResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/ApplicationResource.java
@@ -52,7 +52,7 @@ public class ApplicationResource {
protected UriInfo uriInfo;
@Context
- protected Application keycloak;
+ protected KeycloakApplication keycloak;
protected KeycloakApplication getKeycloakApplication() {
return (KeycloakApplication)keycloak;
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/OAuthClientResource.java b/services/src/main/java/org/keycloak/services/resources/admin/OAuthClientResource.java
index 5481ae8..eb72e63 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/OAuthClientResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/OAuthClientResource.java
@@ -41,7 +41,7 @@ public class OAuthClientResource {
protected UriInfo uriInfo;
@Context
- protected Application application;
+ protected KeycloakApplication application;
protected KeycloakApplication getApplication() {
return (KeycloakApplication)application;
diff --git a/services/src/main/java/org/keycloak/services/resources/KeycloakApplication.java b/services/src/main/java/org/keycloak/services/resources/KeycloakApplication.java
index e5c48b8..7b8b3dd 100755
--- a/services/src/main/java/org/keycloak/services/resources/KeycloakApplication.java
+++ b/services/src/main/java/org/keycloak/services/resources/KeycloakApplication.java
@@ -1,5 +1,6 @@
package org.keycloak.services.resources;
+import org.jboss.resteasy.core.Dispatcher;
import org.jboss.resteasy.logging.Logger;
import org.keycloak.SkeletonKeyContextResolver;
import org.keycloak.audit.AuditListener;
@@ -52,9 +53,10 @@ public class KeycloakApplication extends Application {
protected ProviderSessionFactory providerSessionFactory;
protected String contextPath;
- public KeycloakApplication(@Context ServletContext context) {
- this.factory = createSessionFactory();
+ public KeycloakApplication(@Context ServletContext context, @Context Dispatcher dispatcher) {
+ dispatcher.getDefaultContextObjects().put(KeycloakApplication.class, this);
this.contextPath = context.getContextPath();
+ this.factory = createSessionFactory();
this.providerSessionFactory = createProviderSessionFactory();
context.setAttribute(KeycloakSessionFactory.class.getName(), factory);
//classes.add(KeycloakSessionCleanupFilter.class);