]> git.argeo.org Git - lgpl/argeo-commons.git/blobdiff - org.argeo.security.ui.rap/src/org/argeo/security/ui/rap/SecureEntryPoint.java
Improve and simplify OSGi Boot
[lgpl/argeo-commons.git] / org.argeo.security.ui.rap / src / org / argeo / security / ui / rap / SecureEntryPoint.java
index 65657dc66204a4642d890e04dd6939aa3dd75a64..a681527f773e67663c0150576d67324a267a6c09 100644 (file)
  */
 package org.argeo.security.ui.rap;
 
+import java.security.AccessControlContext;
+import java.security.AccessController;
 import java.security.PrivilegedAction;
 
 import javax.security.auth.Subject;
+import javax.security.auth.login.CredentialNotFoundException;
+import javax.security.auth.login.FailedLoginException;
 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;
-import org.argeo.ArgeoException;
-import org.argeo.cms.KernelHeader;
-import org.argeo.eclipse.ui.workbench.ErrorFeedback;
-import org.argeo.security.login.LoginCanceledException;
-import org.argeo.security.ui.dialogs.DefaultLoginDialog;
-import org.argeo.util.LocaleUtils;
+import org.argeo.cms.CmsException;
+import org.argeo.cms.auth.AuthConstants;
+import org.argeo.cms.auth.ThreadDeathLoginException;
+import org.argeo.cms.widgets.auth.DefaultLoginDialog;
+import org.argeo.eclipse.ui.dialogs.ErrorFeedback;
 import org.eclipse.jface.dialogs.MessageDialog;
 import org.eclipse.rap.rwt.RWT;
 import org.eclipse.rap.rwt.application.EntryPoint;
 import org.eclipse.swt.widgets.Display;
 import org.eclipse.ui.PlatformUI;
-import org.springframework.security.authentication.BadCredentialsException;
-import org.springframework.security.core.Authentication;
-import org.springframework.security.core.context.SecurityContext;
-import org.springframework.security.core.context.SecurityContextHolder;
 
 /**
  * RAP entry point with login capabilities. Once the user has been
  * authenticated, the workbench is run as a privileged action by the related
  * subject.
  */
+@Deprecated
 public class SecureEntryPoint implements EntryPoint {
+       final static String ACCESS_CONTROL_CONTEXT = "org.argeo.node.accessControlContext";
        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.
@@ -75,79 +71,77 @@ 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);
-
-               // if (log.isDebugEnabled())
-               // log.debug("THREAD=" + Thread.currentThread().getId()
-               // + ", sessionStore=" + RWT.getSessionStore().getId()
-               // + ", remote user=" + httpRequest.getRemoteUser());
-
-               // create display
                final Display display = PlatformUI.createDisplay();
-               Subject subject = new Subject();
 
-               // log in
-               Thread.currentThread().setContextClassLoader(
-                               getClass().getClassLoader());
-               final LoginContext loginContext;
-               try {
-                       loginContext = new LoginContext(KernelHeader.LOGIN_CONTEXT_USER,
-                                       subject, new DefaultLoginDialog(display.getActiveShell()));
-               } 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(ACCESS_CONTROL_CONTEXT);
+
+               final Subject subject;
+               if (acc != null
+                               && Subject.getSubject(acc).getPrincipals(X500Principal.class)
+                                               .size() == 1) {
+                       subject = Subject.getSubject(acc);
+               } else {
+                       subject = new Subject();
 
-               tryLogin: while (subject.getPrincipals(Authentication.class).size() == 0) {
+                       final LoginContext loginContext;
+                       DefaultLoginDialog callbackHandler;
                        try {
-                               loginContext.login();
-                               // if () {
-                               // throw new ArgeoException("Login failed");
-                               // }
-
-                               if (subject.getPrincipals(Authentication.class).size() == 0)
-                                       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());
-                               // add thread locale to RWT session
-                               log.info("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) {
+                               callbackHandler = new DefaultLoginDialog(
+                                               display.getActiveShell());
+                               loginContext = new LoginContext(
+                                               AuthConstants.LOGIN_CONTEXT_USER, subject,
+                                               callbackHandler);
+                       } catch (LoginException e1) {
+                               throw new CmsException("Cannot initialize login context", e1);
+                       }
+
+                       tryLogin: while (subject.getPrincipals(X500Principal.class).size() == 0) {
+                               try {
+                                       loginContext.login();
+                                       if (subject.getPrincipals(X500Principal.class).size() == 0)
+                                               throw new CmsException("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 (FailedLoginException e) {
+                                       MessageDialog.openInformation(display.getActiveShell(),
+                                                       "Bad Credentials", e.getMessage());
+                                       // retry login
+                                       continue tryLogin;
+                               } catch (CredentialNotFoundException e) {
                                        MessageDialog.openInformation(display.getActiveShell(),
-                                                       "Bad Credentials", bce.getMessage());
+                                                       "No Credentials", e.getMessage());
                                        // retry login
                                        continue tryLogin;
+                               } catch (LoginException e) {
+                                       callbackHandler.getShell().dispose();
+                                       return processLoginDeath(display, e);
                                }
-                               return processLoginDeath(display, e);
                        }
                }
-
-               final String username = subject.getPrincipals(Authentication.class)
+               final String username = subject.getPrincipals(X500Principal.class)
                                .iterator().next().getName();
                // Logout callback when the display is disposed
                display.disposeExec(new Runnable() {
                        public void run() {
-                               log.debug("Display disposed");
-                               // logout(loginContext, username);
+                               if (log.isTraceEnabled())
+                                       log.trace("Display disposed");
                                try {
+                                       LoginContext loginContext = new LoginContext(
+                                                       AuthConstants.LOGIN_CONTEXT_USER, subject);
                                        loginContext.logout();
                                } catch (LoginException e) {
                                        log.error("Error when logging out", e);
@@ -162,6 +156,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);
@@ -169,14 +168,14 @@ public class SecureEntryPoint implements EntryPoint {
                                }
                        });
                        // Explicit exit from workbench
-                       logout(loginContext, username);
+                       fullLogout(subject, username);
                } finally {
                        display.dispose();
                }
                return returnCode;
        }
 
-       private Integer processLoginDeath(Display display, LoginException e) {
+       private Integer processLoginDeath(Display display, Throwable e) {
                // check thread death
                ThreadDeath td = wasCausedByThreadDeath(e);
                if (td != null) {
@@ -190,26 +189,12 @@ public class SecureEntryPoint implements EntryPoint {
                        display.dispose();
                        return -1;
                } else {
-                       throw new ArgeoException(
+                       throw new CmsException(
                                        "Unexpected exception during authentication", e);
                }
 
        }
 
-       /** Recursively look for {@link BadCredentialsException} in the root causes. */
-       private BadCredentialsException wasCausedByBadCredentials(Throwable t) {
-               if (t instanceof BadCredentialsException)
-                       return (BadCredentialsException) t;
-
-               if (t instanceof LoginCanceledException)
-                       return new BadCredentialsException("Login canceled");
-
-               if (t.getCause() != null)
-                       return wasCausedByBadCredentials(t.getCause());
-               else
-                       return null;
-       }
-
        /**
         * If there is a {@link ThreadDeath} in the root causes, rethrow it
         * (important for RAP cleaning mechanism)
@@ -217,26 +202,27 @@ public class SecureEntryPoint implements EntryPoint {
        protected ThreadDeath wasCausedByThreadDeath(Throwable t) {
                if (t instanceof ThreadDeath)
                        return (ThreadDeath) t;
-
+               if (t instanceof ThreadDeathLoginException)
+                       return ((ThreadDeathLoginException) t).getThreadDeath();
                if (t.getCause() != null)
                        return wasCausedByThreadDeath(t.getCause());
                else
                        return null;
        }
 
-       private void logout(LoginContext loginContext, String username) {
+       private void fullLogout(Subject subject, String username) {
                try {
+                       LoginContext loginContext = new LoginContext(
+                                       AuthConstants.LOGIN_CONTEXT_USER, subject);
                        loginContext.logout();
-                       SecurityContextHolder.clearContext();
-
                        HttpServletRequest httpRequest = RWT.getRequest();
                        HttpSession httpSession = httpRequest.getSession();
-                       httpSession.setAttribute(SPRING_SECURITY_CONTEXT_KEY, null);
+                       httpSession.setAttribute(ACCESS_CONTROL_CONTEXT, null);
                        RWT.getRequest().getSession().setMaxInactiveInterval(1);
                        log.info("Logged out " + (username != null ? username : "")
                                        + " (THREAD=" + Thread.currentThread().getId() + ")");
                } catch (LoginException e) {
-                       log.error("Erorr when logging out", e);
+                       log.error("Error when logging out", e);
                }
        }
 }