    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 = (ClassLoader) AccessController.doPrivileged(new PrivilegedAction() {
    065                    public Object 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