keycloak-memoizeit

Changes

pom.xml 1(+1 -0)

Details

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>
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"]
+            }
+        ]
+    }
+
+}
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);