keycloak-uncached

Merge pull request #871 from patriot1burke/master proxy

11/24/2014 10:22:44 PM

Details

diff --git a/core/src/main/java/org/keycloak/util/CertificateUtils.java b/core/src/main/java/org/keycloak/util/CertificateUtils.java
index ae18376..073ef3f 100755
--- a/core/src/main/java/org/keycloak/util/CertificateUtils.java
+++ b/core/src/main/java/org/keycloak/util/CertificateUtils.java
@@ -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();
diff --git a/distribution/pom.xml b/distribution/pom.xml
index de6a724..0ca3283 100755
--- a/distribution/pom.xml
+++ b/distribution/pom.xml
@@ -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>
diff --git a/distribution/proxy/assembly.xml b/distribution/proxy/assembly.xml
new file mode 100755
index 0000000..f5f9a80
--- /dev/null
+++ b/distribution/proxy/assembly.xml
@@ -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>
diff --git a/distribution/proxy/pom.xml b/distribution/proxy/pom.xml
new file mode 100755
index 0000000..e386059
--- /dev/null
+++ b/distribution/proxy/pom.xml
@@ -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>
diff --git a/docbook/reference/en/en-US/master.xml b/docbook/reference/en/en-US/master.xml
index c9a6f21..e6cd953 100755
--- a/docbook/reference/en/en-US/master.xml
+++ b/docbook/reference/en/en-US/master.xml
@@ -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>
diff --git a/docbook/reference/en/en-US/modules/proxy.xml b/docbook/reference/en/en-US/modules/proxy.xml
new file mode 100755
index 0000000..62848ec
--- /dev/null
+++ b/docbook/reference/en/en-US/modules/proxy.xml
@@ -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>
\ No newline at end of file
diff --git a/integration/undertow/src/main/java/org/keycloak/adapters/undertow/UndertowUserSessionManagement.java b/integration/undertow/src/main/java/org/keycloak/adapters/undertow/UndertowUserSessionManagement.java
index cc0a7c5..6165d76 100755
--- a/integration/undertow/src/main/java/org/keycloak/adapters/undertow/UndertowUserSessionManagement.java
+++ b/integration/undertow/src/main/java/org/keycloak/adapters/undertow/UndertowUserSessionManagement.java
@@ -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();
-
     }
 
 

pom.xml 2(+1 -1)

diff --git a/pom.xml b/pom.xml
index ba351f1..1bf8595 100755
--- a/pom.xml
+++ b/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>
diff --git a/proxy/launcher/pom.xml b/proxy/launcher/pom.xml
new file mode 100755
index 0000000..d70d14d
--- /dev/null
+++ b/proxy/launcher/pom.xml
@@ -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>
diff --git a/proxy/launcher/src/main/java/org/keycloak/Launcher.java b/proxy/launcher/src/main/java/org/keycloak/Launcher.java
new file mode 100755
index 0000000..56eab1e
--- /dev/null
+++ b/proxy/launcher/src/main/java/org/keycloak/Launcher.java
@@ -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);
+    }
+}

proxy/pom.xml 31(+31 -0)

diff --git a/proxy/pom.xml b/proxy/pom.xml
new file mode 100755
index 0000000..b9d77ef
--- /dev/null
+++ b/proxy/pom.xml
@@ -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>
diff --git a/proxy/proxy-server/pom.xml b/proxy/proxy-server/pom.xml
index 4b4d12a..ddc4a54 100755
--- a/proxy/proxy-server/pom.xml
+++ b/proxy/proxy-server/pom.xml
@@ -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>
diff --git a/proxy/proxy-server/src/main/java/org/keycloak/proxy/ConstraintMatcherHandler.java b/proxy/proxy-server/src/main/java/org/keycloak/proxy/ConstraintMatcherHandler.java
index 9eb49db..2fd260b 100755
--- a/proxy/proxy-server/src/main/java/org/keycloak/proxy/ConstraintMatcherHandler.java
+++ b/proxy/proxy-server/src/main/java/org/keycloak/proxy/ConstraintMatcherHandler.java
@@ -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);
diff --git a/proxy/proxy-server/src/main/java/org/keycloak/proxy/Main.java b/proxy/proxy-server/src/main/java/org/keycloak/proxy/Main.java
new file mode 100755
index 0000000..69dbbe0
--- /dev/null
+++ b/proxy/proxy-server/src/main/java/org/keycloak/proxy/Main.java
@@ -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();
+
+    }
+}
diff --git a/proxy/proxy-server/src/main/java/org/keycloak/proxy/ProxyServerBuilder.java b/proxy/proxy-server/src/main/java/org/keycloak/proxy/ProxyServerBuilder.java
index 3e03c3b..379656b 100755
--- a/proxy/proxy-server/src/main/java/org/keycloak/proxy/ProxyServerBuilder.java
+++ b/proxy/proxy-server/src/main/java/org/keycloak/proxy/ProxyServerBuilder.java
@@ -137,6 +137,7 @@ public class ProxyServerBuilder {
         }
 
         public ConstraintBuilder constraint(String pattern) {
+            log.debugv("add constraint: {0}", pattern);
             return new ConstraintBuilder(pattern);
         }
 
diff --git a/testsuite/proxy/src/test/resources/proxy-config.json b/testsuite/proxy/src/test/resources/proxy-config.json
index f26d8e3..c6f583b 100755
--- a/testsuite/proxy/src/test/resources/proxy-config.json
+++ b/testsuite/proxy/src/test/resources/proxy-config.json
@@ -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": [
         {
diff --git a/testsuite/proxy/src/test/resources/ssl.jks b/testsuite/proxy/src/test/resources/ssl.jks
new file mode 100755
index 0000000..341ff48
Binary files /dev/null and b/testsuite/proxy/src/test/resources/ssl.jks differ