changeset 668:a94a9a400c5d

Allow for remembered unsigned trust based on codebase
author Adam Domurad <adomurad@redhat.com>
date Thu, 11 Apr 2013 10:02:11 -0400
parents 29db8f77bae4
children 50863f01bf84
files ChangeLog netx/net/sourceforge/jnlp/resources/Messages.properties netx/net/sourceforge/jnlp/security/SecurityDialogs.java netx/net/sourceforge/jnlp/security/UnsignedAppletTrustWarningDialog.java netx/net/sourceforge/jnlp/security/UnsignedAppletTrustWarningPanel.java netx/net/sourceforge/jnlp/security/appletextendedsecurity/UnsignedAppletTrustConfirmation.java
diffstat 6 files changed, 108 insertions(+), 22 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog	Wed Apr 10 16:15:16 2013 +0200
+++ b/ChangeLog	Thu Apr 11 10:02:11 2013 -0400
@@ -1,3 +1,17 @@
+2013-04-11  Adam Domurad  <adomurad@redhat.com>
+
+	Allow remembering applet confirmation for whole codebase.
+	* netx/net/sourceforge/jnlp/resources/Messages.properties:
+	Added SRememberAppletOnly, SRememberCodebase messages
+	* netx/net/sourceforge/jnlp/security/SecurityDialogs.java
+	(showUnsignedWarningDialog): Use UnsignedWarningAction
+	* netx/net/sourceforge/jnlp/security/UnsignedAppletTrustWarningDialog.java
+	(UnsignedAppletTrustWarningDialog): Use UnsignedWarningAction
+	* net/sourceforge/jnlp/security/UnsignedAppletTrustWarningPanel.java:
+	Introduce UnsignedWarningAction, add additional confirmation choices
+	* netx/net/sourceforge/jnlp/security/appletextendedsecurity/UnsignedAppletTrustConfirmation.java:
+	Support remembering action for entire codebase. 
+
 2013-04-10  Jana Fabrikova  <jfabriko@redhat.com>
 
 	* /tests/reproducers/simple/JSToJFuncResol/testcases/JSToJFuncResolTest.java:
--- a/netx/net/sourceforge/jnlp/resources/Messages.properties	Wed Apr 10 16:15:16 2013 +0200
+++ b/netx/net/sourceforge/jnlp/resources/Messages.properties	Thu Apr 11 10:02:11 2013 -0400
@@ -224,6 +224,8 @@
 SAlwaysTrustPublisher=Always trust content from this publisher
 SHttpsUnverified=The website's HTTPS certificate cannot be verified.
 SRememberOption=<b>Remember this option?</b>
+SRememberAppletOnly=For applet
+SRememberCodebase=For site
 SUnsignedSummary=An unsigned Java application wants to run
 SUnsignedDetail=An unsigned application from the following location wants to run:<br><u>{0}</u><br><br><b>It is recommended you only run applications from sites you trust.</b> 
 SUnsignedAllowedBefore=<font color="green">You have accepted this applet previously.</font>
--- a/netx/net/sourceforge/jnlp/security/SecurityDialogs.java	Wed Apr 10 16:15:16 2013 +0200
+++ b/netx/net/sourceforge/jnlp/security/SecurityDialogs.java	Thu Apr 11 10:02:11 2013 -0400
@@ -37,6 +37,7 @@
 
 package net.sourceforge.jnlp.security;
 
+import net.sourceforge.jnlp.security.UnsignedAppletTrustWarningPanel.UnsignedWarningAction;
 import net.sourceforge.jnlp.security.appletextendedsecurity.ExecuteUnsignedApplet;
 
 import java.awt.Dialog.ModalityType;
@@ -182,10 +183,10 @@
      *
      * @return true if permission was granted by the user, false otherwise.
      */
-    public static ExecuteUnsignedApplet showUnsignedWarningDialog(JNLPFile file) {
+    public static UnsignedWarningAction showUnsignedWarningDialog(JNLPFile file) {
 
         if (!shouldPromptUser()) {
-            return ExecuteUnsignedApplet.NO;
+            return new UnsignedWarningAction(ExecuteUnsignedApplet.NO, false);
         }
 
         final SecurityDialogMessage message = new SecurityDialogMessage();
@@ -193,7 +194,7 @@
         message.accessType = AccessType.UNSIGNED;
         message.file = file;
 
-        return (ExecuteUnsignedApplet)getUserResponse(message);
+        return (UnsignedWarningAction)getUserResponse(message);
     }
 
     /**
--- a/netx/net/sourceforge/jnlp/security/UnsignedAppletTrustWarningDialog.java	Wed Apr 10 16:15:16 2013 +0200
+++ b/netx/net/sourceforge/jnlp/security/UnsignedAppletTrustWarningDialog.java	Thu Apr 11 10:02:11 2013 -0400
@@ -37,8 +37,8 @@
 package net.sourceforge.jnlp.security;
 
 import net.sourceforge.jnlp.PluginBridge;
+import net.sourceforge.jnlp.security.UnsignedAppletTrustWarningPanel.UnsignedWarningAction;
 import net.sourceforge.jnlp.security.UnsignedAppletTrustWarningPanel.ActionChoiceListener;
-import net.sourceforge.jnlp.security.appletextendedsecurity.ExecuteUnsignedApplet;
 
 /**
  * A panel that confirms that the user is OK with unsigned code running.
@@ -52,7 +52,7 @@
         add(new UnsignedAppletTrustWarningPanel(file,
                 new ActionChoiceListener() {
                     @Override
-                    public void actionChosen(ExecuteUnsignedApplet action) {
+                    public void actionChosen(UnsignedWarningAction action) {
                         parent.setValue(action);
                         parent.dispose();
                     }
--- a/netx/net/sourceforge/jnlp/security/UnsignedAppletTrustWarningPanel.java	Wed Apr 10 16:15:16 2013 +0200
+++ b/netx/net/sourceforge/jnlp/security/UnsignedAppletTrustWarningPanel.java	Thu Apr 11 10:02:11 2013 -0400
@@ -43,19 +43,21 @@
 import java.awt.Dimension;
 import java.awt.FlowLayout;
 import java.awt.Font;
+import java.awt.GridLayout;
 import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
 
 import javax.swing.BorderFactory;
 import javax.swing.BoxLayout;
+import javax.swing.ButtonGroup;
 import javax.swing.ImageIcon;
 import javax.swing.JButton;
 import javax.swing.JCheckBox;
 import javax.swing.JLabel;
 import javax.swing.JPanel;
+import javax.swing.JRadioButton;
 import javax.swing.SwingConstants;
 
-import net.sourceforge.jnlp.JNLPFile;
 import net.sourceforge.jnlp.PluginBridge;
 import net.sourceforge.jnlp.security.appletextendedsecurity.ExecuteUnsignedApplet;
 import net.sourceforge.jnlp.security.appletextendedsecurity.UnsignedAppletTrustConfirmation;
@@ -63,10 +65,31 @@
 public class UnsignedAppletTrustWarningPanel extends JPanel {
 
     /*
+     * Details of decided action.
+     */
+    public static class UnsignedWarningAction {
+        private ExecuteUnsignedApplet action;
+        private boolean applyToCodeBase;
+
+        public UnsignedWarningAction(ExecuteUnsignedApplet action,
+                boolean applyToCodeBase) {
+            this.action = action;
+            this.applyToCodeBase = applyToCodeBase;
+        }
+
+        public ExecuteUnsignedApplet getAction() {
+            return action;
+        }
+        public boolean rememberForCodeBase() {
+            return applyToCodeBase;
+        }
+    }
+
+    /*
      * Callback for when action is decided.
      */
     public static interface ActionChoiceListener {
-        void actionChosen(ExecuteUnsignedApplet action);
+        void actionChosen(UnsignedWarningAction action);
     }
 
     private final int PANE_WIDTH = 500;
@@ -79,6 +102,8 @@
     private JButton allowButton;
     private JButton rejectButton;
     private JCheckBox permanencyCheckBox;
+    private JRadioButton applyToAppletButton;
+    private JRadioButton applyToCodeBaseButton;
 
     private PluginBridge file;
 
@@ -128,7 +153,7 @@
 
     private void setupInfoPanel() {
         String infoLabelText = R("SUnsignedDetail", file.getCodeBase());
-        ExecuteUnsignedApplet rememberedAction = UnsignedAppletTrustConfirmation.getStoredAction((PluginBridge)file);
+        ExecuteUnsignedApplet rememberedAction = UnsignedAppletTrustConfirmation.getStoredAction(file);
         int panelHeight = INFO_PANEL_HEIGHT;
         if (rememberedAction == ExecuteUnsignedApplet.YES) {
             infoLabelText += "<br>" + R("SUnsignedAllowedBefore");
@@ -158,14 +183,33 @@
         add(questionPanel);
     }
 
+    private JPanel createMatchOptionsPanel() {
+        JPanel matchOptionsPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT));
+
+        ButtonGroup group = new ButtonGroup();
+        applyToAppletButton = new JRadioButton(R("SRememberAppletOnly"));
+        applyToAppletButton.setSelected(true);
+        applyToAppletButton.setEnabled(false); // Start disabled until 'Remember this option' is selected
+
+        applyToCodeBaseButton = new JRadioButton(R("SRememberCodebase"));
+        applyToCodeBaseButton.setEnabled(false);
+
+        group.add(applyToAppletButton);
+        group.add(applyToCodeBaseButton);
+
+        matchOptionsPanel.add(applyToAppletButton);
+        matchOptionsPanel.add(applyToCodeBaseButton);
+
+        return matchOptionsPanel;
+    }
+
     private JPanel createCheckBoxPanel() {
         JPanel checkBoxPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT));
 
         permanencyCheckBox = new JCheckBox(htmlWrap(R("SRememberOption")));
+        permanencyCheckBox.addActionListener(permanencyListener());
         checkBoxPanel.add(permanencyCheckBox);
 
-        checkBoxPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
-
         return checkBoxPanel;
     }
 
@@ -189,8 +233,12 @@
     // Set up 'Remember Option' checkbox & Proceed/Cancel buttons
     private void setupButtonAndCheckBoxPanel() {
         JPanel outerPanel = new JPanel(new BorderLayout());
+        JPanel rememberPanel = new JPanel(new GridLayout(2 /*rows*/, 1 /*column*/));
+        rememberPanel.add(createCheckBoxPanel());
+        rememberPanel.add(createMatchOptionsPanel());
+        rememberPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
 
-        outerPanel.add(createCheckBoxPanel(), BorderLayout.WEST);
+        outerPanel.add(rememberPanel, BorderLayout.WEST);
         outerPanel.add(createButtonPanel(), BorderLayout.EAST);
 
         add(outerPanel);
@@ -208,6 +256,16 @@
         setupButtonAndCheckBoxPanel();
     }
 
+    // Toggles whether 'match applet' or 'match codebase' options are greyed out
+    private ActionListener permanencyListener() {
+        return new ActionListener() {
+            @Override
+            public void actionPerformed(ActionEvent e) {
+                applyToAppletButton.setEnabled(permanencyCheckBox.isSelected());
+                applyToCodeBaseButton.setEnabled(permanencyCheckBox.isSelected());
+            }
+        };
+    }
     // Sets action depending on allowApplet + checkbox state
     private ActionListener chosenActionSetter(final boolean allowApplet) {
         return new ActionListener() {
@@ -221,7 +279,8 @@
                     action = permanencyCheckBox.isSelected() ? ExecuteUnsignedApplet.NEVER : ExecuteUnsignedApplet.NO;
                 }
 
-                actionChoiceListener.actionChosen(action);
+                boolean applyToCodeBase = applyToCodeBaseButton.isSelected();
+                actionChoiceListener.actionChosen(new UnsignedWarningAction(action, applyToCodeBase));
             }
         };
     }
--- a/netx/net/sourceforge/jnlp/security/appletextendedsecurity/UnsignedAppletTrustConfirmation.java	Wed Apr 10 16:15:16 2013 +0200
+++ b/netx/net/sourceforge/jnlp/security/appletextendedsecurity/UnsignedAppletTrustConfirmation.java	Thu Apr 11 10:02:11 2013 -0400
@@ -51,6 +51,7 @@
 import net.sourceforge.jnlp.PluginBridge;
 import net.sourceforge.jnlp.cache.ResourceTracker;
 import net.sourceforge.jnlp.security.SecurityDialogs;
+import net.sourceforge.jnlp.security.UnsignedAppletTrustWarningPanel.UnsignedWarningAction;
 
 public class UnsignedAppletTrustConfirmation {
     static private final boolean DEBUG = System.getenv().containsKey("ICEDTEAPLUGIN_DEBUG");
@@ -116,9 +117,9 @@
         return fileNames;
     }
 
-    private static void updateAppletAction(PluginBridge file, ExecuteUnsignedApplet behaviour) {
+    private static void updateAppletAction(PluginBridge file, ExecuteUnsignedApplet behaviour, boolean rememberForCodeBase) {
+        UnsignedAppletActionStorage userActionStorage = securitySettings.getUnsignedAppletActionCustomStorage();
 
-        UnsignedAppletActionStorage userActionStorage = securitySettings.getUnsignedAppletActionCustomStorage();
         userActionStorage.lock(); // We should ensure this operation is atomic
         try {
             UnsignedAppletActionEntry oldEntry = getMatchingItem(userActionStorage, file);
@@ -136,14 +137,22 @@
 
             /* Else, create a new entry */
             UrlRegEx codebaseRegex = new UrlRegEx("\\Q" + codebase + "\\E");
-            UrlRegEx documentbaseRegex = new UrlRegEx("\\Q" + documentbase + "\\E");
+            UrlRegEx documentbaseRegex = new UrlRegEx(".*"); // Match any from codebase
+            List<String> archiveMatches = null; // Match any from codebase
+
+            if (!rememberForCodeBase) { 
+                documentbaseRegex = new UrlRegEx("\\Q" + documentbase + "\\E"); // Match only this applet
+                archiveMatches = toRelativePaths(file.getArchiveJars(), file.getCodeBase().toString()); // Match only this applet
+            }
 
             UnsignedAppletActionEntry entry = new UnsignedAppletActionEntry(
                     behaviour, 
                     new Date(),
                     documentbaseRegex, 
-                    codebaseRegex, 
-                    toRelativePaths(file.getArchiveJars(), file.getCodeBase().toString()));
+                    codebaseRegex,
+                    archiveMatches
+            );
+
             userActionStorage.add(entry);
         } finally {
             userActionStorage.unlock();
@@ -179,15 +188,16 @@
             appletOK = false;
         } else {
             // No remembered decision, prompt the user
-            ExecuteUnsignedApplet decidedAction = SecurityDialogs.showUnsignedWarningDialog(file);
+            UnsignedWarningAction warningResponse = SecurityDialogs.showUnsignedWarningDialog(file);
+            ExecuteUnsignedApplet executeAction = warningResponse.getAction();
 
-            appletOK = (decidedAction == ExecuteUnsignedApplet.YES || decidedAction == ExecuteUnsignedApplet.ALWAYS);
+            appletOK = (executeAction == ExecuteUnsignedApplet.YES || executeAction == ExecuteUnsignedApplet.ALWAYS);
 
-            if (decidedAction != null) {
-                updateAppletAction(file, decidedAction);
+            if (executeAction != null) {
+                updateAppletAction(file, executeAction, warningResponse.rememberForCodeBase());
             }
 
-            debug("Decided action for unsigned applet at " + file.getCodeBase() +" was " + decidedAction);
+            debug("Decided action for unsigned applet at " + file.getCodeBase() +" was " + executeAction);
         }
 
         if (!appletOK) {