]> git.argeo.org Git - lgpl/argeo-commons.git/blob - org.argeo.cms.ui/src/org/argeo/cms/ui/widgets/auth/AbstractLoginDialog.java
Expose servlet context helpers.
[lgpl/argeo-commons.git] / org.argeo.cms.ui / src / org / argeo / cms / ui / widgets / auth / AbstractLoginDialog.java
1 package org.argeo.cms.ui.widgets.auth;
2
3 import java.io.IOException;
4 import java.util.Arrays;
5
6 import javax.security.auth.callback.Callback;
7 import javax.security.auth.callback.CallbackHandler;
8 import javax.security.auth.callback.NameCallback;
9 import javax.security.auth.callback.PasswordCallback;
10
11 import org.apache.commons.logging.Log;
12 import org.apache.commons.logging.LogFactory;
13 import org.eclipse.core.runtime.IProgressMonitor;
14 import org.eclipse.core.runtime.NullProgressMonitor;
15 import org.eclipse.jface.dialogs.IDialogConstants;
16 import org.eclipse.jface.dialogs.TrayDialog;
17 import org.eclipse.jface.operation.IRunnableWithProgress;
18 import org.eclipse.jface.operation.ModalContext;
19 import org.eclipse.swt.events.SelectionEvent;
20 import org.eclipse.swt.events.SelectionListener;
21 import org.eclipse.swt.widgets.Button;
22 import org.eclipse.swt.widgets.Display;
23 import org.eclipse.swt.widgets.Shell;
24 import org.osgi.framework.FrameworkUtil;
25
26 /** Base for login dialogs */
27 public abstract class AbstractLoginDialog extends TrayDialog implements CallbackHandler {
28 private static final long serialVersionUID = -8046708963512717709L;
29
30 private final static Log log = LogFactory.getLog(AbstractLoginDialog.class);
31
32 private Thread modalContextThread = null;
33 boolean processCallbacks = false;
34 boolean isCancelled = false;
35 Callback[] callbackArray;
36
37 protected final Callback[] getCallbacks() {
38 return this.callbackArray;
39 }
40
41 public abstract void internalHandle();
42
43 public boolean isCancelled() {
44 return isCancelled;
45 }
46
47 protected AbstractLoginDialog(Shell parentShell) {
48 super(parentShell);
49 }
50
51 /*
52 * (non-Javadoc)
53 *
54 * @see
55 * javax.security.auth.callback.CallbackHandler#handle(javax.security.auth
56 * .callback.Callback[])
57 */
58 public void handle(final Callback[] callbacks) throws IOException {
59 // clean previous usage
60 if (processCallbacks) {
61 // this handler was already used
62 processCallbacks = false;
63 }
64
65 if (modalContextThread != null) {
66 try {
67 modalContextThread.join(1000);
68 } catch (InterruptedException e) {
69 // silent
70 }
71 modalContextThread = null;
72 }
73
74 // initialize
75 this.callbackArray = callbacks;
76 final Display display = Display.getDefault();
77 display.syncExec(new Runnable() {
78
79 public void run() {
80 isCancelled = false;
81 setBlockOnOpen(false);
82 open();
83
84 final Button okButton = getButton(IDialogConstants.OK_ID);
85 okButton.setText("Login");
86 okButton.addSelectionListener(new SelectionListener() {
87 private static final long serialVersionUID = -200281625679096775L;
88
89 public void widgetSelected(final SelectionEvent event) {
90 processCallbacks = true;
91 }
92
93 public void widgetDefaultSelected(final SelectionEvent event) {
94 // nothing to do
95 }
96 });
97 final Button cancel = getButton(IDialogConstants.CANCEL_ID);
98 cancel.addSelectionListener(new SelectionListener() {
99 private static final long serialVersionUID = -3826030278084915815L;
100
101 public void widgetSelected(final SelectionEvent event) {
102 isCancelled = true;
103 processCallbacks = true;
104 }
105
106 public void widgetDefaultSelected(final SelectionEvent event) {
107 // nothing to do
108 }
109 });
110 }
111 });
112 try {
113 ModalContext.setAllowReadAndDispatch(true); // Works for now.
114 ModalContext.run(new IRunnableWithProgress() {
115
116 public void run(final IProgressMonitor monitor) {
117 modalContextThread = Thread.currentThread();
118 // Wait here until OK or cancel is pressed, then let it rip.
119 // The event
120 // listener
121 // is responsible for closing the dialog (in the
122 // loginSucceeded
123 // event).
124 while (!processCallbacks && (modalContextThread != null)
125 && (modalContextThread == Thread.currentThread())
126 && FrameworkUtil.getBundle(AbstractLoginDialog.class).getBundleContext() != null) {
127 // Note: SecurityUiPlugin.getDefault() != null is false
128 // when the OSGi runtime is shut down
129 try {
130 Thread.sleep(100);
131 // if (display.isDisposed()) {
132 // log.warn("Display is disposed, killing login
133 // dialog thread");
134 // throw new ThreadDeath();
135 // }
136 } catch (final Exception e) {
137 // do nothing
138 }
139 }
140 processCallbacks = false;
141 // Call the adapter to handle the callbacks
142 if (!isCancelled())
143 internalHandle();
144 else
145 // clear callbacks are when cancelling
146 for (Callback callback : callbacks)
147 if (callback instanceof PasswordCallback) {
148 char[] arr = ((PasswordCallback) callback).getPassword();
149 if (arr != null) {
150 Arrays.fill(arr, '*');
151 ((PasswordCallback) callback).setPassword(null);
152 }
153 } else if (callback instanceof NameCallback)
154 ((NameCallback) callback).setName(null);
155 }
156 }, true, new NullProgressMonitor(), Display.getDefault());
157 } catch (ThreadDeath e) {
158 isCancelled = true;
159 log.debug("Thread " + Thread.currentThread().getId() + " died");
160 throw e;
161 } catch (Exception e) {
162 isCancelled = true;
163 IOException ioe = new IOException("Unexpected issue in login dialog, see root cause for more details");
164 ioe.initCause(e);
165 throw ioe;
166 } finally {
167 // so that the modal thread dies
168 processCallbacks = true;
169 // try {
170 // // wait for the modal context thread to gracefully exit
171 // modalContextThread.join();
172 // } catch (InterruptedException ie) {
173 // // silent
174 // }
175 modalContextThread = null;
176 }
177 }
178
179 protected void configureShell(Shell shell) {
180 super.configureShell(shell);
181 shell.setText("Authentication");
182 }
183 }