changeset 2328:1da6f883f1d3

Track security descriptors per jar, and made permission decisions based on it.
author Deepak Bhole <dbhole@redhat.com>
date Wed, 28 Jul 2010 15:52:36 -0400
parents b4d1a0a7ad8f
children a6702aa5f9e7
files ChangeLog netx/net/sourceforge/jnlp/runtime/JNLPClassLoader.java
diffstat 2 files changed, 94 insertions(+), 14 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog	Wed Jul 28 15:42:55 2010 -0400
+++ b/ChangeLog	Wed Jul 28 15:52:36 2010 -0400
@@ -1,3 +1,16 @@
+2010-07-28  Deepak Bhole <dbhole@redhat.com>
+
+	* netx/net/sourceforge/jnlp/runtime/JNLPClassLoader.java: Added a new
+	HashMap to map source locations to security descriptors for that location.
+	(getInstance): Use the new merge() method to merge loader data.
+	(initializeResources): Add map entries to the new jarLocationSecurityMap.
+	(getPermissions): Decide permissions based on security descriptor
+	associated with the calling code, rather than with the jnlp file.
+	(getCodeSourceSecurity): New method. Returns the security descriptor
+	associated with the given code source URL.
+	(merge): New method. Merges loader classpaths, native dir paths, and
+	security descriptor mappings.
+
 2010-07-28  Deepak Bhole <dbhole@redhat.com>
 
 	* netx/net/sourceforge/jnlp/runtime/JNLPClassLoader.java (activateJars): Add
--- a/netx/net/sourceforge/jnlp/runtime/JNLPClassLoader.java	Wed Jul 28 15:42:55 2010 -0400
+++ b/netx/net/sourceforge/jnlp/runtime/JNLPClassLoader.java	Wed Jul 28 15:52:36 2010 -0400
@@ -26,6 +26,7 @@
 import java.net.URLClassLoader;
 import java.security.AccessControlContext;
 import java.security.AccessController;
+import java.security.AllPermission;
 import java.security.CodeSource;
 import java.security.Permission;
 import java.security.PermissionCollection;
@@ -140,6 +141,9 @@
         /** File entries in the jar files available to this classloader */
         private TreeSet jarEntries = new TreeSet();
 
+        /** Map of specific codesources to securitydesc */
+        private HashMap<URL, SecurityDesc> jarLocationSecurityMap = new HashMap<URL, SecurityDesc>();
+
     /**
      * Create a new JNLPClassLoader from the specified file.
      *
@@ -253,19 +257,13 @@
                                 if (!SecurityWarningDialog.showNotAllSignedWarningDialog(file))
                                     throw new LaunchException(file, null, R("LSFatal"), R("LCClient"), R("LSignedAppJarUsingUnsignedJar"), R("LSignedAppJarUsingUnsignedJarInfo"));
 
-                            for (URL u : extLoader.getURLs())
-                                loader.addURL(u);
-                            for (File nativeDirectory: extLoader.getNativeDirectories())
-                                loader.addNativeDirectory(nativeDirectory);
+                                loader.merge(extLoader);
                         }
 
                 // loader is now current + ext. But we also need to think of
                 // the baseLoader
                         if (baseLoader != null && baseLoader != loader) {
-                    for (URL u : baseLoader.getURLs())
-                        loader.addURL(u);
-                    for (File nativeDirectory: baseLoader.getNativeDirectories())
-                        loader.addNativeDirectory(nativeDirectory);
+                                loader.merge(baseLoader);
                 }
 
                     } else {
@@ -424,6 +422,34 @@
                         }
                 }
 
+                for (JARDesc jarDesc: file.getResources().getJARs()) {
+                        try {
+                                URL location = tracker.getCacheFile(jarDesc.getLocation()).toURI().toURL();
+                                SecurityDesc jarSecurity = file.getSecurity();
+
+                                if (file instanceof PluginBridge) {
+
+                                URL codebase = null;
+
+                                if (file.getCodeBase() != null) {
+                                    codebase = file.getCodeBase();
+                                } else {
+                                    //Fixme: codebase should be the codebase of the Main Jar not
+                                    //the location. Although, it still works in the current state.
+                                    codebase = file.getResources().getMainJAR().getLocation();
+                                }
+
+                                        jarSecurity = new SecurityDesc(file,
+                                                        SecurityDesc.ALL_PERMISSIONS,
+                                                        codebase.getHost());
+                                }
+
+                                jarLocationSecurityMap.put(location, jarSecurity);
+                        } catch (MalformedURLException mfe) {
+                                System.err.println(mfe.getMessage());
+                        }
+                }
+
         activateJars(initialJars);
     }
 
@@ -505,13 +531,15 @@
             // set default perms
             PermissionCollection permissions = security.getSandBoxPermissions();
 
-            // If more than default is needed, evaluate based on codesource
-            if (security.getSecurityType().equals(SecurityDesc.ALL_PERMISSIONS) ||
-                security.getSecurityType().equals(SecurityDesc.J2EE_PERMISSIONS)) {
+            // If more than default is needed:
+            // 1. Code must be signed
+            // 2. ALL or J2EE permissions must be requested (note: plugin requests ALL automatically)
+            if (cs.getCodeSigners() != null &&
+                    (getCodeSourceSecurity(cs.getLocation()).getSecurityType().equals(SecurityDesc.ALL_PERMISSIONS) ||
+                     getCodeSourceSecurity(cs.getLocation()).getSecurityType().equals(SecurityDesc.J2EE_PERMISSIONS))
+                    ) {
 
-                if (cs.getCodeSigners() != null) {
-                    permissions = security.getPermissions();
-                }
+                permissions = getCodeSourceSecurity(cs.getLocation()).getPermissions();
             }
 
             Enumeration<Permission> e = permissions.elements();
@@ -1121,4 +1149,43 @@
         protected SecurityDesc getSecurity() {
                 return security;
         }
+
+        /**
+         * Returns the security descriptor for given code source URL
+         *
+         * @param source The code source
+         * @return The SecurityDescriptor for that source
+         */
+
+        protected SecurityDesc getCodeSourceSecurity(URL source) {
+                return jarLocationSecurityMap.get(source);
+        }
+
+        /**
+         * Merges the code source/security descriptor mapping from another loader
+         *
+         * @param extLoader The loader form which to merge
+         * @throws SecurityException if the code is called from an untrusted source
+         */
+        private void merge(JNLPClassLoader extLoader) {
+
+                try {
+                        System.getSecurityManager().checkPermission(new AllPermission());
+                } catch (SecurityException se) {
+                        throw new SecurityException("JNLPClassLoader() may only be called from trusted sources!");
+                }
+
+                // jars
+                for (URL u : extLoader.getURLs())
+                addURL(u);
+
+                // native search paths
+        for (File nativeDirectory: extLoader.getNativeDirectories())
+            addNativeDirectory(nativeDirectory);
+
+        // security descriptors
+                for (URL key: extLoader.jarLocationSecurityMap.keySet()) {
+                        jarLocationSecurityMap.put(key, extLoader.jarLocationSecurityMap.get(key));
+                }
+        }
 }