Start improving CMS login
authorMathieu Baudier <mbaudier@argeo.org>
Thu, 26 Feb 2015 00:56:27 +0000 (00:56 +0000)
committerMathieu Baudier <mbaudier@argeo.org>
Thu, 26 Feb 2015 00:56:27 +0000 (00:56 +0000)
git-svn-id: https://svn.argeo.org/commons/trunk@7969 4cfe0d0a-d680-48aa-b62c-e0a02a3f76cc

org.argeo.cms/src/org/argeo/cms/AbstractCmsEntryPoint.java
org.argeo.cms/src/org/argeo/cms/CmsLogin.java
org.argeo.cms/src/org/argeo/cms/internal/auth/AbstractLoginModule.java
org.argeo.cms/src/org/argeo/cms/internal/kernel/KernelConstants.java
org.argeo.cms/src/org/argeo/cms/internal/kernel/NodeHttp.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 60758da887d63b66b80af07bf4317cab780b0690..cd7eae42346104197264428562d6768bf26da6a1 100644 (file)
@@ -1,7 +1,5 @@
 package org.argeo.cms;
 
-import static org.argeo.cms.internal.kernel.KernelConstants.SPRING_SECURITY_CONTEXT_KEY;
-
 import java.util.Locale;
 import java.util.ResourceBundle;
 
@@ -10,7 +8,6 @@ import javax.jcr.Repository;
 import javax.jcr.RepositoryException;
 import javax.jcr.Session;
 import javax.jcr.nodetype.NodeType;
-import javax.servlet.http.HttpSession;
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
@@ -23,7 +20,6 @@ import org.eclipse.rap.rwt.client.service.BrowserNavigationEvent;
 import org.eclipse.rap.rwt.client.service.BrowserNavigationListener;
 import org.eclipse.swt.widgets.Display;
 import org.eclipse.swt.widgets.Shell;
-import org.springframework.security.core.context.SecurityContext;
 import org.springframework.security.core.context.SecurityContextHolder;
 
 /** Manages history and navigation */
@@ -44,16 +40,17 @@ abstract class AbstractCmsEntryPoint extends AbstractEntryPoint implements
        private BrowserNavigation history;
 
        public AbstractCmsEntryPoint(Repository repository, String workspace) {
-               if (SecurityContextHolder.getContext().getAuthentication() == null) {
-                       HttpSession httpSession = RWT.getRequest().getSession();
-                       // log.debug("Session: " + httpSession.getId());
-                       SecurityContext contextFromSessionObject = (SecurityContext) httpSession
-                                       .getAttribute(SPRING_SECURITY_CONTEXT_KEY);
-                       if (contextFromSessionObject != null)
-                               SecurityContextHolder.setContext(contextFromSessionObject);
-                       else
-                               logAsAnonymous();
-               }
+               // if (SecurityContextHolder.getContext().getAuthentication() == null) {
+               // HttpSession httpSession = RWT.getRequest().getSession();
+               // // log.debug("Session: " + httpSession.getId());
+               // SecurityContext contextFromSessionObject = (SecurityContext)
+               // httpSession
+               // .getAttribute(SPRING_SECURITY_CONTEXT_KEY);
+               // if (contextFromSessionObject != null)
+               // SecurityContextHolder.setContext(contextFromSessionObject);
+               // else
+               // logAsAnonymous();
+               // }
 
                this.repository = repository;
                this.workspace = workspace;
index 0919ee9c9f7cbc6e5394a51bb274fc9506283efe..eab83ee316113f6cdce0a36126cca7edfd193d84 100644 (file)
@@ -1,18 +1,14 @@
 package org.argeo.cms;
 
-import static org.argeo.cms.internal.kernel.KernelConstants.SPRING_SECURITY_CONTEXT_KEY;
-
 import javax.security.auth.Subject;
 import javax.security.auth.login.LoginContext;
 import javax.security.auth.login.LoginException;
-import javax.servlet.http.HttpSession;
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.argeo.ArgeoException;
 import org.argeo.cms.auth.ArgeoLoginContext;
 import org.argeo.security.NodeAuthenticationToken;
-import org.eclipse.rap.rwt.RWT;
 import org.springframework.security.authentication.AuthenticationManager;
 import org.springframework.security.core.Authentication;
 import org.springframework.security.core.context.SecurityContextHolder;
@@ -42,9 +38,9 @@ public class CmsLogin {
                Authentication authentication = authenticationManager
                                .authenticate(token);
                SecurityContextHolder.getContext().setAuthentication(authentication);
-               HttpSession httpSession = RWT.getRequest().getSession();
-               httpSession.setAttribute(SPRING_SECURITY_CONTEXT_KEY,
-                               SecurityContextHolder.getContext());
+               // HttpSession httpSession = RWT.getRequest().getSession();
+               // httpSession.setAttribute(SPRING_SECURITY_CONTEXT_KEY,
+               // SecurityContextHolder.getContext());
                if (log.isDebugEnabled())
                        log.debug("Authenticated as " + authentication);
        }
index 427ec83188f2db7d70b17620dbe109513065a114..f464ebad9c37669f16c41c28c078f36b5441fe0b 100644 (file)
@@ -23,19 +23,31 @@ import javax.security.auth.callback.CallbackHandler;
 import javax.security.auth.callback.UnsupportedCallbackException;
 import javax.security.auth.login.LoginException;
 import javax.security.auth.spi.LoginModule;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpSession;
 
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
 import org.argeo.ArgeoException;
 import org.argeo.cms.internal.kernel.Activator;
+import org.eclipse.rap.rwt.RWT;
+import org.eclipse.swt.widgets.Display;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.ServiceReference;
 import org.springframework.security.authentication.AuthenticationManager;
 import org.springframework.security.core.Authentication;
+import org.springframework.security.core.context.SecurityContext;
 import org.springframework.security.core.context.SecurityContextHolder;
 
 /** Login module which caches one subject per thread. */
 public abstract class AbstractLoginModule implements LoginModule {
-       // private final static Log log = LogFactory
-       // .getLog(AbstractSpringLoginModule.class);
+       /**
+        * From org.springframework.security.context.
+        * HttpSessionContextIntegrationFilter
+        */
+       private final static String SPRING_SECURITY_CONTEXT_KEY = "SPRING_SECURITY_CONTEXT";
+
+       private final static Log log = LogFactory.getLog(AbstractLoginModule.class);
        private CallbackHandler callbackHandler;
        private Subject subject;
 
@@ -62,9 +74,24 @@ public abstract class AbstractLoginModule implements LoginModule {
        @Override
        public boolean login() throws LoginException {
                try {
-                       // thread already logged in
                        Authentication currentAuth = SecurityContextHolder.getContext()
                                        .getAuthentication();
+
+                       if (currentAuth == null && Display.getCurrent() != null) {
+                               // try to load authentication from session
+                               HttpServletRequest httpRequest = RWT.getRequest();
+                               HttpSession httpSession = httpRequest.getSession();
+                               // log.debug(httpSession.getId());
+                               Object contextFromSessionObject = httpSession
+                                               .getAttribute(SPRING_SECURITY_CONTEXT_KEY);
+                               if (contextFromSessionObject != null) {
+                                       currentAuth = (Authentication) contextFromSessionObject;
+                                       SecurityContextHolder.getContext().setAuthentication(
+                                                       currentAuth);
+                               }
+                       }
+
+                       // thread already logged in
                        if (currentAuth != null) {
                                if (subject.getPrincipals(Authentication.class).size() == 0) {
                                        // throw new LoginException(
@@ -85,8 +112,19 @@ public abstract class AbstractLoginModule implements LoginModule {
 
                        authentication = processLogin(callbackHandler);
                        if (authentication != null) {
-                               SecurityContextHolder.getContext().setAuthentication(
-                                               authentication);
+                               //
+                               // SET THE AUTHENTICATION
+                               //
+                               SecurityContext securityContext = SecurityContextHolder
+                                               .getContext();
+                               securityContext.setAuthentication(authentication);
+                               if (Display.getCurrent() != null) {
+                                       HttpServletRequest httpRequest = RWT.getRequest();
+                                       HttpSession httpSession = httpRequest.getSession();
+                                       if (httpSession.getAttribute(SPRING_SECURITY_CONTEXT_KEY) == null)
+                                               httpSession.setAttribute(SPRING_SECURITY_CONTEXT_KEY,
+                                                               authentication);
+                               }
                                return true;
                        } else {
                                throw new LoginException("No authentication returned");
@@ -109,6 +147,12 @@ public abstract class AbstractLoginModule implements LoginModule {
        @Override
        public boolean logout() throws LoginException {
                SecurityContextHolder.getContext().setAuthentication(null);
+               if (Display.getCurrent() != null) {
+                       HttpServletRequest httpRequest = RWT.getRequest();
+                       HttpSession httpSession = httpRequest.getSession();
+                       if (httpSession.getAttribute(SPRING_SECURITY_CONTEXT_KEY) != null)
+                               httpSession.setAttribute(SPRING_SECURITY_CONTEXT_KEY, null);
+               }
                return true;
        }
 
@@ -139,12 +183,6 @@ public abstract class AbstractLoginModule implements LoginModule {
                return bc.getService(authenticationManager);
        }
 
-       // protected UserAdmin getUserAdmin(BundleContextCallback
-       // bundleContextCallback) {
-       // BundleContext bc = bundleContextCallback.getBundleContext();
-       // return bc.getService(bc.getServiceReference(UserAdmin.class));
-       // }
-
        protected Subject getSubject() {
                return subject;
        }
index b3c0c519661c49ee0f6561eda12691ad9a68444a..6d73e118860c0fe8564dd525d42da63ab0463bdf 100644 (file)
@@ -1,9 +1,6 @@
 package org.argeo.cms.internal.kernel;
 
 public interface KernelConstants {
-       // (internal) API
-       public final static String SPRING_SECURITY_CONTEXT_KEY = "SPRING_SECURITY_CONTEXT";
-
        // Node
        final static String REPO_HOME = "argeo.node.repo.home";
        final static String REPO_TYPE = "argeo.node.repo.type";
index 28c569bfdf6ff4908f9a28e10eeb736fe0581a8b..7afab675fcf4012726c44f2b0da6ed7f708509d0 100644 (file)
@@ -30,7 +30,6 @@ import org.osgi.service.http.NamespaceException;
 import org.springframework.security.authentication.AuthenticationManager;
 import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
 import org.springframework.security.core.Authentication;
-import org.springframework.security.core.context.SecurityContext;
 import org.springframework.security.core.context.SecurityContextHolder;
 
 /**
@@ -137,11 +136,11 @@ class NodeHttp implements KernelConstants, ArgeoJcrConstants {
                httpService.registerServlet(path, (Servlet) remotingServlet, ip, null);
        }
 
-       private Boolean isSessionAuthenticated(HttpSession httpSession) {
-               SecurityContext contextFromSession = (SecurityContext) httpSession
-                               .getAttribute(SPRING_SECURITY_CONTEXT_KEY);
-               return contextFromSession != null;
-       }
+//     private Boolean isSessionAuthenticated(HttpSession httpSession) {
+//             SecurityContext contextFromSession = (SecurityContext) httpSession
+//                             .getAttribute(SPRING_SECURITY_CONTEXT_KEY);
+//             return contextFromSession != null;
+//     }
 
        private void requestBasicAuth(HttpSession httpSession,
                        HttpServletResponse response) {
@@ -277,10 +276,10 @@ class NodeHttp implements KernelConstants, ArgeoJcrConstants {
                                FilterChain filterChain) throws IOException, ServletException {
 
                        // Authenticate from session
-                       if (isSessionAuthenticated(httpSession)) {
-                               filterChain.doFilter(request, response);
-                               return;
-                       }
+//                     if (isSessionAuthenticated(httpSession)) {
+//                             filterChain.doFilter(request, response);
+//                             return;
+//                     }
 
                        KernelUtils.anonymousLogin(authenticationManager);
                        filterChain.doFilter(request, response);
@@ -307,9 +306,9 @@ class NodeHttp implements KernelConstants, ArgeoJcrConstants {
                                UsernamePasswordAuthenticationToken token = basicAuth(basicAuth);
                                Authentication auth = authenticationManager.authenticate(token);
                                SecurityContextHolder.getContext().setAuthentication(auth);
-                               httpSession.setAttribute(SPRING_SECURITY_CONTEXT_KEY,
-                                               SecurityContextHolder.getContext());
-                               httpSession.setAttribute(ATTR_AUTH, Boolean.FALSE);
+//                             httpSession.setAttribute(SPRING_SECURITY_CONTEXT_KEY,
+//                                             SecurityContextHolder.getContext());
+//                             httpSession.setAttribute(ATTR_AUTH, Boolean.FALSE);
                                filterChain.doFilter(request, response);
                                return;
                        }
index 98311560ac10e7bf21a4f6374456f31ac9f5366c..622ce1c31ead869dbc97fe62ad0165af1fe9488a 100644 (file)
@@ -1,13 +1,23 @@
 package org.argeo.cms.util;
 
-import static org.argeo.cms.internal.kernel.KernelConstants.SPRING_SECURITY_CONTEXT_KEY;
-
-import javax.servlet.http.HttpSession;
-
+import java.io.IOException;
+
+import javax.security.auth.Subject;
+import javax.security.auth.callback.Callback;
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.auth.callback.NameCallback;
+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 org.argeo.ArgeoException;
 import org.argeo.cms.CmsLogin;
 import org.argeo.cms.CmsMsg;
 import org.argeo.cms.CmsSession;
 import org.argeo.cms.CmsStyles;
+import org.argeo.cms.KernelHeader;
+import org.argeo.cms.auth.ArgeoLoginContext;
 import org.eclipse.rap.rwt.RWT;
 import org.eclipse.swt.SWT;
 import org.eclipse.swt.events.MouseAdapter;
@@ -25,11 +35,12 @@ import org.eclipse.swt.widgets.Text;
 import org.springframework.security.core.context.SecurityContextHolder;
 
 /** The site-related user menu */
-public class UserMenu extends Shell implements CmsStyles {
+public class UserMenu extends Shell implements CmsStyles, CallbackHandler {
        private static final long serialVersionUID = -5788157651532106301L;
 
        private CmsLogin cmsLogin;
-       private String username = null;
+       // private String username = null;
+       private Text username, password;
 
        public UserMenu(CmsLogin cmsLogin, Control source) {
                super(source.getDisplay(), SWT.NO_TRIM | SWT.BORDER | SWT.ON_TOP);
@@ -37,8 +48,8 @@ public class UserMenu extends Shell implements CmsStyles {
 
                setData(RWT.CUSTOM_VARIANT, CMS_USER_MENU);
 
-               username = SecurityContextHolder.getContext().getAuthentication()
-                               .getName();
+               String username = SecurityContextHolder.getContext()
+                               .getAuthentication().getName();
                if (username.equals("anonymous")) {
                        username = null;
                        anonymousUi();
@@ -69,6 +80,9 @@ public class UserMenu extends Shell implements CmsStyles {
        protected void userUi() {
                setLayout(new GridLayout());
 
+               String username = SecurityContextHolder.getContext()
+                               .getAuthentication().getName();
+
                Label l = new Label(this, SWT.NONE);
                l.setData(RWT.CUSTOM_VARIANT, CMS_USER_MENU_ITEM);
                l.setData(RWT.MARKUP_ENABLED, true);
@@ -88,9 +102,19 @@ public class UserMenu extends Shell implements CmsStyles {
                        private static final long serialVersionUID = 6444395812777413116L;
 
                        public void mouseDown(MouseEvent e) {
-                               SecurityContextHolder.getContext().setAuthentication(null);
-                               HttpSession httpSession = RWT.getRequest().getSession();
-                               httpSession.removeAttribute(SPRING_SECURITY_CONTEXT_KEY);
+                               Subject subject = new Subject();
+                               try {
+                                       new ArgeoLoginContext(KernelHeader.LOGIN_CONTEXT_USER,
+                                                       subject).logout();
+                                       new ArgeoLoginContext(KernelHeader.LOGIN_CONTEXT_ANONYMOUS,
+                                                       subject).login();
+                               } catch (LoginException e1) {
+                                       throw new ArgeoException("Cannot authenticate anonymous",
+                                                       e1);
+                               }
+                               // SecurityContextHolder.getContext().setAuthentication(null);
+                               // HttpSession httpSession = RWT.getRequest().getSession();
+                               // httpSession.removeAttribute(SPRING_SECURITY_CONTEXT_KEY);
                                close();
                                dispose();
                                cmsSession.authChange();
@@ -104,14 +128,14 @@ public class UserMenu extends Shell implements CmsStyles {
                setLayout(new GridLayout(2, false));
 
                new Label(this, SWT.NONE).setText(CmsMsg.username.lead());
-               final Text username = new Text(this, SWT.BORDER);
+               username = new Text(this, SWT.BORDER);
                username.setData(RWT.CUSTOM_VARIANT, CMS_LOGIN_DIALOG_USERNAME);
                GridData gd = CmsUtils.fillWidth();
                gd.widthHint = textWidth;
                username.setLayoutData(gd);
 
                new Label(this, SWT.NONE).setText(CmsMsg.password.lead());
-               final Text password = new Text(this, SWT.BORDER | SWT.PASSWORD);
+               password = new Text(this, SWT.BORDER | SWT.PASSWORD);
                password.setData(RWT.CUSTOM_VARIANT, CMS_LOGIN_DIALOG_PASSWORD);
                gd = CmsUtils.fillWidth();
                gd.widthHint = textWidth;
@@ -123,21 +147,46 @@ public class UserMenu extends Shell implements CmsStyles {
 
                        public void keyTraversed(TraverseEvent e) {
                                if (e.detail == SWT.TRAVERSE_RETURN)
-                                       login(username.getText(), password.getTextChars());
+                                       login();
                        }
                };
                username.addTraverseListener(tl);
                password.addTraverseListener(tl);
        }
 
-       protected void login(String username, char[] password) {
+       protected void login() {
                CmsSession cmsSession = (CmsSession) getDisplay().getData(
                                CmsSession.KEY);
-               cmsLogin.logInWithPassword(username, password);
+
+               Subject subject = new Subject();
+               try {
+                       new ArgeoLoginContext(KernelHeader.LOGIN_CONTEXT_ANONYMOUS, subject)
+                                       .logout();
+                       LoginContext loginContext = new ArgeoLoginContext(
+                                       KernelHeader.LOGIN_CONTEXT_USER, subject, this);
+                       loginContext.login();
+               } catch (LoginException e1) {
+                       throw new ArgeoException("Cannot authenticate anonymous", e1);
+               }
+
+               // cmsLogin.logInWithPassword(username, password);
                close();
                dispose();
                // refreshUi(source.getParent());
                cmsSession.authChange();
        }
 
+       @Override
+       public void handle(Callback[] callbacks) throws IOException,
+                       UnsupportedCallbackException {
+               ((NameCallback) callbacks[0]).setName(username.getText());
+               ((PasswordCallback) callbacks[1]).setPassword(password.getTextChars());
+               // while (!isDisposed())
+               // try {
+               // Thread.sleep(500);
+               // } catch (InterruptedException e) {
+               // // silent
+               // }
+       }
+
 }
index 67e76ceae92c3be835fe54743da102b0ce605064..b79d60d261e469abde35663237dcf4cf5b3a7b47 100644 (file)
@@ -78,13 +78,13 @@ public class SecureEntryPoint implements EntryPoint {
                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);
+//             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();
@@ -106,9 +106,9 @@ public class SecureEntryPoint implements EntryPoint {
                                        throw new ArgeoException("Login succeeded but no auth");// fatal
 
                                // add security context to session
-                               if (httpSession.getAttribute(SPRING_SECURITY_CONTEXT_KEY) == null)
-                                       httpSession.setAttribute(SPRING_SECURITY_CONTEXT_KEY,
-                                                       SecurityContextHolder.getContext());
+//                             if (httpSession.getAttribute(SPRING_SECURITY_CONTEXT_KEY) == null)
+//                                     httpSession.setAttribute(SPRING_SECURITY_CONTEXT_KEY,
+//                                                     SecurityContextHolder.getContext());
 
                                // add thread locale to RWT session
                                if (log.isTraceEnabled())
@@ -222,9 +222,9 @@ public class SecureEntryPoint implements EntryPoint {
                        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(SPRING_SECURITY_CONTEXT_KEY, null);
                        RWT.getRequest().getSession().setMaxInactiveInterval(1);
                        log.info("Logged out " + (username != null ? username : "")
                                        + " (THREAD=" + Thread.currentThread().getId() + ")");