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 0000000000..b9dbe7bec8
--- /dev/null
+++ b/bundled-war-example/src/main/resources/META-INF/persistence.xml
@@ -0,0 +1,39 @@
+
+
+ java:jboss/datasources/ExampleDS
+ org.keycloak.models.jpa.entities.ApplicationEntity
+ org.keycloak.models.jpa.entities.CredentialEntity
+ org.keycloak.models.jpa.entities.OAuthClientEntity
+ org.keycloak.models.jpa.entities.RealmEntity
+ org.keycloak.models.jpa.entities.RequiredCredentialEntity
+ org.keycloak.models.jpa.entities.AuthenticationProviderEntity
+ org.keycloak.models.jpa.entities.ApplicationRoleEntity
+ org.keycloak.models.jpa.entities.RealmRoleEntity
+ org.keycloak.models.jpa.entities.SocialLinkEntity
+ org.keycloak.models.jpa.entities.AuthenticationLinkEntity
+ org.keycloak.models.jpa.entities.UserEntity
+ org.keycloak.models.jpa.entities.UserRoleMappingEntity
+ org.keycloak.models.jpa.entities.ScopeMappingEntity
+
+ true
+
+
+
+
+
+
+
+ java:jboss/datasources/ExampleDS
+ org.keycloak.audit.jpa.EventEntity
+
+ true
+
+
+
+
+
+
+
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 0000000000..5457fd5b27
--- /dev/null
+++ b/bundled-war-example/src/main/webapp/WEB-INF/jboss-deployment-structure.xml
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ 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 0000000000..2f94ba4bca
--- /dev/null
+++ b/bundled-war-example/src/main/webapp/WEB-INF/jboss-web.xml
@@ -0,0 +1,5 @@
+
+
+ org.keycloak.adapters.as7.KeycloakAuthenticatorValve
+
+
\ 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 0000000000..35ae9ad219
--- /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 0000000000..5d17437d11
--- /dev/null
+++ b/bundled-war-example/src/main/webapp/WEB-INF/web.xml
@@ -0,0 +1,144 @@
+
+
+
+ app-bundle
+
+ host-port
+ localhost:8080
+
+
+
+ Keycloak REST Interface
+ org.jboss.resteasy.plugins.server.servlet.HttpServlet30Dispatcher
+
+ javax.ws.rs.Application
+ org.keycloak.server.KeycloakServerApplication
+
+
+ resteasy.servlet.mapping.prefix
+ /rest
+
+ 1
+ true
+
+
+
+ Customer REST Interface
+ org.jboss.resteasy.plugins.server.servlet.HttpServlet30Dispatcher
+
+ javax.ws.rs.Application
+ org.keycloak.example.oauth.DataApplication
+
+
+ resteasy.servlet.mapping.prefix
+ /database
+
+ 2
+ true
+
+
+
+ TmpAdminRedirectServlet
+ org.keycloak.services.tmp.TmpAdminRedirectServlet
+
+
+
+ org.keycloak.services.listeners.KeycloakSessionDestroyListener
+
+
+
+ index.html
+
+
+
+ Keycloak Client Connection Filter
+ org.keycloak.services.filters.ClientConnectionFilter
+
+
+
+ Keycloak Session Management
+ org.keycloak.services.filters.KeycloakSessionServletFilter
+
+
+
+ Keycloak Session Management
+ /rest/*
+
+
+
+ Keycloak Client Connection Filter
+ /rest/*
+
+
+
+ Keycloak REST Interface
+ /rest/*
+
+
+
+ Customer REST Interface
+ /database/*
+
+
+
+ TmpAdminRedirectServlet
+ /admin
+ /admin/
+
+
+
+
+
+
+ Customers
+ /customers/*
+
+
+ user
+
+
+
+
+
+ Database
+ /database/*
+
+
+ user
+
+
+
+
+ deny
+ /rest/customers/*
+
+
+
+
+
+ BASIC
+ demo
+
+
+
+ admin
+
+
+ user
+
+
+
+
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 0000000000..5b7aba6ea7
--- /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" %>
+
+
+ Customer View Page
+
+
+<%
+ 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);
+%>
+logout | manage acct
+Servlet User Principal <%=request.getUserPrincipal().getName()%>
+ made this request.
+Caller IDToken values (You can specify what is returned in IDToken in the customer-portal claims page in the admin console:
+Username: <%=idToken.getPreferredUsername()%>
+Email: <%=idToken.getEmail()%>
+Full Name: <%=idToken.getName()%>
+First: <%=idToken.getGivenName()%>
+Last: <%=idToken.getFamilyName()%>
+Customer Listing
+<%
+ java.util.List 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("");
+ out.print(cust);
+ out.println("
");
+
+ }
+%>
+
+
+
\ 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 0000000000..681fa08a17
--- /dev/null
+++ b/bundled-war-example/src/main/webapp/index.html
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+Customer Portal
+
+Customer Listing
+
+
+
\ No newline at end of file
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 0000000000..3dfce8e05a
--- /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 Bill Burke
+ * @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 bd2eabce48..722c40f0c1 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 fc09bbe7c7..04f8c15a87 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 370b313927..c937809ceb 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 84f5ab6347..4d78076cc5 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 74050be830..291eb5f3eb 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
diff --git a/pom.xml b/pom.xml
index c600c6bc42..31ae93b047 100755
--- a/pom.xml
+++ b/pom.xml
@@ -102,6 +102,7 @@
testsuite
server
timer
+ bundled-war-example
diff --git a/server/src/main/java/org/keycloak/server/KeycloakServerApplication.java b/server/src/main/java/org/keycloak/server/KeycloakServerApplication.java
index 262bf60268..823b44b395 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/KeycloakApplication.java b/services/src/main/java/org/keycloak/services/resources/KeycloakApplication.java
index e5c48b8265..7b8b3ddfba 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);
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 e0aedb08a8..0fb20a9493 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 5481ae8545..eb72e63091 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;