mirror of git://gcc.gnu.org/git/gcc.git
				
				
				
			
		
			
				
	
	
		
			550 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			Java
		
	
	
	
			
		
		
	
	
			550 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			Java
		
	
	
	
| /* MBeanPermission.java -- Permissions controlling server access.
 | |
|    Copyright (C) 2006 Free Software Foundation, Inc.
 | |
| 
 | |
| This file is part of GNU Classpath.
 | |
| 
 | |
| GNU Classpath is free software; you can redistribute it and/or modify
 | |
| it under the terms of the GNU General Public License as published by
 | |
| the Free Software Foundation; either version 2, or (at your option)
 | |
| any later version.
 | |
| 
 | |
| GNU Classpath 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 for more details.
 | |
| 
 | |
| You should have received a copy of the GNU General Public License
 | |
| along with GNU Classpath; see the file COPYING.  If not, write to the
 | |
| Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 | |
| 02110-1301 USA.
 | |
| 
 | |
| Linking this library statically or dynamically with other modules is
 | |
| making a combined work based on this library.  Thus, the terms and
 | |
| conditions of the GNU General Public License cover the whole
 | |
| combination.
 | |
| 
 | |
| As a special exception, the copyright holders of this library give you
 | |
| permission to link this library with independent modules to produce an
 | |
| executable, regardless of the license terms of these independent
 | |
| modules, and to copy and distribute the resulting executable under
 | |
| terms of your choice, provided that you also meet, for each linked
 | |
| independent module, the terms and conditions of the license of that
 | |
| module.  An independent module is a module which is not derived from
 | |
| or based on this library.  If you modify this library, you may extend
 | |
| this exception to your version of the library, but you are not
 | |
| obligated to do so.  If you do not wish to do so, delete this
 | |
| exception statement from your version. */
 | |
| 
 | |
| package javax.management;
 | |
| 
 | |
| import gnu.java.lang.CPStringBuilder;
 | |
| 
 | |
| import java.security.Permission;
 | |
| 
 | |
| import java.io.IOException;
 | |
| import java.io.ObjectInputStream;
 | |
| 
 | |
| import java.util.HashSet;
 | |
| import java.util.Iterator;
 | |
| import java.util.Set;
 | |
| import java.util.TreeSet;
 | |
| 
 | |
| /**
 | |
|  * <p>
 | |
|  * Represents the permissions required to perform
 | |
|  * operations using the {@link MBeanServer}.  As with
 | |
|  * all {@link java.security.Permission} objects, an
 | |
|  * instance of this class either represents a permission
 | |
|  * already held or one that is required to access a
 | |
|  * particular service.  In the case of {@link MBeanPermission}s,
 | |
|  * implication checks are made using an instance of this class
 | |
|  * when a user requests an operation from the server, and a
 | |
|  * {@link SecurityManager} is in place.
 | |
|  * </p>
 | |
|  * <p>
 | |
|  * An {@link MBeanPermission} consists of four elements,
 | |
|  * which all have to match for the permission to be implied.
 | |
|  * These are as follows:
 | |
|  * </p>
 | |
|  * <ol>
 | |
|  * <li><strong>The action</strong>.  For a required permission,
 | |
|  * this is a single value.  For a permission held by the user,
 | |
|  * this is a list of comma-separated actions (with spaces allowed),
 | |
|  * or <code>*</code> (representing all actions).  {@link #getActions()}
 | |
|  * returns this value.</li>
 | |
|  * <li><strong>The class name</strong>.  For a required permission,
 | |
|  * this is the class name of the bean being accessed, if any.  If
 | |
|  * a bean isn't involved in this action, the value is <code>null</code>.
 | |
|  * For a permission held by the user, it has one of three values:
 | |
|  * <ol>
 | |
|  * <li>The empty string, implying any class.</li>
 | |
|  * <li><code>*</code>, also implying any class.</li>
 | |
|  * <li>A class name pattern, which may specify a single class
 | |
|  * (e.g. <code>java.lang.Object</code>) or a series of classes
 | |
|  * using the wildcard character <code>*</code> (e.g.
 | |
|  * <code>javax.swing.*</code>.)</li>
 | |
|  * </ol></li>
 | |
|  * <li><strong>The member</strong>.  For a required permission,
 | |
|  * this is the member of the bean being accessed (an attribute
 | |
|  * or operation), if any.  If a member of the bean isn't involved
 | |
|  * in this action, the value is <code>null</code>.
 | |
|  * For a permission held by the user, it has one of three values:
 | |
|  * <ol>
 | |
|  * <li>The empty string, implying any member.</li>
 | |
|  * <li><code>*</code>, also implying any member.</li>
 | |
|  * <li>The name of a member.</li>
 | |
|  * </ol></li>
 | |
|  * <li>The object name</strong>.  For a required permission,
 | |
|  * this is the {@link ObjectName} of the bean being accessed, if
 | |
|  * any.  If a bean isn't involved in this action, the value is
 | |
|  * <code>null</code>.  The name may not be a pattern.
 | |
|  * For a permission held by the user, it may be the empty
 | |
|  * string (allowing everything) or an {@link ObjectName}
 | |
|  * pattern.
 | |
|  * </li></ol>
 | |
|  * {@link #getName()} returns the latter three of these as a
 | |
|  * single string:
 | |
|  * </p>
 | |
|  * <p><code>className#member[objectName]</code></p>
 | |
|  * <p>
 | |
|  * where <code>""</code> is disallowed, as, although any of
 | |
|  * the elements may be omitted, not all of them should be
 | |
|  * left out simultaneously.  <code>"-"</code> is used to
 | |
|  * represent <code>null</code>.  When this occurs in a
 | |
|  * required permission, anything may match it.  When this
 | |
|  * forms part of a permission held by the user, it only
 | |
|  * matches another <code>null</code> value.
 | |
|  * </p>
 | |
|  * <p>The list of valid actions is as follows:</p>
 | |
|  * <ul>
 | |
|  * <li>addNotificationListener</li>
 | |
|  * <li>getAttribute</li>
 | |
|  * <li>getClassLoader</li>
 | |
|  * <li>getClassLoaderFor</li>
 | |
|  * <li>getClassLoaderRepository</li>
 | |
|  * <li>getDomains</li>
 | |
|  * <li>getMBeanInfo</li>
 | |
|  * <li>getObjectInstance</li>
 | |
|  * <li>instantiate</li>
 | |
|  * <li>invoke</li>
 | |
|  * <li>isInstanceOf</li>
 | |
|  * <li>queryMBeans</li>
 | |
|  * <li>queryNames</li>
 | |
|  * <li>registerMBean</li>
 | |
|  * <li>removeNotificationListener</li>
 | |
|  * <li>setAttribute</li>
 | |
|  * <li>unregisterMBean</li>
 | |
|  * </ul>
 | |
|  *
 | |
|  * @author Andrew John Hughes (gnu_andrew@member.fsf.org)
 | |
|  * @since 1.5
 | |
|  */
 | |
| public class MBeanPermission
 | |
|   extends Permission
 | |
| {
 | |
| 
 | |
|   /**
 | |
|    * Compatible with JDK 1.5
 | |
|    */
 | |
|   private static final long serialVersionUID = -2416928705275160661L;
 | |
| 
 | |
|   /**
 | |
|    * The list of actions associated with this permission.
 | |
|    */
 | |
|   private String actions;
 | |
| 
 | |
|   /**
 | |
|    * The list of actions as an ordered set.
 | |
|    */
 | |
|   private transient Set<String> actionSet;
 | |
| 
 | |
|   /**
 | |
|    * The set of valid actions.
 | |
|    */
 | |
|   private static final Set<String> validSet;
 | |
| 
 | |
|   /**
 | |
|    * Initialise the set of valid actions.
 | |
|    */
 | |
|   static
 | |
|   {
 | |
|     validSet = new HashSet<String>();
 | |
|     validSet.add("addNotificationListener");
 | |
|     validSet.add("getAttribute");
 | |
|     validSet.add("getClassLoader");
 | |
|     validSet.add("getClassLoaderFor");
 | |
|     validSet.add("getClassLoaderRepository");
 | |
|     validSet.add("getDomains");
 | |
|     validSet.add("getMBeanInfo");
 | |
|     validSet.add("getObjectInstance");
 | |
|     validSet.add("instantiate");
 | |
|     validSet.add("invoke");
 | |
|     validSet.add("isInstanceOf");
 | |
|     validSet.add("queryMBeans");
 | |
|     validSet.add("queryNames");
 | |
|     validSet.add("registerMBean");
 | |
|     validSet.add("removeNotificationListener");
 | |
|     validSet.add("setAttribute");
 | |
|     validSet.add("unregisterMBean");
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Constructs a new {@link MBeanPermission} with the specified name
 | |
|    * and actions.  The name is of the form <code>className#member[objectName]</code>,
 | |
|    * where each element is optional, but a completely empty or <code>null</code>
 | |
|    * name is disallowed.  Actions are specified as a comma-separated list
 | |
|    * and may also not be empty or <code>null</code>.
 | |
|    *
 | |
|    * @param name the name of the permission.
 | |
|    * @param actions the actions associated with this permission.
 | |
|    * @throws IllegalArgumentException if the name or actions are invalid.
 | |
|    */
 | |
|   public MBeanPermission(String name, String actions)
 | |
|   {
 | |
|     super(name);
 | |
|     if (name == null || name.length() == 0)
 | |
|       throw new IllegalArgumentException("The supplied name was null or empty.");
 | |
|     if (actions == null || actions.length() == 0)
 | |
|       throw new IllegalArgumentException("The supplied action list was null or empty.");
 | |
|     this.actions = actions;
 | |
|     updateActionSet();
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Constructs a new {@link MBeanPermission} with the specified class name,
 | |
|    * member, object name and actions.  The name of the permission is created
 | |
|    * using the form <code>className#member[objectName]</code>,
 | |
|    * where each element is optional, but an empty or <code>null</code>
 | |
|    * name is disallowed.  Actions are specified as a comma-separated list
 | |
|    * and may also not be empty or <code>null</code>.
 | |
|    *
 | |
|    * @param className the name of the class to which this permission applies,
 | |
|    *                  or either <code>null</code> or <code>"-"</code> for a
 | |
|    *                  value which may be implied by any class name, but not
 | |
|    *                  imply any class name itself.
 | |
|    * @param member the member of the class to which this permission applies,
 | |
|    *               or either <code>null</code> or <code>"-"</code> for a
 | |
|    *               value which may be implied by any member, but not
 | |
|    *               imply any member itself.
 | |
|    * @param name the {@link ObjectName} to which this permission applies,
 | |
|    *                  or <code>null</code> for a value which may be implied by
 | |
|    *                  any object name, but not imply any object name itself.
 | |
|    * @param actions the actions associated with this permission.
 | |
|    */
 | |
|   public MBeanPermission(String className, String member,
 | |
|                          ObjectName name, String actions)
 | |
|   {
 | |
|     this((className == null ? "-" : className) + "#"
 | |
|          + (member == null ? "-" : member) + "["
 | |
|          + (name == null ? "-" : name.toString()) + "]", actions);
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Returns true if the given object is also an {@link MBeanPermission}
 | |
|    * with the same name and actions.
 | |
|    *
 | |
|    * @param obj the object to test.
 | |
|    * @return true if the object is an {@link MBeanPermission} with
 | |
|    *         the same name and actions.
 | |
|    */
 | |
|   public boolean equals(Object obj)
 | |
|   {
 | |
|     if (obj instanceof MBeanPermission)
 | |
|       {
 | |
|         MBeanPermission p = (MBeanPermission) obj;
 | |
|         return (p.getName().equals(getName()) &&
 | |
|                 p.getActions().equals(actions));
 | |
|       }
 | |
|     return false;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Returns the list of actions in alphabetical order.
 | |
|    *
 | |
|    * @return the list of actions.
 | |
|    */
 | |
|   public String getActions()
 | |
|   {
 | |
|     Iterator<String> it = actionSet.iterator();
 | |
|     CPStringBuilder builder = new CPStringBuilder();
 | |
|     while (it.hasNext())
 | |
|       {
 | |
|         builder.append(it.next());
 | |
|         if (it.hasNext())
 | |
|           builder.append(",");
 | |
|       }
 | |
|     return builder.toString();
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Returns the hashcode of the permission as the sum
 | |
|    * of the hashcodes of the name and actions.
 | |
|    *
 | |
|    * @return the hashcode of the permission.
 | |
|    */
 | |
|   public int hashCode()
 | |
|   {
 | |
|     return getName().hashCode() + actions.hashCode();
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * <p>
 | |
|    * Returns true if this permission implies the supplied permission.
 | |
|    * This happens if the following holds:
 | |
|    * </p>
 | |
|    * <ul>
 | |
|    * <li>The supplied permission is an {@link MBeanPermission}</li>
 | |
|    * <li>The supplied permission has either a <code>null</code> classname
 | |
|    * or its classname matches the classname of this permission.  A
 | |
|    * classname of <code>"*"</code> for this permission always matches
 | |
|    * the classname of the supplied permission.  Generally, <code>'*'</code>
 | |
|    * acts as a wildcard, so <code>".*"</code> matches <code>'.'</code>
 | |
|    * followed by anything.</li>
 | |
|    * <li>The supplied permission has either a <code>null</code> member
 | |
|    * or its member matches the member of this permission.  A member of
 | |
|    * <code>"*"</code> for this permission always matches the member
 | |
|    * of the supplied permission.</li>
 | |
|    * <li>The supplied permission has either a <code>null</code> object name
 | |
|    * or its object name matches the object name of this permission.  If the
 | |
|    * object name of this permission is a pattern, {@link ObjectName#apply(ObjectName)}
 | |
|    * may be used as well.</li>
 | |
|    * <li>The supplied permission's actions are a subset of the actions
 | |
|    * of this permission.  If the <code>queryMBeans</code> action is presented,
 | |
|    * the <code>queryNames</code> action is implied.</li>
 | |
|    * </ul>
 | |
|    *
 | |
|    * @param p the permission to check that this permission implies.
 | |
|    * @return true if this permission implies <code>p</code>.
 | |
|    */
 | |
|   public boolean implies(Permission p)
 | |
|   {
 | |
|     if (p instanceof MBeanPermission)
 | |
|       {
 | |
|         MBeanPermission mp = (MBeanPermission) p;
 | |
|         NameHolder pName = new NameHolder(mp.getName());
 | |
|         NameHolder name = new NameHolder(getName());
 | |
|         if (!(name.equals(pName)))
 | |
|           return false;
 | |
|         for (String nextAction : mp.actionSet)
 | |
|           {
 | |
|             boolean found = actions.contains(nextAction);
 | |
|             if (!found)
 | |
|               if (nextAction.equals("queryNames"))
 | |
|                 found = actions.contains("queryMBeans");
 | |
|             if (!found)
 | |
|               return false;
 | |
|           }
 | |
|         return true;
 | |
|       }
 | |
|     return false;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Small helper class to handle deconstruction of the name.
 | |
|    *
 | |
|    * @author Andrew John Hughes (gnu_andrew@member.fsf.org)
 | |
|    */
 | |
|   private class NameHolder
 | |
|   {
 | |
| 
 | |
|     /**
 | |
|      * The class name.
 | |
|      */
 | |
|     private String className;
 | |
| 
 | |
|     /**
 | |
|      * The member.
 | |
|      */
 | |
|     private String member;
 | |
| 
 | |
|     /**
 | |
|      * The object name.
 | |
|      */
 | |
|     private ObjectName objectName;
 | |
| 
 | |
|     /**
 | |
|      * Constructs a broken-down name from a given name.
 | |
|      *
 | |
|      * @param name the name to break down.
 | |
|      */
 | |
|     public NameHolder(String name)
 | |
|     {
 | |
|       String objectName = null;
 | |
|       int memberIndex = name.indexOf("#");
 | |
|       int onIndex = name.indexOf("[");
 | |
|       if (onIndex == -1)
 | |
|         {
 | |
|           if (memberIndex == -1)
 | |
|             className = name;
 | |
|           else
 | |
|             {
 | |
|               className = name.substring(0, memberIndex);
 | |
|               member = name.substring(memberIndex + 1);
 | |
|             }
 | |
|         }
 | |
|       else
 | |
|         {
 | |
|           if (memberIndex == -1)
 | |
|             {
 | |
|               className = name.substring(0, onIndex);
 | |
|               objectName = name.substring(onIndex + 1,
 | |
|                                           name.length() - 1);
 | |
|             }
 | |
|           else
 | |
|             {
 | |
|               className = name.substring(0, memberIndex);
 | |
|               member = name.substring(memberIndex + 1, onIndex);
 | |
|               objectName = name.substring(onIndex + 1,
 | |
|                                           name.length() - 1);
 | |
|             }
 | |
|         }
 | |
|       if (className.equals("-"))
 | |
|         className = null;
 | |
|       if (member.equals("-"))
 | |
|         member = null;
 | |
|       if (objectName == null || objectName.equals("-"))
 | |
|         this.objectName = null;
 | |
|       else
 | |
|         try
 | |
|           {
 | |
|             this.objectName = new ObjectName(objectName);
 | |
|           }
 | |
|         catch (MalformedObjectNameException e)
 | |
|           {
 | |
|             throw (Error)
 | |
|               (new InternalError("Invalid object name.").initCause(e));
 | |
|           }
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * <p>
 | |
|      * Returns true if the supplied object is also a
 | |
|      * {@link NameHolder} and the following holds:
 | |
|      * </p>
 | |
|      * <ul>
 | |
|      * <li>The supplied classname is <code>null</code> or the two match.  A
 | |
|      * classname of <code>"*"</code> for this holder always matches
 | |
|      * the classname of the supplied holder.  Generally, <code>'*'</code>
 | |
|      * acts as a wildcard, so <code>".*"</code> matches <code>'.'</code>
 | |
|      * followed by anything.</li>
 | |
|      * <li>The supplied name holder has either a <code>null</code> member
 | |
|      * or its member matches the member of this name holder.  A member of
 | |
|      * <code>"*"</code> for this name holder always matches the member
 | |
|      * of the supplied name holder.</li>
 | |
|      * <li>The supplied name holder has either a <code>null</code> object name
 | |
|      * or its object name matches the object name of this name holder.  If the
 | |
|      * object name of this name holder is a pattern,
 | |
|      * {@link ObjectName#apply(ObjectName)} may be used as well.</li>
 | |
|      * </ul>
 | |
|      *
 | |
|      * @param obj the object to compare with this.
 | |
|      * @return true if the above holds.
 | |
|      */
 | |
|     public boolean equals(Object obj)
 | |
|     {
 | |
|       if (obj instanceof NameHolder)
 | |
|         {
 | |
|           NameHolder nh = (NameHolder) obj;
 | |
|           boolean cn = false;
 | |
|           String ocn = nh.getClassName();
 | |
|           if (ocn == null || className.equals("*"))
 | |
|             cn = true;
 | |
|           else
 | |
|             {
 | |
|               int wcIndex = className.indexOf("*");
 | |
|               if (wcIndex != -1)
 | |
|                 cn = ocn.startsWith(className.substring(0, wcIndex));
 | |
|               else
 | |
|                 cn = ocn.equals(className);
 | |
|             }
 | |
|           boolean m = false;
 | |
|           String om = nh.getMember();
 | |
|           if (om == null || member.equals("*"))
 | |
|             m = true;
 | |
|           else
 | |
|             m = om.equals(member);
 | |
|           boolean on = false;
 | |
|           ObjectName oon = nh.getObjectName();
 | |
|           if (oon == null)
 | |
|             on = true;
 | |
|           else if (objectName.isPattern())
 | |
|             on = objectName.apply(oon);
 | |
|           else
 | |
|             on = oon.equals(objectName);
 | |
|           return (cn && m && on);
 | |
|         }
 | |
|       return false;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Returns the class name.
 | |
|      */
 | |
|     public String getClassName()
 | |
|     {
 | |
|       return className;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Returns the member.
 | |
|      */
 | |
|     public String getMember()
 | |
|     {
 | |
|       return member;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Returns the object name.
 | |
|      */
 | |
|     public ObjectName getObjectName()
 | |
|     {
 | |
|       return objectName;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Updates the action set from the current value of
 | |
|    * the actions string.
 | |
|    */
 | |
|   private void updateActionSet()
 | |
|   {
 | |
|     String[] actionsArray = actions.split(",");
 | |
|     actionSet = new TreeSet<String>();
 | |
|     for (int a = 0; a < actionsArray.length; ++a)
 | |
|       actionSet.add(actionsArray[a].trim());
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Reads the object from a stream and ensures the incoming
 | |
|    * data is valid.
 | |
|    *
 | |
|    * @param in the input stream.
 | |
|    * @throws IOException if an I/O error occurs.
 | |
|    * @throws ClassNotFoundException if a class used by the object
 | |
|    *                                can not be found.
 | |
|    */
 | |
|   private void readObject(ObjectInputStream in)
 | |
|     throws IOException, ClassNotFoundException
 | |
|   {
 | |
|     in.defaultReadObject();
 | |
|     updateActionSet();
 | |
|     checkActions();
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Checks that the actions used in this permission
 | |
|    * are from the valid set.
 | |
|    *
 | |
|    * @throws IllegalArgumentException if the name or actions are invalid.
 | |
|    */
 | |
|   private void checkActions()
 | |
|   {
 | |
|     for (String action : actionSet)
 | |
|       {
 | |
|         if (!(validSet.contains(action)))
 | |
|           throw new IllegalArgumentException("Invalid action "
 | |
|                                              + action + " found.");
 | |
|       }
 | |
|   }
 | |
| 
 | |
| }
 |