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
.auth
;
18 import java
.io
.IOException
;
19 import java
.util
.Arrays
;
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
;
26 import org
.apache
.commons
.logging
.Log
;
27 import org
.apache
.commons
.logging
.LogFactory
;
28 import org
.argeo
.security
.ui
.SecurityUiPlugin
;
29 import org
.eclipse
.core
.runtime
.IProgressMonitor
;
30 import org
.eclipse
.core
.runtime
.NullProgressMonitor
;
31 import org
.eclipse
.jface
.dialogs
.IDialogConstants
;
32 import org
.eclipse
.jface
.dialogs
.TrayDialog
;
33 import org
.eclipse
.jface
.operation
.IRunnableWithProgress
;
34 import org
.eclipse
.jface
.operation
.ModalContext
;
35 import org
.eclipse
.swt
.events
.SelectionEvent
;
36 import org
.eclipse
.swt
.events
.SelectionListener
;
37 import org
.eclipse
.swt
.widgets
.Button
;
38 import org
.eclipse
.swt
.widgets
.Display
;
39 import org
.eclipse
.swt
.widgets
.Shell
;
41 /** Base for login dialogs */
42 public abstract class AbstractLoginDialog
extends TrayDialog
implements
44 private static final long serialVersionUID
= -8046708963512717709L;
46 private final static Log log
= LogFactory
.getLog(AbstractLoginDialog
.class);
48 private Thread modalContextThread
= null;
49 boolean processCallbacks
= false;
50 boolean isCancelled
= false;
51 Callback
[] callbackArray
;
53 protected final Callback
[] getCallbacks() {
54 return this.callbackArray
;
57 public abstract void internalHandle();
59 public boolean isCancelled() {
63 protected AbstractLoginDialog(Shell parentShell
) {
71 * javax.security.auth.callback.CallbackHandler#handle(javax.security.auth
72 * .callback.Callback[])
74 public void handle(final Callback
[] callbacks
) throws IOException
{
75 // clean previous usage
76 if (processCallbacks
) {
77 // this handler was already used
78 processCallbacks
= false;
81 if (modalContextThread
!= null) {
83 modalContextThread
.join(1000);
84 } catch (InterruptedException e
) {
87 modalContextThread
= null;
91 this.callbackArray
= callbacks
;
92 final Display display
= Display
.getDefault();
93 display
.syncExec(new Runnable() {
97 setBlockOnOpen(false);
100 final Button okButton
= getButton(IDialogConstants
.OK_ID
);
101 okButton
.setText("Login");
102 okButton
.addSelectionListener(new SelectionListener() {
103 private static final long serialVersionUID
= -200281625679096775L;
105 public void widgetSelected(final SelectionEvent event
) {
106 processCallbacks
= true;
109 public void widgetDefaultSelected(final SelectionEvent event
) {
113 final Button cancel
= getButton(IDialogConstants
.CANCEL_ID
);
114 cancel
.addSelectionListener(new SelectionListener() {
115 private static final long serialVersionUID
= -3826030278084915815L;
117 public void widgetSelected(final SelectionEvent event
) {
119 processCallbacks
= true;
122 public void widgetDefaultSelected(final SelectionEvent event
) {
129 ModalContext
.setAllowReadAndDispatch(true); // Works for now.
130 ModalContext
.run(new IRunnableWithProgress() {
132 public void run(final IProgressMonitor monitor
) {
133 modalContextThread
= Thread
.currentThread();
134 // Wait here until OK or cancel is pressed, then let it rip.
137 // is responsible for closing the dialog (in the
140 while (!processCallbacks
&& (modalContextThread
!= null)
141 && (modalContextThread
== Thread
.currentThread())
142 && SecurityUiPlugin
.getBundleContext() != null) {
143 // Note: SecurityUiPlugin.getDefault() != null is false
144 // when the OSGi runtime is shut down
147 // if (display.isDisposed()) {
148 // log.warn("Display is disposed, killing login dialog thread");
149 // throw new ThreadDeath();
151 } catch (final Exception e
) {
155 processCallbacks
= false;
156 // Call the adapter to handle the callbacks
160 // clear callbacks are when cancelling
161 for (Callback callback
: callbacks
)
162 if (callback
instanceof PasswordCallback
) {
163 char[] arr
= ((PasswordCallback
) callback
)
166 Arrays
.fill(arr
, '*');
167 ((PasswordCallback
) callback
)
170 } else if (callback
instanceof NameCallback
)
171 ((NameCallback
) callback
).setName(null);
173 }, true, new NullProgressMonitor(), Display
.getDefault());
174 } catch (ThreadDeath e
) {
176 log
.debug("Thread " + Thread
.currentThread().getId() + " died");
178 } catch (Exception e
) {
180 IOException ioe
= new IOException(
181 "Unexpected issue in login dialog, see root cause for more details");
185 // so that the modal thread dies
186 processCallbacks
= true;
188 // // wait for the modal context thread to gracefully exit
189 // modalContextThread.join();
190 // } catch (InterruptedException ie) {
193 modalContextThread
= null;
197 protected void configureShell(Shell shell
) {
198 super.configureShell(shell
);
199 shell
.setText("Authentication");