diff options
Diffstat (limited to 'netx/net/sourceforge/jnlp/security/appletextendedsecurity/UnsignedAppletTrustConfirmation.java')
-rw-r--r-- | netx/net/sourceforge/jnlp/security/appletextendedsecurity/UnsignedAppletTrustConfirmation.java | 209 |
1 files changed, 209 insertions, 0 deletions
diff --git a/netx/net/sourceforge/jnlp/security/appletextendedsecurity/UnsignedAppletTrustConfirmation.java b/netx/net/sourceforge/jnlp/security/appletextendedsecurity/UnsignedAppletTrustConfirmation.java new file mode 100644 index 0000000..26bc1d4 --- /dev/null +++ b/netx/net/sourceforge/jnlp/security/appletextendedsecurity/UnsignedAppletTrustConfirmation.java @@ -0,0 +1,209 @@ +/* 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.appletextendedsecurity; + +import static net.sourceforge.jnlp.runtime.Translator.R; + +import java.io.IOException; +import java.net.URISyntaxException; +import java.net.URL; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +import net.sourceforge.jnlp.LaunchException; +import net.sourceforge.jnlp.PluginBridge; +import net.sourceforge.jnlp.cache.ResourceTracker; +import net.sourceforge.jnlp.security.SecurityDialogs; + +public class UnsignedAppletTrustConfirmation { + static private final boolean DEBUG = System.getenv().containsKey("ICEDTEAPLUGIN_DEBUG"); + + 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(); + + if (userAction == ExecuteUnsignedApplet.ALWAYS || userAction == ExecuteUnsignedApplet.NEVER) { + return userAction; + } else if (globalAction == ExecuteUnsignedApplet.ALWAYS || globalAction == ExecuteUnsignedApplet.NEVER) { + return globalAction; + } else { + return userAction; + } + } + + private static UnsignedAppletActionEntry getMatchingItem(UnsignedAppletActionStorage actionStorage, PluginBridge file) { + return actionStorage.getMatchingItem( + normalizeUrlAndStripParams(file.getSourceLocation()).toString(), + normalizeUrlAndStripParams(file.getCodeBase()).toString(), + toRelativePaths(file.getArchiveJars(), file.getCodeBase().toString())); + } + + static URL normalizeUrlAndStripParams(URL url) { + try { + String[] urlParts = url.toString().split("\\?"); + URL strippedUrl = new URL(urlParts[0]); + return ResourceTracker.normalizeUrl(strippedUrl, false); + } catch (IOException e) { + e.printStackTrace(); + } catch (URISyntaxException e) { + e.printStackTrace(); + } + return url; + } + + /* Extract the archives as relative paths */ + static List<String> toRelativePaths(List<String> paths, String rootPath) { + List<String> fileNames = new ArrayList<String>(); + for (String path : paths) { + if (path.startsWith(rootPath)) { + fileNames.add(path.substring(rootPath.length())); + } else { + fileNames.add(path); + } + } + return fileNames; + } + + 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; + } + + URL codebase = normalizeUrlAndStripParams(file.getCodeBase()); + URL documentbase = normalizeUrlAndStripParams(file.getSourceLocation()); + + /* Else, create a new entry */ + UrlRegEx codebaseRegex = new UrlRegEx("\\Q" + codebase + "\\E"); + UrlRegEx documentbaseRegex = new UrlRegEx("\\Q" + documentbase + "\\E"); + + UnsignedAppletActionEntry entry = new UnsignedAppletActionEntry( + behaviour, + new Date(), + documentbaseRegex, + codebaseRegex, + toRelativePaths(file.getArchiveJars(), file.getCodeBase().toString())); + userActionStorage.add(entry); + } finally { + userActionStorage.unlock(); + } + } + static private void debug(String logMessage) { + if (DEBUG) { + System.err.println(logMessage); + } + + } + + public static void checkUnsignedWithUserIfRequired(PluginBridge file) throws LaunchException { + + if (unsignedAppletsAreForbidden()) { + debug("Not running unsigned applet at " + file.getCodeBase() +" because unsigned applets are disallowed by security policy."); + throw new LaunchException(file, null, R("LSFatal"), R("LCClient"), R("LUnsignedApplet"), R("LUnsignedAppletPolicyDenied")); + } + + if (!unsignedConfirmationIsRequired()) { + debug("Running unsigned applet at " + file.getCodeBase() +" does not require confirmation according to security policy."); + return; + } + + ExecuteUnsignedApplet storedAction = getStoredAction(file); + debug("Stored action for unsigned applet at " + file.getCodeBase() +" was " + storedAction); + + 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); + } + + debug("Decided action for unsigned applet at " + file.getCodeBase() +" was " + decidedAction); + } + + if (!appletOK) { + throw new LaunchException(file, null, R("LSFatal"), R("LCClient"), R("LUnsignedApplet"), R("LUnsignedAppletUserDenied")); + } + + } +}
\ No newline at end of file |