MBeanPermission.java |
/* * JBoss, the OpenSource J2EE webOS * * Distributable under LGPL license. * See terms of license at gnu.org. */ package javax.management; // $Id: MBeanPermission.java,v 1.7 2004/05/17 19:46:34 ejort Exp $ import java.io.IOException; import java.io.ObjectInputStream; import java.security.Permission; import java.util.StringTokenizer; import java.util.TreeSet; import java.util.Iterator; /** Permission controlling access to MBeanServer operations. If a security manager has been set using System.setSecurityManager(java.lang.SecurityManager), most operations on the MBean Server require that the caller's permissions imply an MBeanPermission appropriate for the operation. This is described in detail in the documentation for the MBeanServer interface. As with other Permission objects, an MBeanPermission can represent either a permission that you have or a permission that you need. When a sensitive operation is being checked for permission, an MBeanPermission is constructed representing the permission you need. The operation is only allowed if the permissions you have imply the permission you need. An MBeanPermission contains four items of information: - The action. For a permission you need, this is one of the actions in the list below. For a permission you have, this is a comma-separated list of those actions, or *, representing all actions. The action is returned by getActions(). - The class name. For a permission you need, this is the class name of an MBean you are accessing, as returned by MBeanServer.getMBeanInfo(name).getClassName(). Certain operations do not reference a class name, in which case the class name is null. For a permission you have, this is either empty or a class name pattern. A class name pattern is a string following the Java conventions for dot-separated class names. It may end with ".*" meaning that the permission grants access to any class that begins with the string preceding ".*". For instance, "javax.management.*" grants access to javax.management.MBeanServerDelegate and javax.management.timer.Timer, among other classes. A class name pattern can also be empty or the single character "*", both of which grant access to any class. - The member. For a permission you need, this is the name of the attribute or operation you are accessing. For operations that do not reference an attribute or operation, the member is null. For a permission you have, this is either the name of an attribute or operation you can access, or it is empty or the single character "*", both of which grant access to any member. - The object name. For a permission you need, this is the ObjectName of the MBean you are accessing. For operations that do not reference a single MBean, it is null. It is never an object name pattern. For a permission you have, this is the ObjectName of the MBean or MBeans you can access. It may be an object name pattern to grant access to all MBeans whose names match the pattern. It may also be empty, which grants access to all MBeans whatever their name. If you have an MBeanPermission, it allows operations only if all four of the items match. The class name, member, and object name can be written together as a single string, which is the name of this permission. The name of the permission is the string returned by getName(). The format of the string is: className#member[objectName] The object name is written using the usual syntax for ObjectName. It may contain any legal characters, including ]. It is terminated by a ] character that is the last character in the string. One or more of the className, member, or objectName may be omitted. If the member is omitted, the # may be too (but does not have to be). If the objectName is omitted, the [] may be too (but does not have to be). It is not legal to omit all three items, that is to have a name that is the empty string. One or more of the className, member, or objectName may be the character "-", which is equivalent to a null value. A null value is implied by any value (including another null value) but does not imply any other value. The possible actions are these: * addNotificationListener * getAttribute * getClassLoader * getClassLoaderFor * getClassLoaderRepository * getDomains * getMBeanInfo * getObjectInstance * instantiate * invoke * isInstanceOf * queryMBeans * queryNames * registerMBean * removeNotificationListener * setAttribute * unregisterMBean In a comma-separated list of actions, spaces are allowed before and after each action. * @author <a href="mailto:thomas.diesler@jboss.org">Thomas Diesler</a>. * @author Scott.Stark@jboss.org * @version $Revision: 1.7 $ */ public class MBeanPermission extends Permission { private static final long serialVersionUID = -2416928705275160661L; private static ObjectName ANY_NAME; private static TreeSet VALID_ACTIONS = new TreeSet(); static { VALID_ACTIONS.add("addNotificationListener"); VALID_ACTIONS.add("getAttribute"); VALID_ACTIONS.add("getClassLoader"); VALID_ACTIONS.add("getClassLoaderFor"); VALID_ACTIONS.add("getClassLoaderRepository"); VALID_ACTIONS.add("getDomains"); VALID_ACTIONS.add("getMBeanInfo"); VALID_ACTIONS.add("getObjectInstance"); VALID_ACTIONS.add("instantiate"); VALID_ACTIONS.add("invoke"); VALID_ACTIONS.add("isInstanceOf"); VALID_ACTIONS.add("queryMBeans"); VALID_ACTIONS.add("queryNames"); VALID_ACTIONS.add("registerMBean"); VALID_ACTIONS.add("removeNotificationListener"); VALID_ACTIONS.add("setAttribute"); VALID_ACTIONS.add("unregisterMBean"); } /** The class name this applies to */ private transient String className; private transient boolean prefixMatch; private transient String member; private transient ObjectName objectName; private transient TreeSet actionSet; private String actions; /** * Create a new MBeanPermission object with the specified target name and actions. * * The target name is of the form "className#member[objectName]" where each * part is optional. It must not be empty or null. * * The actions parameter contains a comma-separated list of the desired * actions granted on the target name. It must not be empty or null. * * @param name the triplet "className#member[objectName]". * @param actions the action string. * @throws IllegalArgumentException if the name or actions is invalid. */ public MBeanPermission(String name, String actions) { super(name); parseName(name); parseActions(actions); } /** Create a new MBeanPermission object with the specified target name * (class name, member, object name) and actions. * * The class name, member and object name parameters define a target name of * the form "className#member[objectName]" where each part is optional. This * will be the result of Permission.getName() on the resultant * MBeanPermission. * * The actions parameter contains a comma-separated list of the desired * actions granted on the target name. It must not be empty or null. * * @param className the class name to which this permission applies. May be * null or "-", which represents a class name that is implied by any class * name but does not imply any other class name. * @param member the member to which this permission applies. May be null or * "-", which represents a member that is implied by any member but does not * imply any other member. * @param objectName the object name to which this permission applies. May * be null, which represents an object name that is implied by any object * name but does not imply any other object name. * @param actions the action string. */ public MBeanPermission(String className, String member, ObjectName objectName, String actions) { super((className == null ? "-" : className) + "#" + (member == null ? "-" : member) +"["+(objectName == null ? "-" : objectName.toString())+"]"); this.className = className; this.member = member; this.objectName = objectName; parseActions(actions); } /** * Returns the "canonical string representation" of the actions. * That is, this method always returns present actions in alphabetical order. * @return the canonical string representation of the actions. */ public String getActions() { return actions; } /** * Returns the hash code value for this object. * @return a hash code value for this object. */ public int hashCode() { int hashCode = getName().hashCode(); if( actionSet != null ) hashCode += actionSet.hashCode(); return hashCode; } /** * Checks if this MBeanPermission object "implies" the specified permission. * * More specifically, this method returns true if: * <ul> * <li>p is an instance of MBeanPermission; and * <li>p has a null className or p's className matches this object's * className; and * <li>p has a null member or p's member matches this object's member; and * <li>p has a null object name name or or p's object name matches this * object's object name; and * <li>p's actions are a subset of this object's actions * </ul> * * If this object's className is "*", p's className always matches it. If it * is "a.*", p's className matches it if it begins with "a.". * * If this object's member is "*", p's member always matches it. * * If this object's objectName n1 is an object name pattern, p's objectName * n2 matches it if n1.equals(n2) or if n1.apply(n2). * * A permission that includes the queryMBeans action is considered to include * queryNames as well. * * @param p the permission to check against. * @return true if the specified permission is implied by this object, false * if not. */ public boolean implies(Permission p) { if( p == null || (p instanceof MBeanPermission) == false ) return false; MBeanPermission perm = (MBeanPermission) p; boolean implies = false; // Check the className if( perm.className == null ) implies = true; else if( className == null ) implies = false; else if( className.length() == 0 ) implies = true; else if( prefixMatch == true && perm.className != null ) implies = perm.className.startsWith(className); else implies = className.equals(perm.className); // Check the member if( implies == true ) { if( perm.member == null ) implies = true; else if( member == null ) implies = false; else if( member.length() == 0 ) implies = true; else implies = member.equals(perm.member); } // Check the object name if( implies == true ) { if( perm.objectName == null ) implies = true; else if( objectName == null ) implies = false; else { implies = objectName == perm.objectName || objectName.apply(perm.objectName); if( implies == false && perm.objectName.isPattern() ) implies = objectName.equals(perm.objectName); } } // Check the actions if( actionSet != null && implies == true ) { implies = perm.actionSet != null && actionSet.containsAll(perm.actionSet); } return implies; } /** * Checks two MBeanPermission objects for equality. Checks that obj is an * MBeanPermission, and has the same name and actions as this object. * @param p the object we are testing for equality with this object. * @return true if obj is an MBeanPermission, and has the same name and * actions as this MBeanPermission object. */ public boolean equals(Object p) { if( p == null || (p instanceof MBeanPermission) == false ) return false; MBeanPermission perm = (MBeanPermission) p; boolean equals = getName().equals(perm.getName()); if( equals ) { equals = actionSet == perm.actionSet; if( equals == false && actionSet != null ) equals = actionSet.equals(perm.actionSet); } return equals; } /** Parse the className#member[objectName] name. * @param name - className#member[objectName] * @throws IllegalArgumentException */ private void parseName(String name) throws IllegalArgumentException { if( name == null || name.length() == 0 ) throw new IllegalArgumentException("name must not be empty or null"); StringTokenizer tokenizer = new StringTokenizer(name, "#[]", true); boolean inMember = false; boolean inObjectName = false; // Parse the className className = tokenizer.nextToken(); if( className.equals("#") ) { className = ""; inMember = true; } else if( className.equals("[") ) { className = ""; inObjectName = true; } else if( className.equals("*") ) className = ""; else if( className.equals("-") ) className = null; else if( className.endsWith(".*") ) { className = className.substring(0, className.length()-2); prefixMatch = true; } // Parse the member member = ""; if( inObjectName == false ) { if( inMember == true ) { // Parse after the # if( tokenizer.hasMoreTokens() ) { member = tokenizer.nextToken(); if( member.equals("[") ) { inObjectName = true; member = ""; } else if( member.equals("*")) { member = ""; } else if( member.equals("-")) { member = null; } } } // See if there is a # else if( tokenizer.hasMoreTokens() ) { // Can only be a # or [ member = tokenizer.nextToken(); if( member.equals("#") ) { if( tokenizer.hasMoreTokens() ) { member = tokenizer.nextToken(); if( member.equals("[") ) { inObjectName = true; member = ""; } else if( member.equals("*")) { member = ""; } else if( member.equals("-")) { member = null; } } else { member = ""; } } else { inObjectName = true; } } } if( ANY_NAME == null ) { try { ANY_NAME = new ObjectName("*:*"); } catch(Exception e) { throw new IllegalStateException("Could not create ObjectName(*:*)"); } } // Parse the objectName objectName = ANY_NAME; if( inObjectName == false && tokenizer.hasMoreTokens() ) { inObjectName = true; // Throw away the [ tokenizer.nextToken(); } if( inObjectName ) { // Get the token upto the trailing ] String token = tokenizer.nextToken("]"); try { if( token.equals("-") ) objectName = null; else if( token.equals("]") ) objectName = ANY_NAME; else objectName = new ObjectName(token); } catch(Exception e) { IllegalArgumentException ex = new IllegalArgumentException("Invalid objectName"); ex.initCause(e); throw ex; } } } /** Parse the actions list * @param actions - a comma-separated list of the desired actions granted on * the target name. It must not be empty or null * @throws IllegalArgumentException */ private void parseActions(String actions) throws IllegalArgumentException { if( actions == null || actions.length() == 0 ) throw new IllegalArgumentException("actions must not be empty or null"); if( actions.equals("*") ) { this.actionSet = null; this.actions = "*"; } else { this.actionSet = new TreeSet(); StringTokenizer tokenizer = new StringTokenizer(actions, ", "); while( tokenizer.hasMoreTokens() ) { String action = tokenizer.nextToken(); if( VALID_ACTIONS.contains(action) == false ) throw new IllegalArgumentException(action+" is not one of: "+VALID_ACTIONS); this.actionSet.add(action); } // queryMBeans -> queryNames; if( this.actionSet.contains("queryMBeans") ) this.actionSet.add("queryNames"); StringBuffer tmp = new StringBuffer(); Iterator iter = this.actionSet.iterator(); while( iter.hasNext() ) { tmp.append(iter.next()); tmp.append(','); } tmp.setLength(tmp.length()-1); this.actions = tmp.toString(); } } private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException { ois.defaultReadObject(); parseName(getName()); parseActions(getActions()); } }
MBeanPermission.java |