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