diff options
author | Omair Majid <[email protected]> | 2010-10-22 10:44:12 -0400 |
---|---|---|
committer | Omair Majid <[email protected]> | 2010-10-22 10:44:12 -0400 |
commit | 12747b34f31cfb98c057f45e8aeb1711ea7341c8 (patch) | |
tree | 45b4d70163f9f19f014017bf33d0adaf725e03a6 /netx/net/sourceforge/jnlp/security | |
parent | 61aeaaf89164aa93280527c7eb80cf4c1432fbee (diff) |
show security dialogs using the main AppContext
2010-10-22 Omair Majid <[email protected]>
* netx/net/sourceforge/jnlp/NetxPanel.java
(runLoader): Do not initialize JNLPRuntime here.
(createAppletThreads): Initialize JNLPRuntim here.
* netx/net/sourceforge/jnlp/runtime/ApplicationInstance.java:
Switch from SecurityWarningDialog.AccessType to
SecurityWarning.AccessType.
* netx/net/sourceforge/jnlp/runtime/JNLPClassLoader.java
(getInstance(JNLPFile,UpdatePolicy)): Switch to SecurityWarning.
(initializeResources): Likewise.
(checkTrustWithUser): Likewise.
* netx/net/sourceforge/jnlp/runtime/JNLPRuntime.java:
Add securityDialogMesasgeHandler.
(initialize): Set System look and feel. Start security thread.
(startSecurityThread): New method. Starts a thread to show security
dialogs.
(getSecurityDialogHandler): Returns the securityDialogMessageHandler.
* netx/net/sourceforge/jnlp/runtime/JNLPSecurityManager.java:
Switch from SecurityWarningDialog.AccessType to
SecurityWarning.AccessType.
(checkAwtEventQueueAccess): New method. Skeleton code for allowing
EventQueue acccess to applets.
* netx/net/sourceforge/jnlp/security/AccessWarningPane.java:
Switch from SecurityWarningDialog.AccessType to
SecurityWarning.AccessType.
* netx/net/sourceforge/jnlp/security/CertWarningPane.java:
Likewise.
* netx/net/sourceforge/jnlp/security/SecurityWarningDialog.java:
Move DialogType and AccessType to SecurityWarning.
(SecurityWarningDialog(DialogType,AccessType,JNLPFile,CertVerifier,
X509Certificate,Object[])): New method. The catch-all construction.
(SecurityWarningDialog(DialogType,AccessType,JNLPFile): Delegate to
the new constructor.
(SecurityWarningDialog(DialogType,AccessType,JNLPFile,CertVerifier)):
Likewise.
(SecurityWarningDialog(DialogType,AccessType,CertVerifier)): Likewise.
(SecurityWarningDialog(DialogType,AccessType,JNLPFile,Object[])):
Likewise.
(SecurityWarningDialog(DialogType,X509Certificate)): Likewise.
(showAccessWarningDialog(AccessType,JNLPFile)): Move to SecurityWarning
class.
(showAccessWarningDialog(AccessType,JNLPFile,Object[])): Likewise.
(showNotAllSignedWarningDialog(JNLPFile)): Likewise.
(showCertWarningDialog(AccessType,JNLPFile,CertVerifier)): Likewise.
(showAppletWarning): Likewise.
(initDialog): Make dialog non modal and remove window closing listener.
(getValue): Make public.
(dispose): New method. Notify listeners.
(notifySelectionMade): New method. Notify listeners that user has made
a decision.
(addActionListener): New method. Add a listener to be notified when
user makes a decision about this security warning.
* netx/net/sourceforge/jnlp/security/VariableX509TrustManager.java:
Switch from SecurityWarningDialog.AccessType to
SecurityWarning.AccessType.
* netx/net/sourceforge/jnlp/services/ServiceUtil.java: Likewise.
* netx/net/sourceforge/jnlp/services/XClipboardService.java: Likewise.
* netx/net/sourceforge/jnlp/services/XExtendedService.java: Likewise.
* netx/net/sourceforge/jnlp/services/XFileOpenService.java: Likewise.
* netx/net/sourceforge/jnlp/services/XFileSaveService.java: Likewise.
* netx/net/sourceforge/jnlp/security/SecurityDialogMessage.java:
New class.
* netx/net/sourceforge/jnlp/security/SecurityDialogMessageHandler.java:
New class.
(run): New method. Runs the security message loop.
(handleMessage): New method. Handles a SecurityDialogMessage to show a
security warning.
(postMessage): New method. Posts a message to sthe security message
queue.
* netx/net/sourceforge/jnlp/security/SecurityWarning.java: New class.
Move AccessType and DialogType from SecurityWarningDialog to here.
(showAccessWarningDialog): Moved from SecurityWarningDialog to here.
(showAccessWarningDialog): Moved from SecurityWarningDialog to here.
Modified to post messages to the security queue instead of showing a
SecurityWarningDialog directly.
(showNotAllSignedWarningDialog): Likewise.
(showCertWarningDialog): Likewise.
(showAppletWarning): Likewise.
(getUserReponse): New method. Posts a message to the security thread and
blocks until it gets a response from the user.
Diffstat (limited to 'netx/net/sourceforge/jnlp/security')
7 files changed, 570 insertions, 191 deletions
diff --git a/netx/net/sourceforge/jnlp/security/AccessWarningPane.java b/netx/net/sourceforge/jnlp/security/AccessWarningPane.java index 5afbfff..64c7727 100644 --- a/netx/net/sourceforge/jnlp/security/AccessWarningPane.java +++ b/netx/net/sourceforge/jnlp/security/AccessWarningPane.java @@ -56,6 +56,7 @@ import javax.swing.JPanel; import javax.swing.SwingConstants; import net.sourceforge.jnlp.JNLPFile; +import net.sourceforge.jnlp.security.SecurityWarning.AccessType; import net.sourceforge.jnlp.util.FileUtils; /** @@ -86,7 +87,7 @@ public class AccessWarningPane extends SecurityDialogPanel { * Creates the actual GUI components, and adds it to this panel */ private void addComponents() { - SecurityWarningDialog.AccessType type = parent.getAccessType(); + AccessType type = parent.getAccessType(); JNLPFile file = parent.getFile(); String name = ""; diff --git a/netx/net/sourceforge/jnlp/security/CertWarningPane.java b/netx/net/sourceforge/jnlp/security/CertWarningPane.java index 59559c4..163c20c 100644 --- a/netx/net/sourceforge/jnlp/security/CertWarningPane.java +++ b/netx/net/sourceforge/jnlp/security/CertWarningPane.java @@ -60,6 +60,7 @@ import javax.swing.SwingConstants; import net.sourceforge.jnlp.JNLPFile; import net.sourceforge.jnlp.PluginBridge; import net.sourceforge.jnlp.runtime.JNLPRuntime; +import net.sourceforge.jnlp.security.SecurityWarning.AccessType; import net.sourceforge.jnlp.tools.KeyTool; /** @@ -85,7 +86,7 @@ public class CertWarningPane extends SecurityDialogPanel { * Creates the actual GUI components, and adds it to this panel */ private void addComponents() { - SecurityWarningDialog.AccessType type = parent.getAccessType(); + AccessType type = parent.getAccessType(); JNLPFile file = parent.getFile(); Certificate c = parent.getJarSigner().getPublisher(); diff --git a/netx/net/sourceforge/jnlp/security/SecurityDialogMessage.java b/netx/net/sourceforge/jnlp/security/SecurityDialogMessage.java new file mode 100644 index 0000000..c958fff --- /dev/null +++ b/netx/net/sourceforge/jnlp/security/SecurityDialogMessage.java @@ -0,0 +1,44 @@ +package net.sourceforge.jnlp.security; + +import java.security.cert.X509Certificate; +import java.util.concurrent.Semaphore; + +import javax.swing.JDialog; + +import net.sourceforge.jnlp.JNLPFile; +import net.sourceforge.jnlp.security.SecurityWarning.AccessType; +import net.sourceforge.jnlp.security.SecurityWarning.DialogType; + +/** + * Represents a message to the security framework to show a specific security + * dialog + */ +final class SecurityDialogMessage { + + /* + * These fields contain information need to display the correct dialog type + */ + + public DialogType dialogType; + public AccessType accessType; + public JNLPFile file; + public CertVerifier certVerifier; + public X509Certificate certificate; + public Object[] extras; + + /* + * Volatile because this is shared between threads and we dont want threads + * to use a cached value of this. + */ + public volatile Object userResponse; + + /* + * These two fields are used to block/unblock the application or the applet. + * If either of them is not null, call release() or dispose() on it to allow + * the application/applet to continue. + */ + + public Semaphore lock; + public JDialog toDispose; + +} diff --git a/netx/net/sourceforge/jnlp/security/SecurityDialogMessageHandler.java b/netx/net/sourceforge/jnlp/security/SecurityDialogMessageHandler.java new file mode 100644 index 0000000..7beca96 --- /dev/null +++ b/netx/net/sourceforge/jnlp/security/SecurityDialogMessageHandler.java @@ -0,0 +1,141 @@ +/* SecurityDialogMessageHandler.java + Copyright (C) 2010 Red Hat, Inc. + +This file is part of IcedTea. + +IcedTea is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License as published by +the Free Software Foundation, version 2. + +IcedTea is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with IcedTea; see the file COPYING. If not, write to +the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. +*/ + +package net.sourceforge.jnlp.security; + +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.LinkedBlockingQueue; + +import sun.awt.AppContext; + +import net.sourceforge.jnlp.runtime.JNLPRuntime; + +/** + * Handles {@link SecurityDialogMessage}s and shows appropriate security + * dialogs. + * <p> + * In the current architecture, {@link SecurityWarningDialog}s are shown from a + * different {@link AppContext} than the {@link AppContext} that asks for a + * security prompt. This ensures that all security prompts are isolated and + * their Look and Feel is not affected by the Look and Feel of the + * applet/application. + * <p> + * This class contains allows a client application to post a + * {@link SecurityDialogMessage}. When this class finds a security message in + * the queue, it shows a security warning to the user, and sets + * {@link SecurityDialogMessage#userResponse} to the appropriate value. + */ +public final class SecurityDialogMessageHandler implements Runnable { + + /** the queue of incoming messages to show security dialogs */ + private BlockingQueue<SecurityDialogMessage> queue = new LinkedBlockingQueue<SecurityDialogMessage>(); + + /** + * Runs the message handler loop. This waits for incoming security messages + * and shows a security dialog. + */ + @Override + public void run() { + if (JNLPRuntime.isDebug()) { + System.out.println("Starting security dialog thread"); + } + while (true) { + try { + SecurityDialogMessage msg = queue.take(); + handleMessage(msg); + } catch (InterruptedException e) { + } + } + } + + /** + * Handles a single {@link SecurityDialogMessage} by showing a + * {@link SecurityWarningDialog}. + * <p> + * Once the user has made a choice the + * {@link SecurityDialogMessage#toDispose} (if not null) is disposed and + * {@link SecurityDialogMessage#lock} (in not null) is released. + * + * @param message the message indicating what type of security dialog to + * show + */ + private void handleMessage(SecurityDialogMessage message) { + final SecurityDialogMessage msg = message; + + final SecurityWarningDialog dialog = new SecurityWarningDialog(message.dialogType, + message.accessType, message.file, message.certVerifier, message.certificate, message.extras); + + dialog.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + msg.userResponse = dialog.getValue(); + /* Allow the client to continue on the other side */ + if (msg.toDispose != null) { + msg.toDispose.dispose(); + } + if (msg.lock != null) { + msg.lock.release(); + } + } + }); + dialog.setVisible(true); + + } + + /** + * Post a message to the security event queue. This message will be picked + * up by the security thread and used to show the appropriate security + * dialog. + * <p> + * Once the user has made a choice the + * {@link SecurityDialogMessage#toDispose} (if not null) is disposed and + * {@link SecurityDialogMessage#lock} (in not null) is released. + * + * @param message indicates the type of security dialog to show + */ + public void postMessage(SecurityDialogMessage message) { + try { + queue.put(message); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + +} diff --git a/netx/net/sourceforge/jnlp/security/SecurityWarning.java b/netx/net/sourceforge/jnlp/security/SecurityWarning.java new file mode 100644 index 0000000..54ffc31 --- /dev/null +++ b/netx/net/sourceforge/jnlp/security/SecurityWarning.java @@ -0,0 +1,298 @@ +/* SecurityWarningDialogFactory.java + Copyright (C) 2010 Red Hat, Inc. + +This file is part of IcedTea. + +IcedTea is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License as published by +the Free Software Foundation, version 2. + +IcedTea is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with IcedTea; see the file COPYING. If not, write to +the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. +*/ + + +package net.sourceforge.jnlp.security; + +import java.awt.Dialog.ModalityType; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.util.concurrent.Semaphore; + +import javax.swing.JDialog; +import javax.swing.SwingUtilities; + +import net.sourceforge.jnlp.JNLPFile; +import net.sourceforge.jnlp.runtime.JNLPRuntime; + +/** + * A factory for showing many possible types of security warning to the user.<p> + * + * This contains all the public methods that classes outside this package should + * use instead of using {@link SecurityWarningDialog} directly. + * + * All of these methods post a message to the + * {@link SecurityDialogMessageHandler} and block waiting for a response. + */ +public class SecurityWarning { + /** Types of dialogs we can create */ + public static enum DialogType { + CERT_WARNING, + MORE_INFO, + CERT_INFO, + SINGLE_CERT_INFO, + ACCESS_WARNING, + NOTALLSIGNED_WARNING, + APPLET_WARNING + } + + /** The types of access which may need user permission. */ + public static enum AccessType { + READ_FILE, + WRITE_FILE, + CREATE_DESTKOP_SHORTCUT, + CLIPBOARD_READ, + CLIPBOARD_WRITE, + PRINTER, + NETWORK, + VERIFIED, + UNVERIFIED, + NOTALLSIGNED, + SIGNING_ERROR + } + + /** + * Shows a warning dialog for different types of system access (i.e. file + * open/save, clipboard read/write, printing, etc). + * + * @param accessType the type of system access requested. + * @param file the jnlp file associated with the requesting application. + * @return true if permission was granted by the user, false otherwise. + */ + public static boolean showAccessWarningDialog(AccessType accessType, JNLPFile file) { + return showAccessWarningDialog(accessType, file, null); + } + + /** + * Shows a warning dialog for different types of system access (i.e. file + * open/save, clipboard read/write, printing, etc). + * + * @param accessType the type of system access requested. + * @param file the jnlp file associated with the requesting application. + * @param extras an optional array of Strings (typically) that gets + * passed to the dialog labels. + * @return true if permission was granted by the user, false otherwise. + */ + public static boolean showAccessWarningDialog(final AccessType accessType, + final JNLPFile file, final Object[] extras) { + final SecurityDialogMessage message = new SecurityDialogMessage(); + + message.dialogType = DialogType.ACCESS_WARNING; + message.accessType = accessType; + message.file = file; + message.extras = extras; + + Object selectedValue = getUserResponse(message); + + if (selectedValue == null) { + return false; + } else if (selectedValue instanceof Integer) { + if (((Integer) selectedValue).intValue() == 0) + return true; + else + return false; + } else { + return false; + } + } + + /** + * Shows a warning dialog for when the main application jars are signed, + * but extensions aren't + * + * @return true if permission was granted by the user, false otherwise. + */ + public static boolean showNotAllSignedWarningDialog(JNLPFile file) { + + final SecurityDialogMessage message = new SecurityDialogMessage(); + message.dialogType = DialogType.NOTALLSIGNED_WARNING; + message.accessType = AccessType.NOTALLSIGNED; + message.file = file; + message.extras = new Object[0]; + + Object selectedValue = getUserResponse(message); + + if (selectedValue == null) { + return false; + } else if (selectedValue instanceof Integer) { + if (((Integer)selectedValue).intValue() == 0) { + return true; + } else { + return false; + } + } else { + return false; + } + } + + /** + * Shows a security warning dialog according to the specified type of + * access. If <code>type</code> is one of AccessType.VERIFIED or + * AccessType.UNVERIFIED, extra details will be available with regards + * to code signing and signing certificates. + * + * @param accessType the type of warning dialog to show + * @param file the JNLPFile associated with this warning + * @param jarSigner the JarSigner used to verify this application + */ + public static boolean showCertWarningDialog(AccessType accessType, + JNLPFile file, CertVerifier jarSigner) { + + final SecurityDialogMessage message = new SecurityDialogMessage(); + message.dialogType = DialogType.CERT_WARNING; + message.accessType = accessType; + message.file = file; + message.certVerifier = jarSigner; + + Object selectedValue = getUserResponse(message); + + if (selectedValue == null) { + return false; + } else if (selectedValue instanceof Integer) { + if (((Integer) selectedValue).intValue() == 0) + return true; + else + return false; + } else { + return false; + } + } + + /** + * FIXME This is unused. Remove it? + * @return (0, 1, 2) => (Yes, No, Cancel) + */ + public static int showAppletWarning() { + + SecurityDialogMessage message = new SecurityDialogMessage(); + message.dialogType = DialogType.APPLET_WARNING; + + Object selectedValue = getUserResponse(message); + + // result 0 = Yes, 1 = No, 2 = Cancel + if (selectedValue == null) { + return 2; + } else if (selectedValue instanceof Integer) { + return ((Integer) selectedValue).intValue(); + } else { + return 2; + } + } + + /** + * Posts the message to the SecurityThread and gets the response. Blocks + * until a response has been recieved. It's safe to call this from an + * EventDispatchThread. + * + * @param message the SecuritDialogMessage indicating what type of dialog to + * display + * @return The user's response. Can be null. The exact answer depends on the + * type of message, but generally an Integer corresponding to the value 0 + * indicates success/proceed, and everything else indicates failure + */ + private static Object getUserResponse(final SecurityDialogMessage message) { + /* + * Want to show a security warning, while blocking the client + * application. This would be easy except there is a bug in showing + * modal JDialogs in a different AppContext. The source EventQueue - + * that sends the message to the (destination) EventQueue which is + * supposed to actually show the dialog - must not block. If the source + * EventQueue blocks, the destination EventQueue stops responding. So we + * have a hack here to work around it. + */ + + /* + * If this is the event dispatch thread the use the hack + */ + if (SwingUtilities.isEventDispatchThread()) { + /* + * Create a tiny modal dialog (which creates a new EventQueue for + * this AppContext, but blocks the original client EventQueue) and + * then post the message - this makes the source EventQueue continue + * running - but dot not allow the actual applet/application to + * continue processing + */ + final JDialog fakeDialog = new JDialog(); + fakeDialog.setSize(0, 0); + fakeDialog.setResizable(false); + fakeDialog.setModalityType(ModalityType.APPLICATION_MODAL); + fakeDialog.addWindowListener(new WindowAdapter() { + + @Override + public void windowOpened(WindowEvent e) { + message.toDispose = fakeDialog; + message.lock = null; + AccessController.doPrivileged(new PrivilegedAction<Void>() { + @Override + public Void run() { + JNLPRuntime.getSecurityDialogHandler().postMessage(message); + return null; + } + }); + } + }); + + /* this dialog will be disposed/hidden when the user closes the security prompt */ + fakeDialog.setVisible(true); + } else { + /* + * Otherwise do it the normal way. Post a message to the security + * thread to make it show the security dialog. Wait until it tells us + * to proceed. + */ + message.toDispose = null; + message.lock = new Semaphore(0); + JNLPRuntime.getSecurityDialogHandler().postMessage(message); + + boolean done = false; + while (!done) { + try { + message.lock.acquire(); + done = true; + } catch (InterruptedException e) { + // ignore; retry + } + } + + } + + return message.userResponse; + } + +} diff --git a/netx/net/sourceforge/jnlp/security/SecurityWarningDialog.java b/netx/net/sourceforge/jnlp/security/SecurityWarningDialog.java index 14f5fe0..1937f1c 100644 --- a/netx/net/sourceforge/jnlp/security/SecurityWarningDialog.java +++ b/netx/net/sourceforge/jnlp/security/SecurityWarningDialog.java @@ -39,49 +39,29 @@ package net.sourceforge.jnlp.security; import net.sourceforge.jnlp.JNLPFile; import net.sourceforge.jnlp.runtime.JNLPRuntime; +import net.sourceforge.jnlp.security.SecurityWarning.AccessType; +import net.sourceforge.jnlp.security.SecurityWarning.DialogType; import java.awt.*; import javax.swing.*; import java.awt.event.*; - import java.security.cert.X509Certificate; +import java.util.concurrent.CopyOnWriteArrayList; + +import java.util.List; /** - * Provides methods for showing security warning dialogs - * for a wide range of JNLP security issues. + * Provides methods for showing security warning dialogs for a wide range of + * JNLP security issues. Note that the security dialogs should be running in the + * secure AppContext - this class should not be used directly from an applet or + * application. See {@link SecurityWarning} for a way to show security dialogs. * * @author <a href="mailto:[email protected]">Joshua Sumali</a> */ public class SecurityWarningDialog extends JDialog { - /** Types of dialogs we can create */ - public static enum DialogType { - CERT_WARNING, - MORE_INFO, - CERT_INFO, - SINGLE_CERT_INFO, - ACCESS_WARNING, - NOTALLSIGNED_WARNING, - APPLET_WARNING - } - - /** The types of access which may need user permission. */ - public static enum AccessType { - READ_FILE, - WRITE_FILE, - CREATE_DESTKOP_SHORTCUT, - CLIPBOARD_READ, - CLIPBOARD_WRITE, - PRINTER, - NETWORK, - VERIFIED, - UNVERIFIED, - NOTALLSIGNED, - SIGNING_ERROR - } - /** The type of dialog we want to show */ private DialogType dialogType; @@ -112,168 +92,67 @@ public class SecurityWarningDialog extends JDialog { */ private Object value; - public SecurityWarningDialog(DialogType dialogType, AccessType accessType, - JNLPFile file) { - super(); - this.dialogType = dialogType; - this.accessType = accessType; - this.file = file; - this.certVerifier = null; - initialized = true; - initDialog(); - } - - public SecurityWarningDialog(DialogType dialogType, AccessType accessType, - JNLPFile file, CertVerifier jarSigner) { - super(); - this.dialogType = dialogType; - this.accessType = accessType; - this.file = file; - this.certVerifier = jarSigner; - initialized = true; - initDialog(); - } - - public SecurityWarningDialog(DialogType dialogType, AccessType accessType, - CertVerifier certVerifier) { + SecurityWarningDialog(DialogType dialogType, AccessType accessType, + JNLPFile file, CertVerifier jarSigner, X509Certificate cert, Object[] extras) { super(); this.dialogType = dialogType; this.accessType = accessType; - this.file = null; - this.certVerifier = certVerifier; + this.file = file; + this.certVerifier = jarSigner; + this.cert = cert; + this.extras = extras; initialized = true; - initDialog(); - } - public SecurityWarningDialog(DialogType dialogType, AccessType accessType, - JNLPFile file, Object[] extras) { - super(); - this.dialogType = dialogType; - this.accessType = accessType; - this.file = file; - this.certVerifier = null; - initialized = true; - this.extras = extras; - initDialog(); + initDialog(); } - //for displaying a single certificate - public SecurityWarningDialog(DialogType dialogType, X509Certificate c) { - super(); - this.dialogType = dialogType; - this.accessType = null; - this.file = null; - this.certVerifier = null; - this.cert = c; - initialized = true; - initDialog(); + /** + * Construct a SecurityWarningDialog to display some sort of access warning + */ + SecurityWarningDialog(DialogType dialogType, AccessType accessType, + JNLPFile file) { + this(dialogType, accessType, file, null, null, null); } /** - * Returns if this dialog has been fully initialized yet. - * @return true if this dialog has been initialized, and false otherwise. + * Create a SecurityWarningDialog to display a certificate-related warning */ - public boolean isInitialized(){ - return initialized; + SecurityWarningDialog(DialogType dialogType, AccessType accessType, + JNLPFile file, CertVerifier jarSigner) { + this(dialogType, accessType, file, jarSigner, null, null); } /** - * Shows a warning dialog for different types of system access (i.e. file - * open/save, clipboard read/write, printing, etc). - * - * @param accessType the type of system access requested. - * @param file the jnlp file associated with the requesting application. - * @return true if permission was granted by the user, false otherwise. + * Create a SecurityWarningDialog to display a certificate-related warning */ - public static boolean showAccessWarningDialog(AccessType accessType, - JNLPFile file) { - return showAccessWarningDialog(accessType, file, null); + SecurityWarningDialog(DialogType dialogType, AccessType accessType, + CertVerifier certVerifier) { + this(dialogType, accessType, null, certVerifier, null, null); } /** - * Shows a warning dialog for different types of system access (i.e. file - * open/save, clipboard read/write, printing, etc). - * - * @param accessType the type of system access requested. - * @param file the jnlp file associated with the requesting application. - * @param extras an optional array of Strings (typically) that gets - * passed to the dialog labels. - * @return true if permission was granted by the user, false otherwise. + * Create a SecurityWarningDialog to display some sort of access warning + * with more information */ - public static boolean showAccessWarningDialog(AccessType accessType, + SecurityWarningDialog(DialogType dialogType, AccessType accessType, JNLPFile file, Object[] extras) { - SecurityWarningDialog dialog = new SecurityWarningDialog( - DialogType.ACCESS_WARNING, accessType, file, extras); - dialog.setVisible(true); - dialog.dispose(); - - Object selectedValue = dialog.getValue(); - if (selectedValue == null) { - return false; - } else if (selectedValue instanceof Integer) { - if (((Integer)selectedValue).intValue() == 0) - return true; - else - return false; - } else { - return false; - } - } + this(dialogType, accessType, file, null, null, extras); + } /** - * Shows a warning dialog for when the main application jars are signed, - * but extensions aren't - * - * @return true if permission was granted by the user, false otherwise. + * Create a SecurityWarningDailog to display information about a single + * certificate */ - public static boolean showNotAllSignedWarningDialog(JNLPFile file) { - SecurityWarningDialog dialog = new SecurityWarningDialog( - DialogType.NOTALLSIGNED_WARNING, AccessType.NOTALLSIGNED, file, (new Object[0])); - dialog.setVisible(true); - dialog.dispose(); - - Object selectedValue = dialog.getValue(); - if (selectedValue == null) { - return false; - } else if (selectedValue instanceof Integer) { - if (((Integer)selectedValue).intValue() == 0) - return true; - else - return false; - } else { - return false; - } - } + SecurityWarningDialog(DialogType dialogType, X509Certificate c) { + this(dialogType, null, null, null, c, null); + } /** - * Shows a security warning dialog according to the specified type of - * access. If <code>type</code> is one of AccessType.VERIFIED or - * AccessType.UNVERIFIED, extra details will be available with regards - * to code signing and signing certificates. - * - * @param accessType the type of warning dialog to show - * @param file the JNLPFile associated with this warning - * @param jarSigner the JarSigner used to verify this application + * Returns if this dialog has been fully initialized yet. + * @return true if this dialog has been initialized, and false otherwise. */ - public static boolean showCertWarningDialog(AccessType accessType, - JNLPFile file, CertVerifier jarSigner) { - SecurityWarningDialog dialog = - new SecurityWarningDialog(DialogType.CERT_WARNING, accessType, file, - jarSigner); - dialog.setVisible(true); - dialog.dispose(); - - Object selectedValue = dialog.getValue(); - if (selectedValue == null) { - return false; - } else if (selectedValue instanceof Integer) { - if (((Integer)selectedValue).intValue() == 0) - return true; - else - return false; - } else { - return false; - } + public boolean isInitialized(){ + return initialized; } /** @@ -320,23 +199,7 @@ public class SecurityWarningDialog extends JDialog { dialog.dispose(); } - public static int showAppletWarning() { - SecurityWarningDialog dialog = new SecurityWarningDialog(DialogType.APPLET_WARNING, - null, null, (CertVerifier) null); - dialog.setVisible(true); - dialog.dispose(); - Object selectedValue = dialog.getValue(); - - //result 0 = Yes, 1 = No, 2 = Cancel - if (selectedValue == null) { - return 2; - } else if (selectedValue instanceof Integer) { - return ((Integer)selectedValue).intValue(); - } else { - return 2; - } - } private void initDialog() { setSystemLookAndFeel(); @@ -356,7 +219,7 @@ public class SecurityWarningDialog extends JDialog { dialogTitle = "Security Warning"; setTitle(dialogTitle); - setModal(true); + setModal(false); setDefaultCloseOperation(DISPOSE_ON_CLOSE); @@ -366,10 +229,7 @@ public class SecurityWarningDialog extends JDialog { WindowAdapter adapter = new WindowAdapter() { private boolean gotFocus = false; - @Override - public void windowClosing(WindowEvent we) { - setValue(null); - } + @Override public void windowGainedFocus(WindowEvent we) { // Once window gets focus, set initial focus @@ -454,7 +314,7 @@ public class SecurityWarningDialog extends JDialog { this.value = value; } - protected Object getValue() { + public Object getValue() { if (JNLPRuntime.isDebug()) { System.out.println("Returning value:" + value); } @@ -462,6 +322,16 @@ public class SecurityWarningDialog extends JDialog { } /** + * Called when the SecurityWarningDialog is hidden - either because the user + * made a choice (Ok, Cancel, etc) or closed the window + */ + @Override + public void dispose() { + notifySelectionMade(); + super.dispose(); + } + + /** * Updates the look and feel of the window to be the system look and feel */ protected void setSystemLookAndFeel() { @@ -471,4 +341,26 @@ public class SecurityWarningDialog extends JDialog { //don't worry if we can't. } } + + private List<ActionListener> listeners = new CopyOnWriteArrayList<ActionListener>(); + + /** + * Notify all the listeners that the user has made a decision using this + * security dialog. + */ + public void notifySelectionMade() { + for (ActionListener listener : listeners) { + listener.actionPerformed(null); + } + } + + /** + * Adds an {@link ActionListener} which will be notified if the user makes a + * choice using this SecurityWarningDialog. The listener should use {@link #getValue()} + * to actually get the user's response. + */ + public void addActionListener(ActionListener listener) { + listeners.add(listener); + } + } diff --git a/netx/net/sourceforge/jnlp/security/VariableX509TrustManager.java b/netx/net/sourceforge/jnlp/security/VariableX509TrustManager.java index d5ad6da..5e9c981 100644 --- a/netx/net/sourceforge/jnlp/security/VariableX509TrustManager.java +++ b/netx/net/sourceforge/jnlp/security/VariableX509TrustManager.java @@ -52,6 +52,8 @@ import sun.security.validator.ValidatorException; import com.sun.net.ssl.internal.ssl.X509ExtendedTrustManager; +import net.sourceforge.jnlp.security.SecurityWarning.AccessType; + /** * This class implements an X509 Trust Manager. The certificates it trusts are * "variable", in the sense that it can dynamically, and temporarily support @@ -293,8 +295,8 @@ public class VariableX509TrustManager extends X509ExtendedTrustManager { private boolean askUser(X509Certificate[] chain, String authType, boolean isTrusted, boolean hostMatched, String hostName) { - return SecurityWarningDialog.showCertWarningDialog( - SecurityWarningDialog.AccessType.UNVERIFIED, null, + return SecurityWarning.showCertWarningDialog( + AccessType.UNVERIFIED, null, new HttpsCertVerifier(this, chain, authType, isTrusted, hostMatched, hostName)); |