keycloak-uncached

Merge pull request #2296 from patriot1burke/1.8.x unsecure

2/29/2016 1:05:54 PM

Details

diff --git a/integration/jetty/jetty-core/src/main/java/org/keycloak/adapters/jetty/core/AbstractKeycloakJettyAuthenticator.java b/integration/jetty/jetty-core/src/main/java/org/keycloak/adapters/jetty/core/AbstractKeycloakJettyAuthenticator.java
index dad7570..43f5726 100755
--- a/integration/jetty/jetty-core/src/main/java/org/keycloak/adapters/jetty/core/AbstractKeycloakJettyAuthenticator.java
+++ b/integration/jetty/jetty-core/src/main/java/org/keycloak/adapters/jetty/core/AbstractKeycloakJettyAuthenticator.java
@@ -1,6 +1,8 @@
 package org.keycloak.adapters.jetty.core;
 
 import org.eclipse.jetty.security.DefaultUserIdentity;
+import org.eclipse.jetty.security.IdentityService;
+import org.eclipse.jetty.security.LoginService;
 import org.eclipse.jetty.security.ServerAuthException;
 import org.eclipse.jetty.security.UserAuthentication;
 import org.eclipse.jetty.security.authentication.DeferredAuthentication;
@@ -118,10 +120,43 @@ public abstract class AbstractKeycloakJettyAuthenticator extends LoginAuthentica
         return new DefaultUserIdentity(theSubject, principal, theRoles);
     }
 
+    private class DummyLoginService implements LoginService {
+        @Override
+        public String getName() {
+            return null;
+        }
+
+        @Override
+        public UserIdentity login(String username, Object credentials) {
+            return null;
+        }
+
+        @Override
+        public boolean validate(UserIdentity user) {
+            return false;
+        }
+
+        @Override
+        public IdentityService getIdentityService() {
+            return null;
+        }
+
+        @Override
+        public void setIdentityService(IdentityService service) {
+
+        }
+
+        @Override
+        public void logout(UserIdentity user) {
+
+        }
+    }
     @Override
     public void setConfiguration(AuthConfiguration configuration) {
         //super.setConfiguration(configuration);
         initializeKeycloak();
+        // need this so that getUserPrincipal does not throw NPE
+        _loginService = new DummyLoginService();
         String error = configuration.getInitParameter(FormAuthenticator.__FORM_ERROR_PAGE);
         setErrorPage(error);
     }
diff --git a/integration/servlet-filter/src/main/java/org/keycloak/adapters/servlet/OIDCFilterSessionStore.java b/integration/servlet-filter/src/main/java/org/keycloak/adapters/servlet/OIDCFilterSessionStore.java
index 0fa30dc..9909fd0 100755
--- a/integration/servlet-filter/src/main/java/org/keycloak/adapters/servlet/OIDCFilterSessionStore.java
+++ b/integration/servlet-filter/src/main/java/org/keycloak/adapters/servlet/OIDCFilterSessionStore.java
@@ -69,6 +69,7 @@ public class OIDCFilterSessionStore extends FilterSessionStore implements Adapte
 
     protected void cleanSession(HttpSession session) {
         session.removeAttribute(KeycloakAccount.class.getName());
+        session.removeAttribute(KeycloakSecurityContext.class.getName());
         clearSavedRequest(session);
     }
 
@@ -138,6 +139,7 @@ public class OIDCFilterSessionStore extends FilterSessionStore implements Adapte
         SerializableKeycloakAccount sAccount = new SerializableKeycloakAccount(roles, account.getPrincipal(), securityContext);
         HttpSession httpSession = request.getSession();
         httpSession.setAttribute(KeycloakAccount.class.getName(), sAccount);
+        httpSession.setAttribute(KeycloakSecurityContext.class.getName(), sAccount.getKeycloakSecurityContext());
         if (idMapper != null) idMapper.map(account.getKeycloakSecurityContext().getToken().getClientSession(),  account.getPrincipal().getName(), httpSession.getId());
         //String username = securityContext.getToken().getSubject();
         //log.fine("userSessionManagement.login: " + username);
diff --git a/integration/tomcat/tomcat-core/src/main/java/org/keycloak/adapters/tomcat/CatalinaSessionTokenStore.java b/integration/tomcat/tomcat-core/src/main/java/org/keycloak/adapters/tomcat/CatalinaSessionTokenStore.java
index 9d147fa..2b886ee 100755
--- a/integration/tomcat/tomcat-core/src/main/java/org/keycloak/adapters/tomcat/CatalinaSessionTokenStore.java
+++ b/integration/tomcat/tomcat-core/src/main/java/org/keycloak/adapters/tomcat/CatalinaSessionTokenStore.java
@@ -52,12 +52,22 @@ public class CatalinaSessionTokenStore extends CatalinaAdapterSessionStore imple
         // just in case session got serialized
         if (session.getDeployment() == null) session.setCurrentRequestInfo(deployment, this);
 
-        if (session.isActive() && !session.getDeployment().isAlwaysRefreshToken()) return;
+        if (session.isActive() && !session.getDeployment().isAlwaysRefreshToken()) {
+            request.setAttribute(KeycloakSecurityContext.class.getName(), session);
+            request.setUserPrincipal(account.getPrincipal());
+            request.setAuthType("KEYCLOAK");
+            return;
+        }
 
         // FYI: A refresh requires same scope, so same roles will be set.  Otherwise, refresh will fail and token will
         // not be updated
         boolean success = session.refreshExpiredToken(false);
-        if (success && session.isActive()) return;
+        if (success && session.isActive()) {
+            request.setAttribute(KeycloakSecurityContext.class.getName(), session);
+            request.setUserPrincipal(account.getPrincipal());
+            request.setAuthType("KEYCLOAK");
+            return;
+        }
 
         // Refresh failed, so user is already logged out from keycloak. Cleanup and expire our session
         log.fine("Cleanup and expire session " + catalinaSession.getId() + " after failed refresh");
@@ -68,6 +78,7 @@ public class CatalinaSessionTokenStore extends CatalinaAdapterSessionStore imple
     }
 
     protected void cleanSession(Session catalinaSession) {
+        catalinaSession.getSession().removeAttribute(KeycloakSecurityContext.class.getName());
         catalinaSession.getSession().removeAttribute(OidcKeycloakAccount.class.getName());
         catalinaSession.setPrincipal(null);
         catalinaSession.setAuthType(null);
diff --git a/integration/undertow/src/main/java/org/keycloak/adapters/undertow/ServletSessionTokenStore.java b/integration/undertow/src/main/java/org/keycloak/adapters/undertow/ServletSessionTokenStore.java
index 5996589..ce82584 100755
--- a/integration/undertow/src/main/java/org/keycloak/adapters/undertow/ServletSessionTokenStore.java
+++ b/integration/undertow/src/main/java/org/keycloak/adapters/undertow/ServletSessionTokenStore.java
@@ -68,7 +68,8 @@ public class ServletSessionTokenStore implements AdapterTokenStore {
             return true;
         } else {
             log.debug("Refresh failed. Account was not active. Returning null and invalidating Http session");
-            session.setAttribute(KeycloakUndertowAccount.class.getName(), null);
+            session.removeAttribute(KeycloakSecurityContext.class.getName());
+            session.removeAttribute(KeycloakUndertowAccount.class.getName());
             session.invalidate();
             return false;
         }
@@ -79,6 +80,7 @@ public class ServletSessionTokenStore implements AdapterTokenStore {
         final ServletRequestContext servletRequestContext = exchange.getAttachment(ServletRequestContext.ATTACHMENT_KEY);
         HttpSession session = getSession(true);
         session.setAttribute(KeycloakUndertowAccount.class.getName(), account);
+        session.setAttribute(KeycloakSecurityContext.class.getName(), account.getKeycloakSecurityContext());
         sessionManagement.login(servletRequestContext.getDeployment().getSessionManager());
     }
 
diff --git a/integration/undertow/src/main/java/org/keycloak/adapters/undertow/UndertowSessionTokenStore.java b/integration/undertow/src/main/java/org/keycloak/adapters/undertow/UndertowSessionTokenStore.java
index f9fa6c0..5015062 100755
--- a/integration/undertow/src/main/java/org/keycloak/adapters/undertow/UndertowSessionTokenStore.java
+++ b/integration/undertow/src/main/java/org/keycloak/adapters/undertow/UndertowSessionTokenStore.java
@@ -5,6 +5,7 @@ import io.undertow.server.HttpServerExchange;
 import io.undertow.server.session.Session;
 import io.undertow.util.Sessions;
 import org.jboss.logging.Logger;
+import org.keycloak.KeycloakSecurityContext;
 import org.keycloak.adapters.AdapterTokenStore;
 import org.keycloak.adapters.KeycloakDeployment;
 import org.keycloak.adapters.OidcKeycloakAccount;
@@ -65,6 +66,7 @@ public class UndertowSessionTokenStore implements AdapterTokenStore {
         } else {
             log.debug("Account was not active, returning false");
             session.removeAttribute(KeycloakUndertowAccount.class.getName());
+            session.removeAttribute(KeycloakSecurityContext.class.getName());
             session.invalidate(exchange);
             return false;
         }
@@ -84,6 +86,7 @@ public class UndertowSessionTokenStore implements AdapterTokenStore {
     public void saveAccountInfo(OidcKeycloakAccount account) {
         Session session = Sessions.getOrCreateSession(exchange);
         session.setAttribute(KeycloakUndertowAccount.class.getName(), account);
+        session.setAttribute(KeycloakSecurityContext.class.getName(), account.getKeycloakSecurityContext());
         sessionManagement.login(session.getSessionManager());
     }
 
diff --git a/saml/client-adapter/jetty/jetty-core/src/main/java/org/keycloak/adapters/saml/jetty/AbstractSamlAuthenticator.java b/saml/client-adapter/jetty/jetty-core/src/main/java/org/keycloak/adapters/saml/jetty/AbstractSamlAuthenticator.java
index 2df0fad..991d89b 100755
--- a/saml/client-adapter/jetty/jetty-core/src/main/java/org/keycloak/adapters/saml/jetty/AbstractSamlAuthenticator.java
+++ b/saml/client-adapter/jetty/jetty-core/src/main/java/org/keycloak/adapters/saml/jetty/AbstractSamlAuthenticator.java
@@ -1,6 +1,8 @@
 package org.keycloak.adapters.saml.jetty;
 
 import org.eclipse.jetty.security.DefaultUserIdentity;
+import org.eclipse.jetty.security.IdentityService;
+import org.eclipse.jetty.security.LoginService;
 import org.eclipse.jetty.security.ServerAuthException;
 import org.eclipse.jetty.security.UserAuthentication;
 import org.eclipse.jetty.security.authentication.DeferredAuthentication;
@@ -108,12 +110,45 @@ public abstract class AbstractSamlAuthenticator extends LoginAuthenticator {
 
     }
 
+    private class DummyLoginService implements LoginService {
+        @Override
+        public String getName() {
+            return null;
+        }
+
+        @Override
+        public UserIdentity login(String username, Object credentials) {
+            return null;
+        }
+
+        @Override
+        public boolean validate(UserIdentity user) {
+            return false;
+        }
+
+        @Override
+        public IdentityService getIdentityService() {
+            return null;
+        }
+
+        @Override
+        public void setIdentityService(IdentityService service) {
+
+        }
+
+        @Override
+        public void logout(UserIdentity user) {
+
+        }
+    }
 
 
     @Override
     public void setConfiguration(AuthConfiguration configuration) {
         //super.setConfiguration(configuration);
-        initializeKeycloak();
+        // need this so that getUserPrincipal does not throw NPE
+        _loginService = new DummyLoginService();
+            initializeKeycloak();
         String error = configuration.getInitParameter(FormAuthenticator.__FORM_ERROR_PAGE);
         setErrorPage(error);
     }
diff --git a/saml/client-adapter/tomcat/tomcat-core/src/main/java/org/keycloak/adapters/saml/AbstractSamlAuthenticatorValve.java b/saml/client-adapter/tomcat/tomcat-core/src/main/java/org/keycloak/adapters/saml/AbstractSamlAuthenticatorValve.java
index 3119ba7..2acea91 100755
--- a/saml/client-adapter/tomcat/tomcat-core/src/main/java/org/keycloak/adapters/saml/AbstractSamlAuthenticatorValve.java
+++ b/saml/client-adapter/tomcat/tomcat-core/src/main/java/org/keycloak/adapters/saml/AbstractSamlAuthenticatorValve.java
@@ -151,6 +151,12 @@ public abstract class AbstractSamlAuthenticatorValve extends FormAuthenticator i
     public void invoke(Request request, Response response) throws IOException, ServletException {
         log.fine("*********************** SAML ************");
         try {
+            CatalinaHttpFacade facade = new CatalinaHttpFacade(response, request);
+            SamlDeployment deployment = deploymentContext.resolveDeployment(facade);
+            if (deployment != null) {
+                // sets request UserPrincipal if logged in.  we do this so that the UserPrincipal is available on unsecured, unconstrainted URLs
+                getTokenStore(request, facade, deployment).isLoggedIn();
+            }
             super.invoke(request, response);
         } finally {
         }
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/adapter/AdapterTestStrategy.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/adapter/AdapterTestStrategy.java
index f93c4eb..31eb1eb 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/adapter/AdapterTestStrategy.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/adapter/AdapterTestStrategy.java
@@ -143,6 +143,12 @@ public class AdapterTestStrategy extends ExternalResource {
         String pageSource = driver.getPageSource();
         System.out.println(pageSource);
         Assert.assertTrue(pageSource.contains("parameter=hello"));
+        // test that user principal and KeycloakSecurityContext available
+        driver.navigate().to(APP_SERVER_BASE_URL + "/input-portal/insecure");
+        System.out.println("insecure: ");
+        System.out.println(driver.getPageSource());
+        Assert.assertTrue(driver.getPageSource().contains("Insecure Page"));
+        if (System.getProperty("insecure.user.principal.unsupported") == null) Assert.assertTrue(driver.getPageSource().contains("UserPrincipal"));
 
         // test logout
 
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/adapter/FilterAdapterTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/adapter/FilterAdapterTest.java
index 39c0368..cb5eac7 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/adapter/FilterAdapterTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/adapter/FilterAdapterTest.java
@@ -105,6 +105,7 @@ public class FilterAdapterTest {
 
     @Test
     public void testSavedPostRequest() throws Exception {
+        System.setProperty("insecure.user.principal.unsupported", "true");
         testStrategy.testSavedPostRequest();
     }
 
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/adapter/InputServlet.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/adapter/InputServlet.java
index d2dc090..4f4c461 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/adapter/InputServlet.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/adapter/InputServlet.java
@@ -1,5 +1,8 @@
 package org.keycloak.testsuite.adapter;
 
+import org.junit.Assert;
+import org.keycloak.KeycloakSecurityContext;
+
 import javax.servlet.ServletException;
 import javax.servlet.http.HttpServlet;
 import javax.servlet.http.HttpServletRequest;
@@ -19,6 +22,17 @@ public class InputServlet extends HttpServlet {
     protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
         String appBase = System.getProperty("app.server.base.url", "http://localhost:8081");
         String actionUrl = appBase + "/input-portal/secured/post";
+        if (req.getRequestURI().endsWith("insecure")) {
+            if (System.getProperty("insecure.user.principal.unsupported") == null) Assert.assertNotNull(req.getUserPrincipal());
+            if (System.getProperty("insecure.user.principal.unsupported") == null) Assert.assertNotNull(req.getAttribute(KeycloakSecurityContext.class.getName()));
+            resp.setContentType("text/html");
+            PrintWriter pw = resp.getWriter();
+            pw.printf("<html><head><title>%s</title></head><body>", "Insecure Page");
+            if (req.getUserPrincipal() != null) pw.printf("UserPrincipal: " + req.getUserPrincipal().getName());
+            pw.print("</body></html>");
+            pw.flush();
+            return;
+        }
 
 
         resp.setContentType("text/html");