changeset 1959:eb2ab50f5a28

Track security descriptors per jar, and made permission decisions based on it.
author Deepak Bhole <dbhole@redhat.com>
date Thu, 22 Jul 2010 19:24:19 -0400
parents cf334d2dae6e
children d88454e407dd
files ChangeLog rt/net/sourceforge/jnlp/runtime/JNLPClassLoader.java
diffstat 2 files changed, 95 insertions(+), 15 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog	Thu Jul 22 01:53:55 2010 -0400
+++ b/ChangeLog	Thu Jul 22 19:24:19 2010 -0400
@@ -1,3 +1,16 @@
+2010-07-22  Deepak Bhole <dbhole@redhat.com>
+
+	* rt/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-22  Deepak Bhole <dbhole@redhat.com>
 
 	* rt/net/sourceforge/jnlp/runtime/JNLPClassLoader.java (getInstance):
--- a/rt/net/sourceforge/jnlp/runtime/JNLPClassLoader.java	Thu Jul 22 01:53:55 2010 -0400
+++ b/rt/net/sourceforge/jnlp/runtime/JNLPClassLoader.java	Thu Jul 22 19:24:19 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.
      *
@@ -255,20 +259,14 @@
 		        		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 {
 		        // if key is same and locations match, this is the loader we want
@@ -424,6 +422,34 @@
 				//for permission on certain actions
 			}
 		}
+		
+		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);
     }
@@ -506,13 +532,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();
@@ -1099,6 +1127,45 @@
 	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));
+		}
+	}
 }