diff options
10 files changed, 722 insertions, 1 deletions
@@ -1,5 +1,23 @@ 2014-01-17 Andrew Azores <[email protected]> + 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 + +2014-01-17 Andrew Azores <[email protected]> + Fixes JS reproducer regression. http://mail.openjdk.java.net/pipermail/distro-pkg-dev/2014-January/025764.html * plugin/icedteanp/IcedTeaScriptablePluginObject.cc: (hasMethod) fixed 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/> diff --git a/tests/reproducers/simple/CustomPolicies/resources/CustomPolicies.html b/tests/reproducers/simple/CustomPolicies/resources/CustomPolicies.html new file mode 100644 index 0000000..06d4508 --- /dev/null +++ b/tests/reproducers/simple/CustomPolicies/resources/CustomPolicies.html @@ -0,0 +1,48 @@ +<!-- + +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; either version 2, or (at your option) +any later version. + +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. + + --> +<html> + <head></head> + <body> + <applet code="CustomPolicies.class" + archive="CustomPolicies.jar" + codebase="." + width="800" + height="600"> + </applet> + </body> +</html> diff --git a/tests/reproducers/simple/CustomPolicies/resources/CustomPoliciesApplet.jnlp b/tests/reproducers/simple/CustomPolicies/resources/CustomPoliciesApplet.jnlp new file mode 100644 index 0000000..00d6a83 --- /dev/null +++ b/tests/reproducers/simple/CustomPolicies/resources/CustomPoliciesApplet.jnlp @@ -0,0 +1,53 @@ +<!-- + +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; either version 2, or (at your option) +any later version. + +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. + + --> +<?xml version="1.0" encoding="utf-8"?> +<jnlp spec="1.0" href="CustomPoliciesApplet.jnlp" codebase="."> + <information> + <title>CustomPoliciesApplet</title> + <vendor>IcedTea</vendor> + <homepage href="http://icedtea.classpath.org/wiki/IcedTea-Web#Testing_IcedTea-Web"/> + <description>Test that unsigned applets can perform privileged actions when granted by custom policies</description> + <offline/> + </information> + <resources> + <j2se version="1.4+"/> + <jar href="CustomPolicies.jar"/> + </resources> + <applet-desc main-class="CustomPolicies"> + </applet-desc> +</jnlp> diff --git a/tests/reproducers/simple/CustomPolicies/resources/CustomPoliciesApplication.jnlp b/tests/reproducers/simple/CustomPolicies/resources/CustomPoliciesApplication.jnlp new file mode 100644 index 0000000..31624e8 --- /dev/null +++ b/tests/reproducers/simple/CustomPolicies/resources/CustomPoliciesApplication.jnlp @@ -0,0 +1,53 @@ +<!-- + +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; either version 2, or (at your option) +any later version. + +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. + + --> +<?xml version="1.0" encoding="utf-8"?> +<jnlp spec="1.0" href="CustomPoliciesApplication.jnlp" codebase="."> + <information> + <title>CustomPoliciesApplication</title> + <vendor>IcedTea</vendor> + <homepage href="http://icedtea.classpath.org/wiki/IcedTea-Web#Testing_IcedTea-Web"/> + <description>Test that unsigned applets can perform privileged actions when granted by custom policies</description> + <offline/> + </information> + <resources> + <j2se version="1.4+"/> + <jar href="CustomPolicies.jar"/> + </resources> + <application-desc main-class="CustomPolicies"> + </application-desc> +</jnlp> diff --git a/tests/reproducers/simple/CustomPolicies/resources/CustomPoliciesJnlpHref.html b/tests/reproducers/simple/CustomPolicies/resources/CustomPoliciesJnlpHref.html new file mode 100644 index 0000000..49727e5 --- /dev/null +++ b/tests/reproducers/simple/CustomPolicies/resources/CustomPoliciesJnlpHref.html @@ -0,0 +1,45 @@ +<!-- + +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; either version 2, or (at your option) +any later version. + +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. + + --> +<html> + <head></head> + <body> + <applet width="800" height="600" code="CustomPolicies"> + <param name="jnlp_href" value="CustomPoliciesApplet.jnlp"> + </applet> + </body> +</html> diff --git a/tests/reproducers/simple/CustomPolicies/srcs/CustomPolicies.java b/tests/reproducers/simple/CustomPolicies/srcs/CustomPolicies.java new file mode 100644 index 0000000..2446f55 --- /dev/null +++ b/tests/reproducers/simple/CustomPolicies/srcs/CustomPolicies.java @@ -0,0 +1,23 @@ +import java.applet.Applet; +import java.security.AccessControlException; + +public class CustomPolicies extends Applet { + + @Override + public void start() { + System.out.println("CustomPolicies applet read: " + read("user.home")); + System.exit(0); + } + + private String read(String key) { + try { + return System.getProperty(key); + } catch (AccessControlException ace) { + return ace.toString(); + } + } + + public static void main(String[] args) { + new CustomPolicies().start(); + } +} diff --git a/tests/reproducers/simple/CustomPolicies/testcases/CustomPoliciesTest.java b/tests/reproducers/simple/CustomPolicies/testcases/CustomPoliciesTest.java new file mode 100644 index 0000000..24bdc4c --- /dev/null +++ b/tests/reproducers/simple/CustomPolicies/testcases/CustomPoliciesTest.java @@ -0,0 +1,227 @@ +/* CustomPoliciesTest.java +Copyright (C) 2014 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. + */ + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import java.io.File; +import java.io.FileWriter; +import java.io.FilenameFilter; +import java.io.IOException; +import java.net.URL; + +import net.sourceforge.jnlp.ProcessResult; +import net.sourceforge.jnlp.ServerAccess; +import net.sourceforge.jnlp.annotations.NeedsDisplay; +import net.sourceforge.jnlp.annotations.TestInBrowsers; +import net.sourceforge.jnlp.browsertesting.BrowserTest; +import net.sourceforge.jnlp.browsertesting.Browsers; +import net.sourceforge.jnlp.closinglisteners.RulesFolowingClosingListener; +import net.sourceforge.jnlp.config.DeploymentConfiguration; +import net.sourceforge.jnlp.runtime.JNLPRuntime; + +import org.junit.After; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; + +/* Test that adding permission for all codesources to read the user.home property + * results in an unsigned applet being able to perform this action + */ +public class CustomPoliciesTest extends BrowserTest { + + private static DeploymentConfiguration config = JNLPRuntime.getConfiguration(); + private static File policy, policyBackup; + + @BeforeClass + public static void setPolicyLocation() throws Exception { + policy = new File(new URL(config.getProperty(DeploymentConfiguration.KEY_USER_SECURITY_POLICY)).getPath()); + File securityDir = policy.getParentFile(); + File[] previousBackups = securityDir.listFiles(new FilenameFilter() { + @Override + public boolean accept(File dir, String name) { + return name.startsWith("java.policy.bak"); + } + }); + for (File backup : previousBackups) { + ServerAccess.logErrorReprint("Warning: found previous policy file backup at " + backup); + } + } + + @Before + public void backupPolicy() throws Exception { + if (policy.isFile()) { + policyBackup = File.createTempFile("java.policy.bak", null, policy.getParentFile()); + if (!policy.renameTo(policyBackup)) { + ServerAccess.logErrorReprint("Could not back up existing policy file"); + throw new RuntimeException("Could not back up existing policy file"); + } + } + + } + + @After + public void restorePolicy() { + policy.delete(); + if (policyBackup != null && policyBackup.isFile()) { + policyBackup.renameTo(policy); + } + } + + private void writePolicy() throws IOException { + FileWriter out = new FileWriter(policy); + try { + String policyText="grant {\n permission java.util.PropertyPermission \"user.home\", \"read\";\n};\n"; + out.write(policyText, 0, policyText.length()); + } finally { + out.close(); + } + } + + @NeedsDisplay + @Test + @TestInBrowsers(testIn={Browsers.one}) + public void testHtmlLaunchWithPolicy() throws Exception { + writePolicy(); + assertPolicyExists(); + RulesFolowingClosingListener listener = new RulesFolowingClosingListener(); + listener.addContainsRule("CustomPolicies applet read:"); + ProcessResult pr = server.executeBrowser("CustomPolicies.html", listener, null); + assertInit(pr); + assertReadProps(pr); + assertNoAccessControlException(pr); + } + + @NeedsDisplay + @Test + @TestInBrowsers(testIn={Browsers.one}) + public void testHtmlJnlpHrefLaunchWithPolicy() throws Exception { + writePolicy(); + assertPolicyExists(); + RulesFolowingClosingListener listener = new RulesFolowingClosingListener(); + listener.addContainsRule("CustomPolicies applet read:"); + ProcessResult pr = server.executeBrowser("CustomPoliciesJnlpHref.html", listener, null); + assertInit(pr); + assertReadProps(pr); + assertNoAccessControlException(pr); + } + + @Test + public void testJnlpAppletLaunchWithPolicy() throws Exception { + writePolicy(); + assertPolicyExists(); + ProcessResult pr = server.executeJavawsHeadless("CustomPoliciesApplet.jnlp"); + assertInit(pr); + assertReadProps(pr); + assertNoAccessControlException(pr); + } + + @Test + public void testJnlpApplicationLaunchWithPolicy() throws Exception { + writePolicy(); + assertPolicyExists(); + ProcessResult pr = server.executeJavawsHeadless("CustomPoliciesApplication.jnlp"); + assertInit(pr); + assertReadProps(pr); + assertNoAccessControlException(pr); + } + + @NeedsDisplay + @Test + @TestInBrowsers(testIn = { Browsers.one }) + public void testHtmlLaunch() throws Exception { + assertNoPolicyExists(); + RulesFolowingClosingListener listener = new RulesFolowingClosingListener(); + listener.addContainsRule("CustomPolicies applet read:"); + ProcessResult pr = server.executeBrowser("CustomPolicies.html", listener, null); + assertInit(pr); + assertAccessControlException(pr); + } + + @NeedsDisplay + @Test + @TestInBrowsers(testIn = { Browsers.one }) + public void testHtmlJnlpHrefLaunch() throws Exception { + assertNoPolicyExists(); + RulesFolowingClosingListener listener = new RulesFolowingClosingListener(); + listener.addContainsRule("CustomPolicies applet read:"); + ProcessResult pr = server.executeBrowser("CustomPoliciesJnlpHref.html", listener, null); + assertInit(pr); + assertAccessControlException(pr); + } + + @Test + public void testJnlpAppletLaunch() throws Exception { + assertNoPolicyExists(); + ProcessResult pr = server.executeJavawsHeadless("CustomPoliciesApplet.jnlp"); + assertInit(pr); + assertAccessControlException(pr); + } + + @Test + public void testJnlpApplicationLaunch() throws Exception { + assertNoPolicyExists(); + ProcessResult pr = server.executeJavawsHeadless("CustomPoliciesApplication.jnlp"); + assertInit(pr); + assertAccessControlException(pr); + } + + private void assertAccessControlException(ProcessResult pr) { + assertTrue("Applet should not have been able to read user.home", pr.stdout.contains("AccessControlException: access denied")); + } + + private void assertPolicyExists() { + assertTrue("A user policy file should be installed", policy.isFile()); + } + + private void assertNoPolicyExists() { + assertFalse("A user policy file should not be installed", policy.isFile()); + } + + private void assertInit(ProcessResult pr) { + assertTrue("Applet should have initialized", pr.stdout.contains("CustomPolicies applet read:")); + } + + private void assertReadProps(ProcessResult pr) { + assertTrue("stdout should contain user.home", pr.stdout.contains(System.getProperty("user.home"))); + } + + private void assertNoAccessControlException(ProcessResult pr) { + assertFalse("Applet should have been able to read user.home", pr.stdout.contains("AccessControlException: access denied")); + } + +} |