2 * Copyright (C) 2007-2012 Mathieu Baudier
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
16 package org
.argeo
.security
.ui
.rap
;
18 import java
.security
.PrivilegedAction
;
20 import javax
.security
.auth
.Subject
;
21 import javax
.security
.auth
.login
.LoginException
;
22 import javax
.servlet
.http
.HttpServletRequest
;
23 import javax
.servlet
.http
.HttpSession
;
25 import org
.apache
.commons
.logging
.Log
;
26 import org
.apache
.commons
.logging
.LogFactory
;
27 import org
.argeo
.ArgeoException
;
28 import org
.argeo
.eclipse
.ui
.ErrorFeedback
;
29 import org
.eclipse
.equinox
.security
.auth
.ILoginContext
;
30 import org
.eclipse
.jface
.dialogs
.MessageDialog
;
31 import org
.eclipse
.rwt
.RWT
;
32 import org
.eclipse
.rwt
.lifecycle
.IEntryPoint
;
33 import org
.eclipse
.swt
.widgets
.Display
;
34 import org
.eclipse
.ui
.PlatformUI
;
35 import org
.springframework
.security
.BadCredentialsException
;
36 import org
.springframework
.security
.context
.SecurityContext
;
37 import org
.springframework
.security
.context
.SecurityContextHolder
;
40 * RAP entry point with login capabilities. Once the user has been
41 * authenticated, the workbench is run as a privileged action by the related
44 public class SecureEntryPoint
implements IEntryPoint
{
45 private final static Log log
= LogFactory
.getLog(SecureEntryPoint
.class);
48 * From org.springframework.security.context.
49 * HttpSessionContextIntegrationFilter
51 protected static final String SPRING_SECURITY_CONTEXT_KEY
= "SPRING_SECURITY_CONTEXT";
54 * How many seconds to wait before invalidating the session if the user has
57 private Integer loginTimeout
= 1 * 60;
58 // TODO make it configurable
59 /** Default session timeout is 8 hours (European working day length) */
60 private Integer sessionTimeout
= 8 * 60 * 60;
62 /** Override to provide an application specific workbench advisor */
63 protected RapWorkbenchAdvisor
createRapWorkbenchAdvisor(String username
) {
64 return new RapWorkbenchAdvisor(username
);
68 public final int createUI() {
69 // Short login timeout so that the modal dialog login doesn't hang
71 RWT
.getRequest().getSession().setMaxInactiveInterval(loginTimeout
);
73 HttpServletRequest httpRequest
= RWT
.getRequest();
74 HttpSession httpSession
= httpRequest
.getSession();
75 Object contextFromSessionObject
= httpSession
76 .getAttribute(SPRING_SECURITY_CONTEXT_KEY
);
77 if (contextFromSessionObject
!= null)
79 .setContext((SecurityContext
) contextFromSessionObject
);
81 if (log
.isDebugEnabled())
82 log
.debug("THREAD=" + Thread
.currentThread().getId()
83 + ", sessionStore=" + RWT
.getSessionStore().getId()
84 + ", remote user=" + httpRequest
.getRemoteUser());
87 final Display display
= PlatformUI
.createDisplay();
90 final ILoginContext loginContext
= SecureRapActivator
91 .createLoginContext(SecureRapActivator
.CONTEXT_SPRING
);
92 Subject subject
= null;
93 tryLogin
: while (subject
== null && !display
.isDisposed()) {
96 subject
= loginContext
.getSubject();
98 if (httpSession
.getAttribute(SPRING_SECURITY_CONTEXT_KEY
) == null)
99 httpSession
.setAttribute(SPRING_SECURITY_CONTEXT_KEY
,
100 SecurityContextHolder
.getContext());
102 // Once the user is logged in, she can have a longer session
104 RWT
.getRequest().getSession()
105 .setMaxInactiveInterval(sessionTimeout
);
106 if (log
.isDebugEnabled())
107 log
.debug("Authenticated " + subject
);
108 } catch (LoginException e
) {
109 BadCredentialsException bce
= wasCausedByBadCredentials(e
);
111 MessageDialog
.openInformation(display
.getActiveShell(),
112 "Bad Credentials", bce
.getMessage());
116 return processLoginDeath(display
, e
);
120 final String username
= subject
.getPrincipals().iterator().next()
122 // Logout callback when the display is disposed
123 display
.disposeExec(new Runnable() {
125 log
.debug("Display disposed");
126 logout(loginContext
, username
);
133 Integer returnCode
= null;
135 returnCode
= Subject
.doAs(subject
, new PrivilegedAction
<Integer
>() {
136 public Integer
run() {
137 RapWorkbenchAdvisor workbenchAdvisor
= createRapWorkbenchAdvisor(username
);
138 int result
= PlatformUI
.createAndRunWorkbench(display
,
140 return new Integer(result
);
143 logout(loginContext
, username
);
150 private Integer
processLoginDeath(Display display
, LoginException e
) {
151 // check thread death
152 ThreadDeath td
= wasCausedByThreadDeath(e
);
157 if (!display
.isDisposed()) {
158 ErrorFeedback
.show("Unexpected exception during authentication", e
);
159 // this was not just bad credentials or death thread
160 RWT
.getRequest().getSession().setMaxInactiveInterval(1);
164 throw new ArgeoException(
165 "Unexpected exception during authentication", e
);
170 /** Recursively look for {@link BadCredentialsException} in the root causes. */
171 private BadCredentialsException
wasCausedByBadCredentials(Throwable t
) {
172 if (t
instanceof BadCredentialsException
)
173 return (BadCredentialsException
) t
;
175 if (t
.getCause() != null)
176 return wasCausedByBadCredentials(t
.getCause());
182 * If there is a {@link ThreadDeath} in the root causes, rethrow it
183 * (important for RAP cleaning mechanism)
185 protected ThreadDeath
wasCausedByThreadDeath(Throwable t
) {
186 if (t
instanceof ThreadDeath
)
187 return (ThreadDeath
) t
;
189 if (t
.getCause() != null)
190 return wasCausedByThreadDeath(t
.getCause());
195 protected void logout(ILoginContext secureContext
, String username
) {
197 secureContext
.logout();
198 log
.info("Logged out " + (username
!= null ? username
: "")
199 + " (THREAD=" + Thread
.currentThread().getId() + ")");
200 } catch (LoginException e
) {
201 log
.error("Erorr when logging out", e
);