001 /*****************************************************************************
002 * Copyright (C) PicoContainer Organization. All rights reserved. *
003 * ------------------------------------------------------------------------- *
004 * The software in this package is published under the terms of the BSD *
005 * style license a copy of which has been included with this distribution in *
006 * the LICENSE.txt file. *
007 * *
008 *****************************************************************************/
009
010 package org.picocontainer.security;
011
012 import java.net.URL;
013 import java.net.URLClassLoader;
014 import java.security.AccessController;
015 import java.security.CodeSource;
016 import java.security.PermissionCollection;
017 import java.security.Permissions;
018 import java.security.PrivilegedAction;
019 import java.util.Map;
020
021 /**
022 * CustomPermissionsURLClassLoader extends URLClassLoader, adding the abilty to programatically add permissions easily.
023 * To be effective for permission management, it should be run in conjunction with a policy that restricts
024 * some of the classloaders, but not all.
025 * It's not ordinarily used by PicoContainer, but is here because PicoContainer is common
026 * to most classloader trees.
027 *
028 * @author Paul Hammant
029 */
030 public class CustomPermissionsURLClassLoader extends URLClassLoader {
031 private final Map<URL, Permissions> permissionsMap;
032
033 public CustomPermissionsURLClassLoader(URL[] urls, Map<URL, Permissions> permissionsMap, ClassLoader parent) {
034 super(urls, parent);
035 this.permissionsMap = permissionsMap;
036 }
037
038 public Class<?> loadClass(String name) throws ClassNotFoundException {
039 try {
040 return super.loadClass(name);
041 } catch (ClassNotFoundException e) {
042 throw decorateException(name, e);
043 }
044 }
045
046 protected Class<?> findClass(String name) throws ClassNotFoundException {
047 try {
048 return super.findClass(name);
049 } catch (ClassNotFoundException e) {
050 throw decorateException(name, e);
051 }
052 }
053
054 private ClassNotFoundException decorateException(String name, ClassNotFoundException e) {
055 if (name.startsWith("class ")) {
056 return new ClassNotFoundException("Class '" + name + "' is not a classInstance.getName(). " +
057 "It's a classInstance.toString(). The clue is that it starts with 'class ', no classname contains a space.");
058 }
059 ClassLoader classLoader = this;
060 StringBuffer sb = new StringBuffer("'").append(name).append("' classloader stack [");
061 while (classLoader != null) {
062 sb.append(classLoader.toString()).append("\n");
063 final ClassLoader cl = classLoader;
064 classLoader = AccessController.doPrivileged(new PrivilegedAction<ClassLoader>() {
065 public ClassLoader run() {
066 return cl.getParent();
067 }
068 });
069
070 }
071 return new ClassNotFoundException(sb.append("]").toString(), e);
072 }
073
074 public String toString() {
075 String result = CustomPermissionsURLClassLoader.class.getName() + " " + System.identityHashCode(this) + ":";
076 URL[] urls = getURLs();
077 for (URL url : urls) {
078 result += "\n\t" + url.toString();
079 }
080
081 return result;
082 }
083
084 public PermissionCollection getPermissions(CodeSource codeSource) {
085 return (Permissions) permissionsMap.get(codeSource.getLocation());
086 }
087
088 }
089