SAML SP Filter
This commit is contained in:
parent
0b83325470
commit
7c600e2f4b
18 changed files with 1089 additions and 2 deletions
|
@ -1,6 +1,7 @@
|
|||
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN"
|
||||
"http://www.docbook.org/xml/4.4/docbookx.dtd"
|
||||
[
|
||||
<!ENTITY Overview SYSTEM "modules/overview.xml">
|
||||
<!ENTITY AdapterConfig SYSTEM "modules/adapter-config.xml">
|
||||
<!ENTITY JBossAdapter SYSTEM "modules/jboss-adapter.xml">
|
||||
<!ENTITY TomcatAdapter SYSTEM "modules/tomcat-adapter.xml">
|
||||
|
@ -13,7 +14,7 @@
|
|||
|
||||
<bookinfo>
|
||||
<title>Keycloak SAML Client Adapter Reference Guide</title>
|
||||
<subtitle>SAML 2.0 Client Adapters for Java Applications</subtitle>
|
||||
<subtitle>SAML 2.0 Client Adapters</subtitle>
|
||||
<releaseinfo>&project.version;</releaseinfo>
|
||||
</bookinfo>
|
||||
|
||||
|
@ -39,6 +40,7 @@ This one is short
|
|||
</programlisting>
|
||||
</para>
|
||||
</preface>
|
||||
&Overview;
|
||||
&AdapterConfig;
|
||||
&JBossAdapter;
|
||||
&TomcatAdapter;
|
||||
|
|
9
docbook/saml-adapter-docs/reference/en/en-US/modules/overview.xml
Executable file
9
docbook/saml-adapter-docs/reference/en/en-US/modules/overview.xml
Executable file
|
@ -0,0 +1,9 @@
|
|||
<chapter>
|
||||
<title>Overview</title>
|
||||
<para>
|
||||
This document describes the Keycloak SAML client adapter and how it can be configured for a variety of platforms.
|
||||
The Keycloak SAML client adapter is a standalone component that provides generic SAML 2.0 support for your web applications.
|
||||
There are no Keycloak server extensions built into it. As long as the IDP you are talking to supports standard SAML, the
|
||||
Keycloak SAML client adapter should be able to integrate with it.
|
||||
</para>
|
||||
</chapter>
|
|
@ -17,6 +17,11 @@ public class InMemorySessionIdMapper implements SessionIdMapper {
|
|||
ConcurrentHashMap<String, Set<String>> principalToSession = new ConcurrentHashMap<>();
|
||||
ConcurrentHashMap<String, String> sessionToPrincipal = new ConcurrentHashMap<>();
|
||||
|
||||
@Override
|
||||
public boolean hasSession(String id) {
|
||||
return sessionToSso.containsKey(id) || sessionToPrincipal.containsKey(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getUserSessions(String principal) {
|
||||
Set<String> lookup = principalToSession.get(principal);
|
||||
|
|
|
@ -7,6 +7,8 @@ import java.util.Set;
|
|||
* @version $Revision: 1 $
|
||||
*/
|
||||
public interface SessionIdMapper {
|
||||
boolean hasSession(String id);
|
||||
|
||||
Set<String> getUserSessions(String principal);
|
||||
|
||||
String getSessionFromSSO(String sso);
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
|
||||
<modules>
|
||||
<module>adapter-spi</module>
|
||||
<module>servlet-adapter-spi</module>
|
||||
<module>adapter-core</module>
|
||||
<module>jaxrs-oauth-client</module>
|
||||
<module>servlet-oauth-client</module>
|
||||
|
|
53
integration/servlet-adapter-spi/pom.xml
Executable file
53
integration/servlet-adapter-spi/pom.xml
Executable file
|
@ -0,0 +1,53 @@
|
|||
<?xml version="1.0"?>
|
||||
<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>1.6.0.Final-SNAPSHOT</version>
|
||||
<relativePath>../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>keycloak-servlet-adapter-spi</artifactId>
|
||||
<name>Keycloak Servlet Integration</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.jboss.spec.javax.servlet</groupId>
|
||||
<artifactId>jboss-servlet-api_3.0_spec</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<configuration>
|
||||
<source>${maven.compiler.source}</source>
|
||||
<target>${maven.compiler.target}</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
|
@ -0,0 +1,98 @@
|
|||
package org.keycloak.adapters.servlet;
|
||||
|
||||
import org.keycloak.adapters.AdapterSessionStore;
|
||||
import org.keycloak.adapters.HttpFacade;
|
||||
import org.keycloak.util.MultivaluedHashMap;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpSession;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Enumeration;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class FilterSessionStore implements AdapterSessionStore {
|
||||
public static final String REDIRECT_URI = "__REDIRECT_URI";
|
||||
public static final String SAVED_METHOD = "__SAVED_METHOD";
|
||||
public static final String SAVED_HEADERS = "__SAVED_HEADERS";
|
||||
public static final String SAVED_BODY = "__SAVED_BODY";
|
||||
protected final HttpServletRequest request;
|
||||
protected final HttpFacade facade;
|
||||
protected final int maxBuffer;
|
||||
protected byte[] restoredBuffer = null;
|
||||
|
||||
public FilterSessionStore(HttpServletRequest request, HttpFacade facade, int maxBuffer) {
|
||||
this.request = request;
|
||||
this.facade = facade;
|
||||
this.maxBuffer = maxBuffer;
|
||||
}
|
||||
|
||||
public void clearSavedRequest(HttpSession session) {
|
||||
session.removeAttribute(REDIRECT_URI);
|
||||
session.removeAttribute(SAVED_METHOD);
|
||||
session.removeAttribute(SAVED_HEADERS);
|
||||
session.removeAttribute(SAVED_BODY);
|
||||
}
|
||||
|
||||
public String getRedirectUri() {
|
||||
HttpSession session = request.getSession(true);
|
||||
return (String)session.getAttribute(REDIRECT_URI);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean restoreRequest() {
|
||||
HttpSession session = request.getSession(false);
|
||||
if (session == null) return false;
|
||||
return session.getAttribute(REDIRECT_URI) != null;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void saveRequest() {
|
||||
HttpSession session = request.getSession(true);
|
||||
session.setAttribute(REDIRECT_URI, facade.getRequest().getURI());
|
||||
session.setAttribute(SAVED_METHOD, request.getMethod());
|
||||
MultivaluedHashMap<String, String> headers = new MultivaluedHashMap<>();
|
||||
Enumeration<String> names = request.getHeaderNames();
|
||||
while (names.hasMoreElements()) {
|
||||
String name = names.nextElement();
|
||||
Enumeration<String> values = request.getHeaders(name);
|
||||
while (values.hasMoreElements()) {
|
||||
headers.add(name, values.nextElement());
|
||||
}
|
||||
}
|
||||
session.setAttribute(SAVED_HEADERS, headers);
|
||||
if (request.getMethod().equalsIgnoreCase("GET")) {
|
||||
return;
|
||||
}
|
||||
ByteArrayOutputStream os = new ByteArrayOutputStream();
|
||||
|
||||
byte[] buffer = new byte[4096];
|
||||
int bytesRead;
|
||||
int totalRead = 0;
|
||||
try {
|
||||
InputStream is = request.getInputStream();
|
||||
|
||||
while ( (bytesRead = is.read(buffer) ) >= 0) {
|
||||
os.write(buffer);
|
||||
totalRead += bytesRead;
|
||||
if (totalRead > maxBuffer) {
|
||||
throw new RuntimeException("max buffer reached on a saved request");
|
||||
}
|
||||
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
byte[] body = os.toByteArray();
|
||||
// Only save the request body if there is something to save
|
||||
if (body.length > 0) {
|
||||
session.setAttribute(SAVED_BODY, body);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,189 @@
|
|||
package org.keycloak.adapters.servlet;
|
||||
|
||||
import org.bouncycastle.ocsp.Req;
|
||||
import org.keycloak.adapters.HttpFacade;
|
||||
import org.keycloak.util.KeycloakUriBuilder;
|
||||
import org.keycloak.util.MultivaluedHashMap;
|
||||
import org.keycloak.util.ServerCookie;
|
||||
import org.keycloak.util.UriUtils;
|
||||
|
||||
import javax.security.cert.X509Certificate;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.URI;
|
||||
import java.util.Enumeration;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class ServletHttpFacade implements HttpFacade {
|
||||
protected final RequestFacade requestFacade = new RequestFacade();
|
||||
protected final ResponseFacade responseFacade = new ResponseFacade();
|
||||
protected HttpServletRequest request;
|
||||
protected HttpServletResponse response;
|
||||
protected MultivaluedHashMap<String, String> queryParameters;
|
||||
|
||||
public ServletHttpFacade(HttpServletRequest request, HttpServletResponse response) {
|
||||
this.request = request;
|
||||
this.response = response;
|
||||
}
|
||||
|
||||
protected class RequestFacade implements Request {
|
||||
@Override
|
||||
public String getMethod() {
|
||||
return request.getMethod();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getURI() {
|
||||
StringBuffer buf = request.getRequestURL();
|
||||
if (request.getQueryString() != null) {
|
||||
buf.append('?').append(request.getQueryString());
|
||||
}
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSecure() {
|
||||
return request.isSecure();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFirstParam(String param) {
|
||||
return request.getParameter(param);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getQueryParamValue(String param) {
|
||||
if (queryParameters == null) {
|
||||
queryParameters = UriUtils.decodeQueryString(request.getQueryString());
|
||||
}
|
||||
return queryParameters.getFirst(param);
|
||||
}
|
||||
|
||||
@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 String getHeader(String name) {
|
||||
return request.getHeader(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getHeaders(String name) {
|
||||
Enumeration<String> values = request.getHeaders(name);
|
||||
List<String> list = new LinkedList<>();
|
||||
while (values.hasMoreElements()) list.add(values.nextElement());
|
||||
return list;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream getInputStream() {
|
||||
try {
|
||||
return request.getInputStream();
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRemoteAddr() {
|
||||
return request.getRemoteAddr();
|
||||
}
|
||||
}
|
||||
public boolean isEnded() {
|
||||
return responseFacade.isEnded();
|
||||
}
|
||||
|
||||
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) {
|
||||
StringBuffer cookieBuf = new StringBuffer();
|
||||
ServerCookie.appendCookieValue(cookieBuf, 1, name, value, path, domain, null, maxAge, secure, httpOnly);
|
||||
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, 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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Request getRequest() {
|
||||
return requestFacade;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Response getResponse() {
|
||||
return responseFacade;
|
||||
}
|
||||
|
||||
@Override
|
||||
public X509Certificate[] getCertificateChain() {
|
||||
throw new IllegalStateException("Not supported yet");
|
||||
}
|
||||
}
|
10
pom.xml
10
pom.xml
|
@ -762,6 +762,11 @@
|
|||
<artifactId>keycloak-adapter-spi</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-servlet-adapter-spi</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-adapter-core</artifactId>
|
||||
|
@ -887,6 +892,11 @@
|
|||
<artifactId>keycloak-tomcat6-adapter</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-saml-server-filter-adapter</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-saml-tomcat6-adapter</artifactId>
|
||||
|
|
|
@ -88,6 +88,9 @@ public abstract class SamlAuthenticator {
|
|||
|
||||
protected AuthOutcome globalLogout() {
|
||||
SamlSession account = sessionStore.getAccount();
|
||||
if (account == null) {
|
||||
return AuthOutcome.NOT_ATTEMPTED;
|
||||
}
|
||||
SAML2LogoutRequestBuilder logoutBuilder = new SAML2LogoutRequestBuilder()
|
||||
.assertionExpiration(30)
|
||||
.issuer(deployment.getEntityID())
|
||||
|
|
|
@ -20,5 +20,6 @@
|
|||
<module>jetty</module>
|
||||
<module>wildfly</module>
|
||||
<module>as7-eap6</module>
|
||||
<module>servlet-filter</module>
|
||||
</modules>
|
||||
</project>
|
||||
|
|
69
saml/client-adapter/servlet-filter/pom.xml
Executable file
69
saml/client-adapter/servlet-filter/pom.xml
Executable file
|
@ -0,0 +1,69 @@
|
|||
<?xml version="1.0"?>
|
||||
<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>1.6.0.Final-SNAPSHOT</version>
|
||||
<relativePath>../../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>keycloak-saml-server-filter-adapter</artifactId>
|
||||
<name>Keycloak SAML Servlet Filter</name>
|
||||
<description />
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.jboss.logging</groupId>
|
||||
<artifactId>jboss-logging</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-common</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-adapter-spi</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-servlet-adapter-spi</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.bouncycastle</groupId>
|
||||
<artifactId>bcprov-jdk15on</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-saml-core</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-saml-adapter-core</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jboss.spec.javax.servlet</groupId>
|
||||
<artifactId>jboss-servlet-api_3.0_spec</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<configuration>
|
||||
<source>1.6</source>
|
||||
<target>1.6</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
|
@ -0,0 +1,218 @@
|
|||
package org.keycloak.adapters.saml.servlet;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
import org.keycloak.adapters.HttpFacade;
|
||||
import org.keycloak.adapters.SessionIdMapper;
|
||||
import org.keycloak.adapters.saml.SamlSession;
|
||||
import org.keycloak.adapters.saml.SamlSessionStore;
|
||||
import org.keycloak.adapters.servlet.FilterSessionStore;
|
||||
import org.keycloak.util.MultivaluedHashMap;
|
||||
|
||||
import javax.servlet.ServletInputStream;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletRequestWrapper;
|
||||
import javax.servlet.http.HttpSession;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.security.Principal;
|
||||
import java.util.Collections;
|
||||
import java.util.Enumeration;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class FilterSamlSessionStore extends FilterSessionStore implements SamlSessionStore {
|
||||
protected static Logger log = Logger.getLogger(SamlSessionStore.class);
|
||||
protected final SessionIdMapper idMapper;
|
||||
|
||||
public FilterSamlSessionStore(HttpServletRequest request, HttpFacade facade, int maxBuffer, SessionIdMapper idMapper) {
|
||||
super(request, facade, maxBuffer);
|
||||
this.idMapper = idMapper;
|
||||
}
|
||||
|
||||
protected boolean needRequestRestore;
|
||||
|
||||
@Override
|
||||
public void logoutAccount() {
|
||||
HttpSession session = request.getSession(false);
|
||||
if (session == null) return;
|
||||
if (session != null) {
|
||||
if (idMapper != null) idMapper.removeSession(session.getId());
|
||||
SamlSession samlSession = (SamlSession)session.getAttribute(SamlSession.class.getName());
|
||||
if (samlSession != null) {
|
||||
session.removeAttribute(SamlSession.class.getName());
|
||||
}
|
||||
clearSavedRequest(session);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void logoutByPrincipal(String principal) {
|
||||
SamlSession account = getAccount();
|
||||
if (account != null && account.getPrincipal().getSamlSubject().equals(principal)) {
|
||||
logoutAccount();
|
||||
}
|
||||
if (idMapper != null) {
|
||||
Set<String> sessions = idMapper.getUserSessions(principal);
|
||||
if (sessions != null) {
|
||||
List<String> ids = new LinkedList<String>();
|
||||
ids.addAll(sessions);
|
||||
for (String id : ids) {
|
||||
idMapper.removeSession(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void logoutBySsoId(List<String> ssoIds) {
|
||||
SamlSession account = getAccount();
|
||||
for (String ssoId : ssoIds) {
|
||||
if (account != null && account.getSessionIndex().equals(ssoId)) {
|
||||
logoutAccount();
|
||||
} else if (idMapper != null) {
|
||||
String sessionId = idMapper.getSessionFromSSO(ssoId);
|
||||
idMapper.removeSession(sessionId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLoggedIn() {
|
||||
HttpSession session = request.getSession(false);
|
||||
if (session == null) return false;
|
||||
if (session == null) {
|
||||
log.debug("session was null, returning null");
|
||||
return false;
|
||||
}
|
||||
final SamlSession samlSession = (SamlSession)session.getAttribute(SamlSession.class.getName());
|
||||
if (samlSession == null) {
|
||||
log.debug("SamlSession was not in session, returning null");
|
||||
return false;
|
||||
}
|
||||
if (idMapper != null && !idMapper.hasSession(session.getId())) {
|
||||
logoutAccount();
|
||||
return false;
|
||||
}
|
||||
|
||||
needRequestRestore = restoreRequest();
|
||||
return true;
|
||||
}
|
||||
|
||||
public HttpServletRequestWrapper getWrap() {
|
||||
HttpSession session = request.getSession(true);
|
||||
final SamlSession samlSession = (SamlSession)session.getAttribute(SamlSession.class.getName());
|
||||
if (needRequestRestore) {
|
||||
final String method = (String)session.getAttribute(SAVED_METHOD);
|
||||
final byte[] body = (byte[])session.getAttribute(SAVED_BODY);
|
||||
final MultivaluedHashMap<String, String> headers = (MultivaluedHashMap<String, String>)session.getAttribute(SAVED_HEADERS);
|
||||
clearSavedRequest(session);
|
||||
HttpServletRequestWrapper wrapper = new HttpServletRequestWrapper(request) {
|
||||
@Override
|
||||
public boolean isUserInRole(String role) {
|
||||
return samlSession.getRoles().contains(role);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Principal getUserPrincipal() {
|
||||
return samlSession.getPrincipal();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMethod() {
|
||||
if (needRequestRestore) {
|
||||
return method;
|
||||
} else {
|
||||
return super.getMethod();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getHeader(String name) {
|
||||
if (needRequestRestore && headers != null) {
|
||||
return headers.getFirst(name);
|
||||
}
|
||||
return super.getHeader(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Enumeration<String> getHeaders(String name) {
|
||||
if (needRequestRestore && headers != null) {
|
||||
List<String> values = headers.getList(name);
|
||||
if (values == null) return Collections.emptyEnumeration();
|
||||
else return Collections.enumeration(values);
|
||||
}
|
||||
return super.getHeaders(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Enumeration<String> getHeaderNames() {
|
||||
if (needRequestRestore && headers != null) {
|
||||
return Collections.enumeration(headers.keySet());
|
||||
}
|
||||
return super.getHeaderNames();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServletInputStream getInputStream() throws IOException {
|
||||
|
||||
if (needRequestRestore && body != null) {
|
||||
final ByteArrayInputStream is = new ByteArrayInputStream(body);
|
||||
return new ServletInputStream() {
|
||||
@Override
|
||||
public int read() throws IOException {
|
||||
return is.read();
|
||||
}
|
||||
};
|
||||
}
|
||||
return super.getInputStream();
|
||||
}
|
||||
};
|
||||
return wrapper;
|
||||
} else {
|
||||
return new HttpServletRequestWrapper(request) {
|
||||
@Override
|
||||
public boolean isUserInRole(String role) {
|
||||
return samlSession.getRoles().contains(role);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Principal getUserPrincipal() {
|
||||
return samlSession.getPrincipal();
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveAccount(SamlSession account) {
|
||||
HttpSession session = request.getSession(true);
|
||||
session.setAttribute(SamlSession.class.getName(), account);
|
||||
if (idMapper != null) idMapper.map(account.getSessionIndex(), account.getPrincipal().getSamlSubject(), session.getId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public SamlSession getAccount() {
|
||||
HttpSession session = request.getSession(false);
|
||||
if (session == null) return null;
|
||||
return (SamlSession)session.getAttribute(SamlSession.class.getName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRedirectUri() {
|
||||
HttpSession session = request.getSession(false);
|
||||
if (session == null) return null;
|
||||
return (String)session.getAttribute(REDIRECT_URI);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,147 @@
|
|||
package org.keycloak.adapters.saml.servlet;
|
||||
|
||||
import org.keycloak.adapters.AuthChallenge;
|
||||
import org.keycloak.adapters.AuthOutcome;
|
||||
import org.keycloak.adapters.InMemorySessionIdMapper;
|
||||
import org.keycloak.adapters.SessionIdMapper;
|
||||
import org.keycloak.adapters.saml.DefaultSamlDeployment;
|
||||
import org.keycloak.adapters.saml.SamlAuthenticator;
|
||||
import org.keycloak.adapters.saml.SamlDeployment;
|
||||
import org.keycloak.adapters.saml.SamlDeploymentContext;
|
||||
import org.keycloak.adapters.saml.SamlSession;
|
||||
import org.keycloak.adapters.saml.config.parsers.DeploymentBuilder;
|
||||
import org.keycloak.adapters.saml.config.parsers.ResourceLoader;
|
||||
import org.keycloak.adapters.servlet.ServletHttpFacade;
|
||||
import org.keycloak.saml.common.exceptions.ParsingException;
|
||||
|
||||
import javax.servlet.Filter;
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.FilterConfig;
|
||||
import javax.servlet.RequestDispatcher;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletRequestWrapper;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class SamlFilter implements Filter {
|
||||
protected SamlDeploymentContext deploymentContext;
|
||||
protected SessionIdMapper idMapper = new InMemorySessionIdMapper();
|
||||
private final static Logger log = Logger.getLogger(""+SamlFilter.class);
|
||||
|
||||
@Override
|
||||
public void init(final FilterConfig filterConfig) throws ServletException {
|
||||
String configResolverClass = filterConfig.getInitParameter("keycloak.config.resolver");
|
||||
if (configResolverClass != null) {
|
||||
try {
|
||||
throw new RuntimeException("Not implemented yet");
|
||||
//KeycloakConfigResolver configResolver = (KeycloakConfigResolver) context.getLoader().getClassLoader().loadClass(configResolverClass).newInstance();
|
||||
//deploymentContext = new SamlDeploymentContext(configResolver);
|
||||
//log.log(Level.INFO, "Using {0} to resolve Keycloak configuration on a per-request basis.", configResolverClass);
|
||||
} catch (Exception ex) {
|
||||
log.log(Level.FINE, "The specified resolver {0} could NOT be loaded. Keycloak is unconfigured and will deny all requests. Reason: {1}", new Object[]{configResolverClass, ex.getMessage()});
|
||||
//deploymentContext = new AdapterDeploymentContext(new KeycloakDeployment());
|
||||
}
|
||||
} else {
|
||||
String path = "/WEB-INF/keycloak-saml.xml";
|
||||
String pathParam = filterConfig.getInitParameter("keycloak.config.file");
|
||||
if (pathParam != null) path = pathParam;
|
||||
InputStream is = filterConfig.getServletContext().getResourceAsStream(path);
|
||||
final SamlDeployment deployment;
|
||||
if (is == null) {
|
||||
log.info("No adapter configuration. Keycloak is unconfigured and will deny all requests.");
|
||||
deployment = new DefaultSamlDeployment();
|
||||
} else {
|
||||
try {
|
||||
ResourceLoader loader = new ResourceLoader() {
|
||||
@Override
|
||||
public InputStream getResourceAsStream(String resource) {
|
||||
return filterConfig.getServletContext().getResourceAsStream(resource);
|
||||
}
|
||||
};
|
||||
deployment = new DeploymentBuilder().build(is, loader);
|
||||
} catch (ParsingException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
deploymentContext = new SamlDeploymentContext(deployment);
|
||||
log.fine("Keycloak is using a per-deployment configuration.");
|
||||
}
|
||||
filterConfig.getServletContext().setAttribute(SamlDeploymentContext.class.getName(), deploymentContext);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
|
||||
HttpServletRequest request = (HttpServletRequest) req;
|
||||
HttpServletResponse response = (HttpServletResponse) res;
|
||||
ServletHttpFacade facade = new ServletHttpFacade(request, response);
|
||||
SamlDeployment deployment = deploymentContext.resolveDeployment(facade);
|
||||
if (deployment == null || !deployment.isConfigured()) {
|
||||
response.sendError(403);
|
||||
log.fine("deployment not configured");
|
||||
return;
|
||||
}
|
||||
FilterSamlSessionStore tokenStore = new FilterSamlSessionStore(request, facade, 100000, idMapper);
|
||||
|
||||
|
||||
SamlAuthenticator authenticator = new SamlAuthenticator(facade, deployment, tokenStore) {
|
||||
@Override
|
||||
protected void completeAuthentication(SamlSession account) {
|
||||
|
||||
}
|
||||
};
|
||||
AuthOutcome outcome = authenticator.authenticate();
|
||||
if (outcome == AuthOutcome.AUTHENTICATED) {
|
||||
log.fine("AUTHENTICATED");
|
||||
if (facade.isEnded()) {
|
||||
return;
|
||||
}
|
||||
HttpServletRequestWrapper wrapper = tokenStore.getWrap();
|
||||
chain.doFilter(wrapper, res);
|
||||
return;
|
||||
}
|
||||
if (outcome == AuthOutcome.LOGGED_OUT) {
|
||||
tokenStore.logoutAccount();
|
||||
if (deployment.getLogoutPage() != null) {
|
||||
RequestDispatcher disp = req.getRequestDispatcher(deployment.getLogoutPage());
|
||||
disp.forward(req, res);
|
||||
return;
|
||||
}
|
||||
chain.doFilter(req, res);
|
||||
return;
|
||||
}
|
||||
|
||||
AuthChallenge challenge = authenticator.getChallenge();
|
||||
if (challenge != null) {
|
||||
log.fine("challenge");
|
||||
if (challenge.errorPage()) {
|
||||
response.sendError(403);
|
||||
return;
|
||||
}
|
||||
log.fine("sending challenge");
|
||||
challenge.challenge(facade);
|
||||
}
|
||||
if (outcome == AuthOutcome.FAILED) {
|
||||
response.sendError(403);
|
||||
} else if (!facade.isEnded()) {
|
||||
chain.doFilter(req, res);
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
|
||||
}
|
||||
}
|
|
@ -105,6 +105,10 @@
|
|||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-saml-adapter-core</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-saml-server-filter-adapter</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-saml-undertow-adapter</artifactId>
|
||||
|
|
|
@ -26,7 +26,11 @@ public class SendUsernameServlet extends HttpServlet {
|
|||
if (checkRoles != null) {
|
||||
for (String role : checkRoles) {
|
||||
System.out.println("check role: " + role);
|
||||
Assert.assertTrue(req.isUserInRole(role));
|
||||
//Assert.assertTrue(req.isUserInRole(role));
|
||||
if (!req.isUserInRole(role)) {
|
||||
resp.sendError(403);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,147 @@
|
|||
package org.keycloak.testsuite.samlfilter;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.ClassRule;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.keycloak.testsuite.keycloaksaml.SamlAdapterTestStrategy;
|
||||
import org.keycloak.testsuite.keycloaksaml.SamlSPFacade;
|
||||
import org.keycloak.testsuite.keycloaksaml.SendUsernameServlet;
|
||||
import org.openqa.selenium.WebDriver;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class SamlAdapterTest {
|
||||
|
||||
@ClassRule
|
||||
public static SamlKeycloakRule keycloakRule = new SamlKeycloakRule() {
|
||||
@Override
|
||||
public void initWars() {
|
||||
ClassLoader classLoader = SamlAdapterTest.class.getClassLoader();
|
||||
|
||||
initializeSamlSecuredWar("/keycloak-saml/simple-post", "/sales-post", "post.war", classLoader);
|
||||
initializeSamlSecuredWar("/keycloak-saml/signed-post", "/sales-post-sig", "post-sig.war", classLoader);
|
||||
initializeSamlSecuredWar("/keycloak-saml/signed-post-email", "/sales-post-sig-email", "post-sig-email.war", classLoader);
|
||||
initializeSamlSecuredWar("/keycloak-saml/signed-post-transient", "/sales-post-sig-transient", "post-sig-transient.war", classLoader);
|
||||
initializeSamlSecuredWar("/keycloak-saml/signed-post-persistent", "/sales-post-sig-persistent", "post-sig-persistent.war", classLoader);
|
||||
initializeSamlSecuredWar("/keycloak-saml/signed-metadata", "/sales-metadata", "post-metadata.war", classLoader);
|
||||
initializeSamlSecuredWar("/keycloak-saml/signed-get", "/employee-sig", "employee-sig.war", classLoader);
|
||||
initializeSamlSecuredWar("/keycloak-saml/mappers", "/employee2", "employee2.war", classLoader);
|
||||
initializeSamlSecuredWar("/keycloak-saml/signed-front-get", "/employee-sig-front", "employee-sig-front.war", classLoader);
|
||||
initializeSamlSecuredWar("/keycloak-saml/bad-client-signed-post", "/bad-client-sales-post-sig", "bad-client-post-sig.war", classLoader);
|
||||
initializeSamlSecuredWar("/keycloak-saml/bad-realm-signed-post", "/bad-realm-sales-post-sig", "bad-realm-post-sig.war", classLoader);
|
||||
initializeSamlSecuredWar("/keycloak-saml/encrypted-post", "/sales-post-enc", "post-enc.war", classLoader);
|
||||
SamlAdapterTestStrategy.uploadSP("http://localhost:8081/auth");
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRealmJson() {
|
||||
return "/keycloak-saml/testsaml.json";
|
||||
}
|
||||
};
|
||||
|
||||
@Rule
|
||||
public SamlAdapterTestStrategy testStrategy = new SamlAdapterTestStrategy("http://localhost:8081/auth", "http://localhost:8081", keycloakRule);
|
||||
|
||||
@Test
|
||||
public void testPostBadRealmSignature() {
|
||||
testStrategy.testPostBadRealmSignature( new SamlAdapterTestStrategy.CheckAuthError() {
|
||||
@Override
|
||||
public void check(WebDriver driver) {
|
||||
Assert.assertTrue(driver.getPageSource().contains("Forbidden"));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPostSimpleUnauthorized() {
|
||||
List<String> requiredRoles = new LinkedList<>();
|
||||
requiredRoles.add("manager");
|
||||
requiredRoles.add("employee");
|
||||
requiredRoles.add("user");
|
||||
SendUsernameServlet.checkRoles = requiredRoles;
|
||||
try {
|
||||
testStrategy.testPostSimpleUnauthorized(new SamlAdapterTestStrategy.CheckAuthError() {
|
||||
@Override
|
||||
public void check(WebDriver driver) {
|
||||
Assert.assertTrue(driver.getPageSource().contains("Forbidden"));
|
||||
}
|
||||
});
|
||||
} finally {
|
||||
SendUsernameServlet.checkRoles = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMetadataPostSignedLoginLogout() throws Exception {
|
||||
testStrategy.testMetadataPostSignedLoginLogout();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRedirectSignedLoginLogout() {
|
||||
testStrategy.testRedirectSignedLoginLogout();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPostSignedLoginLogoutEmailNameID() {
|
||||
testStrategy.testPostSignedLoginLogoutEmailNameID();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPostEncryptedLoginLogout() {
|
||||
testStrategy.testPostEncryptedLoginLogout();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRedirectSignedLoginLogoutFrontNoSSO() {
|
||||
testStrategy.testRedirectSignedLoginLogoutFrontNoSSO();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPostSimpleLoginLogout() {
|
||||
testStrategy.testPostSimpleLoginLogout();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPostSignedLoginLogoutTransientNameID() {
|
||||
testStrategy.testPostSignedLoginLogoutTransientNameID();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPostSimpleLoginLogoutIdpInitiated() {
|
||||
testStrategy.testPostSimpleLoginLogoutIdpInitiated();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAttributes() throws Exception {
|
||||
testStrategy.testAttributes();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPostSignedLoginLogoutPersistentNameID() {
|
||||
testStrategy.testPostSignedLoginLogoutPersistentNameID();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPostBadClientSignature() {
|
||||
testStrategy.testPostBadClientSignature();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRedirectSignedLoginLogoutFront() {
|
||||
testStrategy.testRedirectSignedLoginLogoutFront();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPostSignedLoginLogout() {
|
||||
testStrategy.testPostSignedLoginLogout();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,125 @@
|
|||
package org.keycloak.testsuite.samlfilter;
|
||||
|
||||
import io.undertow.security.idm.Account;
|
||||
import io.undertow.security.idm.Credential;
|
||||
import io.undertow.security.idm.IdentityManager;
|
||||
import io.undertow.server.handlers.resource.Resource;
|
||||
import io.undertow.server.handlers.resource.ResourceChangeListener;
|
||||
import io.undertow.server.handlers.resource.ResourceManager;
|
||||
import io.undertow.server.handlers.resource.URLResource;
|
||||
import io.undertow.servlet.api.DeploymentInfo;
|
||||
import io.undertow.servlet.api.FilterInfo;
|
||||
import io.undertow.servlet.api.LoginConfig;
|
||||
import io.undertow.servlet.api.SecurityConstraint;
|
||||
import io.undertow.servlet.api.ServletInfo;
|
||||
import io.undertow.servlet.api.WebResourceCollection;
|
||||
import org.keycloak.adapters.saml.servlet.SamlFilter;
|
||||
import org.keycloak.adapters.saml.undertow.SamlServletExtension;
|
||||
import org.keycloak.testsuite.keycloaksaml.SendUsernameServlet;
|
||||
import org.keycloak.testsuite.rule.AbstractKeycloakRule;
|
||||
|
||||
import javax.servlet.DispatcherType;
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public abstract class SamlKeycloakRule extends AbstractKeycloakRule {
|
||||
|
||||
public static class TestResourceManager implements ResourceManager {
|
||||
|
||||
private final String basePath;
|
||||
|
||||
public TestResourceManager(String basePath){
|
||||
this.basePath = basePath;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Resource getResource(String path) throws IOException {
|
||||
String temp = path;
|
||||
String fullPath = basePath + temp;
|
||||
URL url = getClass().getResource(fullPath);
|
||||
if (url == null) {
|
||||
System.out.println("url is null: " + fullPath);
|
||||
}
|
||||
return new URLResource(url, url.openConnection(), path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isResourceChangeListenerSupported() {
|
||||
throw new RuntimeException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerResourceChangeListener(ResourceChangeListener listener) {
|
||||
throw new RuntimeException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeResourceChangeListener(ResourceChangeListener listener) {
|
||||
throw new RuntimeException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
throw new RuntimeException();
|
||||
}
|
||||
}
|
||||
|
||||
public static class TestIdentityManager implements IdentityManager {
|
||||
@Override
|
||||
public Account verify(Account account) {
|
||||
return account;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Account verify(String userName, Credential credential) {
|
||||
throw new RuntimeException("WTF");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Account verify(Credential credential) {
|
||||
throw new RuntimeException();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setupKeycloak() {
|
||||
String realmJson = getRealmJson();
|
||||
server.importRealm(getClass().getResourceAsStream(realmJson));
|
||||
initWars();
|
||||
}
|
||||
|
||||
public abstract void initWars();
|
||||
|
||||
public void initializeSamlSecuredWar(String warResourcePath, String contextPath, String warDeploymentName, ClassLoader classLoader) {
|
||||
|
||||
ServletInfo regularServletInfo = new ServletInfo("servlet", SendUsernameServlet.class)
|
||||
.addMapping("/*");
|
||||
|
||||
FilterInfo samlFilter = new FilterInfo("saml-filter", SamlFilter.class);
|
||||
|
||||
|
||||
ResourceManager resourceManager = new TestResourceManager(warResourcePath);
|
||||
|
||||
DeploymentInfo deploymentInfo = new DeploymentInfo()
|
||||
.setClassLoader(classLoader)
|
||||
.setIdentityManager(new TestIdentityManager())
|
||||
.setContextPath(contextPath)
|
||||
.setDeploymentName(warDeploymentName)
|
||||
.setResourceManager(resourceManager)
|
||||
.addServlets(regularServletInfo)
|
||||
.addFilter(samlFilter)
|
||||
.addFilterUrlMapping("saml-filter", "/*", DispatcherType.REQUEST)
|
||||
.addServletExtension(new SamlServletExtension());
|
||||
server.getServer().deploy(deploymentInfo);
|
||||
}
|
||||
|
||||
public String getRealmJson() {
|
||||
return "/keycloak-saml/testsaml.json";
|
||||
}
|
||||
|
||||
|
||||
}
|
Loading…
Reference in a new issue