changeset 13:eb998ed0ab1a

show security dialogs using the main AppContext 2010-10-22 Omair Majid <omajid@redhat.com> * 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.
author Omair Majid <omajid@redhat.com>
date Fri, 22 Oct 2010 10:44:12 -0400
parents 85db7b3a1c93
children e9910d92b046
files ChangeLog netx/net/sourceforge/jnlp/NetxPanel.java netx/net/sourceforge/jnlp/runtime/ApplicationInstance.java netx/net/sourceforge/jnlp/runtime/JNLPClassLoader.java netx/net/sourceforge/jnlp/runtime/JNLPRuntime.java netx/net/sourceforge/jnlp/runtime/JNLPSecurityManager.java netx/net/sourceforge/jnlp/security/AccessWarningPane.java netx/net/sourceforge/jnlp/security/CertWarningPane.java netx/net/sourceforge/jnlp/security/SecurityDialogMessage.java netx/net/sourceforge/jnlp/security/SecurityDialogMessageHandler.java netx/net/sourceforge/jnlp/security/SecurityWarning.java netx/net/sourceforge/jnlp/security/SecurityWarningDialog.java netx/net/sourceforge/jnlp/security/VariableX509TrustManager.java netx/net/sourceforge/jnlp/services/ServiceUtil.java netx/net/sourceforge/jnlp/services/XClipboardService.java netx/net/sourceforge/jnlp/services/XExtendedService.java netx/net/sourceforge/jnlp/services/XFileOpenService.java netx/net/sourceforge/jnlp/services/XFileSaveService.java
diffstat 18 files changed, 778 insertions(+), 246 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog	Thu Oct 21 21:12:21 2010 +0100
+++ b/ChangeLog	Fri Oct 22 10:44:12 2010 -0400
@@ -1,3 +1,85 @@
+2010-10-22  Omair Majid  <omajid@redhat.com>
+
+	* 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.
+
 2010-10-20  Andrew John Hughes  <ahughes@redhat.com>
 
 	* netx/javax/jnlp/ServiceManager.java:
--- a/netx/net/sourceforge/jnlp/NetxPanel.java	Thu Oct 21 21:12:21 2010 +0100
+++ b/netx/net/sourceforge/jnlp/NetxPanel.java	Fri Oct 22 10:44:12 2010 -0400
@@ -84,19 +84,6 @@
                                 getHeight(),
                                 atts);
 
-                synchronized(JNLPRuntime.initMutex) {
-                        //The custom NetX Policy and SecurityManager are set here.
-                        if (!JNLPRuntime.isInitialized()) {
-                            if (JNLPRuntime.isDebug())
-                                System.out.println("initializing JNLPRuntime...");
-
-                                JNLPRuntime.initialize(false);
-                        } else {
-                            if (JNLPRuntime.isDebug())
-                                System.out.println("JNLPRuntime already initialized");
-                        }
-                }
-
                 doInit = true;
                 dispatchAppletEvent(APPLET_LOADING, null);
                 status = APPLET_LOAD;
@@ -146,6 +133,20 @@
      */
     // Reminder: Relax visibility in sun.applet.AppletPanel
     protected synchronized void createAppletThread() {
+        // initialize JNLPRuntime in the main threadgroup
+        synchronized(JNLPRuntime.initMutex) {
+            //The custom NetX Policy and SecurityManager are set here.
+            if (!JNLPRuntime.isInitialized()) {
+                if (JNLPRuntime.isDebug())
+                    System.out.println("initializing JNLPRuntime...");
+
+                    JNLPRuntime.initialize(false);
+            } else {
+                if (JNLPRuntime.isDebug())
+                    System.out.println("JNLPRuntime already initialized");
+            }
+        }
+
         // when this was being done (incorrectly) in Launcher, the call was
         // new AppThreadGroup(mainGroup, file.getTitle());
         ThreadGroup tg = new AppThreadGroup(Launcher.mainGroup,
--- a/netx/net/sourceforge/jnlp/runtime/ApplicationInstance.java	Thu Oct 21 21:12:21 2010 +0100
+++ b/netx/net/sourceforge/jnlp/runtime/ApplicationInstance.java	Fri Oct 22 10:44:12 2010 -0400
@@ -35,7 +35,7 @@
 import net.sourceforge.jnlp.ShortcutDesc;
 import net.sourceforge.jnlp.event.ApplicationEvent;
 import net.sourceforge.jnlp.event.ApplicationListener;
-import net.sourceforge.jnlp.security.SecurityWarningDialog.AccessType;
+import net.sourceforge.jnlp.security.SecurityWarning.AccessType;
 import net.sourceforge.jnlp.services.ServiceUtil;
 import net.sourceforge.jnlp.util.WeakList;
 import net.sourceforge.jnlp.util.XDesktopEntry;
--- a/netx/net/sourceforge/jnlp/runtime/JNLPClassLoader.java	Thu Oct 21 21:12:21 2010 +0100
+++ b/netx/net/sourceforge/jnlp/runtime/JNLPClassLoader.java	Fri Oct 22 10:44:12 2010 -0400
@@ -57,7 +57,8 @@
 import net.sourceforge.jnlp.cache.CacheUtil;
 import net.sourceforge.jnlp.cache.ResourceTracker;
 import net.sourceforge.jnlp.cache.UpdatePolicy;
-import net.sourceforge.jnlp.security.SecurityWarningDialog;
+import net.sourceforge.jnlp.security.SecurityWarning;
+import net.sourceforge.jnlp.security.SecurityWarning.AccessType;
 import net.sourceforge.jnlp.tools.JarSigner;
 import net.sourceforge.jnlp.util.FileUtils;
 import sun.misc.JarIndex;
@@ -292,7 +293,7 @@
 
                         if (extLoader != null && extLoader != loader) {
                             if (loader.signing && !extLoader.signing)
-                                if (!SecurityWarningDialog.showNotAllSignedWarningDialog(file))
+                                if (!SecurityWarning.showNotAllSignedWarningDialog(file))
                                     throw new LaunchException(file, null, R("LSFatal"), R("LCClient"), R("LSignedAppJarUsingUnsignedJar"), R("LSignedAppJarUsingUnsignedJarInfo"));
 
                                 loader.merge(extLoader);
@@ -439,7 +440,7 @@
                                 signing = true;
 
                                 if (!js.allJarsSigned() &&
-                                    !SecurityWarningDialog.showNotAllSignedWarningDialog(file))
+                                    !SecurityWarning.showNotAllSignedWarningDialog(file))
                                     throw new LaunchException(file, null, R("LSFatal"), R("LCClient"), R("LSignedAppJarUsingUnsignedJar"), R("LSignedAppJarUsingUnsignedJarInfo"));
 
 
@@ -493,19 +494,19 @@
 
     private void checkTrustWithUser(JarSigner js) throws LaunchException {
         if (!js.getRootInCacerts()) { //root cert is not in cacerts
-            boolean b = SecurityWarningDialog.showCertWarningDialog(
-                SecurityWarningDialog.AccessType.UNVERIFIED, file, js);
+            boolean b = SecurityWarning.showCertWarningDialog(
+                AccessType.UNVERIFIED, file, js);
             if (!b)
                 throw new LaunchException(null, null, R("LSFatal"),
                     R("LCLaunching"), R("LNotVerified"), "");
         } else if (js.getRootInCacerts()) { //root cert is in cacerts
             boolean b = false;
             if (js.noSigningIssues())
-                b = SecurityWarningDialog.showCertWarningDialog(
-                        SecurityWarningDialog.AccessType.VERIFIED, file, js);
+                b = SecurityWarning.showCertWarningDialog(
+                        AccessType.VERIFIED, file, js);
             else if (!js.noSigningIssues())
-                b = SecurityWarningDialog.showCertWarningDialog(
-                        SecurityWarningDialog.AccessType.SIGNING_ERROR, file, js);
+                b = SecurityWarning.showCertWarningDialog(
+                        AccessType.SIGNING_ERROR, file, js);
             if (!b)
                 throw new LaunchException(null, null, R("LSFatal"),
                     R("LCLaunching"), R("LCancelOnUserRequest"), "");
--- a/netx/net/sourceforge/jnlp/runtime/JNLPRuntime.java	Thu Oct 21 21:12:21 2010 +0100
+++ b/netx/net/sourceforge/jnlp/runtime/JNLPRuntime.java	Fri Oct 22 10:44:12 2010 -0400
@@ -25,9 +25,11 @@
 import java.util.List;
 import java.security.*;
 import javax.jnlp.*;
+import javax.swing.UIManager;
 
 import net.sourceforge.jnlp.*;
 import net.sourceforge.jnlp.cache.*;
+import net.sourceforge.jnlp.security.SecurityDialogMessageHandler;
 import net.sourceforge.jnlp.services.*;
 import net.sourceforge.jnlp.util.*;
 
@@ -63,6 +65,9 @@
     /** the security policy */
     private static JNLPPolicy policy;
 
+    /** handles all security message to show appropriate security dialogs */
+    private static SecurityDialogMessageHandler securityDialogMessageHandler;
+
     /** the base dir for cache, etc */
     private static File baseDir;
 
@@ -165,6 +170,8 @@
      * security manager and security policy, initializing the JNLP
      * standard services, etc.<p>
      *
+     * This method should be called from the main AppContext/Thread. <p>
+     *
      * This method cannot be called more than once.  Once
      * initialized, methods that alter the runtime can only be
      * called by the exit class.<p>
@@ -206,15 +213,40 @@
         policy = new JNLPPolicy();
         security = new JNLPSecurityManager(); // side effect: create JWindow
 
+        try {
+            UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
+        } catch (Exception e) {
+            // ignore it
+        }
+
         if (securityEnabled) {
             Policy.setPolicy(policy); // do first b/c our SM blocks setPolicy
             System.setSecurityManager(security);
         }
 
+        securityDialogMessageHandler = startSecurityThreads();
+
         initialized = true;
     }
 
     /**
+     * This must NOT be called form the application ThreadGroup. An application
+     * can inject events into its {@link EventQueue} and bypass the security
+     * dialogs.
+     *
+     * @return a {@link SecurityDialogMessageHandler} that can be used to post
+     * security messages
+     */
+    private static SecurityDialogMessageHandler startSecurityThreads() {
+        ThreadGroup securityThreadGroup = new ThreadGroup("NetxSecurityThreadGroup");
+        SecurityDialogMessageHandler runner = new SecurityDialogMessageHandler();
+        Thread securityThread = new Thread(securityThreadGroup, runner, "NetxSecurityThread");
+        securityThread.setDaemon(true);
+        securityThread.start();
+        return runner;
+    }
+
+    /**
      * Returns true if a webstart application has been initialized, and false
      * for a plugin applet.
      */
@@ -321,6 +353,19 @@
     }
 
     /**
+     *
+     * @return the {@link SecurityDialogMessageHandler} that should be used to
+     * post security dialog messages
+     */
+    public static SecurityDialogMessageHandler getSecurityDialogHandler() {
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            sm.checkPermission(new AllPermission());
+        }
+        return securityDialogMessageHandler;
+    }
+
+    /**
      * Returns the system default base dir for or if not set,
      * prompts the user for the location.
      *
--- a/netx/net/sourceforge/jnlp/runtime/JNLPSecurityManager.java	Thu Oct 21 21:12:21 2010 +0100
+++ b/netx/net/sourceforge/jnlp/runtime/JNLPSecurityManager.java	Fri Oct 22 10:44:12 2010 -0400
@@ -34,7 +34,7 @@
 import javax.swing.JWindow;
 
 import net.sourceforge.jnlp.JNLPFile;
-import net.sourceforge.jnlp.security.SecurityWarningDialog;
+import net.sourceforge.jnlp.security.SecurityWarning.AccessType;
 import net.sourceforge.jnlp.services.ServiceUtil;
 import net.sourceforge.jnlp.util.WeakList;
 import sun.awt.AWTSecurityManager;
@@ -393,7 +393,7 @@
         ApplicationInstance app = getApplication();
         if (app != null && !app.isSigned()) {
                 if (perm instanceof SocketPermission
-                                && ServiceUtil.checkAccess(SecurityWarningDialog.AccessType.NETWORK, perm.getName())) {
+                                && ServiceUtil.checkAccess(AccessType.NETWORK, perm.getName())) {
                         return true;
                 }
         }
@@ -435,7 +435,7 @@
             Window w = (Window) window;
 
             if (JNLPRuntime.isDebug())
-                System.err.println("SM: app: "+app.getTitle()+" is adding a window: "+window);
+                System.err.println("SM: app: "+app.getTitle()+" is adding a window: "+window+" with appContext "+AppContext.getAppContext());
 
             weakWindows.add(w); // for mapping window -> app
             weakApplications.add(app);
@@ -539,4 +539,31 @@
 
     }
 
+    /**
+     * Tests if a client can get access to the AWT event queue. This version allows
+     * complete access to the EventQueue for its own AppContext-specific EventQueue.
+     *
+     * FIXME there are probably huge security implications for this. Eg:
+     * http://hg.openjdk.java.net/jdk7/awt/jdk/rev/8022709a306d
+     *
+     * @exception  SecurityException  if the caller does not have
+     *             permission to accesss the AWT event queue.
+     */
+    public void checkAwtEventQueueAccess() {
+        /*
+         * this is the templace of the code that should allow applets access to
+         * eventqueues
+         */
+
+        // AppContext appContext = AppContext.getAppContext();
+        // ApplicationInstance instance = getApplication();
+
+        // if ((appContext == mainAppContext) && (instance != null)) {
+        // If we're about to allow access to the main EventQueue,
+        // and anything untrusted is on the class context stack,
+        // disallow access.
+        super.checkAwtEventQueueAccess();
+        // }
+    }
+
 }
--- a/netx/net/sourceforge/jnlp/security/AccessWarningPane.java	Thu Oct 21 21:12:21 2010 +0100
+++ b/netx/net/sourceforge/jnlp/security/AccessWarningPane.java	Fri Oct 22 10:44:12 2010 -0400
@@ -56,6 +56,7 @@
 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 @@
          * 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 = "";
--- a/netx/net/sourceforge/jnlp/security/CertWarningPane.java	Thu Oct 21 21:12:21 2010 +0100
+++ b/netx/net/sourceforge/jnlp/security/CertWarningPane.java	Fri Oct 22 10:44:12 2010 -0400
@@ -60,6 +60,7 @@
 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 @@
          * 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();
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/netx/net/sourceforge/jnlp/security/SecurityDialogMessage.java	Fri Oct 22 10:44:12 2010 -0400
@@ -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;
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/netx/net/sourceforge/jnlp/security/SecurityDialogMessageHandler.java	Fri Oct 22 10:44:12 2010 -0400
@@ -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();
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/netx/net/sourceforge/jnlp/security/SecurityWarning.java	Fri Oct 22 10:44:12 2010 -0400
@@ -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;
+    }
+
+}
--- a/netx/net/sourceforge/jnlp/security/SecurityWarningDialog.java	Thu Oct 21 21:12:21 2010 +0100
+++ b/netx/net/sourceforge/jnlp/security/SecurityWarningDialog.java	Fri Oct 22 10:44:12 2010 -0400
@@ -39,49 +39,29 @@
 
 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.security.cert.X509Certificate;
+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:jsumali@redhat.com">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,61 +92,59 @@
      */
         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();
+        /**
+         * Construct a SecurityWarningDialog to display some sort of access warning
+         */
+        SecurityWarningDialog(DialogType dialogType, AccessType accessType,
+                        JNLPFile file) {
+            this(dialogType, accessType, file, null, null, null);
+        }
+
+        /**
+         * Create a SecurityWarningDialog to display a certificate-related warning
+         */
+        SecurityWarningDialog(DialogType dialogType, AccessType accessType,
+                        JNLPFile file, CertVerifier jarSigner) {
+            this(dialogType, accessType, file, jarSigner, null, null);
         }
 
-        //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();
+        /**
+         * Create a SecurityWarningDialog to display a certificate-related warning
+         */
+        SecurityWarningDialog(DialogType dialogType, AccessType accessType,
+                CertVerifier certVerifier) {
+            this(dialogType, accessType, null, certVerifier, null, null);
+        }
+
+        /**
+         * Create a SecurityWarningDialog to display some sort of access warning
+         * with more information
+         */
+        SecurityWarningDialog(DialogType dialogType, AccessType accessType,
+                        JNLPFile file, Object[] extras) {
+            this(dialogType, accessType, file, null, null, extras);
+        }
+
+        /**
+         * Create a SecurityWarningDailog to display information about a single
+         * certificate
+         */
+        SecurityWarningDialog(DialogType dialogType, X509Certificate c) {
+            this(dialogType, null, null, null, c, null);
         }
 
         /**
@@ -178,105 +156,6 @@
         }
 
         /**
-         * 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(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;
-                        }
-                }
-
-        /**
-         * 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) {
-                        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;
-                        }
-                }
-
-        /**
-         * 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) {
-                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;
-                }
-        }
-
-        /**
          * Shows more information regarding jar code signing
          *
          * @param jarSigner the JarSigner used to verify this application
@@ -320,23 +199,7 @@
                         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 @@
                         dialogTitle = "Security Warning";
 
                 setTitle(dialogTitle);
-                setModal(true);
+                setModal(false);
 
                 setDefaultCloseOperation(DISPOSE_ON_CLOSE);
 
@@ -366,10 +229,7 @@
 
                 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 @@
         this.value = value;
     }
 
-    protected Object getValue() {
+    public Object getValue() {
         if (JNLPRuntime.isDebug()) {
             System.out.println("Returning value:" + value);
         }
@@ -462,6 +322,16 @@
     }
 
     /**
+     * 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 @@
             //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);
+    }
+
 }
--- a/netx/net/sourceforge/jnlp/security/VariableX509TrustManager.java	Thu Oct 21 21:12:21 2010 +0100
+++ b/netx/net/sourceforge/jnlp/security/VariableX509TrustManager.java	Fri Oct 22 10:44:12 2010 -0400
@@ -52,6 +52,8 @@
 
 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 @@
     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));
--- a/netx/net/sourceforge/jnlp/services/ServiceUtil.java	Thu Oct 21 21:12:21 2010 +0100
+++ b/netx/net/sourceforge/jnlp/services/ServiceUtil.java	Fri Oct 22 10:44:12 2010 -0400
@@ -40,7 +40,8 @@
 import net.sourceforge.jnlp.JNLPFile;
 import net.sourceforge.jnlp.runtime.ApplicationInstance;
 import net.sourceforge.jnlp.runtime.JNLPRuntime;
-import net.sourceforge.jnlp.security.SecurityWarningDialog;
+import net.sourceforge.jnlp.security.SecurityWarning;
+import net.sourceforge.jnlp.security.SecurityWarning.AccessType;
 
 /**
  * Provides static methods to interact useful for using the JNLP
@@ -219,8 +220,7 @@
      * message formatting.
      * @return true if the access was granted, false otherwise.
      */
-    public static boolean checkAccess(SecurityWarningDialog.AccessType type,
-            Object... extras) {
+    public static boolean checkAccess(AccessType type, Object... extras) {
         return checkAccess(null, type, extras);
     }
 
@@ -235,8 +235,7 @@
      * message formatting.
      * @return true if the access was granted, false otherwise.
      */
-    public static boolean checkAccess(ApplicationInstance app,
-            SecurityWarningDialog.AccessType type,
+    public static boolean checkAccess(ApplicationInstance app, AccessType type,
                 Object... extras) {
 
         if (app == null)
@@ -270,7 +269,7 @@
         }
 
         if (!codeTrusted) {
-                final SecurityWarningDialog.AccessType tmpType = type;
+                final AccessType tmpType = type;
                 final Object[] tmpExtras = extras;
                 final ApplicationInstance tmpApp = app;
 
@@ -279,7 +278,7 @@
                 //from resources.jar.
                 Boolean b = AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
                     public Boolean run() {
-                        boolean b = SecurityWarningDialog.showAccessWarningDialog(tmpType,
+                        boolean b = SecurityWarning.showAccessWarningDialog(tmpType,
                                 tmpApp.getJNLPFile(), tmpExtras);
                         return new Boolean(b);
                     }
--- a/netx/net/sourceforge/jnlp/services/XClipboardService.java	Thu Oct 21 21:12:21 2010 +0100
+++ b/netx/net/sourceforge/jnlp/services/XClipboardService.java	Fri Oct 22 10:44:12 2010 -0400
@@ -39,7 +39,7 @@
 
 import javax.jnlp.*;
 
-import net.sourceforge.jnlp.security.SecurityWarningDialog;
+import net.sourceforge.jnlp.security.SecurityWarning.AccessType;
 
 import java.awt.datatransfer.Transferable;
 import java.awt.Toolkit;
@@ -59,7 +59,7 @@
          */
         public java.awt.datatransfer.Transferable getContents(){
 
-                if (ServiceUtil.checkAccess(SecurityWarningDialog.AccessType.CLIPBOARD_READ)) {
+                if (ServiceUtil.checkAccess(AccessType.CLIPBOARD_READ)) {
                         Transferable t = Toolkit.getDefaultToolkit().getSystemClipboard().getContents(null);
                         return (Transferable) ServiceUtil.createPrivilegedProxy(
                                 Transferable.class, t);
@@ -72,7 +72,7 @@
          * Sets the contents of the system clipboard.
          */
         public void setContents(java.awt.datatransfer.Transferable contents) {
-                if (ServiceUtil.checkAccess(SecurityWarningDialog.AccessType.CLIPBOARD_WRITE)) {
+                if (ServiceUtil.checkAccess(AccessType.CLIPBOARD_WRITE)) {
                         Toolkit.getDefaultToolkit().getSystemClipboard().setContents(
                                 contents, null);
                 }
--- a/netx/net/sourceforge/jnlp/services/XExtendedService.java	Thu Oct 21 21:12:21 2010 +0100
+++ b/netx/net/sourceforge/jnlp/services/XExtendedService.java	Fri Oct 22 10:44:12 2010 -0400
@@ -22,7 +22,7 @@
 import javax.jnlp.ExtendedService;
 import javax.jnlp.FileContents;
 
-import net.sourceforge.jnlp.security.SecurityWarningDialog;
+import net.sourceforge.jnlp.security.SecurityWarning.AccessType;
 
 /**
  * Implementation of ExtendedService
@@ -35,8 +35,7 @@
     public FileContents openFile(File file) throws IOException {
 
         /* FIXME: this opens a file with read/write mode, not just read or write */
-        if (ServiceUtil.checkAccess(SecurityWarningDialog.AccessType.READ_FILE,
-                new Object[]{ file.getAbsolutePath() })) {
+        if (ServiceUtil.checkAccess(AccessType.READ_FILE, new Object[]{ file.getAbsolutePath() })) {
             return (FileContents) ServiceUtil.createPrivilegedProxy(FileContents.class,
                     new XFileContents(file));
         } else {
--- a/netx/net/sourceforge/jnlp/services/XFileOpenService.java	Thu Oct 21 21:12:21 2010 +0100
+++ b/netx/net/sourceforge/jnlp/services/XFileOpenService.java	Fri Oct 22 10:44:12 2010 -0400
@@ -45,7 +45,7 @@
 
 import net.sourceforge.jnlp.*;
 import net.sourceforge.jnlp.runtime.*;
-import net.sourceforge.jnlp.security.SecurityWarningDialog;
+import net.sourceforge.jnlp.security.SecurityWarning.AccessType;
 
 import javax.swing.JFileChooser;
 import javax.swing.JOptionPane;
@@ -67,7 +67,7 @@
     public FileContents openFileDialog (java.lang.String pathHint,
         java.lang.String[] extensions) throws java.io.IOException {
 
-        if (ServiceUtil.checkAccess(SecurityWarningDialog.AccessType.READ_FILE)) {
+        if (ServiceUtil.checkAccess(AccessType.READ_FILE)) {
 
             //open a file dialog here, let the user choose the file.
             JFileChooser chooser = new JFileChooser();
@@ -90,7 +90,7 @@
     public FileContents[] openMultiFileDialog (java.lang.String pathHint,
             java.lang.String[] extensions) throws java.io.IOException {
 
-        if (ServiceUtil.checkAccess(SecurityWarningDialog.AccessType.WRITE_FILE)) {
+        if (ServiceUtil.checkAccess(AccessType.WRITE_FILE)) {
             JFileChooser chooser = new JFileChooser();
             chooser.setMultiSelectionEnabled(true);
             int chosen = chooser.showOpenDialog(null);
--- a/netx/net/sourceforge/jnlp/services/XFileSaveService.java	Thu Oct 21 21:12:21 2010 +0100
+++ b/netx/net/sourceforge/jnlp/services/XFileSaveService.java	Fri Oct 22 10:44:12 2010 -0400
@@ -43,8 +43,7 @@
 import java.lang.ref.*;
 import javax.jnlp.*;
 
-import net.sourceforge.jnlp.*;
-import net.sourceforge.jnlp.security.*;
+import net.sourceforge.jnlp.security.SecurityWarning.AccessType;
 
 import javax.swing.JFileChooser;
 import javax.swing.JOptionPane;
@@ -67,7 +66,7 @@
         java.lang.String[] extensions, java.io.InputStream stream,
         java.lang.String name) throws java.io.IOException {
 
-        if (ServiceUtil.checkAccess(SecurityWarningDialog.AccessType.WRITE_FILE)) {
+        if (ServiceUtil.checkAccess(AccessType.WRITE_FILE)) {
             JFileChooser chooser = new JFileChooser();
             int chosen = chooser.showSaveDialog(null);
 
@@ -90,7 +89,7 @@
     public FileContents saveAsFileDialog(java.lang.String pathHint,
         java.lang.String[] extensions, FileContents contents) throws java.io.IOException {
 
-        if (ServiceUtil.checkAccess(SecurityWarningDialog.AccessType.WRITE_FILE)) {
+        if (ServiceUtil.checkAccess(AccessType.WRITE_FILE)) {
             JFileChooser chooser = new JFileChooser();
             chooser.setSelectedFile(new File(contents.getName()));
             int chosen = chooser.showSaveDialog(null);