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
.cms
.widgets
.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
.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
;
41 /** Base for login dialogs */
42 public abstract class AbstractLoginDialog
extends TrayDialog
implements CallbackHandler
{
43 private static final long serialVersionUID
= -8046708963512717709L;
45 private final static Log log
= LogFactory
.getLog(AbstractLoginDialog
.class);
47 private Thread modalContextThread
= null;
48 boolean processCallbacks
= false;
49 boolean isCancelled
= false;
50 Callback
[] callbackArray
;
52 protected final Callback
[] getCallbacks() {
53 return this.callbackArray
;
56 public abstract void internalHandle();
58 public boolean isCancelled() {
62 protected AbstractLoginDialog(Shell parentShell
) {
70 * javax.security.auth.callback.CallbackHandler#handle(javax.security.auth
71 * .callback.Callback[])
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;
80 if (modalContextThread
!= null) {
82 modalContextThread
.join(1000);
83 } catch (InterruptedException e
) {
86 modalContextThread
= null;
90 this.callbackArray
= callbacks
;
91 final Display display
= Display
.getDefault();
92 display
.syncExec(new Runnable() {
96 setBlockOnOpen(false);
99 final Button okButton
= getButton(IDialogConstants
.OK_ID
);
100 okButton
.setText("Login");
101 okButton
.addSelectionListener(new SelectionListener() {
102 private static final long serialVersionUID
= -200281625679096775L;
104 public void widgetSelected(final SelectionEvent event
) {
105 processCallbacks
= true;
108 public void widgetDefaultSelected(final SelectionEvent event
) {
112 final Button cancel
= getButton(IDialogConstants
.CANCEL_ID
);
113 cancel
.addSelectionListener(new SelectionListener() {
114 private static final long serialVersionUID
= -3826030278084915815L;
116 public void widgetSelected(final SelectionEvent event
) {
118 processCallbacks
= true;
121 public void widgetDefaultSelected(final SelectionEvent event
) {
128 ModalContext
.setAllowReadAndDispatch(true); // Works for now.
129 ModalContext
.run(new IRunnableWithProgress() {
131 public void run(final IProgressMonitor monitor
) {
132 modalContextThread
= Thread
.currentThread();
133 // Wait here until OK or cancel is pressed, then let it rip.
136 // is responsible for closing the dialog (in the
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
146 // if (display.isDisposed()) {
147 // log.warn("Display is disposed, killing login
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
).getPassword();
165 Arrays
.fill(arr
, '*');
166 ((PasswordCallback
) callback
).setPassword(null);
168 } else if (callback
instanceof NameCallback
)
169 ((NameCallback
) callback
).setName(null);
171 }, true, new NullProgressMonitor(), Display
.getDefault());
172 } catch (ThreadDeath e
) {
174 log
.debug("Thread " + Thread
.currentThread().getId() + " died");
176 } catch (Exception e
) {
178 IOException ioe
= new IOException("Unexpected issue in login dialog, see root cause for more details");
182 // so that the modal thread dies
183 processCallbacks
= true;
185 // // wait for the modal context thread to gracefully exit
186 // modalContextThread.join();
187 // } catch (InterruptedException ie) {
190 modalContextThread
= null;
194 protected void configureShell(Shell shell
) {
195 super.configureShell(shell
);
196 shell
.setText("Authentication");