-/*
- * Copyright (C) 2007-2012 Argeo GmbH
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.argeo.cms.widgets.auth;
-
-import java.io.IOException;
-import java.util.Arrays;
-
-import javax.security.auth.callback.Callback;
-import javax.security.auth.callback.CallbackHandler;
-import javax.security.auth.callback.NameCallback;
-import javax.security.auth.callback.PasswordCallback;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.eclipse.core.runtime.IProgressMonitor;
-import org.eclipse.core.runtime.NullProgressMonitor;
-import org.eclipse.jface.dialogs.IDialogConstants;
-import org.eclipse.jface.dialogs.TrayDialog;
-import org.eclipse.jface.operation.IRunnableWithProgress;
-import org.eclipse.jface.operation.ModalContext;
-import org.eclipse.swt.events.SelectionEvent;
-import org.eclipse.swt.events.SelectionListener;
-import org.eclipse.swt.widgets.Button;
-import org.eclipse.swt.widgets.Display;
-import org.eclipse.swt.widgets.Shell;
-import org.osgi.framework.FrameworkUtil;
-
-/** Base for login dialogs */
-public abstract class AbstractLoginDialog extends TrayDialog implements CallbackHandler {
- private static final long serialVersionUID = -8046708963512717709L;
-
- private final static Log log = LogFactory.getLog(AbstractLoginDialog.class);
-
- private Thread modalContextThread = null;
- boolean processCallbacks = false;
- boolean isCancelled = false;
- Callback[] callbackArray;
-
- protected final Callback[] getCallbacks() {
- return this.callbackArray;
- }
-
- public abstract void internalHandle();
-
- public boolean isCancelled() {
- return isCancelled;
- }
-
- protected AbstractLoginDialog(Shell parentShell) {
- super(parentShell);
- }
-
- /*
- * (non-Javadoc)
- *
- * @see
- * javax.security.auth.callback.CallbackHandler#handle(javax.security.auth
- * .callback.Callback[])
- */
- public void handle(final Callback[] callbacks) throws IOException {
- // clean previous usage
- if (processCallbacks) {
- // this handler was already used
- processCallbacks = false;
- }
-
- if (modalContextThread != null) {
- try {
- modalContextThread.join(1000);
- } catch (InterruptedException e) {
- // silent
- }
- modalContextThread = null;
- }
-
- // initialize
- this.callbackArray = callbacks;
- final Display display = Display.getDefault();
- display.syncExec(new Runnable() {
-
- public void run() {
- isCancelled = false;
- setBlockOnOpen(false);
- open();
-
- final Button okButton = getButton(IDialogConstants.OK_ID);
- okButton.setText("Login");
- okButton.addSelectionListener(new SelectionListener() {
- private static final long serialVersionUID = -200281625679096775L;
-
- public void widgetSelected(final SelectionEvent event) {
- processCallbacks = true;
- }
-
- public void widgetDefaultSelected(final SelectionEvent event) {
- // nothing to do
- }
- });
- final Button cancel = getButton(IDialogConstants.CANCEL_ID);
- cancel.addSelectionListener(new SelectionListener() {
- private static final long serialVersionUID = -3826030278084915815L;
-
- public void widgetSelected(final SelectionEvent event) {
- isCancelled = true;
- processCallbacks = true;
- }
-
- public void widgetDefaultSelected(final SelectionEvent event) {
- // nothing to do
- }
- });
- }
- });
- try {
- ModalContext.setAllowReadAndDispatch(true); // Works for now.
- ModalContext.run(new IRunnableWithProgress() {
-
- public void run(final IProgressMonitor monitor) {
- modalContextThread = Thread.currentThread();
- // Wait here until OK or cancel is pressed, then let it rip.
- // The event
- // listener
- // is responsible for closing the dialog (in the
- // loginSucceeded
- // event).
- while (!processCallbacks && (modalContextThread != null)
- && (modalContextThread == Thread.currentThread())
- && FrameworkUtil.getBundle(AbstractLoginDialog.class).getBundleContext() != null) {
- // Note: SecurityUiPlugin.getDefault() != null is false
- // when the OSGi runtime is shut down
- try {
- Thread.sleep(100);
- // if (display.isDisposed()) {
- // log.warn("Display is disposed, killing login
- // dialog thread");
- // throw new ThreadDeath();
- // }
- } catch (final Exception e) {
- // do nothing
- }
- }
- processCallbacks = false;
- // Call the adapter to handle the callbacks
- if (!isCancelled())
- internalHandle();
- else
- // clear callbacks are when cancelling
- for (Callback callback : callbacks)
- if (callback instanceof PasswordCallback) {
- char[] arr = ((PasswordCallback) callback).getPassword();
- if (arr != null) {
- Arrays.fill(arr, '*');
- ((PasswordCallback) callback).setPassword(null);
- }
- } else if (callback instanceof NameCallback)
- ((NameCallback) callback).setName(null);
- }
- }, true, new NullProgressMonitor(), Display.getDefault());
- } catch (ThreadDeath e) {
- isCancelled = true;
- log.debug("Thread " + Thread.currentThread().getId() + " died");
- throw e;
- } catch (Exception e) {
- isCancelled = true;
- IOException ioe = new IOException("Unexpected issue in login dialog, see root cause for more details");
- ioe.initCause(e);
- throw ioe;
- } finally {
- // so that the modal thread dies
- processCallbacks = true;
- // try {
- // // wait for the modal context thread to gracefully exit
- // modalContextThread.join();
- // } catch (InterruptedException ie) {
- // // silent
- // }
- modalContextThread = null;
- }
- }
-
- protected void configureShell(Shell shell) {
- super.configureShell(shell);
- shell.setText("Authentication");
- }
-}