45 public class SecureClassLoader extends ClassLoader { 46 /* 47 * If initialization succeed this is set to true and security checks will 48 * succeed. Otherwise the object is not initialized and the object is 49 * useless. 50 */ 51 private final boolean initialized; 52 53 /* 54 * Map that maps the CodeSource to a ProtectionDomain. The key is a 55 * CodeSourceKey class that uses a String instead of a URL to avoid 56 * potential expensive name service lookups. This does mean that URLs that 57 * are equivalent after nameservice lookup will be placed in separate 58 * ProtectionDomains; however during policy enforcement these URLs will be 59 * canonicalized and resolved resulting in a consistent set of granted 60 * permissions. 61 */ 62 private final Map<CodeSourceKey, ProtectionDomain> pdcache 63 = new ConcurrentHashMap<>(11); 64 65 private static final Debug debug = Debug.getInstance("scl"); 66 67 static { 68 ClassLoader.registerAsParallelCapable(); 69 } 70 71 /** 72 * Creates a new SecureClassLoader using the specified parent 73 * class loader for delegation. 74 * 75 * <p>If there is a security manager, this method first 76 * calls the security manager's {@code checkCreateClassLoader} 77 * method to ensure creation of a class loader is allowed. 78 * 79 * @param parent the parent ClassLoader 80 * @exception SecurityException if a security manager exists and its 81 * {@code checkCreateClassLoader} method doesn't allow 82 * creation of a class loader. 83 * @see SecurityManager#checkCreateClassLoader 84 */ 85 protected SecureClassLoader(ClassLoader parent) { 86 super(parent); 186 187 /** 188 * Returns the permissions for the given CodeSource object. 189 * <p> 190 * This method is invoked by the defineClass method which takes 191 * a CodeSource as an argument when it is constructing the 192 * ProtectionDomain for the class being defined. 193 * 194 * @param codesource the codesource. 195 * 196 * @return the permissions granted to the codesource. 197 * 198 */ 199 protected PermissionCollection getPermissions(CodeSource codesource) 200 { 201 check(); 202 return new Permissions(); // ProtectionDomain defers the binding 203 } 204 205 /* 206 * Returned cached ProtectionDomain for the specified CodeSource. 207 */ 208 private ProtectionDomain getProtectionDomain(CodeSource cs) { 209 if (cs == null) { 210 return null; 211 } 212 213 // Use a CodeSourceKey object key. It should behave in the 214 // same manner as the CodeSource when compared for equality except 215 // that no nameservice lookup is done on the hostname (String comparison 216 // only), and the fragment is not considered. 217 CodeSourceKey key = new CodeSourceKey(cs); 218 return pdcache.computeIfAbsent(key, new Function<>() { 219 @Override 220 public ProtectionDomain apply(CodeSourceKey key /* not used */) { 221 PermissionCollection perms 222 = SecureClassLoader.this.getPermissions(cs); 223 ProtectionDomain pd = new ProtectionDomain( 224 cs, perms, SecureClassLoader.this, null); 225 if (debug != null) { 226 debug.println(" getPermissions " + pd); 227 debug.println(""); 228 } 229 return pd; 230 } 231 }); 232 } 233 234 /* 235 * Check to make sure the class loader has been initialized. 236 */ 237 private void check() { 238 if (!initialized) { 239 throw new SecurityException("ClassLoader object not initialized"); 240 } 241 } 242 243 private static class CodeSourceKey { 244 private final CodeSource cs; 245 246 CodeSourceKey(CodeSource cs) { 247 this.cs = cs; | 45 public class SecureClassLoader extends ClassLoader { 46 /* 47 * If initialization succeed this is set to true and security checks will 48 * succeed. Otherwise the object is not initialized and the object is 49 * useless. 50 */ 51 private final boolean initialized; 52 53 /* 54 * Map that maps the CodeSource to a ProtectionDomain. The key is a 55 * CodeSourceKey class that uses a String instead of a URL to avoid 56 * potential expensive name service lookups. This does mean that URLs that 57 * are equivalent after nameservice lookup will be placed in separate 58 * ProtectionDomains; however during policy enforcement these URLs will be 59 * canonicalized and resolved resulting in a consistent set of granted 60 * permissions. 61 */ 62 private final Map<CodeSourceKey, ProtectionDomain> pdcache 63 = new ConcurrentHashMap<>(11); 64 65 static { 66 ClassLoader.registerAsParallelCapable(); 67 } 68 69 /** 70 * Creates a new SecureClassLoader using the specified parent 71 * class loader for delegation. 72 * 73 * <p>If there is a security manager, this method first 74 * calls the security manager's {@code checkCreateClassLoader} 75 * method to ensure creation of a class loader is allowed. 76 * 77 * @param parent the parent ClassLoader 78 * @exception SecurityException if a security manager exists and its 79 * {@code checkCreateClassLoader} method doesn't allow 80 * creation of a class loader. 81 * @see SecurityManager#checkCreateClassLoader 82 */ 83 protected SecureClassLoader(ClassLoader parent) { 84 super(parent); 184 185 /** 186 * Returns the permissions for the given CodeSource object. 187 * <p> 188 * This method is invoked by the defineClass method which takes 189 * a CodeSource as an argument when it is constructing the 190 * ProtectionDomain for the class being defined. 191 * 192 * @param codesource the codesource. 193 * 194 * @return the permissions granted to the codesource. 195 * 196 */ 197 protected PermissionCollection getPermissions(CodeSource codesource) 198 { 199 check(); 200 return new Permissions(); // ProtectionDomain defers the binding 201 } 202 203 /* 204 * holder class for the static field "debug" to delay its initialization 205 */ 206 private static class DebugHolder { 207 private static final Debug debug = Debug.getInstance("scl"); 208 } 209 210 /* 211 * Returned cached ProtectionDomain for the specified CodeSource. 212 */ 213 private ProtectionDomain getProtectionDomain(CodeSource cs) { 214 if (cs == null) { 215 return null; 216 } 217 218 // Use a CodeSourceKey object key. It should behave in the 219 // same manner as the CodeSource when compared for equality except 220 // that no nameservice lookup is done on the hostname (String comparison 221 // only), and the fragment is not considered. 222 CodeSourceKey key = new CodeSourceKey(cs); 223 return pdcache.computeIfAbsent(key, new Function<>() { 224 @Override 225 public ProtectionDomain apply(CodeSourceKey key /* not used */) { 226 PermissionCollection perms 227 = SecureClassLoader.this.getPermissions(cs); 228 ProtectionDomain pd = new ProtectionDomain( 229 cs, perms, SecureClassLoader.this, null); 230 if (DebugHolder.debug != null) { 231 DebugHolder.debug.println(" getPermissions " + pd); 232 DebugHolder.debug.println(""); 233 } 234 return pd; 235 } 236 }); 237 } 238 239 /* 240 * Check to make sure the class loader has been initialized. 241 */ 242 private void check() { 243 if (!initialized) { 244 throw new SecurityException("ClassLoader object not initialized"); 245 } 246 } 247 248 private static class CodeSourceKey { 249 private final CodeSource cs; 250 251 CodeSourceKey(CodeSource cs) { 252 this.cs = cs; |