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(); }