]> git.argeo.org Git - lgpl/argeo-commons.git/blob - rap/SecureEntryPoint.java
Prepare next development cycle
[lgpl/argeo-commons.git] / rap / SecureEntryPoint.java
1 package org.argeo.security.ui.rap;
2
3 import java.security.PrivilegedAction;
4
5 import javax.security.auth.Subject;
6 import javax.security.auth.login.LoginException;
7
8 import org.apache.commons.logging.Log;
9 import org.apache.commons.logging.LogFactory;
10 import org.argeo.ArgeoException;
11 import org.argeo.eclipse.ui.ErrorFeedback;
12 import org.eclipse.equinox.security.auth.ILoginContext;
13 import org.eclipse.jface.dialogs.MessageDialog;
14 import org.eclipse.rwt.RWT;
15 import org.eclipse.rwt.lifecycle.IEntryPoint;
16 import org.eclipse.swt.widgets.Display;
17 import org.eclipse.ui.PlatformUI;
18 import org.springframework.security.BadCredentialsException;
19
20 /**
21 * RAP entry point with login capabilities. Once the user has been
22 * authenticated, the workbench is run as a privileged action by the related
23 * subject.
24 */
25 public class SecureEntryPoint implements IEntryPoint {
26 private final static Log log = LogFactory.getLog(SecureEntryPoint.class);
27
28 /**
29 * How many seconds to wait before invalidating the session if the user has
30 * not yet logged in.
31 */
32 private Integer loginTimeout = 1 * 60;
33 // TODO make it configurable
34 /** Default session timeout is 8 hours (European working day length) */
35 private Integer sessionTimeout = 8 * 60 * 60;
36
37 @Override
38 public int createUI() {
39 // Short login timeout so that the modal dialog login doesn't hang
40 // around too long
41 RWT.getRequest().getSession().setMaxInactiveInterval(loginTimeout);
42
43 if (log.isDebugEnabled())
44 log.debug("THREAD=" + Thread.currentThread().getId()
45 + ", sessionStore=" + RWT.getSessionStore().getId());
46
47 // create display
48 final Display display = PlatformUI.createDisplay();
49
50 // log in
51 final ILoginContext loginContext = SecureRapActivator
52 .createLoginContext(SecureRapActivator.CONTEXT_SPRING);
53 Subject subject = null;
54 tryLogin: while (subject == null && !display.isDisposed()) {
55 try {
56 loginContext.login();
57 subject = loginContext.getSubject();
58 } catch (LoginException e) {
59 BadCredentialsException bce = wasCausedByBadCredentials(e);
60 if (bce != null) {
61 MessageDialog.openInformation(display.getActiveShell(),
62 "Bad Credentials", bce.getMessage());
63 // retry login
64 continue tryLogin;
65 }
66 return processLoginDeath(display, e);
67 }
68 }
69
70 // Once the user is logged in, she can have a longer session timeout
71 RWT.getRequest().getSession().setMaxInactiveInterval(sessionTimeout);
72 if (log.isDebugEnabled())
73 log.debug("Authenticated " + subject);
74
75 final String username = subject.getPrincipals().iterator().next()
76 .getName();
77 // Logout callback when the display is disposed
78 display.disposeExec(new Runnable() {
79 public void run() {
80 log.debug("Display disposed");
81 logout(loginContext, username);
82 }
83 });
84
85 //
86 // RUN THE WORKBENCH
87 //
88 Integer returnCode = null;
89 try {
90 returnCode = Subject.doAs(subject, new PrivilegedAction<Integer>() {
91 public Integer run() {
92 RapWorkbenchAdvisor workbenchAdvisor = new RapWorkbenchAdvisor(
93 username);
94 int result = PlatformUI.createAndRunWorkbench(display,
95 workbenchAdvisor);
96 return new Integer(result);
97 }
98 });
99 logout(loginContext, username);
100 } finally {
101 display.dispose();
102 }
103 return returnCode;
104 }
105
106 private Integer processLoginDeath(Display display, LoginException e) {
107 // check thread death
108 ThreadDeath td = wasCausedByThreadDeath(e);
109 if (td != null) {
110 display.dispose();
111 throw td;
112 }
113 if (!display.isDisposed()) {
114 ErrorFeedback.show("Unexpected exception during authentication", e);
115 // this was not just bad credentials or death thread
116 RWT.getRequest().getSession().setMaxInactiveInterval(1);
117 display.dispose();
118 return -1;
119 } else {
120 throw new ArgeoException(
121 "Unexpected exception during authentication", e);
122 }
123
124 }
125
126 /** Recursively look for {@link BadCredentialsException} in the root causes. */
127 private BadCredentialsException wasCausedByBadCredentials(Throwable t) {
128 if (t instanceof BadCredentialsException)
129 return (BadCredentialsException) t;
130
131 if (t.getCause() != null)
132 return wasCausedByBadCredentials(t.getCause());
133 else
134 return null;
135 }
136
137 /**
138 * If there is a {@link ThreadDeath} in the root causes, rethrow it
139 * (important for RAP cleaning mechanism)
140 */
141 protected ThreadDeath wasCausedByThreadDeath(Throwable t) {
142 if (t instanceof ThreadDeath)
143 return (ThreadDeath) t;
144
145 if (t.getCause() != null)
146 return wasCausedByThreadDeath(t.getCause());
147 else
148 return null;
149 }
150
151 protected void logout(ILoginContext secureContext, String username) {
152 try {
153 secureContext.logout();
154 log.info("Logged out " + (username != null ? username : "")
155 + " (THREAD=" + Thread.currentThread().getId() + ")");
156 } catch (LoginException e) {
157 log.error("Erorr when logging out", e);
158 }
159 }
160 }