]> git.argeo.org Git - lgpl/argeo-commons.git/blob - security/plugins/org.argeo.security.ui.rap/src/main/java/org/argeo/security/ui/rap/SecureEntryPoint.java
Fix issue with username case in LDAP
[lgpl/argeo-commons.git] / security / plugins / org.argeo.security.ui.rap / src / main / java / org / argeo / security / ui / 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.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 (e.getCause() != null) {
76 // Throwable firstCause = e.getCause();
77 // // log.error("Cause", firstCause);
78 // if (firstCause instanceof LoginException
79 // && firstCause.getCause() != null) {
80 // Throwable secondCause = firstCause.getCause();
81 // if (secondCause instanceof BadCredentialsException) {
82 // MessageDialog.openInformation(
83 // display.getActiveShell(),
84 // "Bad Credentials",
85 // "Your credentials are incorrect");
86 // // retry login
87 // continue tryLogin;
88 // } else if (secondCause instanceof ThreadDeath) {
89 // // rethrow thread death caused by dialog UI timeout
90 // throw (ThreadDeath) secondCause;
91 // }
92 //
93 // } else if (firstCause instanceof ThreadDeath) {
94 // throw (ThreadDeath) firstCause;
95 // }
96 // }
97
98 if (!display.isDisposed()) {
99 org.argeo.eclipse.ui.Error.show(
100 "Unexpected exception during authentication", e);
101 // this was not just bad credentials or death thread
102 RWT.getRequest().getSession().setMaxInactiveInterval(1);
103 display.dispose();
104 return -1;
105 } else {
106 throw new ArgeoException(
107 "Unexpected exception during authentication", e);
108 }
109 }
110 }
111
112 // identify after successful login
113 if (log.isDebugEnabled())
114 log.debug("Authenticated " + subject);
115 final String username = subject.getPrincipals().iterator().next()
116 .getName();
117
118 // Once the user is logged in, she can have a longer session timeout
119 RWT.getRequest().getSession().setMaxInactiveInterval(sessionTimeout);
120
121 // Logout callback when the display is disposed
122 display.disposeExec(new Runnable() {
123 public void run() {
124 log.debug("Display disposed");
125 logout(loginContext, username);
126 }
127 });
128
129 //
130 // RUN THE WORKBENCH
131 //
132 try {
133 returnCode = (Integer) Subject.doAs(subject, getRunAction(display));
134 logout(loginContext, username);
135 } finally {
136 display.dispose();
137 }
138 return processReturnCode(returnCode);
139 }
140
141 /** Recursively look for {@link BadCredentialsException} in the root causes. */
142 private BadCredentialsException wasCausedByBadCredentials(Throwable t) {
143 if (t instanceof BadCredentialsException)
144 return (BadCredentialsException) t;
145
146 if (t.getCause() != null)
147 return wasCausedByBadCredentials(t.getCause());
148 else
149 return null;
150 }
151
152 /**
153 * If there is a {@link ThreadDeath} in the root causes, rethrow it
154 * (important for RAP cleaning mechanism)
155 */
156 protected ThreadDeath wasCausedByThreadDeath(Throwable t) {
157 if (t instanceof ThreadDeath)
158 return (ThreadDeath) t;
159
160 if (t.getCause() != null)
161 return wasCausedByThreadDeath(t.getCause());
162 else
163 return null;
164 }
165
166 protected void logout(ILoginContext secureContext, String username) {
167 try {
168 secureContext.logout();
169 log.info("Logged out " + (username != null ? username : "")
170 + " (THREAD=" + Thread.currentThread().getId() + ")");
171 } catch (LoginException e) {
172 log.error("Erorr when logging out", e);
173 }
174 }
175
176 @SuppressWarnings("rawtypes")
177 private PrivilegedAction getRunAction(final Display display) {
178 return new PrivilegedAction() {
179 public Object run() {
180 int result = createAndRunWorkbench(display);
181 return new Integer(result);
182 }
183 };
184 }
185
186 /** To be overridden */
187 protected Integer createAndRunWorkbench(Display display) {
188 return PlatformUI.createAndRunWorkbench(display,
189 createWorkbenchAdvisor());
190 }
191
192 /** To be overridden */
193 protected Integer processReturnCode(Integer returnCode) {
194 return returnCode;
195 }
196
197 /** To be overridden */
198 protected WorkbenchAdvisor createWorkbenchAdvisor() {
199 return new SecureWorkbenchAdvisor() {
200 public WorkbenchWindowAdvisor createWorkbenchWindowAdvisor(
201 IWorkbenchWindowConfigurer configurer) {
202 return new RapSecureWorkbenchWindowAdvisor(configurer);
203 }
204
205 };
206 }
207 }