diff --git a/ChangeLog b/ChangeLog --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,39 @@ +2014-03-04 Andrew Azores + + Added new PartiallySigned Dialog to replace NotAllSignedWarningPane. + Also includes a Sandbox button. + * netx/net/sourceforge/jnlp/resources/Messages.properties: + (APPEXTSecunsignedAppletActionSandbox, LPartiallySignedApplet, + LPartiallySignedAppletUserDenied) new messages + * netx/net/sourceforge/jnlp/runtime/JNLPClassLoader.java: + Logic added for displaying new PartiallySigned dialog. + (showNotAllSignedDialog) removed. (getSigningState) new method. + (promptUserOnPartialSigning, userPromptedForPartialSigning) new methods for + SecurityDelegate. + * netx/net/sourceforge/jnlp/security/AppTrustWarningDialog.java: + (partiallySigned) new method + * netx/net/sourceforge/jnlp/security/AppTrustWarningPanel.java: + (chosenActionSetter) refactored to allow Sandbox action. (setupInfoPanel) applet + title made overrideable by subclasses + * netx/net/sourceforge/jnlp/security/SecurityDialog.java: (NOTALLSIGNED_WARNING) + renamed PARTIALLYSIGNED_WARNING, display new dialog rather than old + * netx/net/sourceforge/jnlp/security/SecurityDialogs.java: (NOTALLSIGNED_WARNING) + renamed PARTIALLYSIGNED_WARNING. (showNotAllSignedWarningDialog) removed. + (showPartiallySignedWarningDialog) new method + * netx/net/sourceforge/jnlp/security/appletextendedsecurity/ExecuteAppletAction.java: + Added Sandbox action + * netx/net/sourceforge/jnlp/security/appletextendedsecurity/UnsignedAppletTrustConfirmation.java: + (checkPartiallySignedWithUserIfRequired) new method + * tests/reproducers/custom/SignedAppletCodebaseLoading/testcases/SignedAppletCodebaseLoadingTests.java: + test now passes since dialog will not appear if applet security is set to Low. + KnownToFail removed. + * tests/reproducers/custom/SignedAppletExternalMainClass/testcases/SignedAppletExternalMainClassTest.java: + same + * netx/net/sourceforge/jnlp/security/PartiallySignedAppTrustWarningPanel.java: + new class + * netx/net/sourceforge/jnlp/security/NotAllSignedWarningPane.java: deleted + in favour of PartiallySignedAppTrustWarningPanel + 2014-03-04 Andrew Azores * netx/net/sourceforge/jnlp/resources/Messages.properties: 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 @@ -96,6 +96,8 @@ LSignedJNLPAppDifferentCertsInfo=The JNL LUnsignedApplet=The applet was unsigned. LUnsignedAppletPolicyDenied=The applet was unsigned, and the security policy prevented it from running. LUnsignedAppletUserDenied=The applet was unsigned, and was not trusted. +LPartiallySignedApplet=The applet was partially signed. +LPartiallySignedAppletUserDenied=The applet was partially signed, and the user did not trust it. LSignedAppJarUsingUnsignedJar=Signed application using unsigned jars. LSignedAppJarUsingUnsignedJarInfo=The main application jar is signed, but some of the jars it is using aren't. LRunInSandboxError=Run in Sandbox call performed too late. @@ -676,6 +678,7 @@ APPEXTSECappletSecurityLevelLowExplanati APPEXTSECunsignedAppletActionAlways=Always trust this (matching) applet(s) APPEXTSECunsignedAppletActionNever=Never trust this (matching) applet(s) APPEXTSECunsignedAppletActionYes=This applet was visited and allowed +APPEXTSecunsignedAppletActionSandbox=This applet was visited and allowed to run with restricted privileges APPEXTSECunsignedAppletActionNo=This applet was visited and denied APPEXTSECControlPanelExtendedAppletSecurityTitle=Extended applet security APPEXTSECguiTableModelTableColumnAction=Action 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 @@ -80,12 +80,13 @@ import net.sourceforge.jnlp.cache.Illega import net.sourceforge.jnlp.cache.NativeLibraryStorage; import net.sourceforge.jnlp.cache.ResourceTracker; import net.sourceforge.jnlp.cache.UpdatePolicy; +import net.sourceforge.jnlp.security.AppTrustWarningPanel.AppSigningWarningAction; import net.sourceforge.jnlp.security.AppVerifier; +import net.sourceforge.jnlp.security.AppletWarningPane; import net.sourceforge.jnlp.security.JNLPAppVerifier; import net.sourceforge.jnlp.security.PluginAppVerifier; import net.sourceforge.jnlp.security.SecurityDialogs; -import net.sourceforge.jnlp.security.appletextendedsecurity.AppletSecurityLevel; -import net.sourceforge.jnlp.security.appletextendedsecurity.AppletStartupSecuritySettings; +import net.sourceforge.jnlp.security.appletextendedsecurity.ExecuteAppletAction; import net.sourceforge.jnlp.security.appletextendedsecurity.UnsignedAppletTrustConfirmation; import net.sourceforge.jnlp.tools.JarCertVerifier; import net.sourceforge.jnlp.util.ClasspathMatcher.ClasspathMatchers; @@ -359,7 +360,9 @@ public class JNLPClassLoader extends URL // the user was already shown a CertWarning dialog and has chosen to run the applet sandboxed. // This means they've already agreed to running the applet and have specified with which // permission level to do it! - if (!loader.getSigning() && !loader.securityDelegate.userPromptedForSandbox() && file instanceof PluginBridge) { + if (loader.getSigningState() == SigningState.PARTIAL) { + loader.securityDelegate.promptUserOnPartialSigning(); + } else if (!loader.getSigning() && !loader.securityDelegate.userPromptedForSandbox() && file instanceof PluginBridge) { UnsignedAppletTrustConfirmation.checkUnsignedWithUserIfRequired((PluginBridge)file); } @@ -368,10 +371,9 @@ public class JNLPClassLoader extends URL JNLPClassLoader extLoader = uniqueKeyToLoader.get(uniqueKey); if (extLoader != null && extLoader != loader) { - if (loader.getSigning() && !extLoader.getSigning()) - if (!SecurityDialogs.showNotAllSignedWarningDialog(file)) - throw new LaunchException(file, null, R("LSFatal"), R("LCClient"), R("LSignedAppJarUsingUnsignedJar"), R("LSignedAppJarUsingUnsignedJarInfo")); - + if (loader.getSigning() != extLoader.getSigning()) { + loader.securityDelegate.promptUserOnPartialSigning(); + } loader.merge(extLoader); extLoader.decrementLoaderUseCount(); // loader urls have been merged, ext loader is no longer used } @@ -1049,7 +1051,7 @@ public class JNLPClassLoader extends URL return; } - if (jcv.isFullySigned() && !jcv.getAlreadyTrustPublisher()) { + if (getSigningState() == SigningState.FULL && jcv.isFullySigned() && !jcv.getAlreadyTrustPublisher()) { jcv.checkTrustWithUser(securityDelegate, file); } } @@ -1071,21 +1073,6 @@ public class JNLPClassLoader extends URL } /** - * Display a dialog prompting the user to proceed on applets with mixed signing. - * @param file the JNLPFile or PluginBridge describing the applet/application to be launched - * @throws LaunchException if the user does not approve the prompt - */ - private void showNotAllSignedDialog(JNLPFile file) throws LaunchException { - if (JNLPRuntime.isTrustAll()) { - return; - } - - if (!SecurityDialogs.showNotAllSignedWarningDialog(file)) { - throw new LaunchException(file, null, R("LSFatal"), R("LCClient"), R("LSignedAppJarUsingUnsignedJar"), R("LSignedAppJarUsingUnsignedJarInfo")); - } - } - - /** * Add applet's codebase URL. This allows compatibility with * applets that load resources from their codebase instead of * through JARs, but can slow down resource loading. Resources @@ -1915,7 +1902,7 @@ public class JNLPClassLoader extends URL if (signing == SigningState.FULL && JNLPRuntime.isVerifying()) { signing = SigningState.PARTIAL; try { - showNotAllSignedDialog(this.file); + securityDelegate.promptUserOnPartialSigning(); } catch (LaunchException e) { throw new RuntimeException("The signed applet required loading of unsigned code from the codebase, " + "which the user refused", e); @@ -1923,6 +1910,10 @@ public class JNLPClassLoader extends URL } } + public SigningState getSigningState() { + return signing; + } + protected SecurityDesc getSecurity() { return security; } @@ -2308,6 +2299,8 @@ public class JNLPClassLoader extends URL public static interface SecurityDelegate { public boolean isPluginApplet(); + public boolean userPromptedForPartialSigning(); + public boolean userPromptedForSandbox(); public SecurityDesc getCodebaseSecurityDesc(final JARDesc jarDesc, final String codebaseHost); @@ -2316,6 +2309,8 @@ public class JNLPClassLoader extends URL public SecurityDesc getJarPermissions(final String codebaseHost); + public void promptUserOnPartialSigning() throws LaunchException; + public void setRunInSandbox() throws LaunchException; public boolean getRunInSandbox(); @@ -2328,6 +2323,7 @@ public class JNLPClassLoader extends URL public static class SecurityDelegateImpl implements SecurityDelegate { private final JNLPClassLoader classLoader; private boolean runInSandbox; + private boolean promptedForPartialSigning; private boolean promptedForSandbox; public SecurityDelegateImpl(final JNLPClassLoader classLoader) { @@ -2433,10 +2429,22 @@ public class JNLPClassLoader extends URL this.runInSandbox = true; } + public void promptUserOnPartialSigning() throws LaunchException { + if (promptedForPartialSigning || JNLPRuntime.isTrustAll()) { + return; + } + promptedForPartialSigning = true; + UnsignedAppletTrustConfirmation.checkPartiallySignedWithUserIfRequired(this, classLoader.file, classLoader.jcv); + } + public boolean getRunInSandbox() { return this.runInSandbox; } + public boolean userPromptedForPartialSigning() { + return this.promptedForPartialSigning; + } + public boolean userPromptedForSandbox() { return this.promptedForSandbox; } diff --git a/netx/net/sourceforge/jnlp/security/AppTrustWarningDialog.java b/netx/net/sourceforge/jnlp/security/AppTrustWarningDialog.java --- a/netx/net/sourceforge/jnlp/security/AppTrustWarningDialog.java +++ b/netx/net/sourceforge/jnlp/security/AppTrustWarningDialog.java @@ -55,6 +55,12 @@ public class AppTrustWarningDialog exten return warningDialog; } + public static AppTrustWarningDialog partiallySigned(final SecurityDialog dialog, final JNLPFile file) { + final AppTrustWarningDialog warningDialog = new AppTrustWarningDialog(dialog); + warningDialog.add(new PartiallySignedAppTrustWarningPanel(file, warningDialog.getActionChoiceListener(), dialog)); + return warningDialog; + } + private ActionChoiceListener getActionChoiceListener() { return new ActionChoiceListener() { @Override diff --git a/netx/net/sourceforge/jnlp/security/AppTrustWarningPanel.java b/netx/net/sourceforge/jnlp/security/AppTrustWarningPanel.java --- a/netx/net/sourceforge/jnlp/security/AppTrustWarningPanel.java +++ b/netx/net/sourceforge/jnlp/security/AppTrustWarningPanel.java @@ -136,8 +136,8 @@ public abstract class AppTrustWarningPan rejectButton = new JButton(R("ButCancel")); helpButton = new JButton(R("APPEXTSECguiPanelHelpButton")); - allowButton.addActionListener(chosenActionSetter(true)); - rejectButton.addActionListener(chosenActionSetter(false)); + allowButton.addActionListener(chosenActionSetter(ExecuteAppletAction.YES)); + rejectButton.addActionListener(chosenActionSetter(ExecuteAppletAction.NO)); helpButton.addActionListener(getHelpButtonAction()); @@ -206,8 +206,12 @@ public abstract class AppTrustWarningPan add(topPanel); } + protected String getAppletTitle() { + return R("SAppletTitle", file.getTitle()); + } + private void setupInfoPanel() { - String titleText = R("SAppletTitle", file.getTitle()); + String titleText = getAppletTitle(); JLabel titleLabel = new JLabel(titleText); titleLabel.setFont(new Font(titleLabel.getFont().getName(), Font.BOLD, 18)); @@ -306,7 +310,7 @@ public abstract class AppTrustWarningPan } // Toggles whether 'match applet' or 'match codebase' options are greyed out - private ActionListener permanencyListener() { + protected ActionListener permanencyListener() { return new ActionListener() { @Override public void actionPerformed(ActionEvent e) { @@ -316,21 +320,22 @@ public abstract class AppTrustWarningPan }; } - // Sets action depending on allowApplet + checkbox state - private ActionListener chosenActionSetter(final boolean allowApplet) { + protected ActionListener chosenActionSetter(final ExecuteAppletAction action) { return new ActionListener() { @Override public void actionPerformed(ActionEvent e) { - ExecuteAppletAction action; + ExecuteAppletAction realAction; - if (allowApplet) { - action = permanencyCheckBox.isSelected() ? ExecuteAppletAction.ALWAYS : ExecuteAppletAction.YES; + if (action == ExecuteAppletAction.YES) { + realAction = permanencyCheckBox.isSelected() ? ExecuteAppletAction.ALWAYS : ExecuteAppletAction.YES; + } else if (action == ExecuteAppletAction.NO) { + realAction = permanencyCheckBox.isSelected() ? ExecuteAppletAction.NEVER : ExecuteAppletAction.NO; } else { - action = permanencyCheckBox.isSelected() ? ExecuteAppletAction.NEVER : ExecuteAppletAction.NO; + realAction = action; } boolean applyToCodeBase = applyToCodeBaseButton.isSelected(); - actionChoiceListener.actionChosen(new AppSigningWarningAction(action, applyToCodeBase)); + actionChoiceListener.actionChosen(new AppSigningWarningAction(realAction, applyToCodeBase)); } }; } diff --git a/netx/net/sourceforge/jnlp/security/NotAllSignedWarningPane.java b/netx/net/sourceforge/jnlp/security/NotAllSignedWarningPane.java deleted file mode 100644 --- a/netx/net/sourceforge/jnlp/security/NotAllSignedWarningPane.java +++ /dev/null @@ -1,114 +0,0 @@ -/* NotAllSignedWarningPane.java - Copyright (C) 2008 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 javax.swing.BorderFactory; -import javax.swing.BoxLayout; -import javax.swing.ImageIcon; -import javax.swing.JButton; -import javax.swing.JLabel; -import javax.swing.JPanel; -import javax.swing.SwingConstants; - -public class NotAllSignedWarningPane extends SecurityDialogPanel { - - public NotAllSignedWarningPane(SecurityDialog x) { - super(x); - addComponents(); - } - - /** - * Creates the actual GUI components, and adds it to this panel - */ - private void addComponents() { - - String topLabelText = R("SNotAllSignedSummary"); - String infoLabelText = R("SNotAllSignedDetail"); - String questionLabelText = R("SNotAllSignedQuestion"); - - ImageIcon icon = new ImageIcon((new sun.misc.Launcher()).getClassLoader().getResource("net/sourceforge/jnlp/resources/warning.png")); - JLabel topLabel = new JLabel(htmlWrap(topLabelText), icon, 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(500, 80)); - topPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10)); - - JLabel infoLabel = new JLabel(htmlWrap(infoLabelText)); - JPanel infoPanel = new JPanel(new BorderLayout()); - infoPanel.add(infoLabel, BorderLayout.CENTER); - infoPanel.setPreferredSize(new Dimension(500, 100)); - infoPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10)); - - JLabel questionLabel = new JLabel(htmlWrap(questionLabelText)); - JPanel questionPanel = new JPanel(new BorderLayout()); - questionPanel.add(questionLabel, BorderLayout.CENTER); - questionPanel.setPreferredSize(new Dimension(500, 100)); - questionPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10)); - - //run and cancel buttons - JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT)); - - JButton run = new JButton(R("ButProceed")); - JButton cancel = new JButton(R("ButCancel")); - run.addActionListener(createSetValueListener(parent, 0)); - cancel.addActionListener(createSetValueListener(parent, 1)); - initialFocusComponent = cancel; - buttonPanel.add(run); - buttonPanel.add(cancel); - buttonPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10)); - - //all of the above - setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); - add(topPanel); - add(infoPanel); - add(questionPanel); - add(buttonPanel); - - } -} diff --git a/netx/net/sourceforge/jnlp/security/PartiallySignedAppTrustWarningPanel.java b/netx/net/sourceforge/jnlp/security/PartiallySignedAppTrustWarningPanel.java new file mode 100644 --- /dev/null +++ b/netx/net/sourceforge/jnlp/security/PartiallySignedAppTrustWarningPanel.java @@ -0,0 +1,149 @@ +package net.sourceforge.jnlp.security; + +import static net.sourceforge.jnlp.runtime.Translator.R; + +import java.security.cert.Certificate; +import java.security.cert.X509Certificate; + +import javax.swing.ImageIcon; +import javax.swing.JButton; + +import net.sourceforge.jnlp.JNLPFile; +import net.sourceforge.jnlp.PluginBridge; +import net.sourceforge.jnlp.security.SecurityDialogs.AccessType; +import net.sourceforge.jnlp.security.appletextendedsecurity.ExecuteAppletAction; +import net.sourceforge.jnlp.security.appletextendedsecurity.UnsignedAppletTrustConfirmation; +import net.sourceforge.jnlp.tools.CertInformation; +import net.sourceforge.jnlp.tools.JarCertVerifier; + +public class PartiallySignedAppTrustWarningPanel extends AppTrustWarningPanel { + + private JarCertVerifier jcv; + private JButton sandboxButton; + + public PartiallySignedAppTrustWarningPanel(JNLPFile file, ActionChoiceListener actionChoiceListener, + SecurityDialog securityDialog) { + super(file, actionChoiceListener); + this.jcv = (JarCertVerifier) securityDialog.getCertVerifier(); + this.INFO_PANEL_HEIGHT = 200; + + sandboxButton = new JButton(); + sandboxButton.setText(R("ButSandbox")); + sandboxButton.addActionListener(chosenActionSetter(ExecuteAppletAction.SANDBOX)); + buttons.add(1, sandboxButton); + addComponents(); + } + + @Override + protected String getAppletTitle() { + String title; + try { + if (file instanceof PluginBridge) { + title = file.getTitle(); + } else { + title = file.getInformation().getTitle(); + } + } catch (Exception e) { + title = ""; + } + return R("SAppletTitle", title); + } + + private String getAppletInfo() { + Certificate c = jcv.getPublisher(null); + + String publisher = ""; + String from = ""; + + try { + if (c instanceof X509Certificate) { + publisher = SecurityUtil.getCN(((X509Certificate) c) + .getSubjectX500Principal().getName()); + } + } catch (Exception e) { + } + + try { + if (file instanceof PluginBridge) { + from = file.getCodeBase().getHost(); + } else { + from = file.getInformation().getHomepage().toString(); + } + } catch (Exception e) { + } + + return "
" + R("Publisher") + ": " + publisher + + "
" + R("From") + ": " + from; + } + + private String getSigningInfo() { + CertInformation info = jcv.getCertInformation(jcv.getCertPath(null)); + + AccessType type; + if (info != null && info.isRootInCacerts() && !info.hasSigningIssues()) { + type = AccessType.VERIFIED; + } else if (info != null && info.isRootInCacerts()) { + type = AccessType.SIGNING_ERROR; + } else { + type = AccessType.UNVERIFIED; + } + + String mainText = ""; + switch (type) { + case VERIFIED: + mainText = R("SSigVerified"); + break; + case UNVERIFIED: + mainText = R("SSigUnverified"); + break; + case SIGNING_ERROR: + mainText = R("SSignatureError"); + break; + } + + return mainText; + } + + @Override + protected ImageIcon getInfoImage() { + final String location = "net/sourceforge/jnlp/resources/warning.png"; + return new ImageIcon(ClassLoader.getSystemClassLoader().getResource(location)); + } + + protected static String getTopPanelTextKey() { + return "SNotAllSignedSummary"; + } + + protected static String getInfoPanelTextKey() { + return "SNotAllSignedDetail"; + } + + protected static String getQuestionPanelTextKey() { + return "SNotAllSignedQuestion"; + } + + @Override + protected String getTopPanelText() { + return htmlWrap(R(getTopPanelTextKey())); + } + + @Override + protected String getInfoPanelText() { + String text = getAppletInfo(); + text += "

" + R(getInfoPanelTextKey(), file.getCodeBase(), file.getSourceLocation()); + text += "

" + getSigningInfo(); + ExecuteAppletAction rememberedAction = UnsignedAppletTrustConfirmation.getStoredAction(file); + if (rememberedAction == ExecuteAppletAction.YES) { + text += "
" + R("SUnsignedAllowedBefore"); + } else if (rememberedAction == ExecuteAppletAction.NO) { + text += "
" + R("SUnsignedRejectedBefore"); + } + return htmlWrap(text); + } + + @Override + protected String getQuestionPanelText() { + return htmlWrap(R(getQuestionPanelTextKey())); + } + +} 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 @@ -230,7 +230,7 @@ public class SecurityDialog extends JDia dialogTitle = "Security Warning"; else if (dialogType == DialogType.APPLET_WARNING) dialogTitle = "Applet Warning"; - else if (dialogType == DialogType.NOTALLSIGNED_WARNING) + else if (dialogType == DialogType.PARTIALLYSIGNED_WARNING) dialogTitle = "Security Warning"; else if (dialogType == DialogType.AUTHENTICATION) dialogTitle = "Authentication Required"; @@ -303,10 +303,10 @@ public class SecurityDialog extends JDia panel = new AccessWarningPane(this, extras, this.certVerifier); else if (dialogType == DialogType.APPLET_WARNING) panel = new AppletWarningPane(this, this.certVerifier); - else if (dialogType == DialogType.NOTALLSIGNED_WARNING) - panel = new NotAllSignedWarningPane(this); + else if (dialogType == DialogType.PARTIALLYSIGNED_WARNING) + panel = AppTrustWarningDialog.partiallySigned(this, file); else if (dialogType == DialogType.UNSIGNED_WARNING) // Only necessary for applets on 'high security' or above - panel = new UnsignedAppletTrustWarningDialog(this, file); + panel = AppTrustWarningDialog.unsigned(this, 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 @@ -75,7 +75,7 @@ public class SecurityDialogs { CERT_INFO, SINGLE_CERT_INFO, ACCESS_WARNING, - NOTALLSIGNED_WARNING, + PARTIALLYSIGNED_WARNING, UNSIGNED_WARNING, /* requires confirmation with 'high-security' setting */ APPLET_WARNING, AUTHENTICATION, @@ -92,7 +92,7 @@ public class SecurityDialogs { NETWORK, VERIFIED, UNVERIFIED, - NOTALLSIGNED, + PARTIALLYSIGNED, UNSIGNED, /* requires confirmation with 'high-security' setting */ SIGNING_ERROR } @@ -157,29 +157,6 @@ public class SecurityDialogs { } /** - * Shows a warning dialog for when the main application jars are signed, - * but extensions aren't - * - * @return true if permission was granted by the user, false otherwise. - */ - public static boolean showNotAllSignedWarningDialog(JNLPFile file) { - - if (!shouldPromptUser()) { - return false; - } - - final SecurityDialogMessage message = new SecurityDialogMessage(); - message.dialogType = DialogType.NOTALLSIGNED_WARNING; - message.accessType = AccessType.NOTALLSIGNED; - message.file = file; - message.extras = new Object[0]; - - Object selectedValue = getUserResponse(message); - - return getIntegerResponseAsBoolean(selectedValue); - } - - /** * Shows a warning dialog for when a plugin applet is unsigned. * This is used with 'high-security' setting. * @@ -232,6 +209,22 @@ public class SecurityDialogs { } /** + * Shows a warning dialog for when an applet or application is partially signed. + * + * @return true if permission was granted by the user, false otherwise. + */ + public static AppSigningWarningAction showPartiallySignedWarningDialog(JNLPFile file, CertVerifier certVerifier) { + + final SecurityDialogMessage message = new SecurityDialogMessage(); + message.dialogType = DialogType.PARTIALLYSIGNED_WARNING; + message.accessType = AccessType.PARTIALLYSIGNED; + message.file = file; + message.certVerifier = certVerifier; + + return (AppSigningWarningAction) getUserResponse(message); + } + + /** * Present a dialog to the user asking them for authentication information, * and returns the user's response. The caller must have * NetPermission("requestPasswordAuthentication") for this to work. diff --git a/netx/net/sourceforge/jnlp/security/appletextendedsecurity/ExecuteAppletAction.java b/netx/net/sourceforge/jnlp/security/appletextendedsecurity/ExecuteAppletAction.java --- a/netx/net/sourceforge/jnlp/security/appletextendedsecurity/ExecuteAppletAction.java +++ b/netx/net/sourceforge/jnlp/security/appletextendedsecurity/ExecuteAppletAction.java @@ -39,7 +39,7 @@ import net.sourceforge.jnlp.runtime.Tran public enum ExecuteAppletAction { - ALWAYS, NEVER, YES, NO; + ALWAYS, NEVER, YES, SANDBOX, NO; public String toChar() { switch (this) { @@ -49,6 +49,8 @@ public enum ExecuteAppletAction { return "N"; case YES: return "y"; + case SANDBOX: + return "s"; case NO: return "n"; } @@ -63,6 +65,8 @@ public enum ExecuteAppletAction { return Translator.R("APPEXTSECunsignedAppletActionNever"); case YES: return Translator.R("APPEXTSECunsignedAppletActionYes"); + case SANDBOX: + return Translator.R("APPEXTSECunsignedAppletActionSandbox"); case NO: return Translator.R("APPEXTSECunsignedAppletActionNo"); } @@ -76,6 +80,8 @@ public enum ExecuteAppletAction { return ExecuteAppletAction.NEVER; } else if (s.startsWith("y")) { return ExecuteAppletAction.YES; + } else if (s.startsWith("s")) { + return ExecuteAppletAction.SANDBOX; } else if (s.startsWith("n")) { return ExecuteAppletAction.NO; } else { diff --git a/netx/net/sourceforge/jnlp/security/appletextendedsecurity/UnsignedAppletTrustConfirmation.java b/netx/net/sourceforge/jnlp/security/appletextendedsecurity/UnsignedAppletTrustConfirmation.java --- a/netx/net/sourceforge/jnlp/security/appletextendedsecurity/UnsignedAppletTrustConfirmation.java +++ b/netx/net/sourceforge/jnlp/security/appletextendedsecurity/UnsignedAppletTrustConfirmation.java @@ -48,6 +48,8 @@ import net.sourceforge.jnlp.JARDesc; import net.sourceforge.jnlp.JNLPFile; import net.sourceforge.jnlp.LaunchException; import net.sourceforge.jnlp.PluginBridge; +import net.sourceforge.jnlp.runtime.JNLPRuntime; +import net.sourceforge.jnlp.runtime.JNLPClassLoader.SecurityDelegate; import net.sourceforge.jnlp.security.AppTrustWarningPanel.AppSigningWarningAction; import net.sourceforge.jnlp.security.CertVerifier; import net.sourceforge.jnlp.security.SecurityDialogs; @@ -212,4 +214,52 @@ public class UnsignedAppletTrustConfirma } + public static void checkPartiallySignedWithUserIfRequired(SecurityDelegate securityDelegate, JNLPFile file, + CertVerifier certVerifier) throws LaunchException { + + if (JNLPRuntime.isTrustNone()) { + OutputController.getLogger().log(OutputController.Level.ERROR_DEBUG, "Running partially signed applet at " + file.getCodeBase() + " with only Sandbox permissions due to -Xtrustnone flag"); + securityDelegate.setRunInSandbox(); + return; + } + + if (!unsignedConfirmationIsRequired()) { + OutputController.getLogger().log(OutputController.Level.ERROR_DEBUG, "Running partially signed applet at " + file.getCodeBase() + " does not require confirmation according to security policy."); + return; + } + + ExecuteAppletAction storedAction = getStoredAction(file); + OutputController.getLogger().log(OutputController.Level.ERROR_DEBUG, "Stored action for partially signed applet at " + file.getCodeBase() + " was " + storedAction); + + boolean appletOK; + + if (storedAction == ExecuteAppletAction.ALWAYS) { + appletOK = true; + } else if (storedAction == ExecuteAppletAction.NEVER) { + appletOK = false; + } else { + // No remembered decision, prompt the user + AppSigningWarningAction warningResponse = SecurityDialogs.showPartiallySignedWarningDialog(file, certVerifier); + ExecuteAppletAction executeAction = warningResponse.getAction(); + + if (executeAction == ExecuteAppletAction.SANDBOX) { + securityDelegate.setRunInSandbox(); + } + + appletOK = (executeAction == ExecuteAppletAction.YES || executeAction == ExecuteAppletAction.ALWAYS + || executeAction == ExecuteAppletAction.SANDBOX); + + if (executeAction != null) { + updateAppletAction(file, executeAction, warningResponse.rememberForCodeBase()); + } + + OutputController.getLogger().log(OutputController.Level.ERROR_DEBUG, "Decided action for unsigned applet at " + file.getCodeBase() + " was " + executeAction); + } + + if (!appletOK) { + throw new LaunchException(file, null, R("LSFatal"), R("LCClient"), R("LPartiallySignedApplet"), R("LPartiallySignedAppletUserDenied")); + } + + } + } \ No newline at end of file diff --git a/tests/reproducers/custom/SignedAppletCodebaseLoading/testcases/SignedAppletCodebaseLoadingTests.java b/tests/reproducers/custom/SignedAppletCodebaseLoading/testcases/SignedAppletCodebaseLoadingTests.java --- a/tests/reproducers/custom/SignedAppletCodebaseLoading/testcases/SignedAppletCodebaseLoadingTests.java +++ b/tests/reproducers/custom/SignedAppletCodebaseLoading/testcases/SignedAppletCodebaseLoadingTests.java @@ -59,14 +59,11 @@ public class SignedAppletCodebaseLoading private static final String RUNNING_STRING = "SignedAppletCodebaseLoading Applet Running"; private static final String CLOSE_STRING = AutoOkClosingListener.MAGICAL_OK_CLOSING_STRING; - @KnownToFail @Bug(id="PR1513") @NeedsDisplay @Test @TestInBrowsers(testIn={Browsers.one}) public void testCodebaseLoading() throws Exception { - assertTrue("NotAllSigned dialog will appear if this test runs. Remove this exception and KnownToFail " - + "when a proper replacement is in place", false); ProcessResult pr = server.executeBrowser("SignedAppletCodebaseLoading.html", AutoClose.CLOSE_ON_CORRECT_END); assertProperStart(pr); assertCloseString(pr); diff --git a/tests/reproducers/custom/SignedAppletExternalMainClass/testcases/SignedAppletExternalMainClassTest.java b/tests/reproducers/custom/SignedAppletExternalMainClass/testcases/SignedAppletExternalMainClassTest.java --- a/tests/reproducers/custom/SignedAppletExternalMainClass/testcases/SignedAppletExternalMainClassTest.java +++ b/tests/reproducers/custom/SignedAppletExternalMainClass/testcases/SignedAppletExternalMainClassTest.java @@ -55,14 +55,11 @@ public class SignedAppletExternalMainCla private static final String RUNNING_STRING = "SignedAppletExternalMainClass Applet Running"; private static final String CLOSE_STRING = AutoOkClosingListener.MAGICAL_OK_CLOSING_STRING; - @KnownToFail @Bug(id="PR1513") @NeedsDisplay @Test @TestInBrowsers(testIn={Browsers.one}) public void testSignedAppletWithExternalMainClassLaunch() throws Exception { - assertTrue("NotAllSigned dialog will appear if this test runs. Remove this exception and KnownToFail " - + "when a proper replacement is in place", false); ProcessResult pr = server.executeBrowser("SignedAppletExternalMainClass.html", AutoClose.CLOSE_ON_CORRECT_END); assertProperStart(pr); assertCloseString(pr);