/* * $Id$ * * Copyright (C) 2003-2015 JNode.org * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this library; If not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ package org.jnode.security; import gnu.java.security.PolicyFile; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.net.MalformedURLException; import java.net.URL; import java.security.CodeSource; import java.security.Permission; import java.security.PermissionCollection; import java.security.Permissions; import java.security.Policy; import java.security.cert.Certificate; import java.util.Enumeration; import java.util.HashMap; import java.util.Map; import org.jnode.bootlog.BootLogInstance; import org.jnode.plugin.ConfigurationElement; import org.jnode.plugin.Extension; import org.jnode.plugin.ExtensionPoint; /** * Default policy implementation for JNode. * * @author Ewout Prangsma (epr@users.sourceforge.net) */ final class JNodePolicy extends Policy { /** * The permissions extension point */ private final ExtensionPoint permissionsEp; /** * The configured policies */ private final PolicyFile policyFile; /** * Mapping between a codesource (derived from plugin id) and a set of * permissions */ private final HashMap<CodeSource, PermissionCollection> codeSource2Permissions; /** * Initialize this instance. */ public JNodePolicy(ExtensionPoint permissionsEp) { this.policyFile = new PolicyFile(ClassLoader .getSystemResource("/org/jnode/security/jnode.policy")); this.codeSource2Permissions = new HashMap<CodeSource, PermissionCollection>(); this.permissionsEp = permissionsEp; loadExtensions(); } /** * Gets the permissions for a given code source. * * @see java.security.Policy#getPermissions(java.security.CodeSource) */ public PermissionCollection getPermissions(CodeSource codesource) { PermissionCollection coll = policyFile.getPermissions(codesource); addPermissions(codesource, coll); return coll; } /** * Allow extended classes to add permissions before the permissions * collection is set to read-only. * * @param codeSource * @param perms */ protected void addPermissions(CodeSource codeSource, PermissionCollection perms) { for (Map.Entry<CodeSource, PermissionCollection> e : codeSource2Permissions .entrySet()) { final CodeSource cs = e.getKey(); if (cs.implies(codeSource)) { // BootLogInstance.get().info(cs + " -> " + codeSource); final PermissionCollection pc = e.getValue(); for (Enumeration<?> ee = pc.elements(); ee.hasMoreElements();) { perms.add((Permission) ee.nextElement()); } } } } /** * @see java.security.Policy#refresh() */ public synchronized void refresh() { policyFile.refresh(); loadExtensions(); } /** * Fill the plugin2Permissions map from the extensions connected to the * extensionpoint. */ private final void loadExtensions() { if (permissionsEp != null) { codeSource2Permissions.clear(); final Extension[] exts = permissionsEp.getExtensions(); final int count = exts.length; for (int i = 0; i < count; i++) { loadExtension(exts[i]); } } } private static final Class[] NAME_ACTIONS_ARGS = new Class[]{ String.class, String.class}; private static final Class[] NAME_ARGS = new Class[]{String.class}; private final void loadExtension(Extension ext) { final String id = ext.getDeclaringPluginDescriptor().getId(); final URL url; try { //note: ".../-" match everything starting with "plugin:" + id + "!/" url = new URL("plugin:" + id + "!/-"); final ClassLoader cl = ext.getDeclaringPluginDescriptor() .getPluginClassLoader(); final CodeSource cs = new CodeSource(url, (Certificate[]) null); final Permissions perms = new Permissions(); codeSource2Permissions.put(cs, perms); // BootLogInstance.get().debug("Adding permissions for " + cs); final ConfigurationElement[] elems = ext.getConfigurationElements(); final int count = elems.length; for (int i = 0; i < count; i++) { final ConfigurationElement elem = elems[i]; final String type = elem.getAttribute("class"); final String name = elem.getAttribute("name"); final String actions = elem.getAttribute("actions"); if (type != null) { final Object perm; try { final Class permClass = cl.loadClass(type); if ((name != null) && (actions != null)) { final Constructor c = permClass .getConstructor(NAME_ACTIONS_ARGS); perm = c .newInstance(new Object[]{name, actions}); } else if (name != null) { final Constructor c = permClass .getConstructor(NAME_ARGS); perm = c.newInstance(new Object[]{name}); } else { perm = permClass.newInstance(); } final Permission p = (Permission) perm; perms.add(p); } catch (ClassNotFoundException ex) { BootLogInstance.get() .error("Permission class " + type + " not found"); } catch (InstantiationException ex) { BootLogInstance.get().error("Cannot instantiate permission class " + type); } catch (IllegalAccessException ex) { BootLogInstance.get().error("Illegal access to permission class " + type); } catch (NoSuchMethodException ex) { BootLogInstance.get() .error("Constructor not found on permission class " + type + " in plugin " + id); } catch (InvocationTargetException ex) { BootLogInstance.get().error("Error constructing permission class " + type, ex); } catch (ClassCastException ex) { BootLogInstance.get().error("Permission class " + type + " not instance of Permission"); } } } } catch (MalformedURLException ex) { BootLogInstance.get().error("Cannot create plugin codesource", ex); } } }