diff --git a/netx/net/sourceforge/jnlp/Parser.java b/netx/net/sourceforge/jnlp/Parser.java --- a/netx/net/sourceforge/jnlp/Parser.java +++ b/netx/net/sourceforge/jnlp/Parser.java @@ -25,6 +25,7 @@ import java.lang.reflect.Method; import java.net.*; import java.util.*; +import net.sourceforge.jnlp.SecurityDesc.RequestedPermissionLevel; import net.sourceforge.jnlp.UpdateDesc.Check; import net.sourceforge.jnlp.UpdateDesc.Policy; import net.sourceforge.jnlp.runtime.JNLPRuntime; @@ -595,20 +596,26 @@ class Parser { throw new ParseException(R("PTwoSecurity")); Object type = SecurityDesc.SANDBOX_PERMISSIONS; + RequestedPermissionLevel requestedPermissionLevel = RequestedPermissionLevel.NONE; - if (nodes.length == 0) + if (nodes.length == 0) { type = SecurityDesc.SANDBOX_PERMISSIONS; - else if (null != getChildNode(nodes[0], "all-permissions")) + requestedPermissionLevel = RequestedPermissionLevel.NONE; + } else if (null != getChildNode(nodes[0], "all-permissions")) { type = SecurityDesc.ALL_PERMISSIONS; - else if (null != getChildNode(nodes[0], "j2ee-application-client-permissions")) + requestedPermissionLevel = RequestedPermissionLevel.ALL; + } else if (null != getChildNode(nodes[0], "j2ee-application-client-permissions")) { type = SecurityDesc.J2EE_PERMISSIONS; - else if (strict) + requestedPermissionLevel = RequestedPermissionLevel.J2SE; + } else if (strict) { throw new ParseException(R("PEmptySecurity")); + } - if (base != null) - return new SecurityDesc(file, type, base.getHost()); - else - return new SecurityDesc(file, type, null); + if (base != null) { + return new SecurityDesc(file, requestedPermissionLevel, type, base.getHost()); + } else { + return new SecurityDesc(file, requestedPermissionLevel, type, null); + } } /** 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 @@ -36,6 +36,7 @@ import java.util.Locale; import java.util.Map; import java.util.Set; +import net.sourceforge.jnlp.SecurityDesc.RequestedPermissionLevel; import net.sourceforge.jnlp.runtime.JNLPRuntime; import net.sourceforge.jnlp.util.logging.OutputController; import net.sourceforge.jnlp.util.replacements.BASE64Decoder; @@ -226,6 +227,21 @@ public class PluginBridge extends JNLPFi return useJNLPHref; } + public RequestedPermissionLevel getPermissions() { + final String level = params.getPermissions(); + if (level == null) { + return RequestedPermissionLevel.NONE; + } else if (level.equals("default")) { + return RequestedPermissionLevel.NONE; + } else if (level.equals("sandbox")) { + return RequestedPermissionLevel.SANDBOX; + } else if (level.equals("all-permissions")) { + return RequestedPermissionLevel.ALL; + } else { + return RequestedPermissionLevel.NONE; + } + } + /** * {@inheritDoc } */ diff --git a/netx/net/sourceforge/jnlp/PluginParameters.java b/netx/net/sourceforge/jnlp/PluginParameters.java --- a/netx/net/sourceforge/jnlp/PluginParameters.java +++ b/netx/net/sourceforge/jnlp/PluginParameters.java @@ -156,6 +156,10 @@ public class PluginParameters { return Integer.valueOf(heightStr); } + public String getPermissions() { + return get("permissions"); + } + public void updateSize(int width, int height) { parameters.put("width", Integer.toString(width)); parameters.put("height", Integer.toString(height)); diff --git a/netx/net/sourceforge/jnlp/SecurityDesc.java b/netx/net/sourceforge/jnlp/SecurityDesc.java --- a/netx/net/sourceforge/jnlp/SecurityDesc.java +++ b/netx/net/sourceforge/jnlp/SecurityDesc.java @@ -34,6 +34,10 @@ import net.sourceforge.jnlp.util.logging */ public class SecurityDesc { + public enum RequestedPermissionLevel { + NONE, SANDBOX, J2SE, ALL + } + /* * We do not verify security here, the classloader deals with security */ @@ -47,6 +51,9 @@ public class SecurityDesc { /** J2EE permissions. */ public static final Object J2EE_PERMISSIONS = "J2SE"; + /** requested permissions type according to HTML or JNLP */ + private final RequestedPermissionLevel requestedPermissionLevel; + /** permissions type */ private Object type; @@ -147,14 +154,16 @@ public class SecurityDesc { * Create a security descriptor. * * @param file the JNLP file + * @param requestedPermissionLevel the permission level specified in the JNLP * @param type the type of security * @param downloadHost the download host (can always connect to) */ - public SecurityDesc(JNLPFile file, Object type, String downloadHost) { + public SecurityDesc(JNLPFile file, RequestedPermissionLevel requestedPermissionLevel, Object type, String downloadHost) { if (file == null) { throw new NullJnlpFileException(); } this.file = file; + this.requestedPermissionLevel = requestedPermissionLevel; this.type = type; this.downloadHost = downloadHost; @@ -165,6 +174,17 @@ public class SecurityDesc { } /** + * Create a security descriptor. + * + * @param file the JNLP file + * @param type the type of security + * @param downloadHost the download host (can always connect to) + */ + public SecurityDesc(JNLPFile file, Object type, String downloadHost) { + this(file, RequestedPermissionLevel.NONE, type, downloadHost); + } + + /** * Returns a Policy object that represents a custom policy to use instead * of granting {@link AllPermission} to a {@link CodeSource} * @@ -226,6 +246,13 @@ public class SecurityDesc { } /** + * @return the permission level requested in the JNLP + */ + public RequestedPermissionLevel getRequestedPermissionLevel() { + return requestedPermissionLevel; + } + + /** * Returns a PermissionCollection containing the sandbox permissions */ public PermissionCollection getSandBoxPermissions() { diff --git a/netx/net/sourceforge/jnlp/runtime/ManifestAttributesChecker.java b/netx/net/sourceforge/jnlp/runtime/ManifestAttributesChecker.java --- a/netx/net/sourceforge/jnlp/runtime/ManifestAttributesChecker.java +++ b/netx/net/sourceforge/jnlp/runtime/ManifestAttributesChecker.java @@ -44,6 +44,7 @@ import net.sourceforge.jnlp.ExtensionDes import net.sourceforge.jnlp.JARDesc; import net.sourceforge.jnlp.JNLPFile; import net.sourceforge.jnlp.JNLPFile.ManifestBoolean; +import net.sourceforge.jnlp.SecurityDesc.RequestedPermissionLevel; import net.sourceforge.jnlp.LaunchException; import net.sourceforge.jnlp.PluginBridge; import net.sourceforge.jnlp.ResourcesDesc; @@ -168,43 +169,65 @@ public class ManifestAttributesChecker { */ private void checkPermissionsAttribute() throws LaunchException { final ManifestBoolean permissions = file.getManifestsAttributes().isSandboxForced(); - AppletSecurityLevel level = AppletStartupSecuritySettings.getInstance().getSecurityLevel(); + final AppletSecurityLevel level = AppletStartupSecuritySettings.getInstance().getSecurityLevel(); if (level == AppletSecurityLevel.ALLOW_UNSIGNED || securityDelegate.getRunInSandbox()) { OutputController.getLogger().log(OutputController.Level.WARNING_ALL, "Although 'permissions' attribute of this application is '" + file.getManifestsAttributes().permissionsToString() + "' Your Extended applets security is at 'low', or you have specifically chosen to run the applet Sandboxed. Continuing"); return; } - switch (permissions) { - case UNDEFINED: { - if (level == AppletSecurityLevel.DENY_UNSIGNED) { - throw new LaunchException("Your Extended applets security is at 'Very high', and this application is missing the 'permissions' attribute in manifest. This is fatal"); - } - if (level == AppletSecurityLevel.ASK_UNSIGNED) { - boolean a = SecurityDialogs.showMissingPermissionsAttributeDialogue(file.getTitle(), file.getCodeBase()); - if (!a) { - throw new LaunchException("Your Extended applets security is at 'high' and this applicationis missing the 'permissions' attribute in manifest. And you have refused to run it."); - } else { - OutputController.getLogger().log("Your Extended applets security is at 'high' and this applicationis missing the 'permissions' attribute in manifest. And you have allowed to run it."); - } - } - //default for missing is sandbox - if (!SecurityDesc.SANDBOX_PERMISSIONS.equals(security.getSecurityType())) { - throw new LaunchException("The 'permissions' attribute is not specified, and application is requesting permissions. This is fatal"); - } - break; + + if (permissions == ManifestBoolean.UNDEFINED) { + if (level == AppletSecurityLevel.DENY_UNSIGNED) { + throw new LaunchException("Your Extended applets security is at 'Very high', and this application is missing the 'permissions' attribute in manifest. This is fatal"); } - case TRUE: { - if (SecurityDesc.SANDBOX_PERMISSIONS.equals(security.getSecurityType())) { - OutputController.getLogger().log("The permissions attribute of this application is " + file.getManifestsAttributes().permissionsToString() + "' and security is '" + security.getSecurityType() + "'. Thats correct"); + if (level == AppletSecurityLevel.ASK_UNSIGNED) { + boolean a = SecurityDialogs.showMissingPermissionsAttributeDialogue(file.getTitle(), file.getCodeBase()); + if (!a) { + throw new LaunchException("Your Extended applets security is at 'high' and this application is missing the 'permissions' attribute in manifest. And you have refused to run it."); } else { - throw new LaunchException("The 'permissions' attribute is '" + file.getManifestsAttributes().permissionsToString() + "' but security is '" + security.getSecurityType() + "'. This is fatal"); + OutputController.getLogger().log("Your Extended applets security is at 'high' and this application is missing the 'permissions' attribute in manifest. And you have allowed to run it."); + return; } } - case FALSE: { - if (SecurityDesc.SANDBOX_PERMISSIONS.equals(security.getSecurityType())) { - throw new LaunchException("The 'permissions' attribute is '" + file.getManifestsAttributes().permissionsToString() + "' but security is' " + security.getSecurityType() + "'. This is fatal"); - } else { - OutputController.getLogger().log("The permissions attribute of this application is '" + file.getManifestsAttributes().permissionsToString() + "' and security is '" + security.getSecurityType() + "'. Thats correct"); + } + + final RequestedPermissionLevel requested; + if (file instanceof PluginBridge) { // HTML applet + requested = ((PluginBridge) file).getPermissions(); + + if (requested == RequestedPermissionLevel.ALL && permissions != ManifestBoolean.FALSE) { + throw new LaunchException("The 'permissions' attribute is '" + file.getManifestsAttributes().permissionsToString() + "' but the applet requested " + requested + ". This is fatal"); + } + + if (requested == RequestedPermissionLevel.SANDBOX && permissions != ManifestBoolean.TRUE) { + throw new LaunchException("The 'permissions' attribute is '" + file.getManifestsAttributes().permissionsToString() + "' but the applet requested " + requested + ". This is fatal"); + } + + if (requested == RequestedPermissionLevel.NONE) { + if (permissions == ManifestBoolean.TRUE && signing != SigningState.NONE) { + // http://docs.oracle.com/javase/7/docs/technotes/guides/jweb/security/manifest.html#permissions + // FIXME: attempting to follow the spec, but it is too late now to actually set the applet + // to run in sandbox, so the applet will not be run at all, rather than run sandboxed! + //securityDelegate.setRunInSandbox(); + } + } + } else { // JNLP + requested = security.getRequestedPermissionLevel(); + + if (requested == RequestedPermissionLevel.ALL && permissions != ManifestBoolean.FALSE) { + throw new LaunchException("The 'permissions' attribute is '" + file.getManifestsAttributes().permissionsToString() + "' but the applet requested " + requested + ". This is fatal"); + } + + if (requested == RequestedPermissionLevel.SANDBOX && permissions != ManifestBoolean.TRUE) { + throw new LaunchException("The 'permissions' attribute is '" + file.getManifestsAttributes().permissionsToString() + "' but the applet requested " + requested + ". This is fatal"); + } + + if (requested == RequestedPermissionLevel.NONE) { + if (permissions == ManifestBoolean.TRUE && signing != SigningState.NONE) { + throw new LaunchException("The 'permissions' attribute is '" + file.getManifestsAttributes().permissionsToString() + "' and the applet is signed. This is fatal."); + } + if (permissions == ManifestBoolean.FALSE && signing == SigningState.NONE) { + throw new LaunchException("The 'permissions' attribute is '" + file.getManifestsAttributes().permissionsToString() + "' and the applet is unsigned. This is fatal."); } } }