2 * Copyright (C) 2007-2012 Argeo GmbH
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
16 package org
.argeo
.security
.ui
.dialogs
;
18 import java
.io
.IOException
;
20 import javax
.security
.auth
.callback
.Callback
;
21 import javax
.security
.auth
.callback
.CallbackHandler
;
22 import javax
.security
.auth
.callback
.NameCallback
;
23 import javax
.security
.auth
.callback
.PasswordCallback
;
25 import org
.apache
.commons
.logging
.Log
;
26 import org
.apache
.commons
.logging
.LogFactory
;
27 import org
.argeo
.security
.ui
.SecurityUiPlugin
;
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
;
40 /** Base for login dialogs */
41 public abstract class AbstractLoginDialog
extends TrayDialog
implements
44 private final static Log log
= LogFactory
.getLog(AbstractLoginDialog
.class);
46 private Thread modalContextThread
= null;
47 boolean processCallbacks
= false;
48 boolean isCancelled
= false;
49 Callback
[] callbackArray
;
51 protected final Callback
[] getCallbacks() {
52 return this.callbackArray
;
55 public abstract void internalHandle();
57 public boolean isCancelled() {
61 protected AbstractLoginDialog(Shell parentShell
) {
69 * javax.security.auth.callback.CallbackHandler#handle(javax.security.auth
70 * .callback.Callback[])
72 public void handle(final Callback
[] callbacks
) throws IOException
{
73 // clean previous usage
74 if (processCallbacks
) {
75 // this handler was already used
76 processCallbacks
= false;
79 if (modalContextThread
!= null) {
81 modalContextThread
.join(1000);
82 } catch (InterruptedException e
) {
85 modalContextThread
= null;
89 this.callbackArray
= callbacks
;
90 final Display display
= Display
.getDefault();
91 display
.syncExec(new Runnable() {
95 setBlockOnOpen(false);
98 final Button okButton
= getButton(IDialogConstants
.OK_ID
);
99 okButton
.setText("Login");
100 okButton
.addSelectionListener(new SelectionListener() {
102 public void widgetSelected(final SelectionEvent event
) {
103 processCallbacks
= true;
106 public void widgetDefaultSelected(final SelectionEvent event
) {
110 final Button cancel
= getButton(IDialogConstants
.CANCEL_ID
);
111 cancel
.addSelectionListener(new SelectionListener() {
113 public void widgetSelected(final SelectionEvent event
) {
115 processCallbacks
= true;
118 public void widgetDefaultSelected(final SelectionEvent event
) {
125 ModalContext
.setAllowReadAndDispatch(true); // Works for now.
126 ModalContext
.run(new IRunnableWithProgress() {
128 public void run(final IProgressMonitor monitor
) {
129 modalContextThread
= Thread
.currentThread();
130 // Wait here until OK or cancel is pressed, then let it rip.
133 // is responsible for closing the dialog (in the
136 while (!processCallbacks
&& (modalContextThread
!= null)
137 && (modalContextThread
== Thread
.currentThread())
138 && SecurityUiPlugin
.getBundleContext() != null) {
139 // Note: SecurityUiPlugin.getDefault() != null is false
140 // when the OSGi runtime is shut down
143 // if (display.isDisposed()) {
144 // log.warn("Display is disposed, killing login dialog thread");
145 // throw new ThreadDeath();
147 } catch (final Exception e
) {
151 processCallbacks
= false;
152 // Call the adapter to handle the callbacks
156 // clear callbacks are when cancelling
157 for (Callback callback
: callbacks
)
158 if (callback
instanceof PasswordCallback
)
159 ((PasswordCallback
) callback
).setPassword(null);
160 else if (callback
instanceof NameCallback
)
161 ((NameCallback
) callback
).setName(null);
163 }, true, new NullProgressMonitor(), Display
.getDefault());
164 } catch (ThreadDeath e
) {
166 log
.debug("Thread " + Thread
.currentThread().getId() + " died");
168 } catch (Exception e
) {
170 IOException ioe
= new IOException(
171 "Unexpected issue in login dialog, see root cause for more details");
175 // so that the modal thread dies
176 processCallbacks
= true;
178 // // wait for the modal context thread to gracefully exit
179 // modalContextThread.join();
180 // } catch (InterruptedException ie) {
183 modalContextThread
= null;
187 protected void configureShell(Shell shell
) {
188 super.configureShell(shell
);
189 shell
.setText("Authentication");