Remove Tomcat OIDC adapter
Closes #28778 Signed-off-by: Douglas Palmer <dpalmer@redhat.com>
This commit is contained in:
parent
98faf6e6a0
commit
43aa10e091
37 changed files with 0 additions and 2274 deletions
|
@ -42,7 +42,6 @@
|
|||
<module>spring-boot-adapter-core</module>
|
||||
<module>spring-boot-container-bundle</module>
|
||||
<module>spring-security</module>
|
||||
<module>tomcat</module>
|
||||
<module>undertow</module>
|
||||
<module>wildfly</module>
|
||||
<module>wildfly-elytron</module>
|
||||
|
|
|
@ -15,11 +15,6 @@
|
|||
<artifactId>keycloak-adapter-core</artifactId>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-tomcat-adapter</artifactId>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-undertow-adapter</artifactId>
|
||||
|
@ -45,11 +40,8 @@
|
|||
<configuration>
|
||||
<artifactSet>
|
||||
<includes>
|
||||
<include>org.keycloak:keycloak-tomcat-adapter</include>
|
||||
<include>org.keycloak:keycloak-undertow-adapter</include>
|
||||
<include>org.keycloak:keycloak-jetty94-adapter</include>
|
||||
<include>org.keycloak:keycloak-tomcat-core-adapter</include>
|
||||
<include>org.keycloak:keycloak-tomcat-adapter-spi</include>
|
||||
<include>org.keycloak:keycloak-undertow-adapter</include>
|
||||
<include>org.keycloak:keycloak-undertow-adapter-spi</include>
|
||||
<include>org.keycloak:keycloak-jetty-core</include>
|
||||
|
|
|
@ -1,38 +0,0 @@
|
|||
<!--
|
||||
~ 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.
|
||||
-->
|
||||
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>999.0.0-SNAPSHOT</version>
|
||||
<relativePath>../../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<name>Keycloak Tomcat Integration</name>
|
||||
<description/>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>keycloak-tomcat-integration-pom</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
|
||||
<modules>
|
||||
<module>tomcat-core</module>
|
||||
<module>tomcat</module>
|
||||
</modules>
|
||||
|
||||
</project>
|
|
@ -1,108 +0,0 @@
|
|||
<?xml version="1.0"?>
|
||||
<!--
|
||||
~ 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.
|
||||
-->
|
||||
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<parent>
|
||||
<artifactId>keycloak-tomcat-integration-pom</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>999.0.0-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>keycloak-tomcat-core-adapter</artifactId>
|
||||
<name>Keycloak Tomcat Core Integration</name>
|
||||
<description />
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.jboss.logging</groupId>
|
||||
<artifactId>jboss-logging</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jboss.logging</groupId>
|
||||
<artifactId>commons-logging-jboss-logging</artifactId>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-core</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-adapter-spi</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-tomcat-adapter-spi</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-adapter-core</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.httpcomponents</groupId>
|
||||
<artifactId>httpclient</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.bouncycastle</groupId>
|
||||
<artifactId>bcprov-jdk18on</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-core</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-databind</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-annotations</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Authorization -->
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-authz-client</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!--
|
||||
<dependency>
|
||||
<groupId>org.apache.tomcat</groupId>
|
||||
<artifactId>tomcat-servlet-api</artifactId>
|
||||
<version>${tomcat.version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
-->
|
||||
<dependency>
|
||||
<groupId>org.apache.tomcat</groupId>
|
||||
<artifactId>tomcat-catalina</artifactId>
|
||||
<version>${tomcat8.version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
|
@ -1,69 +0,0 @@
|
|||
/*
|
||||
* 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.adapters.tomcat;
|
||||
|
||||
import org.apache.catalina.Container;
|
||||
import org.apache.catalina.Valve;
|
||||
import org.apache.catalina.connector.Request;
|
||||
import org.apache.catalina.connector.Response;
|
||||
import org.apache.catalina.valves.ValveBase;
|
||||
import org.jboss.logging.Logger;
|
||||
import org.keycloak.adapters.AdapterDeploymentContext;
|
||||
import org.keycloak.adapters.AuthenticatedActionsHandler;
|
||||
import org.keycloak.adapters.KeycloakDeployment;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Abstract base for pre-installed actions that must be authenticated
|
||||
* <p/>
|
||||
* Actions include:
|
||||
* <p/>
|
||||
* CORS Origin Check and Response headers
|
||||
* k_query_bearer_token: Get bearer token from server for Javascripts CORS requests
|
||||
*
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public abstract class AbstractAuthenticatedActionsValve extends ValveBase {
|
||||
private static final Logger log = Logger.getLogger(AbstractAuthenticatedActionsValve.class);
|
||||
protected AdapterDeploymentContext deploymentContext;
|
||||
|
||||
public AbstractAuthenticatedActionsValve(AdapterDeploymentContext deploymentContext, Valve next, Container container) {
|
||||
this.deploymentContext = deploymentContext;
|
||||
if (next == null) throw new RuntimeException("Next valve is null!!!");
|
||||
setNext(next);
|
||||
setContainer(container);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invoke(Request request, Response response) throws IOException, ServletException {
|
||||
log.debugv("AuthenticatedActionsValve.invoke {0}", request.getRequestURI());
|
||||
CatalinaHttpFacade facade = new OIDCCatalinaHttpFacade(request, response);
|
||||
KeycloakDeployment deployment = deploymentContext.resolveDeployment(facade);
|
||||
if (deployment != null && deployment.isConfigured()) {
|
||||
AuthenticatedActionsHandler handler = new AuthenticatedActionsHandler(deployment, new OIDCCatalinaHttpFacade(request, response));
|
||||
if (handler.handledRequest()) {
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
getNext().invoke(request, response);
|
||||
}
|
||||
}
|
|
@ -1,266 +0,0 @@
|
|||
/*
|
||||
* 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.adapters.tomcat;
|
||||
|
||||
import org.apache.catalina.*;
|
||||
import org.apache.catalina.authenticator.FormAuthenticator;
|
||||
import org.apache.catalina.connector.Request;
|
||||
import org.apache.catalina.connector.Response;
|
||||
import org.jboss.logging.Logger;
|
||||
import org.keycloak.KeycloakSecurityContext;
|
||||
import org.keycloak.adapters.AdapterDeploymentContext;
|
||||
import org.keycloak.adapters.AdapterTokenStore;
|
||||
import org.keycloak.adapters.KeycloakConfigResolver;
|
||||
import org.keycloak.adapters.KeycloakDeployment;
|
||||
import org.keycloak.adapters.KeycloakDeploymentBuilder;
|
||||
import org.keycloak.adapters.NodesRegistrationManagement;
|
||||
import org.keycloak.adapters.PreAuthActionsHandler;
|
||||
import org.keycloak.adapters.RefreshableKeycloakSecurityContext;
|
||||
import org.keycloak.adapters.spi.AuthChallenge;
|
||||
import org.keycloak.adapters.spi.AuthOutcome;
|
||||
import org.keycloak.adapters.spi.HttpFacade;
|
||||
import org.keycloak.constants.AdapterConstants;
|
||||
import org.keycloak.enums.TokenStore;
|
||||
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
/**
|
||||
* Keycloak authentication valve
|
||||
*
|
||||
* @author <a href="mailto:ungarida@gmail.com">Davide Ungari</a>
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public abstract class AbstractKeycloakAuthenticatorValve extends FormAuthenticator implements LifecycleListener {
|
||||
|
||||
public static final String TOKEN_STORE_NOTE = "TOKEN_STORE_NOTE";
|
||||
|
||||
private final static Logger log = Logger.getLogger(AbstractKeycloakAuthenticatorValve.class);
|
||||
protected CatalinaUserSessionManagement userSessionManagement = new CatalinaUserSessionManagement();
|
||||
protected AdapterDeploymentContext deploymentContext;
|
||||
protected NodesRegistrationManagement nodesRegistrationManagement;
|
||||
|
||||
@Override
|
||||
public void lifecycleEvent(LifecycleEvent event) {
|
||||
if (Lifecycle.START_EVENT.equals(event.getType())) {
|
||||
cache = false;
|
||||
} else if (Lifecycle.AFTER_START_EVENT.equals(event.getType())) {
|
||||
keycloakInit();
|
||||
} else if (Lifecycle.BEFORE_STOP_EVENT.equals(event.getType())) {
|
||||
beforeStop();
|
||||
}
|
||||
}
|
||||
|
||||
protected void logoutInternal(Request request) {
|
||||
KeycloakSecurityContext ksc = (KeycloakSecurityContext)request.getAttribute(KeycloakSecurityContext.class.getName());
|
||||
if (ksc != null) {
|
||||
CatalinaHttpFacade facade = new OIDCCatalinaHttpFacade(request, null);
|
||||
KeycloakDeployment deployment = deploymentContext.resolveDeployment(facade);
|
||||
if (ksc instanceof RefreshableKeycloakSecurityContext) {
|
||||
((RefreshableKeycloakSecurityContext) ksc).logout(deployment);
|
||||
}
|
||||
|
||||
AdapterTokenStore tokenStore = getTokenStore(request, facade, deployment);
|
||||
tokenStore.logout();
|
||||
request.removeAttribute(KeycloakSecurityContext.class.getName());
|
||||
}
|
||||
request.setUserPrincipal(null);
|
||||
}
|
||||
|
||||
protected void beforeStop() {
|
||||
if (nodesRegistrationManagement != null) {
|
||||
nodesRegistrationManagement.stop();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings("UseSpecificCatch")
|
||||
public void keycloakInit() {
|
||||
// Possible scenarios:
|
||||
// 1) The deployment has a keycloak.config.resolver specified and it exists:
|
||||
// Outcome: adapter uses the resolver
|
||||
// 2) The deployment has a keycloak.config.resolver and isn't valid (doesn't exist, isn't a resolver, ...) :
|
||||
// Outcome: adapter is left unconfigured
|
||||
// 3) The deployment doesn't have a keycloak.config.resolver , but has a keycloak.json (or equivalent)
|
||||
// Outcome: adapter uses it
|
||||
// 4) The deployment doesn't have a keycloak.config.resolver nor keycloak.json (or equivalent)
|
||||
// Outcome: adapter is left unconfigured
|
||||
|
||||
String configResolverClass = context.getServletContext().getInitParameter("keycloak.config.resolver");
|
||||
if (configResolverClass != null) {
|
||||
try {
|
||||
KeycloakConfigResolver configResolver = (KeycloakConfigResolver) context.getLoader().getClassLoader().loadClass(configResolverClass).newInstance();
|
||||
deploymentContext = new AdapterDeploymentContext(configResolver);
|
||||
log.debugv("Using {0} to resolve Keycloak configuration on a per-request basis.", configResolverClass);
|
||||
} catch (Exception ex) {
|
||||
log.errorv("The specified resolver {0} could NOT be loaded. Keycloak is unconfigured and will deny all requests. Reason: {1}", configResolverClass, ex.getMessage());
|
||||
deploymentContext = new AdapterDeploymentContext(new KeycloakDeployment());
|
||||
}
|
||||
} else {
|
||||
InputStream configInputStream = getConfigInputStream(context);
|
||||
KeycloakDeployment kd;
|
||||
if (configInputStream == null) {
|
||||
log.warn("No adapter configuration. Keycloak is unconfigured and will deny all requests.");
|
||||
kd = new KeycloakDeployment();
|
||||
} else {
|
||||
kd = KeycloakDeploymentBuilder.build(configInputStream);
|
||||
}
|
||||
deploymentContext = new AdapterDeploymentContext(kd);
|
||||
log.debug("Keycloak is using a per-deployment configuration.");
|
||||
}
|
||||
|
||||
context.getServletContext().setAttribute(AdapterDeploymentContext.class.getName(), deploymentContext);
|
||||
AbstractAuthenticatedActionsValve actions = createAuthenticatedActionsValve(deploymentContext, getNext(), getContainer());
|
||||
setNext(actions);
|
||||
|
||||
nodesRegistrationManagement = new NodesRegistrationManagement();
|
||||
}
|
||||
|
||||
|
||||
private static InputStream getJSONFromServletContext(ServletContext servletContext) {
|
||||
String json = servletContext.getInitParameter(AdapterConstants.AUTH_DATA_PARAM_NAME);
|
||||
if (json == null) {
|
||||
return null;
|
||||
}
|
||||
log.trace("**** using " + AdapterConstants.AUTH_DATA_PARAM_NAME);
|
||||
return new ByteArrayInputStream(json.getBytes());
|
||||
}
|
||||
|
||||
private static InputStream getConfigInputStream(Context context) {
|
||||
InputStream is = getJSONFromServletContext(context.getServletContext());
|
||||
if (is == null) {
|
||||
String path = context.getServletContext().getInitParameter("keycloak.config.file");
|
||||
if (path == null) {
|
||||
log.trace("**** using /WEB-INF/keycloak.json");
|
||||
is = context.getServletContext().getResourceAsStream("/WEB-INF/keycloak.json");
|
||||
} else {
|
||||
try {
|
||||
is = new FileInputStream(path);
|
||||
} catch (FileNotFoundException e) {
|
||||
log.errorv("NOT FOUND {0}", path);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
return is;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invoke(Request request, Response response) throws IOException, ServletException {
|
||||
try {
|
||||
CatalinaHttpFacade facade = new OIDCCatalinaHttpFacade(request, response);
|
||||
Manager sessionManager = request.getContext().getManager();
|
||||
CatalinaUserSessionManagementWrapper sessionManagementWrapper = new CatalinaUserSessionManagementWrapper(userSessionManagement, sessionManager);
|
||||
PreAuthActionsHandler handler = new PreAuthActionsHandler(sessionManagementWrapper, deploymentContext, facade);
|
||||
if (handler.handleRequest()) {
|
||||
return;
|
||||
}
|
||||
checkKeycloakSession(request, facade);
|
||||
super.invoke(request, response);
|
||||
} finally {
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract PrincipalFactory createPrincipalFactory();
|
||||
protected abstract boolean forwardToErrorPageInternal(Request request, HttpServletResponse response, Object loginConfig) throws IOException;
|
||||
protected abstract AbstractAuthenticatedActionsValve createAuthenticatedActionsValve(AdapterDeploymentContext deploymentContext, Valve next, Container container);
|
||||
|
||||
protected boolean authenticateInternal(Request request, HttpServletResponse response, Object loginConfig) throws IOException {
|
||||
CatalinaHttpFacade facade = new OIDCCatalinaHttpFacade(request, response);
|
||||
KeycloakDeployment deployment = deploymentContext.resolveDeployment(facade);
|
||||
if (deployment == null || !deployment.isConfigured()) {
|
||||
//needed for the EAP6/AS7 adapter relying on the tomcat core adapter
|
||||
facade.getResponse().sendError(401);
|
||||
return false;
|
||||
}
|
||||
AdapterTokenStore tokenStore = getTokenStore(request, facade, deployment);
|
||||
|
||||
nodesRegistrationManagement.tryRegister(deployment);
|
||||
|
||||
CatalinaRequestAuthenticator authenticator = createRequestAuthenticator(request, facade, deployment, tokenStore);
|
||||
AuthOutcome outcome = authenticator.authenticate();
|
||||
if (outcome == AuthOutcome.AUTHENTICATED) {
|
||||
if (facade.isEnded()) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
AuthChallenge challenge = authenticator.getChallenge();
|
||||
if (challenge != null) {
|
||||
challenge.challenge(facade);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
protected CatalinaRequestAuthenticator createRequestAuthenticator(Request request, CatalinaHttpFacade facade, KeycloakDeployment deployment, AdapterTokenStore tokenStore) {
|
||||
return new CatalinaRequestAuthenticator(deployment, tokenStore, facade, request, createPrincipalFactory());
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that access token is still valid. Will attempt refresh of token if it is not.
|
||||
*
|
||||
* @param request
|
||||
*/
|
||||
protected void checkKeycloakSession(Request request, HttpFacade facade) {
|
||||
KeycloakDeployment deployment = deploymentContext.resolveDeployment(facade);
|
||||
AdapterTokenStore tokenStore = getTokenStore(request, facade, deployment);
|
||||
tokenStore.checkCurrentToken();
|
||||
}
|
||||
|
||||
public void keycloakSaveRequest(Request request) throws IOException {
|
||||
saveRequest(request, request.getSessionInternal(true));
|
||||
}
|
||||
|
||||
public boolean keycloakRestoreRequest(Request request) {
|
||||
try {
|
||||
return restoreRequest(request, request.getSessionInternal());
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
protected AdapterTokenStore getTokenStore(Request request, HttpFacade facade, KeycloakDeployment resolvedDeployment) {
|
||||
AdapterTokenStore store = (AdapterTokenStore)request.getNote(TOKEN_STORE_NOTE);
|
||||
if (store != null) {
|
||||
return store;
|
||||
}
|
||||
|
||||
if (resolvedDeployment.getTokenStore() == TokenStore.SESSION) {
|
||||
store = createSessionTokenStore(request, resolvedDeployment);
|
||||
} else {
|
||||
store = new CatalinaCookieTokenStore(request, facade, resolvedDeployment, createPrincipalFactory());
|
||||
}
|
||||
|
||||
request.setNote(TOKEN_STORE_NOTE, store);
|
||||
return store;
|
||||
}
|
||||
|
||||
private AdapterTokenStore createSessionTokenStore(Request request, KeycloakDeployment resolvedDeployment) {
|
||||
AdapterTokenStore store;
|
||||
store = new CatalinaSessionTokenStore(request, resolvedDeployment, userSessionManagement, createPrincipalFactory(), this);
|
||||
return store;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,49 +0,0 @@
|
|||
/*
|
||||
* 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.adapters.tomcat;
|
||||
|
||||
import org.apache.catalina.connector.Request;
|
||||
import org.keycloak.adapters.spi.AdapterSessionStore;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class CatalinaAdapterSessionStore implements AdapterSessionStore {
|
||||
protected Request request;
|
||||
protected AbstractKeycloakAuthenticatorValve valve;
|
||||
|
||||
public CatalinaAdapterSessionStore(Request request, AbstractKeycloakAuthenticatorValve valve) {
|
||||
this.request = request;
|
||||
this.valve = valve;
|
||||
}
|
||||
|
||||
public void saveRequest() {
|
||||
try {
|
||||
valve.keycloakSaveRequest(request);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean restoreRequest() {
|
||||
return valve.keycloakRestoreRequest(request);
|
||||
}
|
||||
}
|
|
@ -1,138 +0,0 @@
|
|||
/*
|
||||
* 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.adapters.tomcat;
|
||||
|
||||
import org.apache.catalina.connector.Request;
|
||||
import org.apache.catalina.realm.GenericPrincipal;
|
||||
import org.keycloak.KeycloakPrincipal;
|
||||
import org.keycloak.KeycloakSecurityContext;
|
||||
import org.keycloak.adapters.AdapterTokenStore;
|
||||
import org.keycloak.adapters.AdapterUtils;
|
||||
import org.keycloak.adapters.CookieTokenStore;
|
||||
import org.keycloak.adapters.KeycloakDeployment;
|
||||
import org.keycloak.adapters.OidcKeycloakAccount;
|
||||
import org.keycloak.adapters.RefreshableKeycloakSecurityContext;
|
||||
import org.keycloak.adapters.RequestAuthenticator;
|
||||
import org.keycloak.adapters.spi.HttpFacade;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
*/
|
||||
public class CatalinaCookieTokenStore implements AdapterTokenStore {
|
||||
|
||||
private static final Logger log = Logger.getLogger(""+CatalinaCookieTokenStore.class);
|
||||
|
||||
private Request request;
|
||||
private HttpFacade facade;
|
||||
private KeycloakDeployment deployment;
|
||||
private PrincipalFactory principalFactory;
|
||||
|
||||
private KeycloakPrincipal<RefreshableKeycloakSecurityContext> authenticatedPrincipal;
|
||||
|
||||
public CatalinaCookieTokenStore(Request request, HttpFacade facade, KeycloakDeployment deployment, PrincipalFactory principalFactory) {
|
||||
this.request = request;
|
||||
this.facade = facade;
|
||||
this.deployment = deployment;
|
||||
this.principalFactory = principalFactory;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void checkCurrentToken() {
|
||||
this.authenticatedPrincipal = checkPrincipalFromCookie();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCached(RequestAuthenticator authenticator) {
|
||||
// Assuming authenticatedPrincipal set by previous call of checkCurrentToken() during this request
|
||||
if (authenticatedPrincipal != null) {
|
||||
log.fine("remote logged in already. Establish state from cookie");
|
||||
RefreshableKeycloakSecurityContext securityContext = authenticatedPrincipal.getKeycloakSecurityContext();
|
||||
|
||||
if (!securityContext.getRealm().equals(deployment.getRealm())) {
|
||||
log.fine("Account from cookie is from a different realm than for the request.");
|
||||
return false;
|
||||
}
|
||||
|
||||
securityContext.setCurrentRequestInfo(deployment, this);
|
||||
Set<String> roles = AdapterUtils.getRolesFromSecurityContext(securityContext);
|
||||
GenericPrincipal principal = principalFactory.createPrincipal(request.getContext().getRealm(), authenticatedPrincipal, roles);
|
||||
|
||||
request.setAttribute(KeycloakSecurityContext.class.getName(), securityContext);
|
||||
request.setUserPrincipal(principal);
|
||||
request.setAuthType("KEYCLOAK");
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveAccountInfo(OidcKeycloakAccount account) {
|
||||
RefreshableKeycloakSecurityContext securityContext = (RefreshableKeycloakSecurityContext)account.getKeycloakSecurityContext();
|
||||
CookieTokenStore.setTokenCookie(deployment, facade, securityContext);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void logout() {
|
||||
CookieTokenStore.removeCookie(deployment, facade);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void refreshCallback(RefreshableKeycloakSecurityContext secContext) {
|
||||
CookieTokenStore.setTokenCookie(deployment, facade, secContext);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveRequest() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean restoreRequest() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify if we already have authenticated and active principal in cookie. Perform refresh if it's not active
|
||||
*
|
||||
* @return valid principal
|
||||
*/
|
||||
protected KeycloakPrincipal<RefreshableKeycloakSecurityContext> checkPrincipalFromCookie() {
|
||||
KeycloakPrincipal<RefreshableKeycloakSecurityContext> principal = CookieTokenStore.getPrincipalFromCookie(deployment, facade, this);
|
||||
if (principal == null) {
|
||||
log.fine("Account was not in cookie or was invalid");
|
||||
return null;
|
||||
}
|
||||
|
||||
RefreshableKeycloakSecurityContext session = principal.getKeycloakSecurityContext();
|
||||
|
||||
if (session.isActive() && !session.getDeployment().isAlwaysRefreshToken()) return principal;
|
||||
boolean success = session.refreshExpiredToken(false);
|
||||
if (success && session.isActive()) return principal;
|
||||
|
||||
log.fine("Cleanup and expire cookie for user " + principal.getName() + " after failed refresh");
|
||||
request.setUserPrincipal(null);
|
||||
request.setAuthType(null);
|
||||
CookieTokenStore.removeCookie(deployment, facade);
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -1,107 +0,0 @@
|
|||
/*
|
||||
* 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.adapters.tomcat;
|
||||
|
||||
import org.apache.catalina.connector.Request;
|
||||
import org.keycloak.KeycloakPrincipal;
|
||||
import org.keycloak.KeycloakSecurityContext;
|
||||
import org.keycloak.adapters.AdapterTokenStore;
|
||||
import org.keycloak.adapters.AdapterUtils;
|
||||
import org.keycloak.adapters.KeycloakDeployment;
|
||||
import org.keycloak.adapters.OAuthRequestAuthenticator;
|
||||
import org.keycloak.adapters.OidcKeycloakAccount;
|
||||
import org.keycloak.adapters.RefreshableKeycloakSecurityContext;
|
||||
import org.keycloak.adapters.RequestAuthenticator;
|
||||
|
||||
import javax.servlet.http.HttpSession;
|
||||
import java.security.Principal;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:ungarida@gmail.com">Davide Ungari</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class CatalinaRequestAuthenticator extends RequestAuthenticator {
|
||||
private static final Logger log = Logger.getLogger(""+CatalinaRequestAuthenticator.class);
|
||||
protected Request request;
|
||||
protected PrincipalFactory principalFactory;
|
||||
|
||||
public CatalinaRequestAuthenticator(KeycloakDeployment deployment,
|
||||
AdapterTokenStore tokenStore,
|
||||
CatalinaHttpFacade facade,
|
||||
Request request,
|
||||
PrincipalFactory principalFactory) {
|
||||
super(facade, deployment, tokenStore, request.getConnector().getRedirectPort());
|
||||
this.request = request;
|
||||
this.principalFactory = principalFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected OAuthRequestAuthenticator createOAuthAuthenticator() {
|
||||
return new OAuthRequestAuthenticator(this, facade, deployment, sslRedirectPort, tokenStore);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void completeOAuthAuthentication(final KeycloakPrincipal<RefreshableKeycloakSecurityContext> skp) {
|
||||
final RefreshableKeycloakSecurityContext securityContext = skp.getKeycloakSecurityContext();
|
||||
final Set<String> roles = AdapterUtils.getRolesFromSecurityContext(securityContext);
|
||||
OidcKeycloakAccount account = new OidcKeycloakAccount() {
|
||||
|
||||
@Override
|
||||
public Principal getPrincipal() {
|
||||
return skp;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getRoles() {
|
||||
return roles;
|
||||
}
|
||||
|
||||
@Override
|
||||
public KeycloakSecurityContext getKeycloakSecurityContext() {
|
||||
return securityContext;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
request.setAttribute(KeycloakSecurityContext.class.getName(), securityContext);
|
||||
this.tokenStore.saveAccountInfo(account);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void completeBearerAuthentication(KeycloakPrincipal<RefreshableKeycloakSecurityContext> principal, String method) {
|
||||
RefreshableKeycloakSecurityContext securityContext = principal.getKeycloakSecurityContext();
|
||||
Set<String> roles = AdapterUtils.getRolesFromSecurityContext(securityContext);
|
||||
if (log.isLoggable(Level.FINE)) {
|
||||
log.fine("Completing bearer authentication. Bearer roles: " + roles);
|
||||
}
|
||||
Principal generalPrincipal = principalFactory.createPrincipal(request.getContext().getRealm(), principal, roles);
|
||||
request.setUserPrincipal(generalPrincipal);
|
||||
request.setAuthType(method);
|
||||
request.setAttribute(KeycloakSecurityContext.class.getName(), securityContext);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String changeHttpSessionId(boolean create) {
|
||||
HttpSession session = request.getSession(create);
|
||||
return session != null ? session.getId() : null;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,213 +0,0 @@
|
|||
/*
|
||||
* 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.adapters.tomcat;
|
||||
|
||||
import org.apache.catalina.Session;
|
||||
import org.apache.catalina.connector.Request;
|
||||
import org.apache.catalina.realm.GenericPrincipal;
|
||||
import org.keycloak.KeycloakPrincipal;
|
||||
import org.keycloak.KeycloakSecurityContext;
|
||||
import org.keycloak.adapters.AdapterTokenStore;
|
||||
import org.keycloak.adapters.KeycloakDeployment;
|
||||
import org.keycloak.adapters.OidcKeycloakAccount;
|
||||
import org.keycloak.adapters.RefreshableKeycloakSecurityContext;
|
||||
import org.keycloak.adapters.RequestAuthenticator;
|
||||
import org.keycloak.common.util.DelegatingSerializationFilter;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.Serializable;
|
||||
import java.security.Principal;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
*/
|
||||
public class CatalinaSessionTokenStore extends CatalinaAdapterSessionStore implements AdapterTokenStore {
|
||||
|
||||
private static final Logger log = Logger.getLogger("" + CatalinaSessionTokenStore.class);
|
||||
|
||||
private KeycloakDeployment deployment;
|
||||
private CatalinaUserSessionManagement sessionManagement;
|
||||
protected PrincipalFactory principalFactory;
|
||||
|
||||
|
||||
public CatalinaSessionTokenStore(Request request, KeycloakDeployment deployment,
|
||||
CatalinaUserSessionManagement sessionManagement,
|
||||
PrincipalFactory principalFactory,
|
||||
AbstractKeycloakAuthenticatorValve valve) {
|
||||
super(request, valve);
|
||||
this.deployment = deployment;
|
||||
this.sessionManagement = sessionManagement;
|
||||
this.principalFactory = principalFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkCurrentToken() {
|
||||
Session catalinaSession = request.getSessionInternal(false);
|
||||
if (catalinaSession == null) return;
|
||||
SerializableKeycloakAccount account = (SerializableKeycloakAccount) catalinaSession.getSession().getAttribute(SerializableKeycloakAccount.class.getName());
|
||||
if (account == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
RefreshableKeycloakSecurityContext session = account.getKeycloakSecurityContext();
|
||||
if (session == null) return;
|
||||
|
||||
// just in case session got serialized
|
||||
if (session.getDeployment() == null) session.setCurrentRequestInfo(deployment, this);
|
||||
|
||||
if (session.isActive() && !session.getDeployment().isAlwaysRefreshToken()) {
|
||||
request.setAttribute(KeycloakSecurityContext.class.getName(), session);
|
||||
request.setUserPrincipal(account.getPrincipal());
|
||||
request.setAuthType("KEYCLOAK");
|
||||
return;
|
||||
}
|
||||
|
||||
// FYI: A refresh requires same scope, so same roles will be set. Otherwise, refresh will fail and token will
|
||||
// not be updated
|
||||
boolean success = session.refreshExpiredToken(false);
|
||||
if (success && session.isActive()) {
|
||||
request.setAttribute(KeycloakSecurityContext.class.getName(), session);
|
||||
request.setUserPrincipal(account.getPrincipal());
|
||||
request.setAuthType("KEYCLOAK");
|
||||
return;
|
||||
}
|
||||
|
||||
// Refresh failed, so user is already logged out from keycloak. Cleanup and expire our session
|
||||
log.fine("Cleanup and expire session " + catalinaSession.getId() + " after failed refresh");
|
||||
request.setUserPrincipal(null);
|
||||
request.setAuthType(null);
|
||||
cleanSession(catalinaSession);
|
||||
catalinaSession.expire();
|
||||
}
|
||||
|
||||
protected void cleanSession(Session catalinaSession) {
|
||||
catalinaSession.getSession().removeAttribute(KeycloakSecurityContext.class.getName());
|
||||
catalinaSession.getSession().removeAttribute(SerializableKeycloakAccount.class.getName());
|
||||
catalinaSession.getSession().removeAttribute(OidcKeycloakAccount.class.getName());
|
||||
catalinaSession.setPrincipal(null);
|
||||
catalinaSession.setAuthType(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCached(RequestAuthenticator authenticator) {
|
||||
Session session = request.getSessionInternal(false);
|
||||
if (session == null) return false;
|
||||
SerializableKeycloakAccount account = (SerializableKeycloakAccount) session.getSession().getAttribute(SerializableKeycloakAccount.class.getName());
|
||||
if (account == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
log.fine("remote logged in already. Establish state from session");
|
||||
|
||||
RefreshableKeycloakSecurityContext securityContext = account.getKeycloakSecurityContext();
|
||||
|
||||
if (!deployment.getRealm().equals(securityContext.getRealm())) {
|
||||
log.fine("Account from cookie is from a different realm than for the request.");
|
||||
cleanSession(session);
|
||||
return false;
|
||||
}
|
||||
|
||||
securityContext.setCurrentRequestInfo(deployment, this);
|
||||
request.setAttribute(KeycloakSecurityContext.class.getName(), securityContext);
|
||||
GenericPrincipal principal = (GenericPrincipal) session.getPrincipal();
|
||||
// in clustered environment in JBossWeb, principal is not serialized or saved
|
||||
if (principal == null) {
|
||||
principal = principalFactory.createPrincipal(request.getContext().getRealm(), account.getPrincipal(), account.getRoles());
|
||||
session.setPrincipal(principal);
|
||||
session.setAuthType("KEYCLOAK");
|
||||
|
||||
}
|
||||
request.setUserPrincipal(principal);
|
||||
request.setAuthType("KEYCLOAK");
|
||||
|
||||
restoreRequest();
|
||||
return true;
|
||||
}
|
||||
|
||||
public static class SerializableKeycloakAccount implements OidcKeycloakAccount, Serializable {
|
||||
protected Set<String> roles;
|
||||
protected Principal principal;
|
||||
protected RefreshableKeycloakSecurityContext securityContext;
|
||||
|
||||
public SerializableKeycloakAccount(Set<String> roles, Principal principal, RefreshableKeycloakSecurityContext securityContext) {
|
||||
this.roles = roles;
|
||||
this.principal = principal;
|
||||
this.securityContext = securityContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Principal getPrincipal() {
|
||||
return principal;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getRoles() {
|
||||
return roles;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RefreshableKeycloakSecurityContext getKeycloakSecurityContext() {
|
||||
return securityContext;
|
||||
}
|
||||
|
||||
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
|
||||
DelegatingSerializationFilter.builder()
|
||||
.addAllowedClass(CatalinaSessionTokenStore.SerializableKeycloakAccount.class)
|
||||
.addAllowedClass(RefreshableKeycloakSecurityContext.class)
|
||||
.addAllowedClass(KeycloakSecurityContext.class)
|
||||
.addAllowedClass(KeycloakPrincipal.class)
|
||||
.setFilter(in);
|
||||
|
||||
in.defaultReadObject();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveAccountInfo(OidcKeycloakAccount account) {
|
||||
RefreshableKeycloakSecurityContext securityContext = (RefreshableKeycloakSecurityContext) account.getKeycloakSecurityContext();
|
||||
Set<String> roles = account.getRoles();
|
||||
GenericPrincipal principal = principalFactory.createPrincipal(request.getContext().getRealm(), account.getPrincipal(), roles);
|
||||
|
||||
SerializableKeycloakAccount sAccount = new SerializableKeycloakAccount(roles, account.getPrincipal(), securityContext);
|
||||
Session session = request.getSessionInternal(true);
|
||||
session.setPrincipal(principal);
|
||||
session.setAuthType("KEYCLOAK");
|
||||
session.getSession().setAttribute(SerializableKeycloakAccount.class.getName(), sAccount);
|
||||
session.getSession().setAttribute(KeycloakSecurityContext.class.getName(), account.getKeycloakSecurityContext());
|
||||
String username = securityContext.getToken().getSubject();
|
||||
log.fine("userSessionManagement.login: " + username);
|
||||
this.sessionManagement.login(session);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void logout() {
|
||||
Session session = request.getSessionInternal(false);
|
||||
if (session != null) {
|
||||
cleanSession(session);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void refreshCallback(RefreshableKeycloakSecurityContext securityContext) {
|
||||
// no-op
|
||||
}
|
||||
|
||||
}
|
|
@ -1,40 +0,0 @@
|
|||
/*
|
||||
* 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.adapters.tomcat;
|
||||
|
||||
import org.keycloak.KeycloakSecurityContext;
|
||||
import org.keycloak.adapters.OIDCHttpFacade;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class OIDCCatalinaHttpFacade extends CatalinaHttpFacade implements OIDCHttpFacade{
|
||||
|
||||
public OIDCCatalinaHttpFacade(org.apache.catalina.connector.Request request, HttpServletResponse response) {
|
||||
super(response, request);
|
||||
}
|
||||
|
||||
@Override
|
||||
public KeycloakSecurityContext getSecurityContext() {
|
||||
return (KeycloakSecurityContext)request.getAttribute(KeycloakSecurityContext.class.getName());
|
||||
}
|
||||
|
||||
}
|
|
@ -1,109 +0,0 @@
|
|||
<?xml version="1.0"?>
|
||||
<!--
|
||||
~ 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.
|
||||
-->
|
||||
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<parent>
|
||||
<artifactId>keycloak-tomcat-integration-pom</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>999.0.0-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>keycloak-tomcat-adapter</artifactId>
|
||||
<name>Keycloak Tomcat Integration</name>
|
||||
<description />
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.jboss.logging</groupId>
|
||||
<artifactId>jboss-logging</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jboss.logging</groupId>
|
||||
<artifactId>commons-logging-jboss-logging</artifactId>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-core</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-adapter-core</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.tomcat</groupId>
|
||||
<artifactId>tomcat-servlet-api</artifactId>
|
||||
<version>${tomcat8.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.tomcat</groupId>
|
||||
<artifactId>tomcat-catalina</artifactId>
|
||||
<version>${tomcat8.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-tomcat-core-adapter</artifactId>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.apache.tomcat</groupId>
|
||||
<artifactId>tomcat-servlet-api</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>org.apache.tomcat</groupId>
|
||||
<artifactId>tomcat-catalina</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>org.apache.tomcat</groupId>
|
||||
<artifactId>catalina</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.httpcomponents</groupId>
|
||||
<artifactId>httpclient</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.bouncycastle</groupId>
|
||||
<artifactId>bcprov-jdk18on</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-core</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-databind</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-annotations</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
|
@ -1,17 +0,0 @@
|
|||
package org.keycloak.adapters.tomcat;
|
||||
|
||||
import org.apache.catalina.Container;
|
||||
import org.apache.catalina.Valve;
|
||||
import org.keycloak.adapters.AdapterDeploymentContext;
|
||||
|
||||
public class AuthenticatedActionsValve extends AbstractAuthenticatedActionsValve {
|
||||
|
||||
public AuthenticatedActionsValve(AdapterDeploymentContext deploymentContext, Valve next, Container container) {
|
||||
super(deploymentContext, next, container);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAsyncSupported() {
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -1,118 +0,0 @@
|
|||
/*
|
||||
* 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.adapters.tomcat;
|
||||
|
||||
import org.apache.catalina.Container;
|
||||
import org.apache.catalina.Valve;
|
||||
import org.apache.catalina.authenticator.FormAuthenticator;
|
||||
import org.apache.catalina.connector.Request;
|
||||
import org.apache.catalina.core.StandardContext;
|
||||
import org.apache.catalina.realm.GenericPrincipal;
|
||||
import org.apache.tomcat.util.descriptor.web.LoginConfig;
|
||||
import org.keycloak.adapters.AdapterDeploymentContext;
|
||||
import org.keycloak.adapters.AdapterTokenStore;
|
||||
import org.keycloak.adapters.KeycloakDeployment;
|
||||
import org.keycloak.adapters.spi.HttpFacade;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.security.Principal;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Keycloak authentication valve
|
||||
*
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class KeycloakAuthenticatorValve extends AbstractKeycloakAuthenticatorValve {
|
||||
|
||||
/**
|
||||
* Method called by Tomcat < 8.5.5
|
||||
*/
|
||||
public boolean authenticate(Request request, HttpServletResponse response) throws IOException {
|
||||
return authenticateInternal(request, response, request.getContext().getLoginConfig());
|
||||
}
|
||||
|
||||
/**
|
||||
* Method called by Tomcat >= 8.5.5
|
||||
*/
|
||||
protected boolean doAuthenticate(Request request, HttpServletResponse response) throws IOException {
|
||||
return this.authenticate(request, response);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean forwardToErrorPageInternal(Request request, HttpServletResponse response, Object loginConfig) throws IOException {
|
||||
if (loginConfig == null) return false;
|
||||
LoginConfig config = (LoginConfig)loginConfig;
|
||||
if (config.getErrorPage() == null) return false;
|
||||
// had to do this to get around compiler/IDE issues :(
|
||||
try {
|
||||
Method method = null;
|
||||
/*
|
||||
for (Method m : getClass().getDeclaredMethods()) {
|
||||
if (m.getName().equals("forwardToErrorPage")) {
|
||||
method = m;
|
||||
break;
|
||||
}
|
||||
}
|
||||
*/
|
||||
method = FormAuthenticator.class.getDeclaredMethod("forwardToErrorPage", Request.class, HttpServletResponse.class, LoginConfig.class);
|
||||
method.setAccessible(true);
|
||||
method.invoke(this, request, response, config);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
protected void initInternal() {
|
||||
StandardContext standardContext = (StandardContext) context;
|
||||
standardContext.addLifecycleListener(this);
|
||||
}
|
||||
|
||||
public void logout(Request request) {
|
||||
logoutInternal(request);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected GenericPrincipalFactory createPrincipalFactory() {
|
||||
return new GenericPrincipalFactory() {
|
||||
@Override
|
||||
protected GenericPrincipal createPrincipal(Principal userPrincipal, List<String> roles) {
|
||||
return new GenericPrincipal(userPrincipal.getName(), null, roles, userPrincipal, null);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AdapterTokenStore getTokenStore(Request request, HttpFacade facade, KeycloakDeployment resolvedDeployment) {
|
||||
return super.getTokenStore(request, facade, resolvedDeployment);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AbstractAuthenticatedActionsValve createAuthenticatedActionsValve(AdapterDeploymentContext deploymentContext, Valve next, Container container) {
|
||||
return new AuthenticatedActionsValve(deploymentContext, next, container);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected CatalinaRequestAuthenticator createRequestAuthenticator(Request request, CatalinaHttpFacade facade, KeycloakDeployment deployment, AdapterTokenStore tokenStore) {
|
||||
return new TomcatRequestAuthenticator(deployment, tokenStore, facade, request, createPrincipalFactory());
|
||||
}
|
||||
}
|
|
@ -1,45 +0,0 @@
|
|||
/*
|
||||
* 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.adapters.tomcat;
|
||||
|
||||
import org.apache.catalina.connector.Request;
|
||||
import org.keycloak.adapters.AdapterTokenStore;
|
||||
import org.keycloak.adapters.KeycloakDeployment;
|
||||
|
||||
import javax.servlet.http.HttpSession;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class TomcatRequestAuthenticator extends CatalinaRequestAuthenticator {
|
||||
public TomcatRequestAuthenticator(KeycloakDeployment deployment, AdapterTokenStore tokenStore, CatalinaHttpFacade facade, Request request, GenericPrincipalFactory principalFactory) {
|
||||
super(deployment, tokenStore, facade, request, principalFactory);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String changeHttpSessionId(boolean create) {
|
||||
Request request = this.request;
|
||||
HttpSession session = request.getSession(false);
|
||||
if (session == null) {
|
||||
return request.getSession(true).getId();
|
||||
}
|
||||
if (!deployment.isTurnOffChangeSessionIdOnLogin()) return request.changeSessionId();
|
||||
else return session.getId();
|
||||
}
|
||||
}
|
|
@ -32,7 +32,6 @@
|
|||
|
||||
<modules>
|
||||
<module>adapter-spi</module>
|
||||
<module>tomcat-adapter-spi</module>
|
||||
<module>undertow-adapter-spi</module>
|
||||
<module>servlet-adapter-spi</module>
|
||||
<module>jakarta-servlet-adapter-spi</module>
|
||||
|
|
|
@ -1,67 +0,0 @@
|
|||
<?xml version="1.0"?>
|
||||
<!--
|
||||
~ 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.
|
||||
-->
|
||||
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>999.0.0-SNAPSHOT</version>
|
||||
<relativePath>../../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>keycloak-tomcat-adapter-spi</artifactId>
|
||||
<name>Keycloak Tomcat Adapter SPI</name>
|
||||
<description />
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.jboss.logging</groupId>
|
||||
<artifactId>jboss-logging</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-adapter-spi</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-common</artifactId>
|
||||
</dependency>
|
||||
<!--
|
||||
<dependency>
|
||||
<groupId>org.apache.tomcat</groupId>
|
||||
<artifactId>tomcat-servlet-api</artifactId>
|
||||
<version>${tomcat.version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
-->
|
||||
<dependency>
|
||||
<groupId>org.apache.tomcat</groupId>
|
||||
<artifactId>tomcat-catalina</artifactId>
|
||||
<version>${tomcat8.version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
|
@ -1,264 +0,0 @@
|
|||
/*
|
||||
* 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.adapters.tomcat;
|
||||
|
||||
import org.keycloak.adapters.spi.AuthenticationError;
|
||||
import org.keycloak.adapters.spi.HttpFacade;
|
||||
import org.keycloak.adapters.spi.LogoutError;
|
||||
import org.keycloak.common.util.MultivaluedHashMap;
|
||||
import org.keycloak.common.util.ServerCookie;
|
||||
import org.keycloak.common.util.UriUtils;
|
||||
|
||||
import javax.security.cert.X509Certificate;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Enumeration;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class CatalinaHttpFacade implements HttpFacade {
|
||||
protected org.apache.catalina.connector.Request request;
|
||||
protected HttpServletResponse response;
|
||||
protected RequestFacade requestFacade = new RequestFacade();
|
||||
protected ResponseFacade responseFacade = new ResponseFacade();
|
||||
protected MultivaluedHashMap<String, String> queryParameters;
|
||||
|
||||
public CatalinaHttpFacade(HttpServletResponse response, org.apache.catalina.connector.Request request) {
|
||||
this.response = response;
|
||||
this.request = request;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Request getRequest() {
|
||||
return requestFacade;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Response getResponse() {
|
||||
return responseFacade;
|
||||
}
|
||||
|
||||
@Override
|
||||
public X509Certificate[] getCertificateChain() {
|
||||
throw new IllegalStateException("Not supported yet");
|
||||
}
|
||||
|
||||
public boolean isEnded() {
|
||||
return responseFacade.isEnded();
|
||||
}
|
||||
|
||||
protected class RequestFacade implements Request {
|
||||
|
||||
private InputStream inputStream;
|
||||
|
||||
@Override
|
||||
public String getURI() {
|
||||
StringBuffer buf = request.getRequestURL();
|
||||
if (request.getQueryString() != null) {
|
||||
buf.append('?').append(request.getQueryString());
|
||||
}
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRelativePath() {
|
||||
String uri = request.getRequestURI();
|
||||
String contextPath = request.getContextPath();
|
||||
String servletPath = uri.substring(uri.indexOf(contextPath) + contextPath.length());
|
||||
|
||||
if ("".equals(servletPath)) {
|
||||
servletPath = "/";
|
||||
}
|
||||
|
||||
return servletPath;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSecure() {
|
||||
return request.isSecure();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFirstParam(String param) {
|
||||
return request.getParameter(param);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getQueryParamValue(String paramName) {
|
||||
if (queryParameters == null) {
|
||||
queryParameters = UriUtils.decodeQueryString(request.getQueryString());
|
||||
}
|
||||
return queryParameters.getFirst(paramName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Cookie getCookie(String cookieName) {
|
||||
if (request.getCookies() == null) return null;
|
||||
javax.servlet.http.Cookie cookie = null;
|
||||
for (javax.servlet.http.Cookie c : request.getCookies()) {
|
||||
if (c.getName().equals(cookieName)) {
|
||||
cookie = c;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (cookie == null) return null;
|
||||
return new Cookie(cookie.getName(), cookie.getValue(), cookie.getVersion(), cookie.getDomain(), cookie.getPath());
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getHeaders(String name) {
|
||||
Enumeration<String> headers = request.getHeaders(name);
|
||||
if (headers == null) return null;
|
||||
List<String> list = new ArrayList<String>();
|
||||
while (headers.hasMoreElements()) {
|
||||
list.add(headers.nextElement());
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream getInputStream() {
|
||||
return getInputStream(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream getInputStream(boolean buffered) {
|
||||
if (inputStream != null) {
|
||||
return inputStream;
|
||||
}
|
||||
|
||||
if (buffered) {
|
||||
try {
|
||||
return inputStream = new BufferedInputStream(request.getInputStream());
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
return request.getInputStream();
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMethod() {
|
||||
return request.getMethod();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getHeader(String name) {
|
||||
return request.getHeader(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRemoteAddr() {
|
||||
return request.getRemoteAddr();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setError(AuthenticationError error) {
|
||||
request.setAttribute(AuthenticationError.class.getName(), error);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setError(LogoutError error) {
|
||||
request.setAttribute(LogoutError.class.getName(), error);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
protected class ResponseFacade implements Response {
|
||||
protected boolean ended;
|
||||
|
||||
@Override
|
||||
public void setStatus(int status) {
|
||||
response.setStatus(status);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addHeader(String name, String value) {
|
||||
response.addHeader(name, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setHeader(String name, String value) {
|
||||
response.setHeader(name, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resetCookie(String name, String path) {
|
||||
setCookie(name, "", path, null, 0, false, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCookie(String name, String value, String path, String domain, int maxAge, boolean secure, boolean httpOnly) {
|
||||
StringBuilder cookieBuf = new StringBuilder();
|
||||
ServerCookie.appendCookieValue(cookieBuf, 1, name, value, path, domain, null, maxAge, secure, httpOnly, null);
|
||||
String cookie = cookieBuf.toString();
|
||||
response.addHeader("Set-Cookie", cookie);
|
||||
}
|
||||
|
||||
@Override
|
||||
public OutputStream getOutputStream() {
|
||||
try {
|
||||
return response.getOutputStream();
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendError(int code) {
|
||||
try {
|
||||
response.sendError(code);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendError(int code, String message) {
|
||||
try {
|
||||
response.sendError(code, message);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void end() {
|
||||
ended = true;
|
||||
}
|
||||
|
||||
public boolean isEnded() {
|
||||
return ended;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,94 +0,0 @@
|
|||
/*
|
||||
* 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.adapters.tomcat;
|
||||
|
||||
import org.apache.catalina.Manager;
|
||||
import org.apache.catalina.Session;
|
||||
import org.apache.catalina.SessionEvent;
|
||||
import org.apache.catalina.SessionListener;
|
||||
import org.apache.catalina.realm.GenericPrincipal;
|
||||
import org.jboss.logging.Logger;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Manages relationship to users and sessions so that forced admin logout can be implemented
|
||||
*
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class CatalinaUserSessionManagement implements SessionListener {
|
||||
private static final Logger log = Logger.getLogger(CatalinaUserSessionManagement.class);
|
||||
|
||||
public void login(Session session) {
|
||||
session.addSessionListener(this);
|
||||
}
|
||||
|
||||
public void logoutAll(Manager sessionManager) {
|
||||
Session[] allSessions = sessionManager.findSessions();
|
||||
for (Session session : allSessions) {
|
||||
logoutSession(session);
|
||||
}
|
||||
}
|
||||
|
||||
public void logoutHttpSessions(Manager sessionManager, List<String> sessionIds) {
|
||||
log.debug("logoutHttpSessions: " + sessionIds);
|
||||
|
||||
for (String sessionId : sessionIds) {
|
||||
logoutSession(sessionManager, sessionId);
|
||||
}
|
||||
}
|
||||
|
||||
protected void logoutSession(Manager manager, String httpSessionId) {
|
||||
log.debug("logoutHttpSession: " + httpSessionId);
|
||||
|
||||
Session session;
|
||||
try {
|
||||
session = manager.findSession(httpSessionId);
|
||||
} catch (IOException ioe) {
|
||||
log.warn("IO exception when looking for session " + httpSessionId, ioe);
|
||||
return;
|
||||
}
|
||||
|
||||
logoutSession(session);
|
||||
}
|
||||
|
||||
protected void logoutSession(Session session) {
|
||||
try {
|
||||
if (session != null) session.expire();
|
||||
} catch (Exception e) {
|
||||
log.debug("Session not present or already invalidated.", e);
|
||||
}
|
||||
}
|
||||
|
||||
public void sessionEvent(SessionEvent event) {
|
||||
// We only care about session destroyed events
|
||||
if (!Session.SESSION_DESTROYED_EVENT.equals(event.getType()))
|
||||
return;
|
||||
|
||||
// Look up the single session id associated with this session (if any)
|
||||
Session session = event.getSession();
|
||||
log.debugf("Session %s destroyed", session.getId());
|
||||
|
||||
GenericPrincipal principal = (GenericPrincipal) session.getPrincipal();
|
||||
if (principal == null) return;
|
||||
session.setPrincipal(null);
|
||||
session.setAuthType(null);
|
||||
}
|
||||
}
|
|
@ -1,47 +0,0 @@
|
|||
/*
|
||||
* 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.adapters.tomcat;
|
||||
|
||||
import org.apache.catalina.Manager;
|
||||
import org.keycloak.adapters.spi.UserSessionManagement;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
*/
|
||||
public class CatalinaUserSessionManagementWrapper implements UserSessionManagement {
|
||||
|
||||
private final CatalinaUserSessionManagement delegate;
|
||||
private final Manager sessionManager;
|
||||
|
||||
public CatalinaUserSessionManagementWrapper(CatalinaUserSessionManagement delegate, Manager sessionManager) {
|
||||
this.delegate = delegate;
|
||||
this.sessionManager = sessionManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void logoutAll() {
|
||||
delegate.logoutAll(sessionManager);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void logoutHttpSessions(List<String> ids) {
|
||||
delegate.logoutHttpSessions(sessionManager, ids);
|
||||
}
|
||||
}
|
|
@ -1,107 +0,0 @@
|
|||
/*
|
||||
* 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.adapters.tomcat;
|
||||
|
||||
import org.apache.catalina.Realm;
|
||||
import org.apache.catalina.realm.GenericPrincipal;
|
||||
|
||||
import javax.security.auth.Subject;
|
||||
import java.security.Principal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Enumeration;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:ungarida@gmail.com">Davide Ungari</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public abstract class GenericPrincipalFactory implements PrincipalFactory {
|
||||
|
||||
@Override
|
||||
public GenericPrincipal createPrincipal(Realm realm, final Principal identity, final Set<String> roleSet) {
|
||||
Subject subject = new Subject();
|
||||
Set<Principal> principals = subject.getPrincipals();
|
||||
principals.add(identity);
|
||||
final SimpleGroup[] roleSets = getRoleSets(roleSet);
|
||||
for (SimpleGroup group : roleSets) {
|
||||
String name = group.getName();
|
||||
SimpleGroup subjectGroup = createGroup(name, principals);
|
||||
// Copy the group members to the Subject group
|
||||
Enumeration<? extends Principal> members = group.members();
|
||||
while (members.hasMoreElements()) {
|
||||
Principal role = members.nextElement();
|
||||
subjectGroup.addMember(role);
|
||||
}
|
||||
}
|
||||
return createPrincipal(getPrincipal(subject), new ArrayList<>(roleSet));
|
||||
}
|
||||
|
||||
protected abstract GenericPrincipal createPrincipal(Principal userPrincipal, List<String> roles);
|
||||
|
||||
/**
|
||||
* Get the Principal given the authenticated Subject. Currently the first subject that is not of type {@code Group} is
|
||||
* considered or the single subject inside the CallerPrincipal group.
|
||||
*
|
||||
* @param subject
|
||||
* @return the authenticated subject
|
||||
*/
|
||||
protected Principal getPrincipal(Subject subject) {
|
||||
Principal principal = null;
|
||||
if (subject != null) {
|
||||
Set<Principal> principals = subject.getPrincipals();
|
||||
if (principals != null && !principals.isEmpty()) {
|
||||
for (Principal p : principals) {
|
||||
if (!(p instanceof SimpleGroup) && principal == null) {
|
||||
principal = p;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return principal;
|
||||
}
|
||||
|
||||
protected SimpleGroup createGroup(String name, Set<Principal> principals) {
|
||||
SimpleGroup roles = null;
|
||||
for (final Object next : principals) {
|
||||
if (!(next instanceof SimpleGroup)) continue;
|
||||
SimpleGroup grp = (SimpleGroup) next;
|
||||
if (grp.getName().equals(name)) {
|
||||
roles = grp;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// If we did not find a group create one
|
||||
if (roles == null) {
|
||||
roles = new SimpleGroup(name);
|
||||
principals.add(roles);
|
||||
}
|
||||
return roles;
|
||||
}
|
||||
|
||||
protected SimpleGroup[] getRoleSets(Collection<String> roleSet) {
|
||||
SimpleGroup roles = new SimpleGroup("Roles");
|
||||
SimpleGroup[] roleSets = {roles};
|
||||
for (String role : roleSet) {
|
||||
roles.addMember(new SimplePrincipal(role));
|
||||
}
|
||||
return roleSets;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
package org.keycloak.adapters.tomcat;
|
||||
|
||||
import org.apache.catalina.Realm;
|
||||
import org.apache.catalina.realm.GenericPrincipal;
|
||||
|
||||
import java.security.Principal;
|
||||
import java.util.Set;
|
||||
|
||||
public interface PrincipalFactory {
|
||||
GenericPrincipal createPrincipal(Realm realm, final Principal identity, final Set<String> roleSet);
|
||||
}
|
|
@ -1,57 +0,0 @@
|
|||
/*
|
||||
* 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.adapters.tomcat;
|
||||
|
||||
import java.security.Principal;
|
||||
import java.util.Collections;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
public class SimpleGroup extends SimplePrincipal {
|
||||
private final Set<Principal> members = new HashSet<Principal>();
|
||||
|
||||
/**
|
||||
* Creates a new group with the given name.
|
||||
* @param name Group name.
|
||||
*/
|
||||
public SimpleGroup(final String name) {
|
||||
super(name);
|
||||
}
|
||||
|
||||
public boolean addMember(final Principal user) {
|
||||
return this.members.add(user);
|
||||
}
|
||||
|
||||
public boolean isMember(final Principal member) {
|
||||
return this.members.contains(member);
|
||||
}
|
||||
|
||||
public Enumeration<? extends Principal> members() {
|
||||
return Collections.enumeration(this.members);
|
||||
}
|
||||
|
||||
public boolean removeMember(final Principal user) {
|
||||
return this.members.remove(user);
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return super.toString() + ": " + members.toString();
|
||||
}
|
||||
|
||||
}
|
|
@ -1,67 +0,0 @@
|
|||
/*
|
||||
* 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.adapters.tomcat;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.security.Principal;
|
||||
|
||||
/**
|
||||
* Simple security principal implementation.
|
||||
*
|
||||
* @author Marvin S. Addison
|
||||
* @version $Revision: 22071 $
|
||||
* @since 3.1.11
|
||||
*
|
||||
*/
|
||||
public class SimplePrincipal implements Principal, Serializable {
|
||||
|
||||
/** SimplePrincipal.java */
|
||||
|
||||
/** The unique identifier for this principal. */
|
||||
private final String name;
|
||||
|
||||
/**
|
||||
* Creates a new principal with the given name.
|
||||
* @param name Principal name.
|
||||
*/
|
||||
public SimplePrincipal(final String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public final String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return getName();
|
||||
}
|
||||
|
||||
public boolean equals(final Object o) {
|
||||
if (o == null) {
|
||||
return false;
|
||||
} else if (!(o instanceof SimplePrincipal)) {
|
||||
return false;
|
||||
} else {
|
||||
return getName().equals(((SimplePrincipal)o).getName());
|
||||
}
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return 37 * getName().hashCode();
|
||||
}
|
||||
}
|
|
@ -64,11 +64,6 @@
|
|||
<artifactId>keycloak-saml-adapter-api-public</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-tomcat-adapter</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-undertow-adapter</artifactId>
|
||||
|
|
|
@ -32,6 +32,5 @@
|
|||
|
||||
<modules>
|
||||
<module>wildfly-adapter</module>
|
||||
<module>tomcat-adapter-zip</module>
|
||||
</modules>
|
||||
</project>
|
||||
|
|
|
@ -1,42 +0,0 @@
|
|||
<!--
|
||||
~ 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.
|
||||
-->
|
||||
|
||||
<assembly>
|
||||
<id>war-dist</id>
|
||||
|
||||
<formats>
|
||||
<format>zip</format>
|
||||
<format>tar.gz</format>
|
||||
</formats>
|
||||
<includeBaseDirectory>false</includeBaseDirectory>
|
||||
|
||||
<dependencySets>
|
||||
<dependencySet>
|
||||
<unpack>false</unpack>
|
||||
<useTransitiveDependencies>true</useTransitiveDependencies>
|
||||
<useTransitiveFiltering>true</useTransitiveFiltering>
|
||||
<includes>
|
||||
<include>org.keycloak:keycloak-tomcat-adapter</include>
|
||||
</includes>
|
||||
<excludes>
|
||||
<exclude>org.apache.tomcat:tomcat-servlet-api</exclude>
|
||||
<exclude>org.apache.tomcat:tomcat-catalina</exclude>
|
||||
</excludes>
|
||||
<outputDirectory></outputDirectory>
|
||||
</dependencySet>
|
||||
</dependencySets>
|
||||
</assembly>
|
|
@ -1,68 +0,0 @@
|
|||
<!--
|
||||
~ 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.
|
||||
-->
|
||||
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>999.0.0-SNAPSHOT</version>
|
||||
<relativePath>../../../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
<artifactId>keycloak-tomcat-adapter-dist</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
<name>Keycloak Tomcat Adapter Distro</name>
|
||||
<description/>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-tomcat-adapter</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<artifactId>maven-assembly-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>assemble</id>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>single</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<descriptors>
|
||||
<descriptor>assembly.xml</descriptor>
|
||||
</descriptors>
|
||||
<outputDirectory>
|
||||
target
|
||||
</outputDirectory>
|
||||
<workDirectory>
|
||||
target/assembly/work
|
||||
</workDirectory>
|
||||
<appendAssemblyId>false</appendAssemblyId>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
|
@ -1,8 +1,6 @@
|
|||
mvn:keycloak-quarkus-dist:keycloak
|
||||
mvn:keycloak-api-docs-dist:keycloak-api-docs
|
||||
|
||||
mvn:keycloak-tomcat-adapter-dist:keycloak-oidc-tomcat-adapter
|
||||
|
||||
mvn:documentation/keycloak-documentation:keycloak-documentation
|
||||
|
||||
npm:js/libs/keycloak-admin-client/target/keycloak-keycloak-admin-client-$$VERSION$$.tgz:keycloak-admin-client-$$VERSION$$.tgz
|
||||
|
|
|
@ -32,7 +32,6 @@
|
|||
|
||||
<modules>
|
||||
<module>wildfly-adapter</module>
|
||||
<module>tomcat-adapter-zip</module>
|
||||
</modules>
|
||||
|
||||
</project>
|
||||
|
|
|
@ -20,7 +20,6 @@ include::jboss-adapter.adoc[]
|
|||
include::spring-boot-adapter.adoc[]
|
||||
|
||||
ifeval::[{project_community}==true]
|
||||
include::tomcat-adapter.adoc[]
|
||||
include::spring-security-adapter.adoc[]
|
||||
endif::[]
|
||||
|
||||
|
|
|
@ -1,88 +0,0 @@
|
|||
|
||||
[[_tomcat_adapter]]
|
||||
==== Tomcat 8 and 9 adapters
|
||||
|
||||
include::adapter-deprecation-notice.adoc[]
|
||||
|
||||
To be able to secure WAR apps deployed on Tomcat 8, and 9, you install the Keycloak Tomcat adapter into your Tomcat installation. You then perform extra configuration to secure each WAR you deploy to Tomcat.
|
||||
|
||||
[[_tomcat_adapter_installation]]
|
||||
===== Installing the adapter
|
||||
|
||||
Adapters are no longer included with the appliance or war distribution.
|
||||
Each adapter is a separate download on the Keycloak Downloads site.
|
||||
They are also available as a maven artifact.
|
||||
|
||||
.Procedure
|
||||
|
||||
. Download the adapter for the Tomcat version on your system from the link:https://www.keycloak.org/downloads[Keycloak Downloads] site.
|
||||
|
||||
* Install on Tomcat 8 or 9:
|
||||
+
|
||||
[source]
|
||||
----
|
||||
|
||||
$ cd $TOMCAT_HOME/lib
|
||||
$ unzip keycloak-tomcat-adapter-dist.zip
|
||||
----
|
||||
|
||||
====
|
||||
[NOTE]
|
||||
Including the adapter's jars within your WEB-INF/lib directory will not work. The Keycloak adapter is implemented as a Valve and valve code must reside in Tomcat's main lib/ directory.
|
||||
====
|
||||
|
||||
===== Securing a WAR
|
||||
|
||||
This section describes how to secure a WAR directly by adding config and editing files within your WAR package.
|
||||
|
||||
.Procedure
|
||||
|
||||
. Create a `META-INF/context.xml` file in your WAR package.
|
||||
+
|
||||
This is a Tomcat specific config file and you must define a Keycloak specific Valve.
|
||||
+
|
||||
[source]
|
||||
----
|
||||
<Context path="/your-context-path">
|
||||
<Valve className="org.keycloak.adapters.tomcat.KeycloakAuthenticatorValve"/>
|
||||
</Context>
|
||||
----
|
||||
|
||||
. Create a `keycloak.json` adapter config file within the `WEB-INF` directory of your WAR.
|
||||
+
|
||||
The format of this config file is described in the <<_java_adapter_config,Java adapter configuration>>
|
||||
|
||||
. Specify both a `login-config` and use standard servlet security to specify role-base constraints on your URLs. Here's an example:
|
||||
+
|
||||
[source,xml]
|
||||
----
|
||||
<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>customer-portal</module-name>
|
||||
|
||||
<security-constraint>
|
||||
<web-resource-collection>
|
||||
<web-resource-name>Customers</web-resource-name>
|
||||
<url-pattern>/*</url-pattern>
|
||||
</web-resource-collection>
|
||||
<auth-constraint>
|
||||
<role-name>user</role-name>
|
||||
</auth-constraint>
|
||||
</security-constraint>
|
||||
|
||||
<login-config>
|
||||
<auth-method>BASIC</auth-method>
|
||||
<realm-name>this is ignored currently</realm-name>
|
||||
</login-config>
|
||||
|
||||
<security-role>
|
||||
<role-name>admin</role-name>
|
||||
</security-role>
|
||||
<security-role>
|
||||
<role-name>user</role-name>
|
||||
</security-role>
|
||||
</web-app>
|
||||
----
|
|
@ -14,7 +14,6 @@ ifeval::[{project_community}==true]
|
|||
* {quickstartRepo_link}/tree/latest/jakarta/servlet-authz-client[Wildfly Elytron OIDC]
|
||||
* {quickstartRepo_link}/tree/latest/spring/rest-authz-resource-server[Spring Boot]
|
||||
* <<_jboss_adapter, {project_name} Wildfly Adapter>> (Deprecated)
|
||||
* <<_tomcat_adapter,{project_name} Tomcat Adapter>> (Deprecated)
|
||||
* <<_servlet_filter_adapter,{project_name} Servlet Filter>> (Deprecated)
|
||||
* <<_spring_boot_adapter,{project_name} Spring Boot>> (Deprecated)
|
||||
* <<_spring_security_adapter,{project_name} Spring Security>> (Deprecated)
|
||||
|
|
21
pom.xml
21
pom.xml
|
@ -1112,16 +1112,6 @@
|
|||
<artifactId>keycloak-spring-boot-2-adapter</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-tomcat-adapter-spi</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-tomcat-core-adapter</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-saml-servlet-filter-adapter</artifactId>
|
||||
|
@ -1152,11 +1142,6 @@
|
|||
<artifactId>keycloak-saml-as7-subsystem</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-tomcat-adapter</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-undertow-adapter-spi</artifactId>
|
||||
|
@ -1443,12 +1428,6 @@
|
|||
<version>${project.version}</version>
|
||||
<type>zip</type>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-tomcat-adapter-dist</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<type>zip</type>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-as7-adapter-dist</artifactId>
|
||||
|
|
|
@ -36,7 +36,6 @@
|
|||
<app.server.tomcat.version>${tomcat8.version}</app.server.tomcat.version>
|
||||
<app.server.tomcat.unpacked.folder.name>apache-tomcat-${tomcat8.version}</app.server.tomcat.unpacked.folder.name>
|
||||
|
||||
<app.server.oidc.adapter.artifactId>keycloak-tomcat-adapter-dist</app.server.oidc.adapter.artifactId>
|
||||
<skip.dependencies.for.tomcat8>false</skip.dependencies.for.tomcat8>
|
||||
</properties>
|
||||
|
||||
|
|
|
@ -36,7 +36,6 @@
|
|||
<app.server.tomcat.version>${tomcat9.version}</app.server.tomcat.version>
|
||||
<app.server.tomcat.unpacked.folder.name>apache-tomcat-${tomcat9.version}</app.server.tomcat.unpacked.folder.name>
|
||||
|
||||
<app.server.oidc.adapter.artifactId>keycloak-tomcat-adapter-dist</app.server.oidc.adapter.artifactId>
|
||||
<skip.dependencies.for.tomcat8>false</skip.dependencies.for.tomcat8>
|
||||
</properties>
|
||||
|
||||
|
|
|
@ -21,7 +21,6 @@
|
|||
<springboot-version>2.7</springboot-version>
|
||||
|
||||
<spring-boot-adapter-jetty>false</spring-boot-adapter-jetty>
|
||||
<spring.boot.tomcat.adapter.artifactId>keycloak-tomcat-adapter</spring.boot.tomcat.adapter.artifactId>
|
||||
|
||||
<app.server.debug.port>5006</app.server.debug.port>
|
||||
<app.server.debug.suspend>n</app.server.debug.suspend>
|
||||
|
|
Loading…
Reference in a new issue