keycloak-memoizeit

more jetty adapter

11/7/2014 9:34:53 PM

Details

diff --git a/distribution/jetty9-adapter-zip/assembly.xml b/distribution/jetty9-adapter-zip/assembly.xml
new file mode 100755
index 0000000..ab8c4bb
--- /dev/null
+++ b/distribution/jetty9-adapter-zip/assembly.xml
@@ -0,0 +1,33 @@
+<assembly>
+    <id>war-dist</id>
+
+    <formats>
+        <format>zip</format>
+    </formats>
+    <includeBaseDirectory>false</includeBaseDirectory>
+
+    <fileSets>
+        <fileSet>
+            <directory></directory>
+            <includes>
+                <include>keycloak.mod</include>
+            </includes>
+            <outputDirectory>modules</outputDirectory>
+        </fileSet>
+        <fileSet>
+            <directory>${project.build.directory}/modules</directory>
+            <outputDirectory></outputDirectory>
+        </fileSet>
+    </fileSets>
+    <dependencySets>
+        <dependencySet>
+            <unpack>false</unpack>
+            <useTransitiveDependencies>true</useTransitiveDependencies>
+            <useTransitiveFiltering>true</useTransitiveFiltering>
+            <includes>
+                <include>org.keycloak:keycloak-jetty9-adapter</include>
+            </includes>
+            <outputDirectory>lib/keycloak</outputDirectory>
+        </dependencySet>
+    </dependencySets>
+</assembly>
diff --git a/distribution/jetty9-adapter-zip/keycloak.mod b/distribution/jetty9-adapter-zip/keycloak.mod
new file mode 100755
index 0000000..130f4e9
--- /dev/null
+++ b/distribution/jetty9-adapter-zip/keycloak.mod
@@ -0,0 +1,11 @@
+#
+# Keycloak Jetty Adapter
+#
+
+[depend]
+server
+security
+
+[lib]
+lib/keycloak/*.jar
+
diff --git a/distribution/jetty9-adapter-zip/pom.xml b/distribution/jetty9-adapter-zip/pom.xml
new file mode 100755
index 0000000..344c5af
--- /dev/null
+++ b/distribution/jetty9-adapter-zip/pom.xml
@@ -0,0 +1,53 @@
+<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-jetty9-adapter-dist</artifactId>
+    <packaging>pom</packaging>
+    <name>Keycloak Jetty 9 Adapter Distro</name>
+    <description/>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.keycloak</groupId>
+            <artifactId>keycloak-jetty9-adapter</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/integration/jetty9/adapter/pom.xml b/integration/jetty9/adapter/pom.xml
index ba8ac3b..7550ad4 100755
--- a/integration/jetty9/adapter/pom.xml
+++ b/integration/jetty9/adapter/pom.xml
@@ -12,7 +12,7 @@
 	<artifactId>keycloak-jetty9-adapter</artifactId>
 	<name>Keycloak Jetty 9 Integration</name>
     <properties>
-        <jetty9.version>9.1.0.v20131115</jetty9.version>
+        <jetty9.version>9.2.4.v20141103</jetty9.version>
     </properties>
 	<description />
 
diff --git a/integration/jetty9/adapter/src/main/java/org/keycloak/adapters/jetty/JettyCookieTokenStore.java b/integration/jetty9/adapter/src/main/java/org/keycloak/adapters/jetty/JettyCookieTokenStore.java
index aa685b3..c0b1685 100755
--- a/integration/jetty9/adapter/src/main/java/org/keycloak/adapters/jetty/JettyCookieTokenStore.java
+++ b/integration/jetty9/adapter/src/main/java/org/keycloak/adapters/jetty/JettyCookieTokenStore.java
@@ -5,7 +5,6 @@ import org.jboss.logging.Logger;
 import org.keycloak.KeycloakPrincipal;
 import org.keycloak.KeycloakSecurityContext;
 import org.keycloak.adapters.AdapterTokenStore;
-import org.keycloak.adapters.AdapterUtils;
 import org.keycloak.adapters.CookieTokenStore;
 import org.keycloak.adapters.HttpFacade;
 import org.keycloak.adapters.KeycloakAccount;
@@ -13,8 +12,6 @@ import org.keycloak.adapters.KeycloakDeployment;
 import org.keycloak.adapters.RefreshableKeycloakSecurityContext;
 import org.keycloak.adapters.RequestAuthenticator;
 
-import java.util.Set;
-
 /**
  * Handle storage of token info in cookie. Per-request object.
  *
diff --git a/integration/jetty9/adapter/src/main/java/org/keycloak/adapters/jetty/JettyRequestAuthenticator.java b/integration/jetty9/adapter/src/main/java/org/keycloak/adapters/jetty/JettyRequestAuthenticator.java
index 64ce3a6..c4158b6 100755
--- a/integration/jetty9/adapter/src/main/java/org/keycloak/adapters/jetty/JettyRequestAuthenticator.java
+++ b/integration/jetty9/adapter/src/main/java/org/keycloak/adapters/jetty/JettyRequestAuthenticator.java
@@ -20,7 +20,6 @@ import org.keycloak.enums.TokenStore;
 
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpSession;
-import java.io.IOException;
 import java.security.Principal;
 import java.util.Set;
 
@@ -70,8 +69,9 @@ public class JettyRequestAuthenticator extends RequestAuthenticator {
                 if (MimeTypes.Type.FORM_ENCODED.is(request.getContentType()) && HttpMethod.POST.is(request.getMethod())) {
                     Request base_request = (request instanceof Request) ? (Request) request : HttpChannel
                             .getCurrentHttpChannel().getRequest();
-                    base_request.extractParameters();
-                    session.setAttribute(FormAuthenticator.__J_POST, new MultiMap<String>(base_request.getParameters()));
+                    MultiMap<String> formParameters = new MultiMap<String>();
+                    base_request.extractFormParameters(formParameters);
+                    session.setAttribute(FormAuthenticator.__J_POST, formParameters);
                 }
             }
         }
@@ -134,7 +134,7 @@ public class JettyRequestAuthenticator extends RequestAuthenticator {
                 MultiMap<String> j_post = (MultiMap<String>) session.getAttribute(FormAuthenticator.__J_POST);
                 if (j_post != null) {
                     Request base_request = HttpChannel.getCurrentHttpChannel().getRequest();
-                    base_request.setParameters(j_post);
+                    base_request.setContentParameters(j_post);
                 }
                 session.removeAttribute(FormAuthenticator.__J_URI);
                 session.removeAttribute(FormAuthenticator.__J_METHOD);
diff --git a/integration/jetty9/adapter/src/main/java/org/keycloak/adapters/jetty/JettySessionTokenStore.java b/integration/jetty9/adapter/src/main/java/org/keycloak/adapters/jetty/JettySessionTokenStore.java
index 8859e22..f7b16a3 100755
--- a/integration/jetty9/adapter/src/main/java/org/keycloak/adapters/jetty/JettySessionTokenStore.java
+++ b/integration/jetty9/adapter/src/main/java/org/keycloak/adapters/jetty/JettySessionTokenStore.java
@@ -12,7 +12,6 @@ import org.keycloak.adapters.RefreshableKeycloakSecurityContext;
 import org.keycloak.adapters.RequestAuthenticator;
 
 import javax.servlet.http.HttpSession;
-import java.util.Set;
 
 /**
  * Handle storage of token info in HTTP Session. Per-request object
diff --git a/integration/jetty9/adapter/src/main/java/org/keycloak/adapters/jetty/KeycloakJettyAuthenticator.java b/integration/jetty9/adapter/src/main/java/org/keycloak/adapters/jetty/KeycloakJettyAuthenticator.java
index 9f29340..618f431 100755
--- a/integration/jetty9/adapter/src/main/java/org/keycloak/adapters/jetty/KeycloakJettyAuthenticator.java
+++ b/integration/jetty9/adapter/src/main/java/org/keycloak/adapters/jetty/KeycloakJettyAuthenticator.java
@@ -1,20 +1,18 @@
 package org.keycloak.adapters.jetty;
 
-import org.eclipse.jetty.http.HttpMethod;
-import org.eclipse.jetty.http.MimeTypes;
-import org.eclipse.jetty.security.Authenticator;
 import org.eclipse.jetty.security.DefaultUserIdentity;
 import org.eclipse.jetty.security.ServerAuthException;
 import org.eclipse.jetty.security.UserAuthentication;
-import org.eclipse.jetty.security.authentication.FormAuthenticator;
+import org.eclipse.jetty.security.authentication.DeferredAuthentication;
+import org.eclipse.jetty.security.authentication.LoginAuthenticator;
 import org.eclipse.jetty.server.Authentication;
 import org.eclipse.jetty.server.HttpChannel;
 import org.eclipse.jetty.server.Request;
 import org.eclipse.jetty.server.UserIdentity;
 import org.eclipse.jetty.server.handler.ContextHandler;
-import org.eclipse.jetty.util.MultiMap;
 import org.jboss.logging.Logger;
 import org.keycloak.KeycloakPrincipal;
+import org.keycloak.KeycloakSecurityContext;
 import org.keycloak.adapters.AdapterConstants;
 import org.keycloak.adapters.AdapterDeploymentContext;
 import org.keycloak.adapters.AdapterTokenStore;
@@ -30,89 +28,97 @@ import org.keycloak.adapters.NodesRegistrationManagement;
 import org.keycloak.adapters.PreAuthActionsHandler;
 import org.keycloak.adapters.RefreshableKeycloakSecurityContext;
 import org.keycloak.enums.TokenStore;
+import org.keycloak.representations.adapters.config.AdapterConfig;
 
 import javax.security.auth.Subject;
 import javax.servlet.ServletContext;
 import javax.servlet.ServletRequest;
 import javax.servlet.ServletResponse;
-import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
-import javax.servlet.http.HttpSession;
 import java.io.ByteArrayInputStream;
 import java.io.FileInputStream;
 import java.io.FileNotFoundException;
 import java.io.InputStream;
-import java.security.Principal;
-import java.util.ArrayList;
 import java.util.HashSet;
-import java.util.List;
 import java.util.Set;
 
 /**
  * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
  * @version $Revision: 1 $
  */
-public class KeycloakJettyAuthenticator extends FormAuthenticator {
+public class KeycloakJettyAuthenticator extends LoginAuthenticator {
     private static final org.jboss.logging.Logger log = Logger.getLogger(KeycloakJettyAuthenticator.class);
     protected AdapterDeploymentContext deploymentContext;
     protected NodesRegistrationManagement nodesRegistrationManagement;
+    protected AdapterConfig adapterConfig;
+    protected KeycloakConfigResolver configResolver;
 
     public KeycloakJettyAuthenticator() {
         super();
     }
 
-    public KeycloakJettyAuthenticator(String login, String error, boolean dispatch) {
-        super(login, error, dispatch);
-    }
-
     @Override
     public void setConfiguration(AuthConfiguration configuration) {
-        super.setConfiguration(configuration);
+        //super.setConfiguration(configuration);
         initializeKeycloak();
     }
 
+    @Override
+    public boolean secureResponse(ServletRequest req, ServletResponse res, boolean mandatory, Authentication.User validatedUser) throws ServerAuthException
+    {
+        return true;
+    }
+
+    public AdapterConfig getAdapterConfig() {
+        return adapterConfig;
+    }
+
+    public void setAdapterConfig(AdapterConfig adapterConfig) {
+        this.adapterConfig = adapterConfig;
+    }
+
+    public KeycloakConfigResolver getConfigResolver() {
+        return configResolver;
+    }
+
+    public void setConfigResolver(KeycloakConfigResolver configResolver) {
+        this.configResolver = configResolver;
+    }
+
     @SuppressWarnings("UseSpecificCatch")
     public void initializeKeycloak() {
+        nodesRegistrationManagement = new NodesRegistrationManagement();
         String contextPath = ContextHandler.getCurrentContext().getContextPath();
         ServletContext theServletContext = ContextHandler.getCurrentContext().getContext(contextPath);
-        // Possible scenarios:
-        // 1) The deployment has a keycloak.config.resolver specified and it exists:
-        //    Outcome: adapter uses the resolver
-        // 2) The deployment has a keycloak.config.resolver and isn't valid (doesn't exists, isn't a resolver, ...) :
-        //    Outcome: adapter is left unconfigured
-        // 3) The deployment doesn't have a keycloak.config.resolver , but has a keycloak.json (or equivalent)
-        //    Outcome: adapter uses it
-        // 4) The deployment doesn't have a keycloak.config.resolver nor keycloak.json (or equivalent)
-        //    Outcome: adapter is left unconfigured
-
-        String configResolverClass = theServletContext.getInitParameter("keycloak.config.resolver");
-        if (configResolverClass != null) {
-            try {
-                KeycloakConfigResolver configResolver = (KeycloakConfigResolver) ContextHandler.getCurrentContext().getClassLoader().loadClass(configResolverClass).newInstance();
-                deploymentContext = new AdapterDeploymentContext(configResolver);
-                log.infov("Using {0} to resolve Keycloak configuration on a per-request basis.", configResolverClass);
-            } catch (Exception ex) {
-                log.infov("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());
+
+        if (configResolver == null) {
+            String configResolverClass = theServletContext.getInitParameter("keycloak.config.resolver");
+            if (configResolverClass != null) {
+                try {
+                    configResolver = (KeycloakConfigResolver) ContextHandler.getCurrentContext().getClassLoader().loadClass(configResolverClass).newInstance();
+                    log.infov("Using {0} to resolve Keycloak configuration on a per-request basis.", configResolverClass);
+                } catch (Exception ex) {
+                    log.infov("The specified resolver {0} could NOT be loaded. Keycloak is unconfigured and will deny all requests. Reason: {1}", new Object[]{configResolverClass, ex.getMessage()});
+                }
             }
+        }
+
+        if (configResolver != null) {
+            deploymentContext = new AdapterDeploymentContext(configResolver);
+        } else if (adapterConfig != null) {
+            KeycloakDeployment kd = KeycloakDeploymentBuilder.build(adapterConfig);
+            deploymentContext = new AdapterDeploymentContext(kd);
         } else {
             InputStream configInputStream = getConfigInputStream(theServletContext);
-            KeycloakDeployment kd;
             if (configInputStream == null) {
-                log.debug("No adapter configuration. Keycloak is unconfigured and will deny all requests.");
-                kd = new KeycloakDeployment();
+                deploymentContext = new AdapterDeploymentContext(new KeycloakDeployment());
+
             } else {
-                kd = KeycloakDeploymentBuilder.build(configInputStream);
-            }
-            deploymentContext = new AdapterDeploymentContext(kd);
-            log.debug("Keycloak is using a per-deployment configuration.");
-        }
+                deploymentContext = new AdapterDeploymentContext(KeycloakDeploymentBuilder.build(configInputStream));
+             }
 
+        }
         theServletContext.setAttribute(AdapterDeploymentContext.class.getName(), deploymentContext);
-        //AuthenticatedActionsValve actions = new AuthenticatedActionsValve(deploymentContext, getNext(), getContainer());
-        //setNext(actions);
-
-        nodesRegistrationManagement = new NodesRegistrationManagement();
     }
 
     private static InputStream getJSONFromServletContext(ServletContext servletContext) {
@@ -146,6 +152,8 @@ public class KeycloakJettyAuthenticator extends FormAuthenticator {
         if (log.isTraceEnabled()) {
             log.trace("*** authenticate");
         }
+        if (!mandatory)
+            return new DeferredAuthentication(this);
         Request request = HttpChannel.getCurrentHttpChannel().getRequest();
         JettyHttpFacade facade = new JettyHttpFacade(request, (HttpServletResponse)res);
         KeycloakDeployment deployment = deploymentContext.resolveDeployment(facade);
@@ -189,7 +197,7 @@ public class KeycloakJettyAuthenticator extends FormAuthenticator {
     }
 
     public static final String TOKEN_STORE_NOTE = "TOKEN_STORE_NOTE";
-    protected AdapterTokenStore getTokenStore(Request request, HttpFacade facade, KeycloakDeployment resolvedDeployment) {
+    public static AdapterTokenStore getTokenStore(Request request, HttpFacade facade, KeycloakDeployment resolvedDeployment) {
         AdapterTokenStore store = (AdapterTokenStore)request.getAttribute(TOKEN_STORE_NOTE);
         if (store != null) {
             return store;
@@ -205,24 +213,61 @@ public class KeycloakJettyAuthenticator extends FormAuthenticator {
         return store;
     }
 
-    protected Authentication register(HttpServletRequest httpServletRequest, KeycloakPrincipal<RefreshableKeycloakSecurityContext> principal) {
-        Set<String> roles = AdapterUtils.getRolesFromSecurityContext(principal.getKeycloakSecurityContext());
-        if (roles == null) {
-            roles = new HashSet<String>();
+    public static class KeycloakAuthentication extends UserAuthentication
+    {
+        public KeycloakAuthentication(String method, UserIdentity userIdentity) {
+            super(method, userIdentity);
         }
-        Request request = (Request) httpServletRequest;
-        Authentication authentication = request.getAuthentication();
-        if (!(authentication instanceof UserAuthentication)) {
-            Subject theSubject = new Subject();
-            String[] theRoles = new String[roles.size()];
-            roles.toArray(theRoles);
 
-            UserIdentity userIdentity = new DefaultUserIdentity(theSubject, principal, theRoles);
-            authentication = new UserAuthentication(getAuthMethod(), userIdentity);
+        @Override
+        public void logout() {
+            Request request = HttpChannel.getCurrentHttpChannel().getRequest();
+            logoutCurrent(request);
+        }
+
+
+
+    }
+
+    public static void logoutCurrent(Request request) {
+        AdapterDeploymentContext deploymentContext = (AdapterDeploymentContext)request.getAttribute(AdapterDeploymentContext.class.getName());
+        KeycloakSecurityContext ksc = (KeycloakSecurityContext)request.getAttribute(KeycloakSecurityContext.class.getName());
+        if (ksc != null) {
+            JettyHttpFacade facade = new JettyHttpFacade(request, null);
+            KeycloakDeployment deployment = deploymentContext.resolveDeployment(facade);
+            if (ksc instanceof RefreshableKeycloakSecurityContext) {
+                ((RefreshableKeycloakSecurityContext) ksc).logout(deployment);
+            }
+
+            AdapterTokenStore tokenStore = getTokenStore(request, facade, deployment);
+            tokenStore.logout();
+            request.removeAttribute(KeycloakSecurityContext.class.getName());
+        }
+    }
+
+
+    protected Authentication register(Request request, KeycloakPrincipal<RefreshableKeycloakSecurityContext> principal) {
+        request.setAttribute(AdapterDeploymentContext.class.getName(), deploymentContext);
+        Authentication authentication = request.getAuthentication();
+        if (!(authentication instanceof KeycloakAuthentication)) {
+            UserIdentity userIdentity = createIdentity(principal);
+            authentication = new KeycloakAuthentication(getAuthMethod(), userIdentity);
             request.setAuthentication(authentication);
         }
         return authentication;
     }
 
+    public static UserIdentity createIdentity(KeycloakPrincipal<RefreshableKeycloakSecurityContext> principal) {
+        Set<String> roles = AdapterUtils.getRolesFromSecurityContext(principal.getKeycloakSecurityContext());
+        if (roles == null) {
+            roles = new HashSet<String>();
+        }
+        Subject theSubject = new Subject();
+        String[] theRoles = new String[roles.size()];
+        roles.toArray(theRoles);
+
+        return new DefaultUserIdentity(theSubject, principal, theRoles);
+    }
+
 
 }
diff --git a/testsuite/jetty9/pom.xml b/testsuite/jetty9/pom.xml
index fd72e85..85ba650 100755
--- a/testsuite/jetty9/pom.xml
+++ b/testsuite/jetty9/pom.xml
@@ -12,7 +12,7 @@
     <artifactId>keycloak-testsuite-jetty9</artifactId>
     <name>Keycloak Jetty 9 Integration TestSuite</name>
     <properties>
-        <jetty9.version>9.1.0.v20131115</jetty9.version>
+        <jetty9.version>9.2.4.v20141103</jetty9.version>
     </properties>
     <description />
 
diff --git a/testsuite/jetty9/src/test/java/org/keycloak/testsuite/Jetty9Test.java b/testsuite/jetty9/src/test/java/org/keycloak/testsuite/Jetty9Test.java
index abb019c..115a9e4 100755
--- a/testsuite/jetty9/src/test/java/org/keycloak/testsuite/Jetty9Test.java
+++ b/testsuite/jetty9/src/test/java/org/keycloak/testsuite/Jetty9Test.java
@@ -84,6 +84,14 @@ public class Jetty9Test {
     public static class SendUsernameServlet extends HttpServlet {
         @Override
         protected void doGet(final HttpServletRequest req, final HttpServletResponse resp) throws ServletException, IOException {
+            if (req.getPathInfo().endsWith("logout")) {
+                req.logout();
+                resp.setContentType("text/plain");
+                OutputStream stream = resp.getOutputStream();
+                stream.write("logout".getBytes());
+                return;
+
+            }
             resp.setContentType("text/plain");
             OutputStream stream = resp.getOutputStream();
             Principal principal = req.getUserPrincipal();
@@ -199,6 +207,20 @@ public class Jetty9Test {
         String currentUrl = driver.getCurrentUrl();
         Assert.assertTrue(currentUrl.startsWith(LOGIN_URL));
 
+        // test servletRequest.logout()
+        loginPage.login("bburke@redhat.com", "password");
+        System.out.println("Current url: " + driver.getCurrentUrl());
+        Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8080/customer-portal/");
+        pageSource = driver.getPageSource();
+        System.out.println(pageSource);
+        Assert.assertTrue(pageSource.contains("Bill Burke"));
+        driver.navigate().to("http://localhost:8080/customer-portal/logout");
+        pageSource = driver.getPageSource();
+        Assert.assertTrue(pageSource.contains("logout"));
+        driver.navigate().to("http://localhost:8080/customer-portal");
+        currentUrl = driver.getCurrentUrl();
+        Assert.assertTrue(currentUrl.startsWith(LOGIN_URL));
+
 
     }