Merge pull request #871 from patriot1burke/master
proxy distro and docs
This commit is contained in:
commit
8c451af3f5
17 changed files with 549 additions and 21 deletions
|
@ -19,6 +19,9 @@ import java.util.Date;
|
|||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class CertificateUtils {
|
||||
static {
|
||||
BouncyIntegration.init();
|
||||
}
|
||||
public static X509Certificate generateV3Certificate(KeyPair keyPair, PrivateKey caPrivateKey, X509Certificate caCert, String subject) throws Exception {
|
||||
|
||||
X509V3CertificateGenerator certGen = new X509V3CertificateGenerator();
|
||||
|
|
|
@ -39,6 +39,7 @@
|
|||
<module>theme-template-zip</module>
|
||||
<module>war-zip</module>
|
||||
<module>war-dist</module>
|
||||
<module>proxy</module>
|
||||
<module>appliance-dist</module>
|
||||
<module>src-dist</module>
|
||||
</modules>
|
||||
|
|
30
distribution/proxy/assembly.xml
Executable file
30
distribution/proxy/assembly.xml
Executable file
|
@ -0,0 +1,30 @@
|
|||
<assembly>
|
||||
<id>war-dist</id>
|
||||
|
||||
<formats>
|
||||
<format>zip</format>
|
||||
</formats>
|
||||
<includeBaseDirectory>false</includeBaseDirectory>
|
||||
|
||||
<dependencySets>
|
||||
<dependencySet>
|
||||
<unpack>false</unpack>
|
||||
<useTransitiveDependencies>true</useTransitiveDependencies>
|
||||
<useTransitiveFiltering>true</useTransitiveFiltering>
|
||||
<includes>
|
||||
<include>org.keycloak:launcher</include>
|
||||
</includes>
|
||||
<outputFileNameMapping>${artifact.artifactId}.${artifact.extension}</outputFileNameMapping>
|
||||
<outputDirectory>bin</outputDirectory>
|
||||
</dependencySet>
|
||||
<dependencySet>
|
||||
<unpack>false</unpack>
|
||||
<useTransitiveDependencies>true</useTransitiveDependencies>
|
||||
<useTransitiveFiltering>true</useTransitiveFiltering>
|
||||
<includes>
|
||||
<include>org.keycloak:keycloak-proxy-server</include>
|
||||
</includes>
|
||||
<outputDirectory>lib</outputDirectory>
|
||||
</dependencySet>
|
||||
</dependencySets>
|
||||
</assembly>
|
58
distribution/proxy/pom.xml
Executable file
58
distribution/proxy/pom.xml
Executable file
|
@ -0,0 +1,58 @@
|
|||
<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>1.1.0.Beta2-SNAPSHOT</version>
|
||||
<relativePath>../../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
<artifactId>keycloak-proxy-dist</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
<name>Proxy Distro</name>
|
||||
<description/>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>launcher</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-proxy-server</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<artifactId>maven-assembly-plugin</artifactId>
|
||||
<version>2.4</version>
|
||||
<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>
|
|
@ -39,6 +39,7 @@
|
|||
<!ENTITY Clustering SYSTEM "modules/clustering.xml">
|
||||
<!ENTITY ApplicationClustering SYSTEM "modules/application-clustering.xml">
|
||||
<!ENTITY MultiTenancy SYSTEM "modules/multi-tenancy.xml">
|
||||
<!ENTITY Proxy SYSTEM "modules/proxy.xml">
|
||||
]>
|
||||
|
||||
<book>
|
||||
|
@ -135,6 +136,7 @@ This one is short
|
|||
&SecurityVulnerabilities;
|
||||
&Clustering;
|
||||
&ApplicationClustering;
|
||||
&Proxy;
|
||||
&Migration;
|
||||
|
||||
</book>
|
||||
|
|
277
docbook/reference/en/en-US/modules/proxy.xml
Executable file
277
docbook/reference/en/en-US/modules/proxy.xml
Executable file
|
@ -0,0 +1,277 @@
|
|||
<chapter id="proxy">
|
||||
<title>Keycloak Security Proxy</title>
|
||||
<para>
|
||||
Keycloak has an HTTP(S) proxy that you can put in front of web applications and services where it is not possible
|
||||
to install the keycloak adapter. You can set up URL filters so that certain URLs are secured either by browser login
|
||||
and/or bearer token authentication. You can also define role constraints for URL patterns within your applications.
|
||||
</para>
|
||||
<section>
|
||||
<title>Proxy Install and Run</title>
|
||||
<para>Download the keycloak proxy distribution from the Keycloak download pages and unzip it.
|
||||
<programlisting>
|
||||
$ unzip keycloak-proxy-dist.zip
|
||||
</programlisting>
|
||||
</para>
|
||||
<para>
|
||||
To run it you must have a proxy config file (which we'll discuss in a moment).
|
||||
<programlisting>
|
||||
$ java -jar bin/launcher.jar [your-config.json]
|
||||
</programlisting>
|
||||
</para>
|
||||
<para>
|
||||
If you do not specify a path to the proxy config file, the launcher will look in the current working directory
|
||||
for the file named <literal>proxy.json</literal>
|
||||
</para>
|
||||
</section>
|
||||
<section>
|
||||
<title>Proxy Configuration</title>
|
||||
<para>
|
||||
Here's an example configuration file.
|
||||
<programlisting><![CDATA[
|
||||
{
|
||||
"target-url": "http://localhost:8082",
|
||||
"bind-address": "localhost",
|
||||
"http-port": "8080",
|
||||
"https-port": "8443",
|
||||
"keystore": "classpath:ssl.jks",
|
||||
"keystore-password": "password",
|
||||
"key-password": "password",
|
||||
"applications": [
|
||||
{
|
||||
"base-path": "/customer-portal",
|
||||
"error-page": "/error.html",
|
||||
"adapter-config": {
|
||||
"realm": "demo",
|
||||
"resource": "customer-portal",
|
||||
"realm-public-key": "MIGfMA0GCSqGSIb",
|
||||
"auth-server-url": "http://localhost:8081/auth",
|
||||
"ssl-required" : "external",
|
||||
"principal-attribute": "name",
|
||||
"credentials": {
|
||||
"secret": "password"
|
||||
}
|
||||
}
|
||||
,
|
||||
"constraints": [
|
||||
{
|
||||
"pattern": "/users/*",
|
||||
"roles-allowed": [
|
||||
"user"
|
||||
]
|
||||
},
|
||||
{
|
||||
"pattern": "/admins/*",
|
||||
"roles-allowed": [
|
||||
"admin"
|
||||
]
|
||||
},
|
||||
{
|
||||
"pattern": "/users/permit",
|
||||
"permit": true
|
||||
},
|
||||
{
|
||||
"pattern": "/users/deny",
|
||||
"deny": true
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}]]>
|
||||
</programlisting>
|
||||
</para>
|
||||
<section>
|
||||
<title>Basic Config</title>
|
||||
<para>
|
||||
The basic configuration options for the server are as follows:
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term>target-url</term>
|
||||
<listitem>
|
||||
<para>
|
||||
The URL this server is proxying <emphasis>REQUIRED.</emphasis>.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>bind-address</term>
|
||||
<listitem>
|
||||
<para>
|
||||
DNS name or IP address to bind the proxy server's sockets to.
|
||||
<emphasis>OPTIONAL.</emphasis>. The default value is <emphasis>localhost</emphasis>
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>http-port</term>
|
||||
<listitem>
|
||||
<para>
|
||||
Port to listen for HTTP requests. If you do not specify this value, then the proxy will
|
||||
not listen for regular HTTP requests.
|
||||
<emphasis>OPTIONAL.</emphasis>.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>https-port</term>
|
||||
<listitem>
|
||||
<para>
|
||||
Port to listen for HTTPS requests. If you do not specify this value, then the proxy will
|
||||
not listen for HTTPS requests.
|
||||
<emphasis>OPTIONAL.</emphasis>.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>keystore</term>
|
||||
<listitem>
|
||||
<para>
|
||||
Path to a Java keystore file that contains private key and certificate for the server to be
|
||||
able to handle HTTPS requests. Can be a file path, or, if you prefix it with <literal>classpath:</literal>
|
||||
it will look for this file in the classpath.
|
||||
<emphasis>OPTIONAL.</emphasis>. If you have enabled HTTPS, but have not defined a keystore, the proxy
|
||||
will auto-generate a self-signed certificate and use that.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>buffer-size</term>
|
||||
<listitem>
|
||||
<para>
|
||||
HTTP server socket buffer size. Usually the default is good enough. <emphasis>OPTIONAL.</emphasis>.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>buffers-per-region</term>
|
||||
<listitem>
|
||||
<para>
|
||||
HTTP server socket buffers per region. Usually the default is good enough. <emphasis>OPTIONAL.</emphasis>.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>io-threads</term>
|
||||
<listitem>
|
||||
<para>
|
||||
Number of threads to handle IO. Usually default is good enough. <emphasis>OPTIONAL.</emphasis>.
|
||||
The default is the number of available processors * 2.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>worker-threads</term>
|
||||
<listitem>
|
||||
<para>
|
||||
Number of threads to handle requests. Usually the default is good enough. <emphasis>OPTIONAL.</emphasis>.
|
||||
The default is the number of available processors * 16.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</para>
|
||||
</section>
|
||||
<section>
|
||||
<title>Application Config</title>
|
||||
<para>
|
||||
Next under the <literal>applications</literal> array attribute, you can define one or more applications per host you are proxying.
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term>base-path</term>
|
||||
<listitem>
|
||||
<para>
|
||||
The base context root for the application. Must start with '/' <emphasis>REQUIRED.</emphasis>.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>error-page</term>
|
||||
<listitem>
|
||||
<para>
|
||||
If the proxy has an error, it will display the target application's error page relative URL <emphasis>OPTIONAL.</emphasis>.
|
||||
This is a relative path to the base-path. In the example above it would be <literal>/customer-portal/error.html</literal>.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>adapter-config</term>
|
||||
<listitem>
|
||||
<para>
|
||||
<emphasis>REQUIRED.</emphasis>. Same configuration as any other keycloak adapter. See <link linkend='adapter-config'>Adapter Config</link>
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</para>
|
||||
<section>
|
||||
<title>Constraint Config</title>
|
||||
|
||||
<para>
|
||||
Next under each application you can define one or more constraints in the <literal>constraints</literal> array attribute.
|
||||
A constraint defines a URL pattern relative to the base-path. You can deny, permit, or require authentication for
|
||||
a specific URL pattern. You can specify roles allowed for that path as well. More specific constraints will take
|
||||
precedence over more general ones.
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term>pattern</term>
|
||||
<listitem>
|
||||
<para>
|
||||
URL pattern to match relative to the base-path of the application. Must start with '/' <emphasis>REQUIRED.</emphasis>.
|
||||
You may only have one wildcard and it must come at the end of the pattern. Valid <literal>/foo/bar/*</literal> and <literal>/foo/*.txt</literal>
|
||||
Not valid: <literal>/*/foo/*</literal>.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>roles-allowed</term>
|
||||
<listitem>
|
||||
<para>
|
||||
Array of strings of roles allowed to access this url pattern. <emphasis>OPTIONAL.</emphasis>.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>methods</term>
|
||||
<listitem>
|
||||
<para>
|
||||
Array of strings of HTTP methods that will exclusively match this pattern and HTTP request. <emphasis>OPTIONAL.</emphasis>.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>excluded-methods</term>
|
||||
<listitem>
|
||||
<para>
|
||||
Array of strings of HTTP methods that will be ignored when match this pattern. <emphasis>OPTIONAL.</emphasis>.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>deny</term>
|
||||
<listitem>
|
||||
<para>
|
||||
Deny all access to this URL pattern. <emphasis>OPTIONAL.</emphasis>.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>permit</term>
|
||||
<listitem>
|
||||
<para>
|
||||
Permit all access without requiring authentication or a role mapping. <emphasis>OPTIONAL.</emphasis>.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>authenticate</term>
|
||||
<listitem>
|
||||
<para>
|
||||
Require authentication for this pattern, but no role mapping. <emphasis>OPTIONAL.</emphasis>.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</para>
|
||||
</section>
|
||||
</section>
|
||||
</section>
|
||||
</chapter>
|
|
@ -16,21 +16,15 @@
|
|||
*/
|
||||
package org.keycloak.adapters.undertow;
|
||||
|
||||
import io.undertow.security.api.AuthenticatedSessionManager;
|
||||
import io.undertow.server.HttpServerExchange;
|
||||
import io.undertow.server.session.Session;
|
||||
import io.undertow.server.session.SessionConfig;
|
||||
import io.undertow.server.session.SessionListener;
|
||||
import io.undertow.server.session.SessionManager;
|
||||
import io.undertow.servlet.handlers.security.CachedAuthenticatedSessionHandler;
|
||||
import org.jboss.logging.Logger;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* Manages relationship to users and sessions so that forced admin logout can be implemented
|
||||
|
@ -40,7 +34,6 @@ import java.util.concurrent.ConcurrentHashMap;
|
|||
*/
|
||||
public class UndertowUserSessionManagement implements SessionListener {
|
||||
private static final Logger log = Logger.getLogger(UndertowUserSessionManagement.class);
|
||||
private static final String AUTH_SESSION_NAME = CachedAuthenticatedSessionHandler.class.getName() + ".AuthenticatedSession";
|
||||
protected volatile boolean registered;
|
||||
|
||||
public void login(SessionManager manager) {
|
||||
|
@ -67,7 +60,7 @@ public class UndertowUserSessionManagement implements SessionListener {
|
|||
log.debug("logoutHttpSession: " + httpSessionId);
|
||||
Session session = getSessionById(manager, httpSessionId);
|
||||
try {
|
||||
session.invalidate(null);
|
||||
if (session != null) session.invalidate(null);
|
||||
} catch (Exception e) {
|
||||
log.warnf("Session %s not present or already invalidated.", httpSessionId);
|
||||
}
|
||||
|
@ -115,16 +108,6 @@ public class UndertowUserSessionManagement implements SessionListener {
|
|||
|
||||
@Override
|
||||
public void sessionDestroyed(Session session, HttpServerExchange exchange, SessionDestroyedReason reason) {
|
||||
// Look up the single session id associated with this session (if any)
|
||||
String username = getUsernameFromSession(session);
|
||||
log.debugf("Session destroyed for user: %s, sessionId: %s", username, session.getId());
|
||||
}
|
||||
|
||||
protected String getUsernameFromSession(Session session) {
|
||||
AuthenticatedSessionManager.AuthenticatedSession authSession = (AuthenticatedSessionManager.AuthenticatedSession) session.getAttribute(AUTH_SESSION_NAME);
|
||||
if (authSession == null) return null;
|
||||
return authSession.getAccount().getPrincipal().getName();
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
2
pom.xml
2
pom.xml
|
@ -108,7 +108,7 @@
|
|||
<module>events</module>
|
||||
<module>model</module>
|
||||
<module>integration</module>
|
||||
<module>proxy/proxy-server</module>
|
||||
<module>proxy</module>
|
||||
<module>picketlink</module>
|
||||
<module>federation</module>
|
||||
<module>services</module>
|
||||
|
|
43
proxy/launcher/pom.xml
Executable file
43
proxy/launcher/pom.xml
Executable file
|
@ -0,0 +1,43 @@
|
|||
<?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.1.0.Beta2-SNAPSHOT</version>
|
||||
<relativePath>../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>launcher</artifactId>
|
||||
<name>Keycloak Launcher</name>
|
||||
<description/>
|
||||
|
||||
<dependencies>
|
||||
|
||||
</dependencies>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-jar-plugin</artifactId>
|
||||
<configuration>
|
||||
<archive>
|
||||
<manifest>
|
||||
<mainClass>org.keycloak.Launcher</mainClass>
|
||||
</manifest>
|
||||
</archive>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<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>
|
66
proxy/launcher/src/main/java/org/keycloak/Launcher.java
Executable file
66
proxy/launcher/src/main/java/org/keycloak/Launcher.java
Executable file
|
@ -0,0 +1,66 @@
|
|||
package org.keycloak;
|
||||
|
||||
import java.io.File;
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class Launcher {
|
||||
|
||||
public static File getHome() {
|
||||
String launcherPath = Launcher.class.getName().replace('.', '/') + ".class";
|
||||
URL jarfile = Launcher.class.getClassLoader().getResource(launcherPath);
|
||||
if (jarfile != null) {
|
||||
Matcher m = Pattern.compile("jar:(file:.*)!/" + launcherPath).matcher(jarfile.toString());
|
||||
if (m.matches()) {
|
||||
try {
|
||||
File jarPath = new File(new URI(m.group(1)));
|
||||
File libPath = jarPath.getParentFile().getParentFile();
|
||||
System.out.println("Home directory: " + libPath.toString());
|
||||
if (!libPath.exists()) {
|
||||
System.exit(1);
|
||||
|
||||
}
|
||||
return libPath;
|
||||
} catch (URISyntaxException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
System.err.println("jar file null: " + launcherPath);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
|
||||
File home = getHome();
|
||||
File lib = new File(home, "lib");
|
||||
if (!lib.exists()) {
|
||||
System.err.println("Could not find lib directory: " + lib.toString());
|
||||
System.exit(1);
|
||||
}
|
||||
List<URL> jars = new ArrayList<URL>();
|
||||
for (File file : lib.listFiles()) {
|
||||
jars.add(file.toURI().toURL());
|
||||
}
|
||||
URL[] urls = jars.toArray(new URL[jars.size()]);
|
||||
URLClassLoader loader = new URLClassLoader(urls, Launcher.class.getClassLoader());
|
||||
|
||||
Class mainClass = loader.loadClass("org.keycloak.proxy.Main");
|
||||
Method mainMethod = null;
|
||||
for (Method m : mainClass.getMethods()) if (m.getName().equals("main")) { mainMethod = m; break; }
|
||||
Object obj = args;
|
||||
mainMethod.invoke(null, obj);
|
||||
}
|
||||
}
|
31
proxy/pom.xml
Executable file
31
proxy/pom.xml
Executable file
|
@ -0,0 +1,31 @@
|
|||
<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.1.0.Beta2-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<name>Model Parent</name>
|
||||
<description/>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>keycloak-proxy-pom</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-deploy-plugin</artifactId>
|
||||
<configuration>
|
||||
<skip>true</skip>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
<modules>
|
||||
<module>launcher</module>
|
||||
<module>proxy-server</module>
|
||||
</modules>
|
||||
</project>
|
|
@ -18,7 +18,6 @@
|
|||
<groupId>org.jboss.logging</groupId>
|
||||
<artifactId>jboss-logging</artifactId>
|
||||
<version>${jboss.logging.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
|
@ -63,7 +62,6 @@
|
|||
<dependency>
|
||||
<groupId>io.undertow</groupId>
|
||||
<artifactId>undertow-core</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
|
|
|
@ -4,6 +4,7 @@ import io.undertow.security.handlers.AuthenticationConstraintHandler;
|
|||
import io.undertow.server.HttpHandler;
|
||||
import io.undertow.server.HttpServerExchange;
|
||||
import io.undertow.util.AttachmentKey;
|
||||
import org.jboss.logging.Logger;
|
||||
import org.keycloak.KeycloakSecurityContext;
|
||||
|
||||
/**
|
||||
|
@ -11,6 +12,7 @@ import org.keycloak.KeycloakSecurityContext;
|
|||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class ConstraintMatcherHandler implements HttpHandler {
|
||||
protected static Logger log = Logger.getLogger(ConstraintMatcherHandler.class);
|
||||
public static final AttachmentKey<SingleConstraintMatch> CONSTRAINT_KEY = AttachmentKey.create(SingleConstraintMatch.class);
|
||||
protected SecurityPathMatches matcher;
|
||||
protected HttpHandler securedHandler;
|
||||
|
@ -26,6 +28,7 @@ public class ConstraintMatcherHandler implements HttpHandler {
|
|||
|
||||
@Override
|
||||
public void handleRequest(HttpServerExchange exchange) throws Exception {
|
||||
log.debugv("ConstraintMatcherHandler: {0}", exchange.getRelativePath());
|
||||
SingleConstraintMatch match = matcher.getSecurityInfo(exchange.getRelativePath(), exchange.getRequestMethod().toString()).getMergedConstraint();
|
||||
if (match == null || (match.getRequiredRoles().isEmpty() && match.getEmptyRoleSemantic() == SecurityInfo.EmptyRoleSemantic.PERMIT)) {
|
||||
unsecuredHandler.handleRequest(exchange);
|
||||
|
@ -44,6 +47,7 @@ public class ConstraintMatcherHandler implements HttpHandler {
|
|||
}
|
||||
return;
|
||||
}
|
||||
log.debug("found constraint");
|
||||
exchange.getSecurityContext().setAuthenticationRequired();
|
||||
exchange.putAttachment(CONSTRAINT_KEY, match);
|
||||
securedHandler.handleRequest(exchange);
|
||||
|
|
28
proxy/proxy-server/src/main/java/org/keycloak/proxy/Main.java
Executable file
28
proxy/proxy-server/src/main/java/org/keycloak/proxy/Main.java
Executable file
|
@ -0,0 +1,28 @@
|
|||
package org.keycloak.proxy;
|
||||
|
||||
import io.undertow.Undertow;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class Main {
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
String jsonConfig = "proxy.json";
|
||||
if (args.length > 0) jsonConfig = args[0];
|
||||
File file = new File(jsonConfig);
|
||||
if (!file.exists()) {
|
||||
System.err.println("No proxy config argument and could not find default file proxy.json");
|
||||
System.exit(1);
|
||||
return;
|
||||
}
|
||||
FileInputStream fis = new FileInputStream(file);
|
||||
Undertow proxyServer = ProxyServerBuilder.build(fis);
|
||||
proxyServer.start();
|
||||
|
||||
}
|
||||
}
|
|
@ -137,6 +137,7 @@ public class ProxyServerBuilder {
|
|||
}
|
||||
|
||||
public ConstraintBuilder constraint(String pattern) {
|
||||
log.debugv("add constraint: {0}", pattern);
|
||||
return new ConstraintBuilder(pattern);
|
||||
}
|
||||
|
||||
|
|
|
@ -2,6 +2,9 @@
|
|||
"bind-address": "localhost",
|
||||
"http-port": "8080",
|
||||
"https-port": "8443",
|
||||
"keystore": "classpath:ssl.jks",
|
||||
"keystore-password": "password",
|
||||
"key-password": "password",
|
||||
"target-url": "http://localhost:8082",
|
||||
"applications": [
|
||||
{
|
||||
|
|
BIN
testsuite/proxy/src/test/resources/ssl.jks
Executable file
BIN
testsuite/proxy/src/test/resources/ssl.jks
Executable file
Binary file not shown.
Loading…
Reference in a new issue