[fyi][icedtea-web] backend and itw-settings for extended applets security

Jiri Vanek jvanek at redhat.com
Mon Feb 25 08:20:07 PST 2013


On 02/21/2013 11:07 PM, Adam Domurad wrote:
> On 02/20/2013 04:53 PM, Adam Domurad wrote:
>> Here are some proposed fixes. Thanks.
>>
>> - comapre -> compare typo fix
>> - Never return from a finally block! (Eclipse underlines the whole finally block as a warning.)
>> See http://weblogs.java.net/blog/staufferjames/archive/2007/06/_dont_return_in.html
>> - Added a null check so we don't compare if a null archive list is stored.
>>
>> - Adam
>>
>>
>
> Ignore that one, this trumps it.
>
> OK. I tried to separate what would be considered changes to Jiri's part out.
> AppletSecuritySettings.java had to be moved out of sun.applet to make it accessible.
>
> First apply Jiris latest patch, then the rest of them with integrated-dialogue2.patch last.
>
> Here are the patches. Will make a ChangeLog sometime soon.
>
> All the applet security levels should be working in this patch, as well it should honour the global
> applet settings.
>
> Red/green text indicates if you've accepted a patch before.
red/green was never seen :)

>
> Further implementation question:
> - Currently when many applets share a single classloader on a page and one is rejected, it'd be nice
> if the it did not ask for rejection for all the other applets. It is tricky to get this right.
> Perhaps rejecting a certain unique key should be permanent for a session ? There should be no harm,
> as you can always restart your browser if you accidentally hit reject. And indeed there is harm in
> the other direction, if you reject an applet but accidentally hit OK for one of the other applet
> dialogues that come up.

I agree that applet which would allow /deny others applets runs should really affect already 
prepared/shown dialogues.

Most easy way to achive this is to monitor the file for y/n/Y/N change.... But I agree it is nasty.
>
> Let me know of any issues.
>


Most importatant is the url issue we have discussed
And because it broke integrity of my till-now testing, I will do one more review after this is fixed 
(and my backend support none-mian class)
Except the  uttermost last liens of patch, looks ok.
minnors inline.


diff --git a/netx/net/sourceforge/jnlp/PluginBridge.java b/netx/net/sourceforge/jnlp/PluginBridge.java
--- a/netx/net/sourceforge/jnlp/PluginBridge.java
+++ b/netx/net/sourceforge/jnlp/PluginBridge.java
@@ -206,6 +206,10 @@ public class PluginBridge extends JNLPFi
          }
      }

+    public List<String> getArchiveJars() {
+        return new ArrayList<String>(jars);
+    }
+
      public boolean codeBaseLookup() {
      	return params.useCodebaseLookup();
      }
diff --git a/netx/net/sourceforge/jnlp/resources/Messages.properties 
b/netx/net/sourceforge/jnlp/resources/Messages.properties
--- a/netx/net/sourceforge/jnlp/resources/Messages.properties
+++ b/netx/net/sourceforge/jnlp/resources/Messages.properties
@@ -80,6 +80,8 @@ LUnsignedJarWithSecurity=Cannot grant pe
  LUnsignedJarWithSecurityInfo=Application requested security permissions, but jars are not signed.
  LSignedJNLPAppDifferentCerts=The JNLP application is not fully signed by a single cert.
  LSignedJNLPAppDifferentCertsInfo=The JNLP application has its components individually signed, 
however there must be a common signer to all entries.
+LUnsignedApplet=The applet was unsigned.
+LUnsignedAppletInfo=The applet was unsigned, and the security policy prevented it from running.
  LSignedAppJarUsingUnsignedJar=Signed application using unsigned jars.
  LSignedAppJarUsingUnsignedJarInfo=The main application jar is signed, but some of the jars it is 
using aren't.
  LSignedJNLPFileDidNotMatch=The signed JNLP file did not match the launching JNLP file.
@@ -220,6 +222,12 @@ SNoAssociatedCertificate=<no associated
  SUnverified=(unverified)
  SAlwaysTrustPublisher=Always trust content from this publisher
  SHttpsUnverified=The website's HTTPS certificate cannot be verified.
+SRememberOption=<b>Remember this option?</b>
+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>
+SUnsignedRejectedBefore=<font color="red">You have rejected this applet previously.</font>
+SUnsignedQuestion=Allow the applet to run?
  SNotAllSignedSummary=Only parts of this application code are signed.
  SNotAllSignedDetail=This application contains both signed and unsigned code. While signed code is 
safe if you trust the provider, unsigned code may imply code outside of the trusted provider's control.
  SNotAllSignedQuestion=Do you wish to proceed and run this application anyway?
diff --git a/netx/net/sourceforge/jnlp/runtime/JNLPClassLoader.java 
b/netx/net/sourceforge/jnlp/runtime/JNLPClassLoader.java
--- a/netx/net/sourceforge/jnlp/runtime/JNLPClassLoader.java
+++ b/netx/net/sourceforge/jnlp/runtime/JNLPClassLoader.java
@@ -63,6 +63,7 @@ import java.util.jar.JarEntry;
  import java.util.jar.JarFile;
  import java.util.jar.Manifest;

+import net.sourceforge.jnlp.security.appletextendedsecurity.UnsignedAppletTrustConfirmation;
  import net.sourceforge.jnlp.AppletDesc;
  import net.sourceforge.jnlp.ApplicationDesc;
  import net.sourceforge.jnlp.DownloadOptions;
@@ -364,6 +365,41 @@ public class JNLPClassLoader extends URL
          }
      }

+    private static JNLPClassLoader createInstance(JNLPFile file, UpdatePolicy policy, String 
mainName) throws LaunchException {
+        JNLPClassLoader loader = new JNLPClassLoader(file, policy, mainName);
+
+        String uniqueKey = file.getUniqueKey();
+        JNLPClassLoader baseLoader = uniqueKeyToLoader.get(uniqueKey);
+
+        // If security level is 'high' or greater, we must check if the user allows unsigned applets
+        // when the JNLPClassLoader is created. We do so here, because doing so in the constructor
+        // causes unwanted side-effects for some applets
+        if (!loader.getSigning() && file instanceof PluginBridge) {
+            UnsignedAppletTrustConfirmation.checkUnsignedWithUserIfRequired((PluginBridge)file);
+        }
+
+        // New loader init may have caused extensions to create a
+        // loader for this unique key. Check.
+        JNLPClassLoader extLoader = uniqueKeyToLoader.get(uniqueKey);
+
+        if (extLoader != null && extLoader != loader) {
+            if (loader.signing && !extLoader.signing) {
+                if (!SecurityDialogs.showNotAllSignedWarningDialog(file))
+                    throw new LaunchException(file, null, R("LSFatal"), R("LCClient"), 
R("LSignedAppJarUsingUnsignedJar"), R("LSignedAppJarUsingUnsignedJarInfo"));
+            }
+            loader.merge(extLoader);
+            extLoader.decrementLoaderUseCount(); // loader urls have been merged, ext loader is no 
longer used
+        }
+
+        // loader is now current + ext. But we also need to think of
+        // the baseLoader
+        if (baseLoader != null && baseLoader != loader) {
+           loader.merge(baseLoader);
+        }
+
+        return loader;
+    }
+

I thought this refactoring was already pushed... was not?
      /**
       * Returns a JNLP classloader for the specified JNLP file.
       *
@@ -395,27 +431,7 @@ public class JNLPClassLoader extends URL
                      (file.isApplication() &&
                       !baseLoader.getJNLPFile().getFileLocation().equals(file.getFileLocation()))) {

-                loader = new JNLPClassLoader(file, policy, mainName);
-
-                // New loader init may have caused extentions to create a
-                // loader for this unique key. Check.
-                JNLPClassLoader extLoader = uniqueKeyToLoader.get(uniqueKey);
-
-                if (extLoader != null && extLoader != loader) {
-                    if (loader.signing && !extLoader.signing)
-                        if (!SecurityDialogs.showNotAllSignedWarningDialog(file))
-                            throw new LaunchException(file, null, R("LSFatal"), R("LCClient"), 
R("LSignedAppJarUsingUnsignedJar"), R("LSignedAppJarUsingUnsignedJarInfo"));
-
-                    loader.merge(extLoader);
-                    extLoader.decrementLoaderUseCount(); // loader urls have been merged, ext 
loader is no longer used
-                }
-
-                // loader is now current + ext. But we also need to think of
-                // the baseLoader
-                if (baseLoader != null && baseLoader != loader) {
-                   loader.merge(baseLoader);
-                }
-
+                loader = createInstance(file, policy, mainName);
              } else {
                  // if key is same and locations match, this is the loader we want
                  if (!file.isApplication()) {
@@ -578,11 +594,11 @@ public class JNLPClassLoader extends URL

          JARDesc jars[] = resources.getJARs();

-        if (jars == null || jars.length == 0) {
+        if (jars.length == 0) {

-            boolean allSigned = true;
+            boolean allSigned = (loaders.length > 1) /* has extensions */;
              for (int i = 1; i < loaders.length; i++) {
-                if (!loaders[i].getSigning()) {
+                if (!loaders[i].getSigning() ) {
                      allSigned = false;
                      break;
                  }
@@ -663,7 +679,6 @@ public class JNLPClassLoader extends URL
                                      !SecurityDialogs.showNotAllSignedWarningDialog(file))
                      throw new LaunchException(file, null, R("LSFatal"), R("LCClient"), 
R("LSignedAppJarUsingUnsignedJar"), R("LSignedAppJarUsingUnsignedJarInfo"));

-
                  // Check for main class in the downloaded jars, and check/verify signed JNLP fill
                  checkForMain(initialJars);

@@ -700,9 +715,9 @@ public class JNLPClassLoader extends URL
                  }
              } else {

+                // Otherwise this jar is simply unsigned -- make sure to ask
+                // for permission on certain actions
                  signing = false;
-                //otherwise this jar is simply unsigned -- make sure to ask
-                //for permission on certain actions
              }
          }

diff --git a/netx/net/sourceforge/jnlp/security/SecurityDialog.java 
b/netx/net/sourceforge/jnlp/security/SecurityDialog.java
--- a/netx/net/sourceforge/jnlp/security/SecurityDialog.java
+++ b/netx/net/sourceforge/jnlp/security/SecurityDialog.java
@@ -38,6 +38,7 @@ exception statement from your version.
  package net.sourceforge.jnlp.security;

  import net.sourceforge.jnlp.JNLPFile;
+import net.sourceforge.jnlp.PluginBridge;
  import net.sourceforge.jnlp.runtime.JNLPRuntime;
  import net.sourceforge.jnlp.security.SecurityDialogs.AccessType;
  import net.sourceforge.jnlp.security.SecurityDialogs.DialogType;
@@ -306,6 +307,8 @@ public class SecurityDialog extends JDia
              panel = new AppletWarningPane(this, this.certVerifier);
          else if (dialogType == DialogType.NOTALLSIGNED_WARNING)
              panel = new NotAllSignedWarningPane(this);
+        else if (dialogType == DialogType.UNSIGNED_WARNING) // Only necessary for applets on 'high 
security' or above
+            panel = new UnsignedAppletTrustWarningDialog(this, (PluginBridge)file);
          else if (dialogType == DialogType.AUTHENTICATION)
              panel = new PasswordAuthenticationPane(this, extras);

diff --git a/netx/net/sourceforge/jnlp/security/SecurityDialogs.java 
b/netx/net/sourceforge/jnlp/security/SecurityDialogs.java
--- a/netx/net/sourceforge/jnlp/security/SecurityDialogs.java
+++ b/netx/net/sourceforge/jnlp/security/SecurityDialogs.java
@@ -37,6 +37,8 @@ exception statement from your version.

  package net.sourceforge.jnlp.security;

+import net.sourceforge.jnlp.security.appletextendedsecurity.ExecuteUnsignedApplet;
+
  import java.awt.Dialog.ModalityType;
  import java.awt.event.WindowAdapter;
  import java.awt.event.WindowEvent;
@@ -70,6 +72,7 @@ public class SecurityDialogs {
          SINGLE_CERT_INFO,
          ACCESS_WARNING,
          NOTALLSIGNED_WARNING,
+        UNSIGNED_WARNING,   /* requires confirmation with 'high-security' setting */
          APPLET_WARNING,
          AUTHENTICATION,
      }
@@ -86,6 +89,7 @@ public class SecurityDialogs {
          VERIFIED,
          UNVERIFIED,
          NOTALLSIGNED,
+        UNSIGNED,           /* requires confirmation with 'high-security' setting */
          SIGNING_ERROR
      }

@@ -173,6 +177,26 @@ public class SecurityDialogs {
      }

      /**
+     * Shows a warning dialog for when a plugin applet is unsigned.
+     * This is used with 'high-security' setting.
+     *
+     * @return true if permission was granted by the user, false otherwise.
+     */
+    public static ExecuteUnsignedApplet showUnsignedWarningDialog(JNLPFile file) {
+
+        if (!shouldPromptUser()) {
+            return ExecuteUnsignedApplet.NO;
+        }
+
+        final SecurityDialogMessage message = new SecurityDialogMessage();
+        message.dialogType = DialogType.UNSIGNED_WARNING;
+        message.accessType = AccessType.UNSIGNED;
+        message.file = file;
+
+        return (ExecuteUnsignedApplet)getUserResponse(message);
+    }
+
+    /**
       * 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
diff --git a/netx/net/sourceforge/jnlp/security/UnsignedAppletTrustWarningDialog.java 
b/netx/net/sourceforge/jnlp/security/UnsignedAppletTrustWarningDialog.java
new file mode 100644
--- /dev/null
+++ b/netx/net/sourceforge/jnlp/security/UnsignedAppletTrustWarningDialog.java
@@ -0,0 +1,63 @@
+/* Copyright (C) 2013 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 net.sourceforge.jnlp.PluginBridge;
+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.
+ *
+ */
+public class UnsignedAppletTrustWarningDialog extends SecurityDialogPanel {
+
+    public UnsignedAppletTrustWarningDialog(SecurityDialog x, PluginBridge file) {
+        super(x);
+
+        add(new UnsignedAppletTrustWarningPanel(file,
+                new ActionChoiceListener() {
+                    @Override
+                    public void actionChosen(ExecuteUnsignedApplet action) {
+                        parent.setValue(action);
+                        parent.dispose();
+                    }
+                })
+        );
+    }
+
+}
diff --git a/netx/net/sourceforge/jnlp/security/UnsignedAppletTrustWarningPanel.java 
b/netx/net/sourceforge/jnlp/security/UnsignedAppletTrustWarningPanel.java
new file mode 100644
--- /dev/null
+++ b/netx/net/sourceforge/jnlp/security/UnsignedAppletTrustWarningPanel.java
@@ -0,0 +1,229 @@
+/* Copyright (C) 2013 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 static net.sourceforge.jnlp.runtime.Translator.R;
+
+import java.awt.BorderLayout;
+import java.awt.Color;
+import java.awt.Dimension;
+import java.awt.FlowLayout;
+import java.awt.Font;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+
+import javax.swing.BorderFactory;
+import javax.swing.BoxLayout;
+import javax.swing.ImageIcon;
+import javax.swing.JButton;
+import javax.swing.JCheckBox;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+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;
+
+public class UnsignedAppletTrustWarningPanel extends JPanel {
+

Extending to rember page/code base is palned? //longterm?
+    /*
+     * Callback for when action is decided.
+     */
+    public static interface ActionChoiceListener {
+        void actionChosen(ExecuteUnsignedApplet action);
+    }
+
+    private final int PANE_WIDTH = 500;
+
+    private final int TOP_PANEL_HEIGHT = 60;
+    private final int INFO_PANEL_HEIGHT = 100;
+    private final int INFO_PANEL_HINT_HEIGHT = 25;
+    private final int QUESTION_PANEL_HEIGHT = 35;
+
+    private JButton allowButton;
+    private JButton rejectButton;
+    private JCheckBox checkBox;

what an unhappy name :)
+
+    private PluginBridge file;
+
+    private ActionChoiceListener actionChoiceListener;
+
+    public UnsignedAppletTrustWarningPanel(PluginBridge file, ActionChoiceListener 
actionChoiceListener) {
+
+        this.file = file;
+        this.actionChoiceListener = actionChoiceListener;
+
+        addComponents();
+    }
+
+    public JButton getAllowButton() {
+        return allowButton;
+    }
+
+    public JButton getRejectButton() {
+        return rejectButton;
+    }
+
+    private String htmlWrap(String text) {
+        return "<html>" + text + "</html>";
+    }
+
+    private ImageIcon infoImage() {
+        final String location = "net/sourceforge/jnlp/resources/info-small.png";
+        final ClassLoader appLoader = new sun.misc.Launcher().getClassLoader();
+        return new ImageIcon(appLoader.getResource(location));
+    }
+
+    private void setupTopPanel() {
+        final String topLabelText = R("SUnsignedSummary");
+
+        JLabel topLabel = new JLabel(htmlWrap(topLabelText), infoImage(),
+                SwingConstants.LEFT);
+        topLabel.setFont(new Font(topLabel.getFont().toString(), Font.BOLD, 12));
+
+        JPanel topPanel = new JPanel(new BorderLayout());
+        topPanel.setBackground(Color.WHITE);
+        topPanel.add(topLabel, BorderLayout.CENTER);
+        topPanel.setPreferredSize(new Dimension(PANE_WIDTH, TOP_PANEL_HEIGHT));
+        topPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
+
+        add(topPanel);
+    }
+
+    private void setupInfoPanel() {
+        String infoLabelText = R("SUnsignedDetail", file.getCodeBase());
+        ExecuteUnsignedApplet rememberedAction = 
UnsignedAppletTrustConfirmation.getStoredAction((PluginBridge)file);
+        int panelHeight = INFO_PANEL_HEIGHT;
+        if (rememberedAction == ExecuteUnsignedApplet.YES) {
+            infoLabelText += "<br>" + R("SUnsignedAllowedBefore");
+            panelHeight += INFO_PANEL_HINT_HEIGHT;
+        } else if (rememberedAction == ExecuteUnsignedApplet.NO) {
+            infoLabelText += "<br>" + R("SUnsignedRejectedBefore");
+            panelHeight += INFO_PANEL_HINT_HEIGHT;
+        }
+
+        JLabel infoLabel = new JLabel(htmlWrap(infoLabelText));
+        JPanel infoPanel = new JPanel(new BorderLayout());
+        infoPanel.add(infoLabel, BorderLayout.CENTER);
+        infoPanel.setPreferredSize(new Dimension(PANE_WIDTH, panelHeight));
+        infoPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
+
+        add(infoPanel);
+    }
+
+    private void setupQuestionsPanel() {
+        JPanel questionPanel = new JPanel(new BorderLayout());
+
+        questionPanel.add(new JLabel(htmlWrap(R("SUnsignedQuestion"))), BorderLayout.EAST);
+
+        questionPanel.setPreferredSize(new Dimension(PANE_WIDTH, QUESTION_PANEL_HEIGHT));
+        questionPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
+
+        add(questionPanel);
+    }
+
+    private JPanel createCheckBoxPanel() {
+        JPanel checkBoxPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT));
+
+        checkBox = new JCheckBox();
+        checkBoxPanel.add(checkBox);
+        checkBoxPanel.add(new JLabel(htmlWrap(R("SRememberOption"))));
Chckbox can have caption :))
It will be then much more user-friendly to be abel to click also to caption without need to target 
just the box :P

+
+        checkBoxPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
+
+        return checkBoxPanel;
+    }
+
+    private JPanel createButtonPanel() {
+        JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT));
+
+        allowButton = new JButton(R("ButProceed"));
+        rejectButton = new JButton(R("ButCancel"));
+
+        allowButton.addActionListener(chosenActionSetter(true));
+        rejectButton.addActionListener(chosenActionSetter(false));
+
+        buttonPanel.add(allowButton);
+        buttonPanel.add(rejectButton);
+
+        buttonPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
+
+        return buttonPanel;
+    }
+
+    // Set up 'Remember Option' checkbox & Proceed/Cancel buttons
+    private void setupButtonAndCheckBoxPanel() {
+        JPanel outerPanel = new JPanel(new BorderLayout());
+
+        outerPanel.add(createCheckBoxPanel(), BorderLayout.WEST);
+        outerPanel.add(createButtonPanel(), BorderLayout.EAST);
+
+        add(outerPanel);
+    }
+
+    /**
+     * Creates the actual GUI components, and adds it to this panel
+     */
+    private void addComponents() {
+        setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
+
+        setupTopPanel();
+        setupInfoPanel();
+        setupQuestionsPanel();
+        setupButtonAndCheckBoxPanel();
+    }
+
+    // Sets action depending on allowApplet + checkbox state
+    private ActionListener chosenActionSetter(final boolean allowApplet) {
+        return new ActionListener() {
+            @Override
+            public void actionPerformed(ActionEvent e) {
+                ExecuteUnsignedApplet action;
+
+                if (allowApplet) {
+                    action = checkBox.isSelected() ? ExecuteUnsignedApplet.ALWAYS : 
ExecuteUnsignedApplet.YES;
+                } else {
+                    action = checkBox.isSelected() ? ExecuteUnsignedApplet.NEVER : 
ExecuteUnsignedApplet.NO;
+                }
+
+                actionChoiceListener.actionChosen(action);
+            }
+        };
+    }
+}
\ No newline at end of file
diff --git 
a/netx/net/sourceforge/jnlp/security/appletextendedsecurity/UnsignedAppletActionStorage.java 
b/netx/net/sourceforge/jnlp/security/appletextendedsecurity/UnsignedAppletActionStorage.java
--- a/netx/net/sourceforge/jnlp/security/appletextendedsecurity/UnsignedAppletActionStorage.java
+++ b/netx/net/sourceforge/jnlp/security/appletextendedsecurity/UnsignedAppletActionStorage.java
@@ -19,7 +19,6 @@ package net.sourceforge.jnlp.security.ap

  import java.util.List;

-
  /**
   * This is abstract access to white/blacklist created from some permanent storage.
   *
@@ -35,9 +34,9 @@ public interface UnsignedAppletActionSto

      /**
       * This methods iterates through records in
-     * DeploymentConfiguration.getAppletTrustSettingsPath(), and is mathing
-     * regexes saved here against params. so parameters here are NOR tegexes,
-     * but are matched against saved regexes
+     * DeploymentConfiguration.getAppletTrustSettingsPath(), and is matching
+     * regexes saved here against params. So parameters here are NOT regexes,
+     * but are matched against saved regexes.

unrelated?

       *
       * Null or empty values are dangerously ignored, user, be aware of it. eg:
       * match only codeBase will be null someCodeBase null null match only
@@ -104,4 +103,14 @@ public interface UnsignedAppletActionSto
       * @param item
       */
      public void update(final UnsignedAppletActionEntry item);
+
+    /**
+     * Lock the storage, if necessary. If no ownership issues arise, can be a no-op.
+     */
+    public void lock();
+
+    /**
+     * Unlock the storage, if necessary. If no ownership issues arise, can be a no-op.
+     */
+    public void unlock();
  }
unrelated?

but oook.

diff --git 
a/netx/net/sourceforge/jnlp/security/appletextendedsecurity/UnsignedAppletTrustConfirmation.java 
b/netx/net/sourceforge/jnlp/security/appletextendedsecurity/UnsignedAppletTrustConfirmation.java
new file mode 100644
--- /dev/null
+++ b/netx/net/sourceforge/jnlp/security/appletextendedsecurity/UnsignedAppletTrustConfirmation.java
@@ -0,0 +1,130 @@
+package net.sourceforge.jnlp.security.appletextendedsecurity;
+
+import static net.sourceforge.jnlp.runtime.Translator.R;
+
+import java.util.Date;
+import java.util.Map;
+import java.util.WeakHashMap;
+
+import net.sourceforge.jnlp.LaunchException;
+import net.sourceforge.jnlp.PluginBridge;
+import net.sourceforge.jnlp.security.SecurityDialogs;
+
+public class UnsignedAppletTrustConfirmation {
+
+    private static final AppletStartupSecuritySettings securitySettings = 
AppletStartupSecuritySettings.getInstance();
+
+    private static boolean unsignedConfirmationIsRequired() {
+        // If we are using the 'high' security setting or higher, we must confirm
+        // if the user wishes to run unsigned applets (not applicable to JNLP-launched apps)
+        return !(AppletSecurityLevel.ALLOW_UNSIGNED == securitySettings.getSecurityLevel());
+    }
+
+    private static boolean unsignedAppletsAreForbidden() {
+        // If we are using the 'very high' security setting or higher, we do not
+        // run unsigned applets
+        return AppletSecurityLevel.DENY_UNSIGNED == securitySettings.getSecurityLevel()
+                || AppletSecurityLevel.DENY_ALL == securitySettings.getSecurityLevel();
+    }
+
+    /**
+     * Gets the remembered decision, first checking the user policy for an ALWAYS/NEVER,
+     * and then the global policy.
+     *
+     * @param file the plugin file
+     * @return the remembered decision
+     */
+    public static ExecuteUnsignedApplet getStoredAction(PluginBridge file) {
+        UnsignedAppletActionStorage userActionStorage = 
securitySettings.getUnsignedAppletActionCustomStorage();
+        UnsignedAppletActionStorage globalActionStorage = 
securitySettings.getUnsignedAppletActionGlobalStorage();
+
+        UnsignedAppletActionEntry globalEntry = getMatchingItem(globalActionStorage, file);
+        UnsignedAppletActionEntry userEntry = getMatchingItem(userActionStorage, file);
+
+        ExecuteUnsignedApplet globalAction = globalEntry == null ? null : 
globalEntry.getUnsignedAppletAction();
+        ExecuteUnsignedApplet userAction = userEntry == null ? null : 
userEntry.getUnsignedAppletAction();
+

This does not appear to be correct to me:
check users - if A/N then  proceed
check global if A/N then proceed
print out users a/y if exists
print out gloabl  a/y if exists

hmm?
+        if (globalAction == null || userAction == ExecuteUnsignedApplet.ALWAYS || userAction == 
ExecuteUnsignedApplet.NEVER) {
+            return userAction;
+        } else {
+            return globalAction;
+        }
+    }
+
+    private static UnsignedAppletActionEntry getMatchingItem(UnsignedAppletActionStorage 
actionStorage, PluginBridge file) {
+        return actionStorage.getMatchingItem(
+                file.getSourceLocation().toString(),
+                file.getCodeBase().toString(),
+                null,
+                file.getArchiveJars());
+    }
+
+    private static void updateAppletAction(PluginBridge file, ExecuteUnsignedApplet behaviour) {
+
+        UnsignedAppletActionStorage userActionStorage = 
securitySettings.getUnsignedAppletActionCustomStorage();
+
+        userActionStorage.lock(); // We should ensure this operation is atomic
+        try {
+            UnsignedAppletActionEntry oldEntry = getMatchingItem(userActionStorage, file);
+
+            /* Update, if entry exists */
+            if (oldEntry != null) {
+                oldEntry.setUnsignedAppletAction(behaviour);
+                oldEntry.setTimeStamp(new Date());
+                userActionStorage.update(oldEntry);
+                return;
+            }
+
+            /* Else, create a new entry */
+            UrlRegEx codebaseRegex = new UrlRegEx("\\Q" + file.getCodeBase() + "\\E");
+            UrlRegEx documentbaseRegex = new UrlRegEx("\\Q" + file.getSourceLocation() + "\\E");
+
+            UnsignedAppletActionEntry entry = new UnsignedAppletActionEntry(
+                    behaviour,
+                    new Date(),
+                    documentbaseRegex,
+                    codebaseRegex,
+                    null,
+                    file.getArchiveJars());
+
+            userActionStorage.add(entry);
+        } finally {
+            userActionStorage.unlock();
+        }
+    }
+
+    public static void checkUnsignedWithUserIfRequired(PluginBridge file) throws LaunchException {
+
+        if (unsignedAppletsAreForbidden()) {
+            throw new LaunchException(file, null, R("LSFatal"), R("LCClient"), 
R("LUnsignedApplet"), R("LUnsignedAppletInfo"));
+        }
+
+        if (!unsignedConfirmationIsRequired()) {
+            return;
+        }
+
+        ExecuteUnsignedApplet storedAction = getStoredAction(file);
+
+        boolean appletOK;
+
+        if (storedAction == ExecuteUnsignedApplet.ALWAYS) {
+            appletOK = true;
+        } else if (storedAction == ExecuteUnsignedApplet.NEVER) {
+            appletOK = false;
+        } else {
+            // No remembered decision, prompt the user
+            ExecuteUnsignedApplet decidedAction = SecurityDialogs.showUnsignedWarningDialog(file);
+
+            appletOK = (decidedAction == ExecuteUnsignedApplet.YES || decidedAction == 
ExecuteUnsignedApplet.ALWAYS);
+
+            if (decidedAction != null) {
+                updateAppletAction(file, decidedAction);
+            }
+        }
+
+        if (!appletOK) {
+            throw new LaunchException(file, null, R("LSFatal"), R("LCClient"), 
R("LUnsignedApplet"), R("LUnsignedAppletInfo"));
+        }
+
+    }
+}
\ No newline at end of file
diff --git a/plugin/icedteanp/java/sun/applet/PluginAppletViewer.java 
b/plugin/icedteanp/java/sun/applet/PluginAppletViewer.java
--- a/plugin/icedteanp/java/sun/applet/PluginAppletViewer.java
+++ b/plugin/icedteanp/java/sun/applet/PluginAppletViewer.java
@@ -106,6 +106,9 @@ import javax.swing.SwingUtilities;
  import net.sourceforge.jnlp.NetxPanel;
  import net.sourceforge.jnlp.PluginParameters;
  import net.sourceforge.jnlp.runtime.JNLPClassLoader;
+import net.sourceforge.jnlp.security.appletextendedsecurity.AppletSecurityLevel;
+import net.sourceforge.jnlp.security.appletextendedsecurity.AppletStartupSecuritySettings;
+import net.sourceforge.jnlp.security.appletextendedsecurity.ExecuteUnsignedApplet;
  import net.sourceforge.jnlp.splashscreen.SplashController;
  import net.sourceforge.jnlp.splashscreen.SplashPanel;
  import net.sourceforge.jnlp.splashscreen.SplashUtils;
@@ -408,6 +411,11 @@ public class PluginAppletViewer extends

      private static void handleInitializationMessage(int identifier, String message) throws 
IOException {

+        /* The user has specified via a global setting that applets should not be run.*/
+        if (AppletStartupSecuritySettings.getInstance().getSecurityLevel() == 
AppletSecurityLevel.DENY_ALL) {
+            return;
+        }


I would like to see error spalsh after this - so imho throwing of LaunchError is better.
This is imho the only fatal issue, otherwise it looks liek working.
+
          // If there is a key for this status, it means it
          // was either initialized before, or destroy has been
          // processed. Stop moving further.



More information about the distro-pkg-dev mailing list