From ff718212e89b0ea05087aabe147859efedf186f9 Mon Sep 17 00:00:00 2001 From: Mathieu Baudier Date: Tue, 15 Sep 2015 20:39:29 +0000 Subject: [PATCH] Session authentication working git-svn-id: https://svn.argeo.org/commons/trunk@8404 4cfe0d0a-d680-48aa-b62c-e0a02a3f76cc --- .../org/argeo/cms/AbstractCmsEntryPoint.java | 15 ++- .../src/org/argeo/cms/KernelHeader.java | 3 + .../src/org/argeo/cms/util/UserMenu.java | 38 ++++-- .../security/ui/rap/SecureEntryPoint.java | 126 +++++++++--------- 4 files changed, 111 insertions(+), 71 deletions(-) diff --git a/org.argeo.cms/src/org/argeo/cms/AbstractCmsEntryPoint.java b/org.argeo.cms/src/org/argeo/cms/AbstractCmsEntryPoint.java index 951e177b2..6e30d8e31 100644 --- a/org.argeo.cms/src/org/argeo/cms/AbstractCmsEntryPoint.java +++ b/org.argeo.cms/src/org/argeo/cms/AbstractCmsEntryPoint.java @@ -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(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) diff --git a/org.argeo.cms/src/org/argeo/cms/KernelHeader.java b/org.argeo.cms/src/org/argeo/cms/KernelHeader.java index 8f817df79..2e4049192 100644 --- a/org.argeo.cms/src/org/argeo/cms/KernelHeader.java +++ b/org.argeo.cms/src/org/argeo/cms/KernelHeader.java @@ -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"; diff --git a/org.argeo.cms/src/org/argeo/cms/util/UserMenu.java b/org.argeo.cms/src/org/argeo/cms/util/UserMenu.java index 1c3560001..3fef6792b 100644 --- a/org.argeo.cms/src/org/argeo/cms/util/UserMenu.java +++ b/org.argeo.cms/src/org/argeo/cms/util/UserMenu.java @@ -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() { + + @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); } diff --git a/org.argeo.security.ui.rap/src/org/argeo/security/ui/rap/SecureEntryPoint.java b/org.argeo.security.ui.rap/src/org/argeo/security/ui/rap/SecureEntryPoint.java index fb885377f..48d33d2d4 100644 --- a/org.argeo.security.ui.rap/src/org/argeo/security/ui/rap/SecureEntryPoint.java +++ b/org.argeo.security.ui.rap/src/org/argeo/security/ui/rap/SecureEntryPoint.java @@ -15,6 +15,10 @@ */ 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() { 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() + ")"); -- 2.30.2