[KEYCLOAK-11719] - Remove need for servlets/undertow from Quarkus dist
Co-authored-by: MatthewC <matthewc@backbase.com>
This commit is contained in:
parent
666832d1be
commit
35f622f48e
22 changed files with 324 additions and 97 deletions
|
@ -49,7 +49,7 @@
|
||||||
|
|
||||||
<filter>
|
<filter>
|
||||||
<filter-name>Keycloak Session Management</filter-name>
|
<filter-name>Keycloak Session Management</filter-name>
|
||||||
<filter-class>org.keycloak.services.filters.KeycloakSessionServletFilter</filter-class>
|
<filter-class>org.keycloak.provider.wildfly.KeycloakSessionServletFilter</filter-class>
|
||||||
<async-supported>true</async-supported>
|
<async-supported>true</async-supported>
|
||||||
</filter>
|
</filter>
|
||||||
|
|
||||||
|
|
|
@ -30,6 +30,10 @@
|
||||||
<groupId>org.slf4j</groupId>
|
<groupId>org.slf4j</groupId>
|
||||||
<artifactId>slf4j-simple</artifactId>
|
<artifactId>slf4j-simple</artifactId>
|
||||||
</exclusion>
|
</exclusion>
|
||||||
|
<exclusion>
|
||||||
|
<groupId>org.jboss.spec.javax.servlet</groupId>
|
||||||
|
<artifactId>jboss-servlet-api_4.0_spec</artifactId>
|
||||||
|
</exclusion>
|
||||||
</exclusions>
|
</exclusions>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
|
@ -43,6 +47,12 @@
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.keycloak</groupId>
|
<groupId>org.keycloak</groupId>
|
||||||
<artifactId>keycloak-services</artifactId>
|
<artifactId>keycloak-services</artifactId>
|
||||||
|
<exclusions>
|
||||||
|
<exclusion>
|
||||||
|
<groupId>org.jboss.spec.javax.servlet</groupId>
|
||||||
|
<artifactId>jboss-servlet-api_4.0_spec</artifactId>
|
||||||
|
</exclusion>
|
||||||
|
</exclusions>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.keycloak</groupId>
|
<groupId>org.keycloak</groupId>
|
||||||
|
@ -67,6 +77,20 @@
|
||||||
<artifactId>quarkus-agroal</artifactId>
|
<artifactId>quarkus-agroal</artifactId>
|
||||||
<type>jar</type>
|
<type>jar</type>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.quarkus</groupId>
|
||||||
|
<artifactId>quarkus-vertx-web</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.keycloak</groupId>
|
||||||
|
<artifactId>keycloak-common</artifactId>
|
||||||
|
<exclusions>
|
||||||
|
<exclusion>
|
||||||
|
<groupId>*</groupId>
|
||||||
|
<artifactId>*</artifactId>
|
||||||
|
</exclusion>
|
||||||
|
</exclusions>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>junit</groupId>
|
<groupId>junit</groupId>
|
||||||
<artifactId>junit</artifactId>
|
<artifactId>junit</artifactId>
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
package org.keycloak;
|
||||||
|
|
||||||
|
import javax.ws.rs.ApplicationPath;
|
||||||
|
|
||||||
|
import org.keycloak.services.resources.KeycloakApplication;
|
||||||
|
|
||||||
|
@ApplicationPath("/")
|
||||||
|
public class QuarkusKeycloakApplication extends KeycloakApplication {
|
||||||
|
|
||||||
|
}
|
|
@ -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();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
|
@ -22,7 +22,6 @@ import io.quarkus.runtime.StartupEvent;
|
||||||
import javax.enterprise.context.ApplicationScoped;
|
import javax.enterprise.context.ApplicationScoped;
|
||||||
import javax.enterprise.event.Observes;
|
import javax.enterprise.event.Observes;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import javax.servlet.ServletContext;
|
|
||||||
|
|
||||||
import org.keycloak.Config;
|
import org.keycloak.Config;
|
||||||
import org.keycloak.models.KeycloakSession;
|
import org.keycloak.models.KeycloakSession;
|
||||||
|
@ -31,6 +30,7 @@ import org.keycloak.models.KeycloakTransactionManager;
|
||||||
import org.keycloak.platform.Platform;
|
import org.keycloak.platform.Platform;
|
||||||
import org.keycloak.services.ServicesLogger;
|
import org.keycloak.services.ServicesLogger;
|
||||||
import org.keycloak.services.managers.ApplianceBootstrap;
|
import org.keycloak.services.managers.ApplianceBootstrap;
|
||||||
|
import org.keycloak.services.resources.KeycloakApplication;
|
||||||
|
|
||||||
@ApplicationScoped
|
@ApplicationScoped
|
||||||
public class QuarkusLifecycleObserver {
|
public class QuarkusLifecycleObserver {
|
||||||
|
@ -39,7 +39,7 @@ public class QuarkusLifecycleObserver {
|
||||||
private static final String KEYCLOAK_ADMIN_PASSWORD_ENV_VAR = "KEYCLOAK_ADMIN_PASSWORD";
|
private static final String KEYCLOAK_ADMIN_PASSWORD_ENV_VAR = "KEYCLOAK_ADMIN_PASSWORD";
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
ServletContext servletContext;
|
KeycloakApplication application;
|
||||||
|
|
||||||
private void onStartupEvent(@Observes StartupEvent event) {
|
private void onStartupEvent(@Observes StartupEvent event) {
|
||||||
|
|
||||||
|
@ -70,8 +70,7 @@ public class QuarkusLifecycleObserver {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
KeycloakSessionFactory sessionFactory = (KeycloakSessionFactory) servletContext
|
KeycloakSessionFactory sessionFactory = application.getSessionFactory();
|
||||||
.getAttribute(KeycloakSessionFactory.class.getName());
|
|
||||||
KeycloakSession session = sessionFactory.create();
|
KeycloakSession session = sessionFactory.create();
|
||||||
KeycloakTransactionManager transaction = session.getTransactionManager();
|
KeycloakTransactionManager transaction = session.getTransactionManager();
|
||||||
|
|
||||||
|
|
|
@ -31,7 +31,7 @@
|
||||||
<packaging>pom</packaging>
|
<packaging>pom</packaging>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<quarkus.version>1.2.1.Final</quarkus.version>
|
<quarkus.version>999-SNAPSHOT</quarkus.version>
|
||||||
<resteasy.version>4.4.2.Final</resteasy.version>
|
<resteasy.version>4.4.2.Final</resteasy.version>
|
||||||
<jackson.version>2.10.2</jackson.version>
|
<jackson.version>2.10.2</jackson.version>
|
||||||
<jackson.databind.version>${jackson.version}</jackson.databind.version>
|
<jackson.databind.version>${jackson.version}</jackson.databind.version>
|
||||||
|
|
|
@ -15,10 +15,6 @@
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<!-- Quarkus -->
|
<!-- Quarkus -->
|
||||||
<dependency>
|
|
||||||
<groupId>io.quarkus</groupId>
|
|
||||||
<artifactId>quarkus-undertow</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.quarkus</groupId>
|
<groupId>io.quarkus</groupId>
|
||||||
<artifactId>quarkus-resteasy</artifactId>
|
<artifactId>quarkus-resteasy</artifactId>
|
||||||
|
|
|
@ -1,62 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<!--
|
|
||||||
~ 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.
|
|
||||||
-->
|
|
||||||
|
|
||||||
<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>auth</module-name>
|
|
||||||
|
|
||||||
<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.services.resources.KeycloakApplication</param-value>
|
|
||||||
</init-param>
|
|
||||||
<init-param>
|
|
||||||
<param-name>resteasy.servlet.mapping.prefix</param-name>
|
|
||||||
<param-value>/</param-value>
|
|
||||||
</init-param>
|
|
||||||
<load-on-startup>1</load-on-startup>
|
|
||||||
<async-supported>true</async-supported>
|
|
||||||
</servlet>
|
|
||||||
|
|
||||||
<context-param>
|
|
||||||
<param-name>resteasy.disable.html.sanitizer</param-name>
|
|
||||||
<param-value>true</param-value>
|
|
||||||
</context-param>
|
|
||||||
|
|
||||||
<listener>
|
|
||||||
<listener-class>
|
|
||||||
org.jboss.resteasy.plugins.server.servlet.ResteasyBootstrap
|
|
||||||
</listener-class>
|
|
||||||
</listener>
|
|
||||||
|
|
||||||
<filter>
|
|
||||||
<filter-name>Keycloak Session Management</filter-name>
|
|
||||||
<filter-class>org.keycloak.services.filters.KeycloakSessionServletFilter</filter-class>
|
|
||||||
<async-supported>true</async-supported>
|
|
||||||
</filter>
|
|
||||||
|
|
||||||
<filter-mapping>
|
|
||||||
<filter-name>Keycloak Session Management</filter-name>
|
|
||||||
<url-pattern>/*</url-pattern>
|
|
||||||
</filter-mapping>
|
|
||||||
</web-app>
|
|
|
@ -1,7 +1,6 @@
|
||||||
#quarkus.log.level = DEBUG
|
#quarkus.log.level = DEBUG
|
||||||
|
|
||||||
quarkus.application.name=Keycloak
|
quarkus.application.name=Keycloak
|
||||||
quarkus.servlet.context-path = /auth
|
|
||||||
quarkus.datasource.driver=org.h2.Driver
|
quarkus.datasource.driver=org.h2.Driver
|
||||||
|
|
||||||
resteasy.disable.html.sanitizer = true
|
resteasy.disable.html.sanitizer = true
|
|
@ -79,10 +79,6 @@
|
||||||
<artifactId>keycloak-ldap-federation</artifactId>
|
<artifactId>keycloak-ldap-federation</artifactId>
|
||||||
<scope>provided</scope>
|
<scope>provided</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
|
||||||
<groupId>org.jboss.spec.javax.servlet</groupId>
|
|
||||||
<artifactId>jboss-servlet-api_4.0_spec</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.twitter4j</groupId>
|
<groupId>org.twitter4j</groupId>
|
||||||
<artifactId>twitter4j-core</artifactId>
|
<artifactId>twitter4j-core</artifactId>
|
||||||
|
|
|
@ -56,6 +56,7 @@ import org.keycloak.services.util.AuthenticationFlowURLHelper;
|
||||||
import org.keycloak.sessions.AuthenticationSessionModel;
|
import org.keycloak.sessions.AuthenticationSessionModel;
|
||||||
import org.keycloak.sessions.CommonClientSessionModel;
|
import org.keycloak.sessions.CommonClientSessionModel;
|
||||||
|
|
||||||
|
import javax.ws.rs.core.MultivaluedHashMap;
|
||||||
import javax.ws.rs.core.Response;
|
import javax.ws.rs.core.Response;
|
||||||
import javax.ws.rs.core.UriBuilder;
|
import javax.ws.rs.core.UriBuilder;
|
||||||
import javax.ws.rs.core.UriInfo;
|
import javax.ws.rs.core.UriInfo;
|
||||||
|
@ -508,7 +509,8 @@ public class AuthenticationProcessor {
|
||||||
.setUser(getUser())
|
.setUser(getUser())
|
||||||
.setActionUri(action)
|
.setActionUri(action)
|
||||||
.setExecution(getExecution().getId())
|
.setExecution(getExecution().getId())
|
||||||
.setFormData(request.getDecodedFormParameters())
|
.setFormData(request.getHttpMethod().equalsIgnoreCase("post") ? request.getDecodedFormParameters() :
|
||||||
|
new MultivaluedHashMap<>())
|
||||||
.setClientSessionCode(accessCode);
|
.setClientSessionCode(accessCode);
|
||||||
if (getForwardedErrorMessage() != null) {
|
if (getForwardedErrorMessage() != null) {
|
||||||
provider.addError(getForwardedErrorMessage());
|
provider.addError(getForwardedErrorMessage());
|
||||||
|
|
|
@ -23,6 +23,7 @@ package org.keycloak.services.filters;
|
||||||
import org.keycloak.common.util.Resteasy;
|
import org.keycloak.common.util.Resteasy;
|
||||||
import org.keycloak.models.KeycloakTransaction;
|
import org.keycloak.models.KeycloakTransaction;
|
||||||
|
|
||||||
|
import javax.annotation.Priority;
|
||||||
import javax.ws.rs.container.ContainerRequestContext;
|
import javax.ws.rs.container.ContainerRequestContext;
|
||||||
import javax.ws.rs.container.ContainerResponseContext;
|
import javax.ws.rs.container.ContainerResponseContext;
|
||||||
import javax.ws.rs.container.ContainerResponseFilter;
|
import javax.ws.rs.container.ContainerResponseFilter;
|
||||||
|
@ -31,6 +32,7 @@ import java.io.IOException;
|
||||||
/**
|
/**
|
||||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||||
*/
|
*/
|
||||||
|
@Priority(2)
|
||||||
public class KeycloakTransactionCommitter implements ContainerResponseFilter {
|
public class KeycloakTransactionCommitter implements ContainerResponseFilter {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -58,7 +58,6 @@ import org.keycloak.timer.TimerProvider;
|
||||||
import org.keycloak.transaction.JtaTransactionManagerLookup;
|
import org.keycloak.transaction.JtaTransactionManagerLookup;
|
||||||
import org.keycloak.util.JsonSerialization;
|
import org.keycloak.util.JsonSerialization;
|
||||||
|
|
||||||
import javax.servlet.ServletContext;
|
|
||||||
import javax.transaction.SystemException;
|
import javax.transaction.SystemException;
|
||||||
import javax.transaction.Transaction;
|
import javax.transaction.Transaction;
|
||||||
import javax.ws.rs.core.Application;
|
import javax.ws.rs.core.Application;
|
||||||
|
@ -99,15 +98,12 @@ public class KeycloakApplication extends Application {
|
||||||
logger.debugv("PlatformProvider: {0}", platform.getClass().getName());
|
logger.debugv("PlatformProvider: {0}", platform.getClass().getName());
|
||||||
logger.debugv("RestEasy provider: {0}", Resteasy.getProvider().getClass().getName());
|
logger.debugv("RestEasy provider: {0}", Resteasy.getProvider().getClass().getName());
|
||||||
|
|
||||||
ServletContext context = Resteasy.getContextData(ServletContext.class);
|
|
||||||
|
|
||||||
loadConfig();
|
loadConfig();
|
||||||
|
|
||||||
this.sessionFactory = createSessionFactory();
|
this.sessionFactory = createSessionFactory();
|
||||||
|
|
||||||
Resteasy.pushDefaultContextObject(KeycloakApplication.class, this);
|
Resteasy.pushDefaultContextObject(KeycloakApplication.class, this);
|
||||||
Resteasy.pushContext(KeycloakApplication.class, this); // for injection
|
Resteasy.pushContext(KeycloakApplication.class, this); // for injection
|
||||||
context.setAttribute(KeycloakSessionFactory.class.getName(), this.sessionFactory);
|
|
||||||
|
|
||||||
singletons.add(new RobotsResource());
|
singletons.add(new RobotsResource());
|
||||||
singletons.add(new RealmsResource());
|
singletons.add(new RealmsResource());
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
|
|
||||||
package org.keycloak.services.resources.admin;
|
package org.keycloak.services.resources.admin;
|
||||||
|
|
||||||
|
import org.jboss.resteasy.spi.HttpResponse;
|
||||||
import org.keycloak.events.admin.OperationType;
|
import org.keycloak.events.admin.OperationType;
|
||||||
import org.keycloak.events.admin.ResourceType;
|
import org.keycloak.events.admin.ResourceType;
|
||||||
import org.keycloak.models.ClientInitialAccessModel;
|
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.clientregistration.ClientRegistrationTokenUtils;
|
||||||
import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator;
|
import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator;
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletResponse;
|
|
||||||
import javax.ws.rs.Consumes;
|
import javax.ws.rs.Consumes;
|
||||||
import javax.ws.rs.DELETE;
|
import javax.ws.rs.DELETE;
|
||||||
import javax.ws.rs.GET;
|
import javax.ws.rs.GET;
|
||||||
|
@ -71,7 +71,7 @@ public class ClientInitialAccessResource {
|
||||||
@POST
|
@POST
|
||||||
@Consumes(MediaType.APPLICATION_JSON)
|
@Consumes(MediaType.APPLICATION_JSON)
|
||||||
@Produces(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();
|
auth.clients().requireManage();
|
||||||
|
|
||||||
int expiration = config.getExpiration() != null ? config.getExpiration() : 0;
|
int expiration = config.getExpiration() != null ? config.getExpiration() : 0;
|
||||||
|
@ -87,7 +87,7 @@ public class ClientInitialAccessResource {
|
||||||
rep.setToken(token);
|
rep.setToken(token);
|
||||||
|
|
||||||
response.setStatus(Response.Status.CREATED.getStatusCode());
|
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;
|
return rep;
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,7 +46,6 @@ import org.jboss.shrinkwrap.undertow.api.UndertowWebArchive;
|
||||||
import org.keycloak.common.util.reflections.Reflections;
|
import org.keycloak.common.util.reflections.Reflections;
|
||||||
import org.keycloak.models.KeycloakSession;
|
import org.keycloak.models.KeycloakSession;
|
||||||
import org.keycloak.models.KeycloakSessionFactory;
|
import org.keycloak.models.KeycloakSessionFactory;
|
||||||
import org.keycloak.services.filters.KeycloakSessionServletFilter;
|
|
||||||
import org.keycloak.services.managers.ApplianceBootstrap;
|
import org.keycloak.services.managers.ApplianceBootstrap;
|
||||||
import org.keycloak.services.resources.KeycloakApplication;
|
import org.keycloak.services.resources.KeycloakApplication;
|
||||||
import org.keycloak.testsuite.JsonConfigProviderFactory;
|
import org.keycloak.testsuite.JsonConfigProviderFactory;
|
||||||
|
|
|
@ -33,7 +33,6 @@ import org.keycloak.models.KeycloakSession;
|
||||||
import org.keycloak.models.KeycloakSessionFactory;
|
import org.keycloak.models.KeycloakSessionFactory;
|
||||||
import org.keycloak.models.RealmModel;
|
import org.keycloak.models.RealmModel;
|
||||||
import org.keycloak.representations.idm.RealmRepresentation;
|
import org.keycloak.representations.idm.RealmRepresentation;
|
||||||
import org.keycloak.services.filters.KeycloakSessionServletFilter;
|
|
||||||
import org.keycloak.services.managers.ApplianceBootstrap;
|
import org.keycloak.services.managers.ApplianceBootstrap;
|
||||||
import org.keycloak.services.managers.RealmManager;
|
import org.keycloak.services.managers.RealmManager;
|
||||||
import org.keycloak.services.resources.KeycloakApplication;
|
import org.keycloak.services.resources.KeycloakApplication;
|
||||||
|
|
|
@ -15,14 +15,9 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.keycloak.services.filters;
|
package org.keycloak.testsuite;
|
||||||
|
|
||||||
import org.jboss.resteasy.spi.ResteasyProviderFactory;
|
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;
|
|
||||||
|
|
||||||
import javax.servlet.AsyncEvent;
|
import javax.servlet.AsyncEvent;
|
||||||
import javax.servlet.AsyncListener;
|
import javax.servlet.AsyncListener;
|
||||||
|
@ -33,7 +28,12 @@ import javax.servlet.ServletException;
|
||||||
import javax.servlet.ServletRequest;
|
import javax.servlet.ServletRequest;
|
||||||
import javax.servlet.ServletResponse;
|
import javax.servlet.ServletResponse;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
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 <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
|
@ -25,8 +25,6 @@ import javax.servlet.http.HttpServletRequest;
|
||||||
import javax.servlet.http.HttpServletRequestWrapper;
|
import javax.servlet.http.HttpServletRequestWrapper;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
import org.keycloak.services.filters.KeycloakSessionServletFilter;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
|
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -17,12 +17,20 @@
|
||||||
|
|
||||||
package org.keycloak.testsuite;
|
package org.keycloak.testsuite;
|
||||||
|
|
||||||
|
import org.keycloak.common.util.Resteasy;
|
||||||
|
import org.keycloak.models.KeycloakSessionFactory;
|
||||||
import org.keycloak.platform.PlatformProvider;
|
import org.keycloak.platform.PlatformProvider;
|
||||||
|
import org.keycloak.services.resources.KeycloakApplication;
|
||||||
|
|
||||||
|
import javax.servlet.ServletContext;
|
||||||
|
|
||||||
public class TestPlatform implements PlatformProvider {
|
public class TestPlatform implements PlatformProvider {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onStartup(Runnable startupHook) {
|
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();
|
startupHook.run();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -55,6 +55,11 @@
|
||||||
<artifactId>keycloak-services</artifactId>
|
<artifactId>keycloak-services</artifactId>
|
||||||
<scope>provided</scope>
|
<scope>provided</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.jboss.spec.javax.servlet</groupId>
|
||||||
|
<artifactId>jboss-servlet-api_4.0_spec</artifactId>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>junit</groupId>
|
<groupId>junit</groupId>
|
||||||
<artifactId>junit</artifactId>
|
<artifactId>junit</artifactId>
|
||||||
|
|
|
@ -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 <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||||
|
* @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() {
|
||||||
|
}
|
||||||
|
}
|
|
@ -17,8 +17,13 @@
|
||||||
|
|
||||||
package org.keycloak.provider.wildfly;
|
package org.keycloak.provider.wildfly;
|
||||||
|
|
||||||
|
import org.keycloak.common.util.Resteasy;
|
||||||
|
import org.keycloak.models.KeycloakSessionFactory;
|
||||||
import org.keycloak.platform.PlatformProvider;
|
import org.keycloak.platform.PlatformProvider;
|
||||||
import org.keycloak.services.ServicesLogger;
|
import org.keycloak.services.ServicesLogger;
|
||||||
|
import org.keycloak.services.resources.KeycloakApplication;
|
||||||
|
|
||||||
|
import javax.servlet.ServletContext;
|
||||||
|
|
||||||
public class WildflyPlatform implements PlatformProvider {
|
public class WildflyPlatform implements PlatformProvider {
|
||||||
|
|
||||||
|
@ -26,6 +31,9 @@ public class WildflyPlatform implements PlatformProvider {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onStartup(Runnable startupHook) {
|
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();
|
startupHook.run();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue