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