[jboss-cvs] JBossAS SVN: r79231 - in branches/JBPAPP_4_2_0_GA_CP/naming/src/main/org: jnp/server and 2 other directories.
jboss-cvs-commits at lists.jboss.org
jboss-cvs-commits at lists.jboss.org
Tue Oct 7 12:57:09 EDT 2008
Author: mmoyses
Date: 2008-10-07 12:57:09 -0400 (Tue, 07 Oct 2008)
New Revision: 79231
Added:
branches/JBPAPP_4_2_0_GA_CP/naming/src/main/org/jboss/naming/JndiPermission.java
branches/JBPAPP_4_2_0_GA_CP/naming/src/main/org/jnp/test/JndiPermissionUnitTest.java
branches/JBPAPP_4_2_0_GA_CP/naming/src/main/org/jnp/test/NamingServerSecurityManagerUnitTest.java
branches/JBPAPP_4_2_0_GA_CP/naming/src/main/org/jnp/test/support/
branches/JBPAPP_4_2_0_GA_CP/naming/src/main/org/jnp/test/support/QueueSecurityManager.java
branches/JBPAPP_4_2_0_GA_CP/naming/src/main/org/jnp/test/support/TestSecurityManager.java
Modified:
branches/JBPAPP_4_2_0_GA_CP/naming/src/main/org/jnp/server/NamingServer.java
Log:
JBPAPP-1256: security manager permissions for bind/rebind/unbind/createSubContext
Added: branches/JBPAPP_4_2_0_GA_CP/naming/src/main/org/jboss/naming/JndiPermission.java
===================================================================
--- branches/JBPAPP_4_2_0_GA_CP/naming/src/main/org/jboss/naming/JndiPermission.java (rev 0)
+++ branches/JBPAPP_4_2_0_GA_CP/naming/src/main/org/jboss/naming/JndiPermission.java 2008-10-07 16:57:09 UTC (rev 79231)
@@ -0,0 +1,792 @@
+/*
+ * Copyright 1997-2005 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2008, Red Hat Middleware LLC, and individual contributors
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This 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 software 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 software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.naming;
+
+import java.security.Permission;
+import java.security.PermissionCollection;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.List;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.io.ObjectOutputStream;
+import java.io.ObjectInputStream;
+import java.io.IOException;
+import java.io.Serializable;
+
+import javax.naming.Name;
+
+/**
+ * This class represents access to a path in the JNDI tree. A JndiPermission
+ * consists of a pathname and a set of actions valid for that pathname.
+ * <P>
+ * Pathname is the pathname of the file or directory granted the specified
+ * actions. A pathname that ends in "/*" indicates all the files and directories
+ * contained in that directory. A pathname that ends with "/-" indicates
+ * (recursively) all files and subdirectories contained in that directory. A
+ * pathname consisting of the special token "<<ALL BINDINGS>>" matches
+ * <b>any</b> file.
+ * <P>
+ * The actions to be granted are passed to the constructor in a string
+ * containing a list of one or more comma-separated keywords. The possible
+ * keywords are "bind", "rebind", "unbind", "lookup", "list", "listBindings",
+ * and "createSubcontext". Their meaning is defined as follows:
+ * <P>
+ * <DL>
+ * <DT> bind
+ * <DD> Context.bind permission
+ * <DT> rebind
+ * <DD> Context.rebind permission
+ * <DT> unbind
+ * <DD> Context.unbind permission.
+ * <DT> lookup
+ * <DD> Context.lookup permission.
+ * <DT> list
+ * <DD> Context.list permission.
+ * <DT> listBindings
+ * <DD> Context.listBindings permission.
+ * <DT> createSubcontext
+ * <DD> Context.createSubcontext permission.
+ * </DL>
+ * <P>
+ * The actions string is converted to lowercase before processing.
+ * <P>
+ * Be careful when granting JndiPermissions. Think about the implications of
+ * granting read and especially write access to various files and directories.
+ * The "<<ALL BINDINGS>>" permission with write action is especially
+ * dangerous. This grants permission to write to the entire file system. One
+ * thing this effectively allows is replacement of the system binary, including
+ * the JVM runtime environment.
+ *
+ * <p>
+ * Please note: Code can always read a file from the same directory it's in (or
+ * a subdirectory of that directory); it does not need explicit permission to do
+ * so.
+ *
+ * @see java.security.Permission
+ * @see java.security.Permissions
+ * @see java.security.PermissionCollection
+ *
+ *
+ * @author Marianne Mueller
+ * @author Roland Schemers
+ * @author Scott.Stark at jboss.org
+ *
+ * @serial exclude
+ * @version $Revision: 79036 $
+ */
+public final class JndiPermission extends Permission
+ implements Serializable
+{
+ private static final long serialVersionUID = 1;
+
+ /**
+ * bind action.
+ */
+ public final static int BIND = 1;
+ /**
+ * rebind action.
+ */
+ public final static int REBIND = 2;
+ /**
+ * unbind action.
+ */
+ public final static int UNBIND = 4;
+ /**
+ * lookup action.
+ */
+ public final static int LOOKUP = 8;
+ /**
+ * list action.
+ */
+ public final static int LIST = 16;
+
+ public final static int LIST_BINDINGS = 32;
+
+ public final static int CREATE_SUBCONTEXT = 64;
+ private final static int ACTION_COUNT = 7;
+
+
+ /**
+ * All actions (bind, rebind, unbind, lookup, list, listBindings, createSubcontext)
+ */
+ public final static int ALL = LOOKUP | REBIND | BIND | UNBIND | LIST
+ | LIST_BINDINGS | CREATE_SUBCONTEXT;
+
+ /**
+ * No actions.
+ */
+ public final static int NONE = 0x0;
+
+ public static final String BIND_ACTION = "bind";
+
+ public static final String REBIND_ACTION = "rebind";
+
+ public static final String UNBIND_ACTION = "unbind";
+
+ public static final String LOOKUP_ACTION = "lookup";
+
+ public static final String LIST_ACTION = "list";
+
+ public static final String LIST_BINDINGS_ACTION = "listBindings";
+ public static final String ALL_ACTION = "*";
+
+ public static final String CREATE_SUBCONTEXT_ACTION = "createSubcontext";
+ private static final String[] ALL_ACTIONS = {BIND_ACTION, REBIND_ACTION, UNBIND_ACTION,
+ LOOKUP_ACTION, LIST_ACTION, LIST_BINDINGS_ACTION, CREATE_SUBCONTEXT_ACTION
+ };
+ private static final HashMap<String, Integer> actionMap = new HashMap<String, Integer>();
+ static
+ {
+ actionMap.put(BIND_ACTION, BIND);
+ actionMap.put(REBIND_ACTION, REBIND);
+ actionMap.put(UNBIND_ACTION, UNBIND);
+ actionMap.put(LOOKUP_ACTION, LOOKUP);
+ actionMap.put(LIST_ACTION, LIST);
+ actionMap.put(LIST_BINDINGS_ACTION.toLowerCase(), LIST_BINDINGS);
+ actionMap.put(CREATE_SUBCONTEXT_ACTION.toLowerCase(), CREATE_SUBCONTEXT);
+ actionMap.put(ALL_ACTION, ALL);
+ }
+
+ // the actions mask
+ private transient int mask;
+
+ // does path indicate a directory? (wildcard or recursive)
+ private transient boolean directory;
+
+ // is it a recursive directory specification?
+ private transient boolean recursive;
+
+ /**
+ * the actions string.
+ *
+ * @serial
+ */
+ private String actions; // Left null as long as possible, then
+
+ // created and re-used in the getAction function.
+
+ // canonicalized dir path. In the case of
+ // directories, it is the name "/blah/*" or "/blah/-" without
+ // the last character (the "*" or "-").
+
+ private transient String cpath;
+
+ // static Strings used by init(int mask)
+ private static final char RECURSIVE_CHAR = '-';
+
+ private static final char WILD_CHAR = '*';
+
+ /**
+ * initialize a JndiPermission object. Common to all constructors. Also
+ * called during de-serialization.
+ *
+ * @param mask
+ * the actions mask to use.
+ *
+ */
+ private void init(int mask)
+ {
+ if ((mask & ALL) != mask)
+ throw new IllegalArgumentException("invalid actions mask");
+
+ if (mask == NONE)
+ throw new IllegalArgumentException("invalid actions mask");
+
+ if ((cpath = getName()) == null)
+ throw new NullPointerException("name can't be null");
+
+ this.mask = mask;
+
+ if (cpath.equals("<<ALL BINDINGS>>"))
+ {
+ directory = true;
+ recursive = true;
+ cpath = "";
+ return;
+ }
+
+ int len = cpath.length();
+ char last = ((len > 0) ? cpath.charAt(len - 1) : 0);
+
+ if (last == RECURSIVE_CHAR && cpath.charAt(len - 2) == '/')
+ {
+ directory = true;
+ recursive = true;
+ cpath = cpath.substring(0, --len);
+ }
+ else if (last == WILD_CHAR && cpath.charAt(len - 2) == '/')
+ {
+ directory = true;
+ // recursive = false;
+ cpath = cpath.substring(0, --len);
+ }
+ else
+ {
+ // overkill since they are initialized to false, but
+ // commented out here to remind us...
+ // directory = false;
+ // recursive = false;
+ }
+ }
+
+ /**
+ * Creates a new JndiPermission object with the specified actions. <i>path</i>
+ * is the pathname of a file or directory, and <i>actions</i> contains a
+ * comma-separated list of the desired actions granted on the file or
+ * directory. Possible actions are "bind", "rebind", "unbind", "lookup",
+ * "list", "listBindings", and "createSubcontext".
+ *
+ * <p>
+ * A pathname that ends in "/*" (where "/" is the file separator character,
+ * <code>'/'</code>) indicates all the files and directories contained in
+ * that directory. A pathname that ends with "/-" indicates (recursively) all
+ * files and subdirectories contained in that directory. The special pathname
+ * "<<ALL BINDINGS>>" matches any file.
+ *
+ * <p>
+ * A pathname consisting of a single "*" indicates all the files in the
+ * current directory, while a pathname consisting of a single "-" indicates
+ * all the files in the current directory and (recursively) all files and
+ * subdirectories contained in the current directory.
+ *
+ * <p>
+ * A pathname containing an empty string represents an empty path.
+ *
+ * @param path
+ * the pathname of the file/directory.
+ * @param actions
+ * the action string.
+ *
+ * @throws IllegalArgumentException
+ * If actions is <code>null</code>, empty or contains an action
+ * other than the specified possible actions.
+ */
+
+ public JndiPermission(String path, String actions)
+ {
+ super(path);
+ init(getMask(actions));
+ }
+ public JndiPermission(Name path, String actions)
+ {
+ super(path.toString());
+ init(getMask(actions));
+ }
+
+ /**
+ * Creates a new JndiPermission object using an action mask. More efficient
+ * than the JndiPermission(String, String) constructor. Can be used from
+ * within code that needs to create a JndiPermission object to pass into the
+ * <code>implies</code> method.
+ *
+ * @param path
+ * the pathname of the file/directory.
+ * @param mask
+ * the action mask to use.
+ */
+
+ // package private for use by the JndiPermissionCollection add method
+ JndiPermission(String path, int mask)
+ {
+ super(path);
+ init(mask);
+ }
+ public JndiPermission(Name path, int mask)
+ {
+ super(path.toString());
+ init(mask);
+ }
+
+ /**
+ * Checks if this JndiPermission object "implies" the specified permission.
+ * <P>
+ * More specifically, this method returns true if:
+ * <p>
+ * <ul>
+ * <li> <i>p</i> is an instanceof JndiPermission,
+ * <p>
+ * <li> <i>p</i>'s actions are a proper subset of this object's actions, and
+ * <p>
+ * <li> <i>p</i>'s pathname is implied by this object's pathname. For
+ * example, "/tmp/*" implies "/tmp/foo", since "/tmp/*" encompasses all files
+ * in the "/tmp" directory, including the one named "foo".
+ * </ul>
+ *
+ * @param p
+ * the permission to check against.
+ *
+ * @return <code>true</code> if the specified permission is not
+ * <code>null</code> and is implied by this object,
+ * <code>false</code> otherwise.
+ */
+ public boolean implies(Permission p)
+ {
+ if (!(p instanceof JndiPermission))
+ return false;
+
+ JndiPermission that = (JndiPermission) p;
+
+ // we get the effective mask. i.e., the "and" of this and that.
+ // They must be equal to that.mask for implies to return true.
+
+ return ((this.mask & that.mask) == that.mask) && impliesIgnoreMask(that);
+ }
+
+ /**
+ * Checks if the Permission's actions are a proper subset of the this
+ * object's actions. Returns the effective mask iff the this JndiPermission's
+ * path also implies that JndiPermission's path.
+ *
+ * @param that
+ * the JndiPermission to check against.
+ * @param exact
+ * return immediately if the masks are not equal
+ * @return the effective mask
+ */
+ boolean impliesIgnoreMask(JndiPermission that)
+ {
+ if (this.directory)
+ {
+ if (this.recursive)
+ {
+ // make sure that.path is longer then path so
+ // something like /foo/- does not imply /foo
+ if (that.directory)
+ {
+ return (that.cpath.length() >= this.cpath.length())
+ && that.cpath.startsWith(this.cpath);
+ }
+ else
+ {
+ return ((that.cpath.length() >= this.cpath.length()) && that.cpath
+ .startsWith(this.cpath));
+ }
+ }
+ else
+ {
+ if (that.directory)
+ {
+ // if the permission passed in is a directory
+ // specification, make sure that a non-recursive
+ // permission (i.e., this object) can't imply a recursive
+ // permission.
+ if (that.recursive)
+ return false;
+ else
+ return (this.cpath.equals(that.cpath));
+ }
+ else
+ {
+ int last = that.cpath.lastIndexOf('/');
+ if (last == -1)
+ return false;
+ else
+ {
+ // this.cpath.equals(that.cpath.substring(0, last+1));
+ // Use regionMatches to avoid creating new string
+ return (this.cpath.length() == (last + 1))
+ && this.cpath.regionMatches(0, that.cpath, 0, last + 1);
+ }
+ }
+ }
+ }
+ else if (that.directory)
+ {
+ // if this is NOT recursive/wildcarded,
+ // do not let it imply a recursive/wildcarded permission
+ return false;
+ }
+ else
+ {
+ return (this.cpath.equals(that.cpath));
+ }
+ }
+
+ /**
+ * Checks two JndiPermission objects for equality. Checks that <i>obj</i> is
+ * a JndiPermission, and has the same pathname and actions as this object.
+ * <P>
+ *
+ * @param obj
+ * the object we are testing for equality with this object.
+ * @return <code>true</code> if obj is a JndiPermission, and has the same
+ * pathname and actions as this JndiPermission object,
+ * <code>false</code> otherwise.
+ */
+ public boolean equals(Object obj)
+ {
+ if (obj == this)
+ return true;
+
+ if (!(obj instanceof JndiPermission))
+ return false;
+
+ JndiPermission that = (JndiPermission) obj;
+
+ return (this.mask == that.mask) && this.cpath.equals(that.cpath)
+ && (this.directory == that.directory)
+ && (this.recursive == that.recursive);
+ }
+
+ /**
+ * Returns the hash code value for this object.
+ *
+ * @return a hash code value for this object.
+ */
+
+ public int hashCode()
+ {
+ return this.cpath.hashCode();
+ }
+
+
+ /**
+ * Converts an actions String to an actions mask.
+ *
+ * @param action - the comma separated list of actions.
+ * @return the actions mask.
+ */
+ private static int getMask(String actions)
+ {
+
+ int mask = NONE;
+
+ // Null action valid?
+ if (actions == null || actions.length() == 0)
+ {
+ return mask;
+ }
+ // Check against use of constants
+ if (actions == LOOKUP_ACTION)
+ {
+ return LOOKUP;
+ }
+ else if (actions == REBIND_ACTION)
+ {
+ return REBIND;
+ }
+ else if (actions == BIND_ACTION)
+ {
+ return BIND;
+ }
+ else if (actions == UNBIND_ACTION)
+ {
+ return UNBIND;
+ }
+ else if (actions == LIST_ACTION)
+ {
+ return LIST;
+ }
+ else if (actions == LIST_BINDINGS_ACTION)
+ {
+ return LIST_BINDINGS;
+ }
+ else if (actions == CREATE_SUBCONTEXT_ACTION)
+ {
+ return CREATE_SUBCONTEXT;
+ }
+
+ String[] sa = actions.split(",");
+ for(String s : sa)
+ {
+ String key = s.toLowerCase();
+ if(actionMap.containsKey(key) == false)
+ {
+ throw new IllegalArgumentException("invalid permission, unknown action: " + s);
+ }
+ int i = actionMap.get(key);
+ mask |= i;
+ }
+
+ return mask;
+ }
+
+ /**
+ * Return the current action mask. Used by the JndiPermissionCollection.
+ *
+ * @return the actions mask.
+ */
+
+ int getMask()
+ {
+ return mask;
+ }
+
+ /**
+ * Return the canonical string representation of the actions. Always returns
+ * present actions in the following order: bind, rebind, unbind, lookup,
+ * list, listBindings, createSubcontext
+ *
+ * @return the canonical string representation of the actions.
+ */
+ private static String getActions(int mask)
+ {
+ StringBuilder sb = new StringBuilder();
+ boolean insertComma = false;
+ for(int n = 0; n < ACTION_COUNT; n ++)
+ {
+ int action = 1 << n;
+ if((mask & action) == action)
+ {
+ if(insertComma)
+ sb.append(',');
+ sb.append(ALL_ACTIONS[n]);
+ insertComma = true;
+ }
+ }
+
+ return sb.toString();
+ }
+
+ /**
+ * Returns the "canonical string representation" of the actions. That is,
+ * this method always returns present actions in the following order: bind,
+ * rebind, unbind, lookup, list, listBindings, createSubcontext.
+ * For example, if this JndiPermission object allows
+ * both unbind and bind actions, a call to <code>getActions</code> will
+ * return the string "bind,unbind".
+ *
+ * @return the canonical string representation of the actions.
+ */
+ public String getActions()
+ {
+ if (actions == null)
+ actions = getActions(this.mask);
+
+ return actions;
+ }
+
+ /**
+ * Returns a new PermissionCollection object for storing JndiPermission
+ * objects.
+ * <p>
+ * JndiPermission objects must be stored in a manner that allows them to be
+ * inserted into the collection in any order, but that also enables the
+ * PermissionCollection <code>implies</code> method to be implemented in an
+ * efficient (and consistent) manner.
+ *
+ * <p>
+ * For example, if you have two JndiPermissions:
+ * <OL>
+ * <LI> <code>"/tmp/-", "bind"</code>
+ * <LI> <code>"/tmp/scratch/foo", "unbind"</code>
+ * </OL>
+ *
+ * <p>
+ * and you are calling the <code>implies</code> method with the
+ * JndiPermission:
+ *
+ * <pre>
+ * "/tmp/scratch/foo", "bind,unbind",
+ * </pre>
+ *
+ * then the <code>implies</code> function must take into account both the
+ * "/tmp/-" and "/tmp/scratch/foo" permissions, so the effective permission
+ * is "bind,unbind", and <code>implies</code> returns true. The "implies"
+ * semantics for JndiPermissions are handled properly by the
+ * PermissionCollection object returned by this
+ * <code>newPermissionCollection</code> method.
+ *
+ * @return a new PermissionCollection object suitable for storing
+ * JndiPermissions.
+ */
+
+ public PermissionCollection newPermissionCollection()
+ {
+ return new JndiPermissionCollection();
+ }
+
+ /**
+ * WriteObject is called to save the state of the JndiPermission to a stream.
+ * The actions are serialized, and the superclass takes care of the name.
+ */
+ private void writeObject(ObjectOutputStream s) throws IOException
+ {
+ // Write out the actions. The superclass takes care of the name
+ // call getActions to make sure actions field is initialized
+ if (actions == null)
+ getActions();
+ s.defaultWriteObject();
+ }
+
+ /**
+ * readObject is called to restore the state of the JndiPermission from a
+ * stream.
+ */
+ private void readObject(ObjectInputStream s) throws IOException,
+ ClassNotFoundException
+ {
+ // Read in the actions, then restore everything else by calling init.
+ s.defaultReadObject();
+ init(getMask(actions));
+ }
+}
+
+/**
+ * A JndiPermissionCollection stores a set of JndiPermission permissions.
+ * JndiPermission objects must be stored in a manner that allows them to be
+ * inserted in any order, but enable the implies function to evaluate the
+ * implies method. For example, if you have two JndiPermissions:
+ * <OL>
+ * <LI> "/tmp/-", "bind"
+ * <LI> "/tmp/scratch/foo", "unbind"
+ * </OL>
+ * And you are calling the implies function with the JndiPermission:
+ * "/tmp/scratch/foo", "bind,unbind", then the implies function must take into
+ * account both the /tmp/- and /tmp/scratch/foo permissions, so the effective
+ * permission is "bind,unbind".
+ *
+ * @see java.security.Permission
+ * @see java.security.Permissions
+ * @see java.security.PermissionCollection
+ *
+ *
+ * @author Marianne Mueller
+ * @author Roland Schemers
+ * @author Scott.Stark at jboss.org
+ *
+ * @serial include
+ * @version $Revision: 79036 $
+ *
+ */
+final class JndiPermissionCollection extends PermissionCollection implements
+ Serializable
+{
+ private static final long serialVersionUID = 1;
+ private List<JndiPermission> perms;
+
+ /**
+ * Create an empty JndiPermissions object.
+ *
+ */
+ public JndiPermissionCollection()
+ {
+ perms = new ArrayList<JndiPermission>();
+ }
+
+ /**
+ * Adds a permission to the JndiPermissions. The key for the hash is
+ * permission.path.
+ *
+ * @param permission
+ * the Permission object to add.
+ *
+ * @exception IllegalArgumentException -
+ * if the permission is not a JndiPermission
+ *
+ * @exception SecurityException -
+ * if this JndiPermissionCollection object has been marked
+ * readonly
+ */
+
+ public void add(Permission permission)
+ {
+ if (!(permission instanceof JndiPermission))
+ throw new IllegalArgumentException("invalid permission: " + permission);
+ if (isReadOnly())
+ throw new SecurityException("attempt to add a Permission to a readonly PermissionCollection");
+
+ synchronized (this)
+ {
+ perms.add((JndiPermission)permission);
+ }
+ }
+
+ /**
+ * Check and see if this set of permissions implies the permissions expressed
+ * in "permission".
+ *
+ * @param p
+ * the Permission object to compare
+ *
+ * @return true if "permission" is a proper subset of a permission in the
+ * set, false if not.
+ */
+
+ public boolean implies(Permission permission)
+ {
+ if (!(permission instanceof JndiPermission))
+ return false;
+
+ JndiPermission fp = (JndiPermission) permission;
+
+ int desired = fp.getMask();
+ int effective = 0;
+ int needed = desired;
+
+ synchronized (this)
+ {
+ for(JndiPermission x : perms)
+ {
+ if (((needed & x.getMask()) != 0) && x.impliesIgnoreMask(fp))
+ {
+ effective |= x.getMask();
+ if ((effective & desired) == desired)
+ return true;
+ needed = (desired ^ effective);
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Returns an enumeration of all the JndiPermission objects in the container.
+ *
+ * @return an enumeration of all the JndiPermission objects.
+ */
+
+ public Enumeration elements()
+ {
+ // Convert Iterator into Enumeration
+ synchronized (this)
+ {
+ return Collections.enumeration(perms);
+ }
+ }
+
+}
Modified: branches/JBPAPP_4_2_0_GA_CP/naming/src/main/org/jnp/server/NamingServer.java
===================================================================
--- branches/JBPAPP_4_2_0_GA_CP/naming/src/main/org/jnp/server/NamingServer.java 2008-10-07 16:44:10 UTC (rev 79230)
+++ branches/JBPAPP_4_2_0_GA_CP/naming/src/main/org/jnp/server/NamingServer.java 2008-10-07 16:57:09 UTC (rev 79231)
@@ -43,6 +43,7 @@
import org.jnp.interfaces.NamingContext;
import org.jnp.interfaces.NamingParser;
import org.jboss.logging.Logger;
+import org.jboss.naming.JndiPermission;
/**
* The JNDI naming server implementation class.
@@ -95,8 +96,9 @@
if (name.isEmpty())
{
// Empty names are not allowed
- throw new InvalidNameException();
- } else if (name.size() > 1)
+ throw new InvalidNameException("An empty name cannot be passed to bind");
+ }
+ else if (name.size() > 1)
{
// Recurse to find correct context
// System.out.println("bind#"+name+"#");
@@ -106,8 +108,10 @@
{
if (ctx instanceof NamingServer)
{
- ((NamingServer)ctx).bind(name.getSuffix(1),obj, className);
- } else if (ctx instanceof Reference)
+ NamingServer ns = (NamingServer) ctx;
+ ns.bind(name.getSuffix(1),obj, className);
+ }
+ else if (ctx instanceof Reference)
{
// Federation
if (((Reference)ctx).get("nns") != null)
@@ -116,34 +120,48 @@
cpe.setResolvedObj(ctx);
cpe.setRemainingName(name.getSuffix(1));
throw cpe;
- } else
+ }
+ else
{
throw new NotContextException();
}
- } else
+ }
+ else
{
throw new NotContextException();
}
- } else
+ }
+ else
{
- throw new NameNotFoundException();
+ throw new NameNotFoundException(name.toString()+" in: "+prefix);
}
- } else
+ }
+ else
{
// Bind object
if (name.get(0).equals(""))
{
- throw new InvalidNameException();
- } else
+ throw new InvalidNameException("An empty name cannot be passed to bind");
+ }
+ else
{
// System.out.println("bind "+name+"="+obj);
try
{
getBinding(name);
// Already bound
- throw new NameAlreadyBoundException();
- } catch (NameNotFoundException e)
+ throw new NameAlreadyBoundException(name.toString());
+ }
+ catch (NameNotFoundException e)
{
+ Name fullName = (Name) prefix.clone();
+ fullName.addAll(name);
+ SecurityManager sm = System.getSecurityManager();
+ if(sm != null)
+ {
+ JndiPermission perm = new JndiPermission(fullName, JndiPermission.BIND);
+ sm.checkPermission(perm);
+ }
setBinding(name,obj,className);
}
}
@@ -156,8 +174,9 @@
if (name.isEmpty())
{
// Empty names are not allowed
- throw new InvalidNameException();
- } else if (name.size() > 1)
+ throw new InvalidNameException("An empty name cannot be passed to rebind");
+ }
+ else if (name.size() > 1)
{
// Recurse to find correct context
// System.out.println("rebind#"+name+"#");
@@ -166,7 +185,8 @@
if (ctx instanceof NamingServer)
{
((NamingServer)ctx).rebind(name.getSuffix(1),obj, className);
- } else if (ctx instanceof Reference)
+ }
+ else if (ctx instanceof Reference)
{
// Federation
if (((Reference)ctx).get("nns") != null)
@@ -175,23 +195,35 @@
cpe.setResolvedObj(ctx);
cpe.setRemainingName(name.getSuffix(1));
throw cpe;
- } else
+ }
+ else
{
throw new NotContextException();
}
- } else
+ }
+ else
{
throw new NotContextException();
}
- } else
+ }
+ else
{
// Bind object
if (name.get(0).equals(""))
{
- throw new InvalidNameException();
- } else
+ throw new InvalidNameException("An empty name cannot be passed to rebind");
+ }
+ else
{
-// System.out.println("rebind "+name+"="+obj+"("+this+")");
+ SecurityManager sm = System.getSecurityManager();
+ Name fullName = (Name) prefix.clone();
+ String comp = name.get(0);
+ fullName.add(comp);
+ if(sm != null)
+ {
+ JndiPermission perm = new JndiPermission(fullName, JndiPermission.REBIND);
+ sm.checkPermission(perm);
+ }
setBinding(name,obj,className);
}
}
@@ -204,7 +236,8 @@
{
// Empty names are not allowed
throw new InvalidNameException();
- } else if (name.size() > 1)
+ }
+ else if (name.size() > 1)
{
// Recurse to find correct context
// System.out.println("unbind#"+name+"#");
@@ -213,7 +246,8 @@
if (ctx instanceof NamingServer)
{
((NamingServer)ctx).unbind(name.getSuffix(1));
- } else if (ctx instanceof Reference)
+ }
+ else if (ctx instanceof Reference)
{
// Federation
if (((Reference)ctx).get("nns") != null)
@@ -222,11 +256,13 @@
cpe.setResolvedObj(ctx);
cpe.setRemainingName(name.getSuffix(1));
throw cpe;
- } else
+ }
+ else
{
throw new NotContextException();
}
- } else
+ }
+ else
{
throw new NotContextException();
}
@@ -236,13 +272,23 @@
if (name.get(0).equals(""))
{
throw new InvalidNameException();
- } else
+ }
+ else
{
// System.out.println("unbind "+name+"="+getBinding(name));
if (getBinding(name) != null)
{
+ SecurityManager sm = System.getSecurityManager();
+ Name fullName = (Name) prefix.clone();
+ fullName.addAll(name);
+ if(sm != null)
+ {
+ JndiPermission perm = new JndiPermission(fullName, JndiPermission.UNBIND);
+ sm.checkPermission(perm);
+ }
removeBinding(name);
- } else
+ }
+ else
{
throw new NameNotFoundException();
}
@@ -471,9 +517,15 @@
{
Name fullName = (Name) prefix.clone();
fullName.addAll(name);
+ SecurityManager sm = System.getSecurityManager();
+ if(sm != null)
+ {
+ JndiPermission perm = new JndiPermission(fullName, JndiPermission.CREATE_SUBCONTEXT);
+ sm.checkPermission(perm);
+ }
NamingServer subContext = new NamingServer(fullName, this);
+ subCtx = new NamingContext(null, fullName, getRoot());
setBinding(name, subContext, NamingContext.class.getName());
- subCtx = new NamingContext(null, fullName, getRoot());
}
}
return subCtx;
Added: branches/JBPAPP_4_2_0_GA_CP/naming/src/main/org/jnp/test/JndiPermissionUnitTest.java
===================================================================
--- branches/JBPAPP_4_2_0_GA_CP/naming/src/main/org/jnp/test/JndiPermissionUnitTest.java (rev 0)
+++ branches/JBPAPP_4_2_0_GA_CP/naming/src/main/org/jnp/test/JndiPermissionUnitTest.java 2008-10-07 16:57:09 UTC (rev 79231)
@@ -0,0 +1,53 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2008, Red Hat Middleware LLC, and individual contributors
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This 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 software 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 software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jnp.test;
+
+import org.jboss.naming.JndiPermission;
+
+import junit.framework.TestCase;
+
+/**
+ * Tests of the JndiPermission/JndiPermissionCollection behavior
+ *
+ * @author Scott.Stark at jboss.org
+ * @version $Revision: 79036 $
+ */
+public class JndiPermissionUnitTest extends TestCase
+{
+ public void testBind()
+ {
+ JndiPermission any = new JndiPermission("<<ALL BINDINGS>>", "*");
+ JndiPermission path1 = new JndiPermission("/path1/*", "bind");
+ JndiPermission path1Recursive = new JndiPermission("/path1/-", "bind");
+
+ assertTrue("<<ALL BINDINGS>> implies /path1;bind", any.implies(path1));
+ assertTrue("<<ALL BINDINGS>> implies /path1;bind", any.implies(path1Recursive));
+ JndiPermission p = new JndiPermission("/path1/", "bind");
+ assertTrue(path1+" implies /path1/ bind", path1.implies(p));
+ assertTrue(path1Recursive+" implies /path1/ bind", path1Recursive.implies(p));
+ // A directory permission does not imply access to the unqualified path
+ p = new JndiPermission("/path1", "bind");
+ assertFalse(path1+" implies /path1;bind", path1.implies(p));
+ assertFalse(path1Recursive+" implies /path1;bind", path1Recursive.implies(p));
+
+ }
+}
Added: branches/JBPAPP_4_2_0_GA_CP/naming/src/main/org/jnp/test/NamingServerSecurityManagerUnitTest.java
===================================================================
--- branches/JBPAPP_4_2_0_GA_CP/naming/src/main/org/jnp/test/NamingServerSecurityManagerUnitTest.java (rev 0)
+++ branches/JBPAPP_4_2_0_GA_CP/naming/src/main/org/jnp/test/NamingServerSecurityManagerUnitTest.java 2008-10-07 16:57:09 UTC (rev 79231)
@@ -0,0 +1,229 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2008, Red Hat Middleware LLC, and individual contributors
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This 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 software 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 software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jnp.test;
+
+import java.io.FilePermission;
+import java.io.SerializablePermission;
+import java.lang.reflect.ReflectPermission;
+import java.security.AccessControlException;
+import java.security.Permission;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Properties;
+
+import javax.naming.Context;
+import javax.naming.InitialContext;
+
+import junit.framework.TestCase;
+
+import org.jboss.naming.JndiPermission;
+import org.jnp.server.NamingBeanImpl;
+import org.jnp.test.support.QueueSecurityManager;
+import org.jnp.test.support.TestSecurityManager;
+
+/**
+ * Test using the NamingServer with a SecurityManager
+ *
+ * @author Scott.Stark at jboss.org
+ * @version $Revision: 79036 $
+ */
+public class NamingServerSecurityManagerUnitTest extends TestCase
+{
+ /** The actual namingMain service impl bean */
+ private NamingBeanImpl namingBean;
+
+ private InitialContext ic;
+
+ @Override
+ protected void setUp() throws Exception
+ {
+ System.out.println("+++ setUp, creating NamingBean");
+ namingBean = new NamingBeanImpl();
+ namingBean.setInstallGlobalService(true);
+ namingBean.setUseGlobalService(false);
+ namingBean.start();
+
+ Properties env = new Properties();
+ env.setProperty("java.naming.factory.initial", "org.jnp.interfaces.NamingContextFactory");
+ env.setProperty("java.naming.factory.url.pkgs", "org.jnp.interfaces");
+ ic = new InitialContext(env);
+ }
+
+ protected void tearDown()
+ {
+ System.setSecurityManager(null);
+ }
+
+ /**
+ * Test that the expected JndiPermission are passed to the SecurityManager
+ * @throws Exception
+ */
+ public void testOpPermissions() throws Exception
+ {
+ QueueSecurityManager qsm = new QueueSecurityManager();
+ qsm.clearPerms();
+ System.setSecurityManager(qsm);
+
+ HashSet<JndiPermission> expectedPerms = new HashSet<JndiPermission>();
+ // expected doOps() permissions
+ expectedPerms.add(new JndiPermission("path1", "createSubcontext"));
+ expectedPerms.add(new JndiPermission("path1/x", "bind"));
+ expectedPerms.add(new JndiPermission("path1/x", "rebind"));
+ expectedPerms.add(new JndiPermission("path1/x", "unbind"));
+ expectedPerms.add(new JndiPermission("path1", "unbind"));
+ doOps();
+ // expected doBadOps() permissions
+ expectedPerms.add(new JndiPermission("path2", "createSubcontext"));
+ expectedPerms.add(new JndiPermission("path1x", "createSubcontext"));
+ expectedPerms.add(new JndiPermission("path1x", "rebind"));
+ expectedPerms.add(new JndiPermission("path1x/x", "bind"));
+ expectedPerms.add(new JndiPermission("path1x/x", "rebind"));
+ expectedPerms.add(new JndiPermission("path1x", "unbind"));
+ doBadOps(false);
+
+ List<Permission> perms = qsm.getPerms();
+ for (Permission p : perms)
+ {
+ if (p instanceof JndiPermission)
+ {
+ System.out.println(p);
+ assertTrue(p + " is in expectedPerms", expectedPerms.contains(p));
+ }
+ }
+ }
+
+ /**
+ * Run with a TestSecurityManager that has a fixed set of allowed permissions
+ * @throws Exception
+ */
+ public void testSecurityManager() throws Exception
+ {
+ TestSecurityManager tsm = new TestSecurityManager();
+ /*
+ The permissions that should be needed
+ */
+ tsm.addPermission(new JndiPermission("path1", "createSubcontext,unbind"));
+ tsm.addPermission(new JndiPermission("path1x", "createSubcontext,unbind"));
+ tsm.addPermission(new JndiPermission("path1/x", "bind,rebind,unbind"));
+ tsm.addPermission(new RuntimePermission("setSecurityManager"));
+ tsm.addPermission(new FilePermission("<<ALL FILES>>", "read"));
+ tsm.addPermission(new RuntimePermission("createClassLoader"));
+ tsm.addPermission(new ReflectPermission("suppressAccessChecks"));
+ tsm.addPermission(new SerializablePermission("enableSubstitution"));
+ System.setSecurityManager(tsm);
+
+ doOps();
+ doBadOps(true);
+ }
+
+ /**
+ * Validate that the JndiPermission("<<ALL BINDINGS>>", "*") allows all
+ * naming operations.
+ *
+ * @throws Exception
+ */
+ public void testAllPermission() throws Exception
+ {
+ TestSecurityManager tsm = new TestSecurityManager();
+ tsm.addPermission(new JndiPermission("<<ALL BINDINGS>>", "*"));
+ tsm.addPermission(new RuntimePermission("setSecurityManager"));
+ tsm.addPermission(new FilePermission("<<ALL FILES>>", "read"));
+ tsm.addPermission(new RuntimePermission("createClassLoader"));
+ tsm.addPermission(new ReflectPermission("suppressAccessChecks"));
+ tsm.addPermission(new SerializablePermission("enableSubstitution"));
+ System.setSecurityManager(tsm);
+
+ doOps();
+ doBadOps(false);
+ }
+
+ /**
+ * Naming ops that should succeed.
+ * @throws Exception
+ */
+ protected void doOps() throws Exception
+ {
+ ic.createSubcontext("path1");
+ Object p1 = ic.lookup("path1");
+ ic.list("path1");
+ ic.listBindings("path1");
+ ic.bind("path1/x", "x.bind");
+ ic.rebind("path1/x", "x.rebind");
+ ic.unbind("path1/x");
+ ic.unbind("path1");
+ }
+
+ /**
+ * Naming ops that should fail.
+ * @throws Exception
+ */
+ protected void doBadOps(boolean expectFailure) throws Exception
+ {
+ try
+ {
+ ic.createSubcontext("path2");
+ if (expectFailure)
+ fail("Was able to create path2 subcontext");
+ }
+ catch (AccessControlException e)
+ {
+ System.out.println(e);
+ }
+ Context path1x = ic.createSubcontext("path1x");
+ try
+ {
+ if (expectFailure)
+ {
+ ic.rebind("path1x", "path1x.rebind");
+ fail("Was able to rebind path1x subcontext");
+ }
+ }
+ catch (AccessControlException e)
+ {
+ System.out.println(e);
+ }
+
+ try
+ {
+ ic.bind("path1x/x", "x.bind");
+ if (expectFailure)
+ fail("Was able to bind path1x/x");
+ }
+ catch (AccessControlException e)
+ {
+ System.out.println(e);
+ }
+
+ try
+ {
+ ic.rebind("path1x/x", "x.rebind");
+ if (expectFailure)
+ fail("Was able to rebind path1x/x");
+ }
+ catch (AccessControlException e)
+ {
+ System.out.println(e);
+ }
+
+ ic.unbind("path1x");
+ }
+}
Added: branches/JBPAPP_4_2_0_GA_CP/naming/src/main/org/jnp/test/support/QueueSecurityManager.java
===================================================================
--- branches/JBPAPP_4_2_0_GA_CP/naming/src/main/org/jnp/test/support/QueueSecurityManager.java (rev 0)
+++ branches/JBPAPP_4_2_0_GA_CP/naming/src/main/org/jnp/test/support/QueueSecurityManager.java 2008-10-07 16:57:09 UTC (rev 79231)
@@ -0,0 +1,51 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2008, Red Hat Middleware LLC, and individual contributors
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This 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 software 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 software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jnp.test.support;
+
+import java.security.Permission;
+import java.util.ArrayList;
+
+/**
+ * @author Scott.Stark at jboss.org
+ * @version $Revision: 79030 $
+ */
+public class QueueSecurityManager extends SecurityManager
+{
+ private ArrayList<Permission> perms = new ArrayList<Permission>();
+
+
+ public ArrayList<Permission> getPerms()
+ {
+ return perms;
+ }
+ public void clearPerms()
+ {
+ perms.clear();
+ }
+
+ @Override
+ public void checkPermission(Permission perm)
+ {
+ perms.add(perm);
+ }
+
+}
Added: branches/JBPAPP_4_2_0_GA_CP/naming/src/main/org/jnp/test/support/TestSecurityManager.java
===================================================================
--- branches/JBPAPP_4_2_0_GA_CP/naming/src/main/org/jnp/test/support/TestSecurityManager.java (rev 0)
+++ branches/JBPAPP_4_2_0_GA_CP/naming/src/main/org/jnp/test/support/TestSecurityManager.java 2008-10-07 16:57:09 UTC (rev 79231)
@@ -0,0 +1,60 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2008, Red Hat Middleware LLC, and individual contributors
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This 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 software 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 software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jnp.test.support;
+
+import java.security.Permission;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * @author Scott.Stark at jboss.org
+ * @version $Revision: 79030 $
+ */
+public class TestSecurityManager extends SecurityManager
+{
+ /** The set of allowed test permissions */
+ HashSet<Permission> testPermissions = new HashSet<Permission>();
+
+ public void addPermission(Permission p)
+ {
+ testPermissions.add(p);
+ }
+ public Set<Permission> getPermissions()
+ {
+ return testPermissions;
+ }
+
+ /**
+ *
+ */
+ @Override
+ public void checkPermission(Permission perm)
+ {
+ for(Permission p : testPermissions)
+ {
+ if(p.implies(perm))
+ return;
+ }
+ System.out.println("checkPermission, "+perm);
+ super.checkPermission(perm);
+ }
+}
More information about the jboss-cvs-commits
mailing list