keycloak-memoizeit
Changes
distribution/jetty9-adapter-zip/assembly.xml 33(+33 -0)
distribution/jetty9-adapter-zip/keycloak.mod 11(+11 -0)
distribution/jetty9-adapter-zip/pom.xml 53(+53 -0)
integration/jetty9/adapter/pom.xml 2(+1 -1)
integration/jetty9/adapter/src/main/java/org/keycloak/adapters/jetty/JettyCookieTokenStore.java 3(+0 -3)
integration/jetty9/adapter/src/main/java/org/keycloak/adapters/jetty/JettyRequestAuthenticator.java 8(+4 -4)
integration/jetty9/adapter/src/main/java/org/keycloak/adapters/jetty/JettySessionTokenStore.java 1(+0 -1)
integration/jetty9/adapter/src/main/java/org/keycloak/adapters/jetty/KeycloakJettyAuthenticator.java 165(+105 -60)
testsuite/jetty9/pom.xml 2(+1 -1)
Details
distribution/jetty9-adapter-zip/assembly.xml 33(+33 -0)
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>
distribution/jetty9-adapter-zip/keycloak.mod 11(+11 -0)
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
+
distribution/jetty9-adapter-zip/pom.xml 53(+53 -0)
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>
integration/jetty9/adapter/pom.xml 2(+1 -1)
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);
+ }
+
}
testsuite/jetty9/pom.xml 2(+1 -1)
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));
+
}