From c4bef6cad39892b850022c8f85c1edd97b0c7b40 Mon Sep 17 00:00:00 2001
From: Andrew Azores <aazores@redhat.com>
Date: Fri, 17 Jan 2014 13:43:09 -0500
Subject: Added PolicyPanel to itweb-settings for custom policies

Added itweb-settings panel to explain custom policy files and allow
launching a policy editor for user's policy file.
* netx/net/sourceforge/jnlp/controlpanel/ControlPanel.java:
(createMainSettingsPanel, createPolicySettingsPanel) added PolicyPanel
* netx/net/sourceforge/jnlp/resources/Messages.properties: new messages
for PolicyPanel
* netx/net/sourceforge/jnlp/controlpanel/PolicyPanel.java: new panel to
allow launching of external policy editor
* tests/reproducers/simple/CustomPolicies/resources/CustomPolicies.html:
new test to ensure custom user policy files work correctly
* tests/reproducers/simple/CustomPolicies/resources/CustomPoliciesApplet.jnlp
* tests/reproducers/simple/CustomPolicies/resources/CustomPoliciesApplication.jnlp
* tests/reproducers/simple/CustomPolicies/resources/CustomPoliciesJnlpHref.html
* tests/reproducers/simple/CustomPolicies/srcs/CustomPolicies.java
* tests/reproducers/simple/CustomPolicies/testcases/CustomPoliciesTest.java
---
 .../jnlp/controlpanel/ControlPanel.java            |   7 +-
 .../sourceforge/jnlp/controlpanel/PolicyPanel.java | 239 +++++++++++++++++++++
 .../sourceforge/jnlp/resources/Messages.properties |  10 +
 3 files changed, 255 insertions(+), 1 deletion(-)
 create mode 100644 netx/net/sourceforge/jnlp/controlpanel/PolicyPanel.java

(limited to 'netx/net/sourceforge')

diff --git a/netx/net/sourceforge/jnlp/controlpanel/ControlPanel.java b/netx/net/sourceforge/jnlp/controlpanel/ControlPanel.java
index 3caa4a2..bccf24b 100644
--- a/netx/net/sourceforge/jnlp/controlpanel/ControlPanel.java
+++ b/netx/net/sourceforge/jnlp/controlpanel/ControlPanel.java
@@ -264,7 +264,8 @@ public class ControlPanel extends JFrame {
                 // new SettingsPanel(Translator.R("CPTabRuntimes"), createRuntimesSettingsPanel()),
                 new SettingsPanel(Translator.R("CPTabSecurity"), createSecuritySettingsPanel()),
                 //todo refactor to work with tmp file and apply as asu designed it
-                new SettingsPanel(Translator.R("APPEXTSECControlPanelExtendedAppletSecurityTitle"), new UnsignedAppletsTrustingListPanel(DeploymentConfiguration.getAppletTrustGlobalSettingsPath(),DeploymentConfiguration.getAppletTrustUserSettingsPath(), this.config) )
+                new SettingsPanel(Translator.R("CPTabPolicy"), createPolicySettingsPanel()),
+                new SettingsPanel(Translator.R("APPEXTSECControlPanelExtendedAppletSecurityTitle"), new UnsignedAppletsTrustingListPanel(DeploymentConfiguration.getAppletTrustGlobalSettingsPath(), DeploymentConfiguration.getAppletTrustUserSettingsPath(), this.config))
         };
 
         // Add panels.
@@ -357,6 +358,10 @@ public class ControlPanel extends JFrame {
         return new SecuritySettingsPanel(this.config);
     }
 
+    private JPanel createPolicySettingsPanel() {
+        return new PolicyPanel(this, this.config);
+    }
+
     private JPanel createJVMSettingsPanel() {
         return new JVMPanel(this.config);
     }
diff --git a/netx/net/sourceforge/jnlp/controlpanel/PolicyPanel.java b/netx/net/sourceforge/jnlp/controlpanel/PolicyPanel.java
new file mode 100644
index 0000000..c75611d
--- /dev/null
+++ b/netx/net/sourceforge/jnlp/controlpanel/PolicyPanel.java
@@ -0,0 +1,239 @@
+package net.sourceforge.jnlp.controlpanel;
+
+import static net.sourceforge.jnlp.runtime.Translator.R;
+
+import java.awt.Component;
+import java.awt.Dimension;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.io.File;
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.swing.Box;
+import javax.swing.JButton;
+import javax.swing.JFrame;
+import javax.swing.JLabel;
+import javax.swing.JOptionPane;
+import javax.swing.JTextField;
+import javax.swing.SwingUtilities;
+
+import net.sourceforge.jnlp.config.DeploymentConfiguration;
+import net.sourceforge.jnlp.config.DirectoryValidator;
+import net.sourceforge.jnlp.config.DirectoryValidator.DirectoryCheckResults;
+import net.sourceforge.jnlp.util.FileUtils;
+import net.sourceforge.jnlp.util.logging.OutputController;
+import sun.security.tools.policytool.PolicyTool;
+
+public class PolicyPanel extends NamedBorderPanel {
+
+    private enum OpenFileResult {
+        SUCCESS, FAILURE, CANT_CREATE, CANT_WRITE, NOT_FILE
+    }
+
+    public PolicyPanel(final JFrame frame, final DeploymentConfiguration config) {
+        super(R("CPHeadPolicy"), new GridBagLayout());
+        addComponents(frame, config);
+    }
+
+    private void addComponents(final JFrame frame, final DeploymentConfiguration config) {
+        JLabel aboutLabel = new JLabel("<html>" + R("CPPolicyDetail") + "</html>");
+
+        final String fileUrlString = config.getProperty(DeploymentConfiguration.KEY_USER_SECURITY_POLICY);
+        JButton showUserPolicyButton = new JButton(R("CPButPolicy"));
+        showUserPolicyButton.addActionListener(new ViewPolicyButtonAction(frame, fileUrlString));
+
+        String pathPart = localFilePathFromUrlString(fileUrlString);
+        showUserPolicyButton.setToolTipText(R("CPPolicyTooltip", FileUtils.displayablePath(pathPart, 60)));
+
+        JTextField locationField = new JTextField(pathPart);
+        locationField.setEditable(false);
+
+        GridBagConstraints c = new GridBagConstraints();
+        c.fill = GridBagConstraints.BOTH;
+        c.gridx = 1;
+        c.gridy = 0;
+        c.weightx = 1;
+        add(aboutLabel, c);
+
+        c.weighty = 0;
+        c.weightx = 0;
+        c.gridy++;
+        add(locationField, c);
+
+        c.fill = GridBagConstraints.NONE;
+        c.gridx++;
+        add(showUserPolicyButton, c);
+
+        /* Keep all the elements at the top of the panel (Extra padding) */
+        c.fill = GridBagConstraints.BOTH;
+        Component filler1 = Box.createRigidArea(new Dimension(240, 1));
+        Component filler2 = Box.createRigidArea(new Dimension(1, 1));
+        c.gridx++;
+        add(filler1, c);
+        c.gridx--;
+        c.weighty = 1;
+        c.gridy++;
+        add(filler2, c);
+    }
+
+    /**
+     * Launch the policytool for a specified file path
+     * @param filePath the policy file path to be opened with policytool
+     */
+    private static void launchPolicyTool(final JFrame frame, final String filePath) {
+        try {
+            final File policyFile = new File(filePath).getCanonicalFile();
+            OpenFileResult result = canOpenPolicyFile(policyFile);
+            if (result == OpenFileResult.SUCCESS) {
+                PolicyTool.main(new String[] { "-file", policyFile.getPath() });
+            } else if (result == OpenFileResult.CANT_WRITE) {
+                showReadOnlyDialog(frame);
+                PolicyTool.main(new String[] { "-file", policyFile.getPath() });
+            } else {
+                showCouldNotOpenFileDialog(frame, policyFile.getPath(), result);
+            }
+        } catch (IOException e) {
+            OutputController.getLogger().log(e);
+            showCouldNotOpenFileDialog(frame, filePath);
+        }
+    }
+
+    /**
+     * Verify that a given file object points to a real, accessible plain file.
+     * As a side effect, if the file is accessible but does not yet exist, it will be created
+     * as an empty plain file.
+     * @param policyFile the file to verify
+     * @throws IOException if the file is not accessible
+     */
+    private static OpenFileResult canOpenPolicyFile(final File policyFile) {
+        DirectoryCheckResults dcr = testPolicyFileDirectory(policyFile);
+        if (dcr.getFailures() == 0) {
+            if (policyFile.isDirectory())
+                return OpenFileResult.NOT_FILE;
+            try {
+                if (!policyFile.exists() && !policyFile.createNewFile()) {
+                    return OpenFileResult.CANT_CREATE;
+                }
+            } catch (IOException e) {
+                return OpenFileResult.CANT_CREATE;
+            }
+            boolean read = policyFile.canRead(), write = policyFile.canWrite();
+            if (read && write)
+                return OpenFileResult.SUCCESS;
+            else if (read)
+                return OpenFileResult.CANT_WRITE;
+            else
+                return OpenFileResult.FAILURE;
+        }
+        return OpenFileResult.FAILURE;
+    }
+
+    /**
+     * Ensure that the parent directory of the Policy File exists and that we are
+     * able to create and access files within this directory
+     * @param policyFile the location of the policy file
+     * @return an object representing the results of the test
+     */
+    private static DirectoryCheckResults testPolicyFileDirectory(final File policyFile) {
+        List<File> policyDirectory = new ArrayList<File>();
+        policyDirectory.add(policyFile.getParentFile());
+        DirectoryValidator validator = new DirectoryValidator(policyDirectory);
+        DirectoryCheckResults result = validator.ensureDirs();
+
+        return result;
+    }
+
+    private static void showCouldNotOpenFileDialog(final JFrame frame, final String filePath) {
+        showCouldNotOpenFileDialog(frame, filePath, OpenFileResult.FAILURE);
+    }
+
+    private static void showCouldNotOpenFileDialog(final JFrame frame, final String filePath, final OpenFileResult reason) {
+        String message;
+        switch (reason) {
+            case CANT_CREATE:
+                message = R("RCantCreateFile", filePath);
+                break;
+            case CANT_WRITE:
+                message = R("RCantWriteFile", filePath);
+                break;
+            case NOT_FILE:
+                message = R("RExpectedFile", filePath);
+                break;
+            default:
+                message = R("RCantOpenFile", filePath);
+                break;
+        }
+        showCouldNotOpenFileDialog(frame, filePath, message);
+    }
+
+    /**
+     * Show a dialog informing the user that the policy file could not be opened
+     * @param frame the parent frame for this dialog
+     * @param filePath the path to the file we tried to open
+     * @param message the specific reason the file could not be opened
+     */
+    private static void showCouldNotOpenFileDialog(final JFrame frame, final String filePath, final String message) {
+        OutputController.getLogger().log(OutputController.Level.ERROR_ALL, "Could not open user JNLP policy");
+        JOptionPane.showMessageDialog(frame, message, R("Error"), JOptionPane.ERROR_MESSAGE);
+    }
+
+    /**
+     * Show a dialog informing the user that the policy file is currently read-only
+     * @param frame the parent frame for this dialog
+     */
+    private static void showReadOnlyDialog(final JFrame frame) {
+        OutputController.getLogger().log(OutputController.Level.WARNING_ALL, "Opening user JNLP policy read-only");
+        JOptionPane.showMessageDialog(frame, R("RFileReadOnly"), R("Warning"), JOptionPane.WARNING_MESSAGE);
+    }
+
+    /**
+     * Loosely attempt to get the path part of a file URL string. If this fails,
+     * simply return back the input. This is only intended to be used for displaying
+     * GUI elements such as the CPPolicyTooltip.
+     * @param url the String representing the URL whose path is desired
+     * @return a String representing the local filepath of the given file:/ URL
+     */
+    private static String localFilePathFromUrlString(String url) {
+        try {
+            URL u = new URL(url);
+            return u.getPath();
+        } catch (MalformedURLException e) {
+            return url;
+        }
+    }
+
+    /*
+     * Implements the action to be performed when the "View Policy" button is clicked
+     */
+    private class ViewPolicyButtonAction implements ActionListener {
+        private final JFrame frame;
+        private final String fileUrlString;
+
+        public ViewPolicyButtonAction(final JFrame frame, final String fileUrlString) {
+            this.fileUrlString = fileUrlString;
+            this.frame = frame;
+        }
+
+        @Override
+        public void actionPerformed(ActionEvent event) {
+            try {
+                final URL fileUrl = new URL(fileUrlString);
+                SwingUtilities.invokeLater(new Runnable() {
+                    @Override
+                    public void run() {
+                        launchPolicyTool(frame, fileUrl.getPath());
+                    }
+                });
+            } catch (MalformedURLException ex) {
+                OutputController.getLogger().log(ex);
+                showCouldNotOpenFileDialog(frame, fileUrlString);
+            }
+        }
+    }
+}
diff --git a/netx/net/sourceforge/jnlp/resources/Messages.properties b/netx/net/sourceforge/jnlp/resources/Messages.properties
index be28762..bff5e34 100644
--- a/netx/net/sourceforge/jnlp/resources/Messages.properties
+++ b/netx/net/sourceforge/jnlp/resources/Messages.properties
@@ -21,6 +21,7 @@ AFileOnTheMachine=a file on the machine
 AlwaysAllowAction=Always allow this action
 Usage=Usage:
 Error=Error
+Warning=Warning
 
 Continue=Do you want to continue?
 Field=Field
@@ -159,6 +160,10 @@ RExitTaken=Exit class already set and caller is not exit class.
 RCantReplaceSM=Changing the SecurityManager is not allowed.
 RCantCreateFile=Cant create file {0}
 RCantDeleteFile=Cant delete file {0}
+RCantOpenFile=Could not open file {0}
+RCantWriteFile=Could not write to file {0}
+RFileReadOnly=Opening file in read-only mode
+RExpectedFile=Expected {0} to be a file but it was not
 RRemoveRPermFailed=Removing read permission on file {0} failed
 RRemoveWPermFailed=Removing write permissions on file {0} failed
 RRemoveXPermFailed=Removing execute permissions on file {0} failed
@@ -353,6 +358,8 @@ CPJVMNotokMessage1=You have entered invalid JDK value <u>({0})</u> with followin
 CPJVMNotokMessage2=You might be seeing this message because: <blockquote> * Some validity tests have not been passed<br> * Non-OpenJDK is detected</blockquote>With invalid JDK IcedTea-Web will probably not be able to start.<br>You will have to modify or remove <u>{0}</u> property in your configuration file <u>{1}</u>. <br>You should try to search for OpenJDK in your system or be sure you know what you are doing.
 CPJVMconfirmInvalidJdkTitle=Confirm invalid JDK
 CPJVMconfirmReset=Reset to default?
+CPPolicyDetail=View or edit your user-level Java Policy File. This allows you to grant or deny runtime permissions to applets regardless of the standard security sandboxing rules.
+CPPolicyTooltip=Open {0} in policy editor
 
 # Control Panel - Buttons
 CPButAbout=About...
@@ -360,6 +367,7 @@ CPButNetworkSettings=Network Settings...
 CPButSettings=Settings...
 CPButView=View...
 CPButCertificates=Certificates...
+CPButPolicy=View/Edit with Policy Tool
 
 # Control Panel - Headers
 CPHead=IcedTea-Web Control Panel
@@ -372,6 +380,7 @@ CPHeadDebugging=\u00a0Debugging\u00a0Settings\u00a0
 CPHeadDesktopIntegration=\u00a0Desktop\u00a0Integrations\u00a0
 CPHeadSecurity=\u00a0Security\u00a0Settings\u00a0
 CPHeadJVMSettings=\u00a0JVM\u00a0Settings\u00a0
+CPHeadPolicy=\u00a0Custom\u00a0Policy\u00a0Settings\u00a0
 
 # Control Panel - Tabs
 CPTabAbout=About IcedTea-Web
@@ -384,6 +393,7 @@ CPTabNetwork=Network
 CPTabRuntimes=Runtimes
 CPTabSecurity=Security
 CPTabJVMSettings=JVM Settings
+CPTabPolicy=Policy Settings
 
 # Control Panel - AboutPanel
 CPAboutInfo=This is the control panel for setting deployments.properties.<br/>Not all options will take effect until implemented.<br/>The use of multiple JREs is currently limited to OpenJDK.<br/>
-- 
cgit v1.2.3