Session authentication working
authorMathieu Baudier <mbaudier@argeo.org>
Tue, 15 Sep 2015 20:39:29 +0000 (20:39 +0000)
committerMathieu Baudier <mbaudier@argeo.org>
Tue, 15 Sep 2015 20:39:29 +0000 (20:39 +0000)
git-svn-id: https://svn.argeo.org/commons/trunk@8404 4cfe0d0a-d680-48aa-b62c-e0a02a3f76cc

org.argeo.cms/src/org/argeo/cms/AbstractCmsEntryPoint.java
org.argeo.cms/src/org/argeo/cms/KernelHeader.java
org.argeo.cms/src/org/argeo/cms/util/UserMenu.java
org.argeo.security.ui.rap/src/org/argeo/security/ui/rap/SecureEntryPoint.java

index 951e177b2473f0d5b81b03b1e2532ed2837a2b85..6e30d8e31d7b16b3b9cf4938faf954e0721839b5 100644 (file)
@@ -1,5 +1,6 @@
 package org.argeo.cms;
 
+import java.security.AccessControlContext;
 import java.security.PrivilegedAction;
 import java.util.HashMap;
 import java.util.Locale;
@@ -14,6 +15,8 @@ import javax.jcr.Session;
 import javax.jcr.nodetype.NodeType;
 import javax.security.auth.Subject;
 import javax.security.auth.login.LoginException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpSession;
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
@@ -38,7 +41,7 @@ public abstract class AbstractCmsEntryPoint extends AbstractEntryPoint
                implements CmsSession {
        private final Log log = LogFactory.getLog(AbstractCmsEntryPoint.class);
 
-       private final Subject subject = new Subject();
+       private final Subject subject;
 
        private final Repository repository;
        private final String workspace;
@@ -63,6 +66,16 @@ public abstract class AbstractCmsEntryPoint extends AbstractEntryPoint
                this.defaultPath = defaultPath;
                this.factoryProperties = new HashMap<String, String>(factoryProperties);
 
+               // load context from session
+               HttpServletRequest httpRequest = RWT.getRequest();
+               final HttpSession httpSession = httpRequest.getSession();
+               AccessControlContext acc = (AccessControlContext) httpSession
+                               .getAttribute(KernelHeader.ACCESS_CONTROL_CONTEXT);
+               if (acc != null)
+                       subject = Subject.getSubject(acc);
+               else
+                       subject = new Subject();
+
                // Initial login
                try {
                        new ArgeoLoginContext(KernelHeader.LOGIN_CONTEXT_USER, subject)
index 8f817df791c73514c3ba0474bbeebad13c84113a..2e4049192790da63e0bf06fe1e9d7acc4b5fa768 100644 (file)
@@ -10,6 +10,9 @@ public interface KernelHeader {
        final static String LOGIN_CONTEXT_SYSTEM = "SYSTEM";
        final static String LOGIN_CONTEXT_SINGLE_USER = "SINGLE_USER";
 
+       // HTTP
+       final static String ACCESS_CONTROL_CONTEXT = "org.argeo.node.accessControlContext";
+
        // RESERVED ROLES
        public final static String ROLE_KERNEL = "OU=node";
        public final static String ROLES_BASEDN = "ou=roles,ou=node";
index 1c35600012d9c47e33d031e376bb1d98d627310f..3fef6792b610a4c48a0f66fd518ba2c73fbd6454 100644 (file)
@@ -1,6 +1,12 @@
 package org.argeo.cms.util;
 
+import static org.argeo.cms.KernelHeader.ACCESS_CONTROL_CONTEXT;
+import static org.argeo.cms.KernelHeader.LOGIN_CONTEXT_ANONYMOUS;
+import static org.argeo.cms.KernelHeader.LOGIN_CONTEXT_USER;
+
 import java.io.IOException;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
 
 import javax.security.auth.Subject;
 import javax.security.auth.callback.Callback;
@@ -10,6 +16,8 @@ import javax.security.auth.callback.PasswordCallback;
 import javax.security.auth.callback.UnsupportedCallbackException;
 import javax.security.auth.login.LoginContext;
 import javax.security.auth.login.LoginException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpSession;
 
 import org.argeo.cms.CmsException;
 import org.argeo.cms.CmsMsg;
@@ -167,15 +175,25 @@ public class UserMenu extends Shell implements CmsStyles, CallbackHandler {
                        //
                        // LOGIN
                        //
-                       new ArgeoLoginContext(KernelHeader.LOGIN_CONTEXT_ANONYMOUS, subject)
-                                       .logout();
+                       new ArgeoLoginContext(LOGIN_CONTEXT_ANONYMOUS, subject).logout();
                        LoginContext loginContext = new ArgeoLoginContext(
-                                       KernelHeader.LOGIN_CONTEXT_USER, subject, this);
+                                       LOGIN_CONTEXT_USER, subject, this);
                        loginContext.login();
+
+                       // save context in session
+                       final HttpSession httpSession = RWT.getRequest().getSession();
+                       Subject.doAs(subject, new PrivilegedAction<Void>() {
+
+                               @Override
+                               public Void run() {
+                                       httpSession.setAttribute(ACCESS_CONTROL_CONTEXT,
+                                                       AccessController.getContext());
+                                       return null;
+                               }
+                       });
                } catch (LoginException e1) {
                        try {
-                               new ArgeoLoginContext(KernelHeader.LOGIN_CONTEXT_ANONYMOUS,
-                                               subject).login();
+                               new ArgeoLoginContext(LOGIN_CONTEXT_ANONYMOUS, subject).login();
                        } catch (LoginException e) {
                                throw new CmsException("Cannot authenticate anonymous", e1);
                        }
@@ -194,10 +212,12 @@ public class UserMenu extends Shell implements CmsStyles, CallbackHandler {
                        //
                        // LOGOUT
                        //
-                       new ArgeoLoginContext(KernelHeader.LOGIN_CONTEXT_USER, subject)
-                                       .logout();
-                       new ArgeoLoginContext(KernelHeader.LOGIN_CONTEXT_ANONYMOUS, subject)
-                                       .login();
+                       new ArgeoLoginContext(LOGIN_CONTEXT_USER, subject).logout();
+                       new ArgeoLoginContext(LOGIN_CONTEXT_ANONYMOUS, subject).login();
+
+                       HttpServletRequest httpRequest = RWT.getRequest();
+                       HttpSession httpSession = httpRequest.getSession();
+                       httpSession.setAttribute(ACCESS_CONTROL_CONTEXT, null);
                } catch (LoginException e1) {
                        throw new CmsException("Cannot authenticate anonymous", e1);
                }
index fb885377fed8e64e762fe6b24247eeda4176e265..48d33d2d4b68bb30efc663410b72e100e5b716d3 100644 (file)
  */
 package org.argeo.security.ui.rap;
 
+import static org.argeo.cms.KernelHeader.ACCESS_CONTROL_CONTEXT;
+
+import java.security.AccessControlContext;
+import java.security.AccessController;
 import java.security.PrivilegedAction;
 
 import javax.security.auth.Subject;
@@ -23,6 +27,8 @@ import javax.security.auth.login.CredentialNotFoundException;
 import javax.security.auth.login.LoginContext;
 import javax.security.auth.login.LoginException;
 import javax.security.auth.x500.X500Principal;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpSession;
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
@@ -47,12 +53,6 @@ import org.springframework.security.authentication.BadCredentialsException;
 public class SecureEntryPoint implements EntryPoint {
        private final static Log log = LogFactory.getLog(SecureEntryPoint.class);
 
-       /**
-        * From org.springframework.security.context.
-        * HttpSessionContextIntegrationFilter
-        */
-       protected static final String SPRING_SECURITY_CONTEXT_KEY = "SPRING_SECURITY_CONTEXT";
-
        /**
         * How many seconds to wait before invalidating the session if the user has
         * not yet logged in.
@@ -73,63 +73,60 @@ public class SecureEntryPoint implements EntryPoint {
                // around too long
                RWT.getRequest().getSession().setMaxInactiveInterval(loginTimeout);
 
-               // Try to load security context thanks to the session processing filter
-               // HttpServletRequest httpRequest = RWT.getRequest();
-               // HttpSession httpSession = httpRequest.getSession();
-               // Object contextFromSessionObject = httpSession
-               // .getAttribute(SPRING_SECURITY_CONTEXT_KEY);
-               // if (contextFromSessionObject != null)
-               // SecurityContextHolder
-               // .setContext((SecurityContext) contextFromSessionObject);
-
                final Display display = PlatformUI.createDisplay();
-               Subject subject = new Subject();
 
-               final LoginContext loginContext;
-               try {
-                       CallbackHandler callbackHandler = new DefaultLoginDialog(
-                                       display.getActiveShell());
-                       loginContext = new ArgeoLoginContext(
-                                       KernelHeader.LOGIN_CONTEXT_USER, subject, callbackHandler);
-               } catch (LoginException e1) {
-                       throw new ArgeoException("Cannot initialize login context", e1);
-               }
+               // load context from session
+               HttpServletRequest httpRequest = RWT.getRequest();
+               final HttpSession httpSession = httpRequest.getSession();
+               AccessControlContext acc = (AccessControlContext) httpSession
+                               .getAttribute(KernelHeader.ACCESS_CONTROL_CONTEXT);
+
+               final Subject subject;
+               if (acc != null) {
+                       subject = Subject.getSubject(acc);
+               } else {
+                       subject = new Subject();
 
-               tryLogin: while (subject.getPrincipals(X500Principal.class).size() == 0) {
+                       final LoginContext loginContext;
                        try {
-                               loginContext.login();
-                               if (subject.getPrincipals(X500Principal.class).size() == 0)
-                                       throw new ArgeoException("Login succeeded but no auth");// fatal
+                               CallbackHandler callbackHandler = new DefaultLoginDialog(
+                                               display.getActiveShell());
+                               loginContext = new ArgeoLoginContext(
+                                               KernelHeader.LOGIN_CONTEXT_USER, subject,
+                                               callbackHandler);
+                       } catch (LoginException e1) {
+                               throw new ArgeoException("Cannot initialize login context", e1);
+                       }
 
-                               // add security context to session
-                               // if (httpSession.getAttribute(SPRING_SECURITY_CONTEXT_KEY) ==
-                               // null)
-                               // httpSession.setAttribute(SPRING_SECURITY_CONTEXT_KEY,
-                               // SecurityContextHolder.getContext());
+                       tryLogin: while (subject.getPrincipals(X500Principal.class).size() == 0) {
+                               try {
+                                       loginContext.login();
+                                       if (subject.getPrincipals(X500Principal.class).size() == 0)
+                                               throw new ArgeoException("Login succeeded but no auth");// fatal
 
-                               // add thread locale to RWT session
-                               if (log.isTraceEnabled())
-                                       log.trace("Locale " + LocaleUtils.threadLocale.get());
-                               RWT.setLocale(LocaleUtils.threadLocale.get());
-
-                               // once the user is logged in, longer session timeout
-                               RWT.getRequest().getSession()
-                                               .setMaxInactiveInterval(sessionTimeout);
-
-                               if (log.isDebugEnabled())
-                                       log.debug("Authenticated " + subject);
-                       } catch (LoginException e) {
-                               BadCredentialsException bce = wasCausedByBadCredentials(e);
-                               if (bce != null) {
-                                       MessageDialog.openInformation(display.getActiveShell(),
-                                                       "Bad Credentials", bce.getMessage());
-                                       // retry login
-                                       continue tryLogin;
+                                       // add thread locale to RWT session
+                                       if (log.isTraceEnabled())
+                                               log.trace("Locale " + LocaleUtils.threadLocale.get());
+                                       RWT.setLocale(LocaleUtils.threadLocale.get());
+
+                                       // once the user is logged in, longer session timeout
+                                       RWT.getRequest().getSession()
+                                                       .setMaxInactiveInterval(sessionTimeout);
+
+                                       if (log.isDebugEnabled())
+                                               log.debug("Authenticated " + subject);
+                               } catch (LoginException e) {
+                                       BadCredentialsException bce = wasCausedByBadCredentials(e);
+                                       if (bce != null) {
+                                               MessageDialog.openInformation(display.getActiveShell(),
+                                                               "Bad Credentials", bce.getMessage());
+                                               // retry login
+                                               continue tryLogin;
+                                       }
+                                       return processLoginDeath(display, e);
                                }
-                               return processLoginDeath(display, e);
                        }
                }
-
                final String username = subject.getPrincipals(X500Principal.class)
                                .iterator().next().getName();
                // Logout callback when the display is disposed
@@ -138,6 +135,8 @@ public class SecureEntryPoint implements EntryPoint {
                                if (log.isTraceEnabled())
                                        log.trace("Display disposed");
                                try {
+                                       LoginContext loginContext = new ArgeoLoginContext(
+                                                       KernelHeader.LOGIN_CONTEXT_USER, subject);
                                        loginContext.logout();
                                } catch (LoginException e) {
                                        log.error("Error when logging out", e);
@@ -152,6 +151,11 @@ public class SecureEntryPoint implements EntryPoint {
                try {
                        returnCode = Subject.doAs(subject, new PrivilegedAction<Integer>() {
                                public Integer run() {
+                                       // add security context to session
+                                       httpSession.setAttribute(ACCESS_CONTROL_CONTEXT,
+                                                       AccessController.getContext());
+
+                                       // start workbench
                                        RapWorkbenchAdvisor workbenchAdvisor = createRapWorkbenchAdvisor(username);
                                        int result = PlatformUI.createAndRunWorkbench(display,
                                                        workbenchAdvisor);
@@ -159,7 +163,7 @@ public class SecureEntryPoint implements EntryPoint {
                                }
                        });
                        // Explicit exit from workbench
-                       fullLogout(loginContext, username);
+                       fullLogout(subject, username);
                } finally {
                        display.dispose();
                }
@@ -214,14 +218,14 @@ public class SecureEntryPoint implements EntryPoint {
                        return null;
        }
 
-       private void fullLogout(LoginContext loginContext, String username) {
+       private void fullLogout(Subject subject, String username) {
                try {
+                       LoginContext loginContext = new ArgeoLoginContext(
+                                       KernelHeader.LOGIN_CONTEXT_USER, subject);
                        loginContext.logout();
-                       // SecurityContextHolder.clearContext();
-
-                       // HttpServletRequest httpRequest = RWT.getRequest();
-                       // HttpSession httpSession = httpRequest.getSession();
-                       // httpSession.setAttribute(SPRING_SECURITY_CONTEXT_KEY, null);
+                       HttpServletRequest httpRequest = RWT.getRequest();
+                       HttpSession httpSession = httpRequest.getSession();
+                       httpSession.setAttribute(ACCESS_CONTROL_CONTEXT, null);
                        RWT.getRequest().getSession().setMaxInactiveInterval(1);
                        log.info("Logged out " + (username != null ? username : "")
                                        + " (THREAD=" + Thread.currentThread().getId() + ")");