diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-server-subsystem/main/server-war/WEB-INF/web.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-server-subsystem/main/server-war/WEB-INF/web.xml
index df80df8811..f561b268e1 100755
--- a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-server-subsystem/main/server-war/WEB-INF/web.xml
+++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-server-subsystem/main/server-war/WEB-INF/web.xml
@@ -49,7 +49,7 @@
Keycloak Session Management
- org.keycloak.services.filters.KeycloakSessionServletFilter
+ org.keycloak.provider.wildfly.KeycloakSessionServletFilter
true
diff --git a/quarkus/extensions/pom.xml b/quarkus/extensions/pom.xml
index 70d0a20a98..a652da7d9d 100644
--- a/quarkus/extensions/pom.xml
+++ b/quarkus/extensions/pom.xml
@@ -30,6 +30,10 @@
org.slf4j
slf4j-simple
+
+ org.jboss.spec.javax.servlet
+ jboss-servlet-api_4.0_spec
+
@@ -43,6 +47,12 @@
org.keycloak
keycloak-services
+
+
+ org.jboss.spec.javax.servlet
+ jboss-servlet-api_4.0_spec
+
+
org.keycloak
@@ -67,6 +77,20 @@
quarkus-agroal
jar
+
+ io.quarkus
+ quarkus-vertx-web
+
+
+ org.keycloak
+ keycloak-common
+
+
+ *
+ *
+
+
+
junit
junit
diff --git a/quarkus/extensions/src/main/java/org/keycloak/QuarkusKeycloakApplication.java b/quarkus/extensions/src/main/java/org/keycloak/QuarkusKeycloakApplication.java
new file mode 100644
index 0000000000..6450a19cdf
--- /dev/null
+++ b/quarkus/extensions/src/main/java/org/keycloak/QuarkusKeycloakApplication.java
@@ -0,0 +1,10 @@
+package org.keycloak;
+
+import javax.ws.rs.ApplicationPath;
+
+import org.keycloak.services.resources.KeycloakApplication;
+
+@ApplicationPath("/")
+public class QuarkusKeycloakApplication extends KeycloakApplication {
+
+}
diff --git a/quarkus/extensions/src/main/java/org/keycloak/provider/quarkus/QuarkusFilter.java b/quarkus/extensions/src/main/java/org/keycloak/provider/quarkus/QuarkusFilter.java
new file mode 100644
index 0000000000..7240670dfb
--- /dev/null
+++ b/quarkus/extensions/src/main/java/org/keycloak/provider/quarkus/QuarkusFilter.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright 2019 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.provider.quarkus;
+
+import io.vertx.core.http.HttpServerRequest;
+import io.vertx.ext.web.RoutingContext;
+import org.keycloak.common.ClientConnection;
+import org.keycloak.common.util.Resteasy;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.KeycloakSessionFactory;
+import org.keycloak.models.KeycloakTransaction;
+import org.keycloak.services.resources.KeycloakApplication;
+
+import javax.annotation.Priority;
+import javax.inject.Inject;
+import javax.ws.rs.container.ContainerRequestContext;
+import javax.ws.rs.container.ContainerResponseContext;
+import javax.ws.rs.container.PreMatching;
+import javax.ws.rs.ext.Provider;
+import java.io.IOException;
+
+
+@PreMatching
+@Provider
+@Priority(1)
+public class QuarkusFilter implements javax.ws.rs.container.ContainerRequestFilter,
+ javax.ws.rs.container.ContainerResponseFilter {
+
+ @Inject
+ KeycloakApplication keycloakApplication;
+
+ @Inject
+ RoutingContext routingContext;
+
+ @Override
+ public void filter(ContainerRequestContext containerRequestContext) {
+ KeycloakSessionFactory sessionFactory = keycloakApplication.getSessionFactory();
+ KeycloakSession session = sessionFactory.create();
+
+ Resteasy.pushContext(KeycloakSession.class, session);
+ HttpServerRequest request = routingContext.request();
+
+ session.getContext().setConnection(createConnection(request));
+ Resteasy.pushContext(ClientConnection.class, session.getContext().getConnection());
+
+ KeycloakTransaction tx = session.getTransactionManager();
+ Resteasy.pushContext(KeycloakTransaction.class, tx);
+
+ tx.begin();
+ }
+
+ @Override
+ public void filter(ContainerRequestContext containerRequestContext, ContainerResponseContext containerResponseContext) throws IOException {
+ //End the session and clear context
+ KeycloakSession session = Resteasy.getContextData(KeycloakSession.class);
+
+ // KeycloakTransactionCommitter is responsible for committing the transaction, but if an exception is thrown it's not invoked and transaction
+ // should be rolled back
+ if (session.getTransactionManager() != null && session.getTransactionManager().isActive()) {
+ session.getTransactionManager().rollback();
+ }
+
+ session.close();
+ Resteasy.clearContextData();
+ }
+
+ private ClientConnection createConnection(HttpServerRequest request) {
+ return new ClientConnection() {
+ @Override
+ public String getRemoteAddr() {
+ return request.remoteAddress().host();
+ }
+
+ @Override
+ public String getRemoteHost() {
+ return request.remoteAddress().host();
+ }
+
+ @Override
+ public int getRemotePort() {
+ return request.remoteAddress().port();
+ }
+
+ @Override
+ public String getLocalAddr() {
+ return request.localAddress().host();
+ }
+
+ @Override
+ public int getLocalPort() {
+ return request.localAddress().port();
+ }
+ };
+ }
+}
\ No newline at end of file
diff --git a/quarkus/extensions/src/main/java/org/keycloak/provider/quarkus/QuarkusLifecycleObserver.java b/quarkus/extensions/src/main/java/org/keycloak/provider/quarkus/QuarkusLifecycleObserver.java
index f4a3bbcaa4..31f2dfa9ca 100644
--- a/quarkus/extensions/src/main/java/org/keycloak/provider/quarkus/QuarkusLifecycleObserver.java
+++ b/quarkus/extensions/src/main/java/org/keycloak/provider/quarkus/QuarkusLifecycleObserver.java
@@ -22,7 +22,6 @@ import io.quarkus.runtime.StartupEvent;
import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.event.Observes;
import javax.inject.Inject;
-import javax.servlet.ServletContext;
import org.keycloak.Config;
import org.keycloak.models.KeycloakSession;
@@ -31,6 +30,7 @@ import org.keycloak.models.KeycloakTransactionManager;
import org.keycloak.platform.Platform;
import org.keycloak.services.ServicesLogger;
import org.keycloak.services.managers.ApplianceBootstrap;
+import org.keycloak.services.resources.KeycloakApplication;
@ApplicationScoped
public class QuarkusLifecycleObserver {
@@ -39,7 +39,7 @@ public class QuarkusLifecycleObserver {
private static final String KEYCLOAK_ADMIN_PASSWORD_ENV_VAR = "KEYCLOAK_ADMIN_PASSWORD";
@Inject
- ServletContext servletContext;
+ KeycloakApplication application;
private void onStartupEvent(@Observes StartupEvent event) {
@@ -70,8 +70,7 @@ public class QuarkusLifecycleObserver {
return;
}
- KeycloakSessionFactory sessionFactory = (KeycloakSessionFactory) servletContext
- .getAttribute(KeycloakSessionFactory.class.getName());
+ KeycloakSessionFactory sessionFactory = application.getSessionFactory();
KeycloakSession session = sessionFactory.create();
KeycloakTransactionManager transaction = session.getTransactionManager();
diff --git a/quarkus/pom.xml b/quarkus/pom.xml
index 6bff1dd53a..ae73ce0942 100755
--- a/quarkus/pom.xml
+++ b/quarkus/pom.xml
@@ -31,7 +31,7 @@
pom
- 1.2.1.Final
+ 999-SNAPSHOT
4.4.2.Final
2.10.2
${jackson.version}
diff --git a/quarkus/server/pom.xml b/quarkus/server/pom.xml
index e3962fa1d4..580180dde9 100644
--- a/quarkus/server/pom.xml
+++ b/quarkus/server/pom.xml
@@ -15,10 +15,6 @@
-
- io.quarkus
- quarkus-undertow
-
io.quarkus
quarkus-resteasy
diff --git a/quarkus/server/src/main/resources/META-INF/web.xml b/quarkus/server/src/main/resources/META-INF/web.xml
deleted file mode 100644
index 2f28c8139b..0000000000
--- a/quarkus/server/src/main/resources/META-INF/web.xml
+++ /dev/null
@@ -1,62 +0,0 @@
-
-
-
-
-
- auth
-
-
- Keycloak REST Interface
- org.jboss.resteasy.plugins.server.servlet.HttpServlet30Dispatcher
-
- javax.ws.rs.Application
- org.keycloak.services.resources.KeycloakApplication
-
-
- resteasy.servlet.mapping.prefix
- /
-
- 1
- true
-
-
-
- resteasy.disable.html.sanitizer
- true
-
-
-
-
- org.jboss.resteasy.plugins.server.servlet.ResteasyBootstrap
-
-
-
-
- Keycloak Session Management
- org.keycloak.services.filters.KeycloakSessionServletFilter
- true
-
-
-
- Keycloak Session Management
- /*
-
-
diff --git a/quarkus/server/src/main/resources/application.properties b/quarkus/server/src/main/resources/application.properties
index f2b06d8be3..64d72d082b 100644
--- a/quarkus/server/src/main/resources/application.properties
+++ b/quarkus/server/src/main/resources/application.properties
@@ -1,7 +1,6 @@
#quarkus.log.level = DEBUG
quarkus.application.name=Keycloak
-quarkus.servlet.context-path = /auth
quarkus.datasource.driver=org.h2.Driver
resteasy.disable.html.sanitizer = true
\ No newline at end of file
diff --git a/services/pom.xml b/services/pom.xml
index 279ed11477..4c0a99c01b 100755
--- a/services/pom.xml
+++ b/services/pom.xml
@@ -79,10 +79,6 @@
keycloak-ldap-federation
provided
-
- org.jboss.spec.javax.servlet
- jboss-servlet-api_4.0_spec
-
org.twitter4j
twitter4j-core
diff --git a/services/src/main/java/org/keycloak/authentication/AuthenticationProcessor.java b/services/src/main/java/org/keycloak/authentication/AuthenticationProcessor.java
index 817b15d483..c6dcb09f03 100755
--- a/services/src/main/java/org/keycloak/authentication/AuthenticationProcessor.java
+++ b/services/src/main/java/org/keycloak/authentication/AuthenticationProcessor.java
@@ -56,6 +56,7 @@ import org.keycloak.services.util.AuthenticationFlowURLHelper;
import org.keycloak.sessions.AuthenticationSessionModel;
import org.keycloak.sessions.CommonClientSessionModel;
+import javax.ws.rs.core.MultivaluedHashMap;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriBuilder;
import javax.ws.rs.core.UriInfo;
@@ -508,7 +509,8 @@ public class AuthenticationProcessor {
.setUser(getUser())
.setActionUri(action)
.setExecution(getExecution().getId())
- .setFormData(request.getDecodedFormParameters())
+ .setFormData(request.getHttpMethod().equalsIgnoreCase("post") ? request.getDecodedFormParameters() :
+ new MultivaluedHashMap<>())
.setClientSessionCode(accessCode);
if (getForwardedErrorMessage() != null) {
provider.addError(getForwardedErrorMessage());
diff --git a/services/src/main/java/org/keycloak/services/filters/KeycloakTransactionCommitter.java b/services/src/main/java/org/keycloak/services/filters/KeycloakTransactionCommitter.java
index a7e3415030..677f0764b6 100644
--- a/services/src/main/java/org/keycloak/services/filters/KeycloakTransactionCommitter.java
+++ b/services/src/main/java/org/keycloak/services/filters/KeycloakTransactionCommitter.java
@@ -23,6 +23,7 @@ package org.keycloak.services.filters;
import org.keycloak.common.util.Resteasy;
import org.keycloak.models.KeycloakTransaction;
+import javax.annotation.Priority;
import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerResponseContext;
import javax.ws.rs.container.ContainerResponseFilter;
@@ -31,6 +32,7 @@ import java.io.IOException;
/**
* @author Stian Thorgersen
*/
+@Priority(2)
public class KeycloakTransactionCommitter implements ContainerResponseFilter {
@Override
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 cb12a659eb..2913e69636 100644
--- a/services/src/main/java/org/keycloak/services/resources/KeycloakApplication.java
+++ b/services/src/main/java/org/keycloak/services/resources/KeycloakApplication.java
@@ -58,7 +58,6 @@ import org.keycloak.timer.TimerProvider;
import org.keycloak.transaction.JtaTransactionManagerLookup;
import org.keycloak.util.JsonSerialization;
-import javax.servlet.ServletContext;
import javax.transaction.SystemException;
import javax.transaction.Transaction;
import javax.ws.rs.core.Application;
@@ -99,15 +98,12 @@ public class KeycloakApplication extends Application {
logger.debugv("PlatformProvider: {0}", platform.getClass().getName());
logger.debugv("RestEasy provider: {0}", Resteasy.getProvider().getClass().getName());
- ServletContext context = Resteasy.getContextData(ServletContext.class);
-
loadConfig();
this.sessionFactory = createSessionFactory();
Resteasy.pushDefaultContextObject(KeycloakApplication.class, this);
Resteasy.pushContext(KeycloakApplication.class, this); // for injection
- context.setAttribute(KeycloakSessionFactory.class.getName(), this.sessionFactory);
singletons.add(new RobotsResource());
singletons.add(new RealmsResource());
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/ClientInitialAccessResource.java b/services/src/main/java/org/keycloak/services/resources/admin/ClientInitialAccessResource.java
index 8d0fae36b6..23e67bf626 100644
--- a/services/src/main/java/org/keycloak/services/resources/admin/ClientInitialAccessResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/ClientInitialAccessResource.java
@@ -17,6 +17,7 @@
package org.keycloak.services.resources.admin;
+import org.jboss.resteasy.spi.HttpResponse;
import org.keycloak.events.admin.OperationType;
import org.keycloak.events.admin.ResourceType;
import org.keycloak.models.ClientInitialAccessModel;
@@ -27,7 +28,6 @@ import org.keycloak.representations.idm.ClientInitialAccessPresentation;
import org.keycloak.services.clientregistration.ClientRegistrationTokenUtils;
import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator;
-import javax.servlet.http.HttpServletResponse;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
@@ -71,7 +71,7 @@ public class ClientInitialAccessResource {
@POST
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
- public ClientInitialAccessPresentation create(ClientInitialAccessCreatePresentation config, @Context final HttpServletResponse response) {
+ public ClientInitialAccessPresentation create(ClientInitialAccessCreatePresentation config, @Context final HttpResponse response) {
auth.clients().requireManage();
int expiration = config.getExpiration() != null ? config.getExpiration() : 0;
@@ -87,7 +87,7 @@ public class ClientInitialAccessResource {
rep.setToken(token);
response.setStatus(Response.Status.CREATED.getStatusCode());
- response.setHeader(HttpHeaders.LOCATION, session.getContext().getUri().getAbsolutePathBuilder().path(clientInitialAccessModel.getId()).build().toString());
+ response.getOutputHeaders().add(HttpHeaders.LOCATION, session.getContext().getUri().getAbsolutePathBuilder().path(clientInitialAccessModel.getId()).build().toString());
return rep;
}
diff --git a/testsuite/integration-arquillian/servers/auth-server/undertow/src/main/java/org/keycloak/testsuite/arquillian/undertow/KeycloakOnUndertow.java b/testsuite/integration-arquillian/servers/auth-server/undertow/src/main/java/org/keycloak/testsuite/arquillian/undertow/KeycloakOnUndertow.java
index c94d048f54..362dc6cfad 100644
--- a/testsuite/integration-arquillian/servers/auth-server/undertow/src/main/java/org/keycloak/testsuite/arquillian/undertow/KeycloakOnUndertow.java
+++ b/testsuite/integration-arquillian/servers/auth-server/undertow/src/main/java/org/keycloak/testsuite/arquillian/undertow/KeycloakOnUndertow.java
@@ -46,7 +46,6 @@ import org.jboss.shrinkwrap.undertow.api.UndertowWebArchive;
import org.keycloak.common.util.reflections.Reflections;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.KeycloakSessionFactory;
-import org.keycloak.services.filters.KeycloakSessionServletFilter;
import org.keycloak.services.managers.ApplianceBootstrap;
import org.keycloak.services.resources.KeycloakApplication;
import org.keycloak.testsuite.JsonConfigProviderFactory;
diff --git a/testsuite/utils/src/main/java/org/keycloak/testsuite/KeycloakServer.java b/testsuite/utils/src/main/java/org/keycloak/testsuite/KeycloakServer.java
index aef5cc4eab..4b8c803cc2 100755
--- a/testsuite/utils/src/main/java/org/keycloak/testsuite/KeycloakServer.java
+++ b/testsuite/utils/src/main/java/org/keycloak/testsuite/KeycloakServer.java
@@ -33,7 +33,6 @@ import org.keycloak.models.KeycloakSession;
import org.keycloak.models.KeycloakSessionFactory;
import org.keycloak.models.RealmModel;
import org.keycloak.representations.idm.RealmRepresentation;
-import org.keycloak.services.filters.KeycloakSessionServletFilter;
import org.keycloak.services.managers.ApplianceBootstrap;
import org.keycloak.services.managers.RealmManager;
import org.keycloak.services.resources.KeycloakApplication;
diff --git a/services/src/main/java/org/keycloak/services/filters/KeycloakSessionServletFilter.java b/testsuite/utils/src/main/java/org/keycloak/testsuite/KeycloakSessionServletFilter.java
similarity index 97%
rename from services/src/main/java/org/keycloak/services/filters/KeycloakSessionServletFilter.java
rename to testsuite/utils/src/main/java/org/keycloak/testsuite/KeycloakSessionServletFilter.java
index 90f2b7008a..ffda4242ec 100755
--- a/services/src/main/java/org/keycloak/services/filters/KeycloakSessionServletFilter.java
+++ b/testsuite/utils/src/main/java/org/keycloak/testsuite/KeycloakSessionServletFilter.java
@@ -15,14 +15,9 @@
* limitations under the License.
*/
-package org.keycloak.services.filters;
+package org.keycloak.testsuite;
-import org.jboss.resteasy.spi.ResteasyProviderFactory;
-import org.keycloak.common.ClientConnection;
-import org.keycloak.common.util.Resteasy;
-import org.keycloak.models.KeycloakSession;
-import org.keycloak.models.KeycloakSessionFactory;
-import org.keycloak.models.KeycloakTransaction;
+import java.io.IOException;
import javax.servlet.AsyncEvent;
import javax.servlet.AsyncListener;
@@ -33,7 +28,12 @@ import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
-import java.io.IOException;
+
+import org.keycloak.common.ClientConnection;
+import org.keycloak.common.util.Resteasy;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.KeycloakSessionFactory;
+import org.keycloak.models.KeycloakTransaction;
/**
* @author Bill Burke
diff --git a/testsuite/utils/src/main/java/org/keycloak/testsuite/TestKeycloakSessionServletFilter.java b/testsuite/utils/src/main/java/org/keycloak/testsuite/TestKeycloakSessionServletFilter.java
index b64ebdc48c..629121c167 100644
--- a/testsuite/utils/src/main/java/org/keycloak/testsuite/TestKeycloakSessionServletFilter.java
+++ b/testsuite/utils/src/main/java/org/keycloak/testsuite/TestKeycloakSessionServletFilter.java
@@ -25,8 +25,6 @@ import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.IOException;
-import org.keycloak.services.filters.KeycloakSessionServletFilter;
-
/**
* @author Pedro Igor
*/
diff --git a/testsuite/utils/src/main/java/org/keycloak/testsuite/TestPlatform.java b/testsuite/utils/src/main/java/org/keycloak/testsuite/TestPlatform.java
index 5dfb48d654..152402a45d 100644
--- a/testsuite/utils/src/main/java/org/keycloak/testsuite/TestPlatform.java
+++ b/testsuite/utils/src/main/java/org/keycloak/testsuite/TestPlatform.java
@@ -17,12 +17,20 @@
package org.keycloak.testsuite;
+import org.keycloak.common.util.Resteasy;
+import org.keycloak.models.KeycloakSessionFactory;
import org.keycloak.platform.PlatformProvider;
+import org.keycloak.services.resources.KeycloakApplication;
+
+import javax.servlet.ServletContext;
public class TestPlatform implements PlatformProvider {
@Override
public void onStartup(Runnable startupHook) {
+ KeycloakApplication keycloakApplication = Resteasy.getContextData(KeycloakApplication.class);
+ ServletContext context = Resteasy.getContextData(ServletContext.class);
+ context.setAttribute(KeycloakSessionFactory.class.getName(), keycloakApplication.getSessionFactory());
startupHook.run();
}
diff --git a/wildfly/extensions/pom.xml b/wildfly/extensions/pom.xml
index dea05634cb..dbd7ef4c2b 100755
--- a/wildfly/extensions/pom.xml
+++ b/wildfly/extensions/pom.xml
@@ -55,6 +55,11 @@
keycloak-services
provided
+
+ org.jboss.spec.javax.servlet
+ jboss-servlet-api_4.0_spec
+ provided
+
junit
junit
diff --git a/wildfly/extensions/src/main/java/org/keycloak/provider/wildfly/KeycloakSessionServletFilter.java b/wildfly/extensions/src/main/java/org/keycloak/provider/wildfly/KeycloakSessionServletFilter.java
new file mode 100755
index 0000000000..6dfe63246a
--- /dev/null
+++ b/wildfly/extensions/src/main/java/org/keycloak/provider/wildfly/KeycloakSessionServletFilter.java
@@ -0,0 +1,138 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.provider.wildfly;
+
+import java.io.IOException;
+
+import javax.servlet.AsyncEvent;
+import javax.servlet.AsyncListener;
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+
+import org.keycloak.common.ClientConnection;
+import org.keycloak.common.util.Resteasy;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.KeycloakSessionFactory;
+import org.keycloak.models.KeycloakTransaction;
+
+/**
+ * @author Bill Burke
+ * @version $Revision: 1 $
+ */
+public class KeycloakSessionServletFilter implements Filter {
+
+ @Override
+ public void init(FilterConfig filterConfig) throws ServletException {
+ }
+
+ @Override
+ public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
+ servletRequest.setCharacterEncoding("UTF-8");
+
+ final HttpServletRequest request = (HttpServletRequest)servletRequest;
+
+ KeycloakSessionFactory sessionFactory = (KeycloakSessionFactory) servletRequest.getServletContext().getAttribute(KeycloakSessionFactory.class.getName());
+ KeycloakSession session = sessionFactory.create();
+ Resteasy.pushContext(KeycloakSession.class, session);
+ ClientConnection connection = new ClientConnection() {
+ @Override
+ public String getRemoteAddr() {
+ return request.getRemoteAddr();
+ }
+
+ @Override
+ public String getRemoteHost() {
+ return request.getRemoteHost();
+ }
+
+ @Override
+ public int getRemotePort() {
+ return request.getRemotePort();
+ }
+
+ @Override
+ public String getLocalAddr() {
+ return request.getLocalAddr();
+ }
+
+ @Override
+ public int getLocalPort() {
+ return request.getLocalPort();
+ }
+ };
+ session.getContext().setConnection(connection);
+ Resteasy.pushContext(ClientConnection.class, connection);
+
+ KeycloakTransaction tx = session.getTransactionManager();
+ Resteasy.pushContext(KeycloakTransaction.class, tx);
+ tx.begin();
+
+ try {
+ filterChain.doFilter(servletRequest, servletResponse);
+ } finally {
+ if (servletRequest.isAsyncStarted()) {
+ servletRequest.getAsyncContext().addListener(createAsyncLifeCycleListener(session));
+ } else {
+ closeSession(session);
+ }
+ }
+ }
+
+ private AsyncListener createAsyncLifeCycleListener(final KeycloakSession session) {
+ return new AsyncListener() {
+ @Override
+ public void onComplete(AsyncEvent event) {
+ closeSession(session);
+ }
+
+ @Override
+ public void onTimeout(AsyncEvent event) {
+ closeSession(session);
+ }
+
+ @Override
+ public void onError(AsyncEvent event) {
+ closeSession(session);
+ }
+
+ @Override
+ public void onStartAsync(AsyncEvent event) {
+ }
+ };
+ }
+
+ private void closeSession(KeycloakSession session) {
+ // KeycloakTransactionCommitter is responsible for committing the transaction, but if an exception is thrown it's not invoked and transaction
+ // should be rolled back
+ if (session.getTransactionManager() != null && session.getTransactionManager().isActive()) {
+ session.getTransactionManager().rollback();
+ }
+
+ session.close();
+ Resteasy.clearContextData();
+ }
+
+ @Override
+ public void destroy() {
+ }
+}
diff --git a/wildfly/extensions/src/main/java/org/keycloak/provider/wildfly/WildflyPlatform.java b/wildfly/extensions/src/main/java/org/keycloak/provider/wildfly/WildflyPlatform.java
index 103e318076..fdfecbd97a 100644
--- a/wildfly/extensions/src/main/java/org/keycloak/provider/wildfly/WildflyPlatform.java
+++ b/wildfly/extensions/src/main/java/org/keycloak/provider/wildfly/WildflyPlatform.java
@@ -17,8 +17,13 @@
package org.keycloak.provider.wildfly;
+import org.keycloak.common.util.Resteasy;
+import org.keycloak.models.KeycloakSessionFactory;
import org.keycloak.platform.PlatformProvider;
import org.keycloak.services.ServicesLogger;
+import org.keycloak.services.resources.KeycloakApplication;
+
+import javax.servlet.ServletContext;
public class WildflyPlatform implements PlatformProvider {
@@ -26,6 +31,9 @@ public class WildflyPlatform implements PlatformProvider {
@Override
public void onStartup(Runnable startupHook) {
+ KeycloakApplication keycloakApplication = Resteasy.getContextData(KeycloakApplication.class);
+ ServletContext context = Resteasy.getContextData(ServletContext.class);
+ context.setAttribute(KeycloakSessionFactory.class.getName(), keycloakApplication.getSessionFactory());
startupHook.run();
}