+/*
+ * Copyright (C) 2007-2012 Mathieu Baudier
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.argeo.security.ui.rap;
import java.security.PrivilegedAction;
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;
import org.argeo.ArgeoException;
+import org.argeo.eclipse.ui.ErrorFeedback;
import org.eclipse.equinox.security.auth.ILoginContext;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.rwt.RWT;
import org.eclipse.rwt.lifecycle.IEntryPoint;
import org.eclipse.swt.widgets.Display;
import org.eclipse.ui.PlatformUI;
-import org.eclipse.ui.application.IWorkbenchWindowConfigurer;
-import org.eclipse.ui.application.WorkbenchAdvisor;
-import org.eclipse.ui.application.WorkbenchWindowAdvisor;
import org.springframework.security.BadCredentialsException;
+import org.springframework.security.context.SecurityContext;
+import org.springframework.security.context.SecurityContextHolder;
/**
- * RAP entry point with login capabilities. On the user has been authenticated,
- * the workbench is run as a privileged action by the related subject.
+ * RAP entry point with login capabilities. Once the user has been
+ * authenticated, the workbench is run as a privileged action by the related
+ * subject.
*/
public class SecureEntryPoint implements IEntryPoint {
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.
*/
private Integer loginTimeout = 1 * 60;
- private Integer sessionTimeout = 15 * 60;
+ // TODO make it configurable
+ /** Default session timeout is 8 hours (European working day length) */
+ private Integer sessionTimeout = 8 * 60 * 60;
+
+ /** Override to provide an application specific workbench advisor */
+ protected RapWorkbenchAdvisor createRapWorkbenchAdvisor(String username) {
+ return new RapWorkbenchAdvisor(username);
+ }
@Override
- public int createUI() {
+ public final int createUI() {
// Short login timeout so that the modal dialog login doesn't hang
// around too long
RWT.getRequest().getSession().setMaxInactiveInterval(loginTimeout);
+ 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());
-
- Integer returnCode = null;
+ + ", sessionStore=" + RWT.getSessionStore().getId()
+ + ", remote user=" + httpRequest.getRemoteUser());
// create display
- Display display = PlatformUI.createDisplay();
+ final Display display = PlatformUI.createDisplay();
// log in
final ILoginContext loginContext = SecureRapActivator
- .createLoginContext();
+ .createLoginContext(SecureRapActivator.CONTEXT_SPRING);
Subject subject = null;
tryLogin: while (subject == null && !display.isDisposed()) {
try {
loginContext.login();
subject = loginContext.getSubject();
+
+ if (httpSession.getAttribute(SPRING_SECURITY_CONTEXT_KEY) == null)
+ httpSession.setAttribute(SPRING_SECURITY_CONTEXT_KEY,
+ SecurityContextHolder.getContext());
+
+ // Once the user is logged in, she can have a 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) {
// retry login
continue tryLogin;
}
-
- // check thread death
- ThreadDeath td = wasCausedByThreadDeath(e);
- if (td != null) {
- display.dispose();
- throw td;
- }
-
- // if (e.getCause() != null) {
- // Throwable firstCause = e.getCause();
- // // log.error("Cause", firstCause);
- // if (firstCause instanceof LoginException
- // && firstCause.getCause() != null) {
- // Throwable secondCause = firstCause.getCause();
- // if (secondCause instanceof BadCredentialsException) {
- // MessageDialog.openInformation(
- // display.getActiveShell(),
- // "Bad Credentials",
- // "Your credentials are incorrect");
- // // retry login
- // continue tryLogin;
- // } else if (secondCause instanceof ThreadDeath) {
- // // rethrow thread death caused by dialog UI timeout
- // throw (ThreadDeath) secondCause;
- // }
- //
- // } else if (firstCause instanceof ThreadDeath) {
- // throw (ThreadDeath) firstCause;
- // }
- // }
-
- if (!display.isDisposed()) {
- org.argeo.eclipse.ui.Error.show(
- "Unexpected exception during authentication", e);
- // this was not just bad credentials or death thread
- RWT.getRequest().getSession().setMaxInactiveInterval(1);
- display.dispose();
- return -1;
- } else {
- throw new ArgeoException(
- "Unexpected exception during authentication", e);
- }
+ return processLoginDeath(display, e);
}
}
- // identify after successful login
- if (log.isDebugEnabled())
- log.debug("Authenticated " + subject);
final String username = subject.getPrincipals().iterator().next()
.getName();
-
- // Once the user is logged in, she can have a longer session timeout
- RWT.getRequest().getSession().setMaxInactiveInterval(sessionTimeout);
-
// Logout callback when the display is disposed
display.disposeExec(new Runnable() {
public void run() {
//
// RUN THE WORKBENCH
//
+ Integer returnCode = null;
try {
- returnCode = (Integer) Subject.doAs(subject, getRunAction(display));
+ returnCode = Subject.doAs(subject, new PrivilegedAction<Integer>() {
+ public Integer run() {
+ RapWorkbenchAdvisor workbenchAdvisor = createRapWorkbenchAdvisor(username);
+ int result = PlatformUI.createAndRunWorkbench(display,
+ workbenchAdvisor);
+ return new Integer(result);
+ }
+ });
logout(loginContext, username);
} finally {
display.dispose();
}
- return processReturnCode(returnCode);
+ return returnCode;
+ }
+
+ private Integer processLoginDeath(Display display, LoginException e) {
+ // check thread death
+ ThreadDeath td = wasCausedByThreadDeath(e);
+ if (td != null) {
+ display.dispose();
+ throw td;
+ }
+ if (!display.isDisposed()) {
+ ErrorFeedback.show("Unexpected exception during authentication", e);
+ // this was not just bad credentials or death thread
+ RWT.getRequest().getSession().setMaxInactiveInterval(1);
+ display.dispose();
+ return -1;
+ } else {
+ throw new ArgeoException(
+ "Unexpected exception during authentication", e);
+ }
+
}
/** Recursively look for {@link BadCredentialsException} in the root causes. */
log.error("Erorr when logging out", e);
}
}
-
- @SuppressWarnings("rawtypes")
- private PrivilegedAction getRunAction(final Display display) {
- return new PrivilegedAction() {
- public Object run() {
- int result = createAndRunWorkbench(display);
- return new Integer(result);
- }
- };
- }
-
- /** To be overridden */
- protected Integer createAndRunWorkbench(Display display) {
- return PlatformUI.createAndRunWorkbench(display,
- createWorkbenchAdvisor());
- }
-
- /** To be overridden */
- protected Integer processReturnCode(Integer returnCode) {
- return returnCode;
- }
-
- /** To be overridden */
- protected WorkbenchAdvisor createWorkbenchAdvisor() {
- return new SecureWorkbenchAdvisor() {
- public WorkbenchWindowAdvisor createWorkbenchWindowAdvisor(
- IWorkbenchWindowConfigurer configurer) {
- return new RapSecureWorkbenchWindowAdvisor(configurer);
- }
-
- };
- }
}