/* * Copyright 2002-2007 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. */ package javax.management; import java.io.IOException; import java.io.ObjectInputStream; import java.security.Permission; /** * <p>Permission controlling access to MBeanServer operations. If a * security manager has been set using {@link * System#setSecurityManager}, 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 {@link MBeanServer} interface.</p> * * <p>As with other {@link Permission} objects, an MBeanPermission can * represent either a permission that you <em>have</em> or a * permission that you <em>need</em>. 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 {@link #implies imply} the * permission you need.</p> * * <p>An MBeanPermission contains four items of information:</p> * * <ul> * * <li><p>The <em>action</em>. For a permission you need, * this is one of the actions in the list <a * href="#action-list">below</a>. For a permission you have, this is * a comma-separated list of those actions, or <code>*</code>, * representing all actions.</p> * * <p>The action is returned by {@link #getActions()}.</p> * * <li><p>The <em>class name</em>.</p> * * <p>For a permission you need, this is the class name of an MBean * you are accessing, as returned by {@link * MBeanServer#getMBeanInfo(ObjectName) * MBeanServer.getMBeanInfo(name)}.{@link MBeanInfo#getClassName() * getClassName()}. Certain operations do not reference a class name, * in which case the class name is null.</p> * * <p>For a permission you have, this is either empty or a <em>class * name pattern</em>. A class name pattern is a string following the * Java conventions for dot-separated class names. It may end with * "<code>.*</code>" meaning that the permission grants access to any * class that begins with the string preceding "<code>.*</code>". For * instance, "<code>javax.management.*</code>" grants access to * <code>javax.management.MBeanServerDelegate</code> and * <code>javax.management.timer.Timer</code>, among other classes.</p> * * <p>A class name pattern can also be empty or the single character * "<code>*</code>", both of which grant access to any class.</p> * * <li><p>The <em>member</em>.</p> * * <p>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.</p> * * <p>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 * "<code>*</code>", both of which grant access to any member.</p> * * <li><p>The <em>object name</em>.</p> * * <p>For a permission you need, this is the {@link 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.</p> * * <p>For a permission you have, this is the {@link 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.</p> * * </ul> * * <p>If you have an MBeanPermission, it allows operations only if all * four of the items match.</p> * * <p>The class name, member, and object name can be written together * as a single string, which is the <em>name</em> of this permission. * The name of the permission is the string returned by {@link * Permission#getName() getName()}. The format of the string is:</p> * * <blockquote> * <code>className#member[objectName]</code> * </blockquote> * * <p>The object name is written using the usual syntax for {@link * ObjectName}. It may contain any legal characters, including * <code>]</code>. It is terminated by a <code>]</code> character * that is the last character in the string.</p> * * <p>One or more of the <code>className</code>, <code>member</code>, * or <code>objectName</code> may be omitted. If the * <code>member</code> is omitted, the <code>#</code> may be too (but * does not have to be). If the <code>objectName</code> is omitted, * the <code>[]</code> may be too (but does not have to be). It is * not legal to omit all three items, that is to have a <em>name</em> * that is the empty string.</p> * * <p>One or more of the <code>className</code>, <code>member</code>, * or <code>objectName</code> may be the character "<code>-</code>", * 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.</p> * * <p><a name="action-list">The possible actions are these:</a></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> * * <p>In a comma-separated list of actions, spaces are allowed before * and after each action.</p> * * @since 1.5 */ public class MBeanPermission extends Permission { private static final long serialVersionUID = -2416928705275160661L; /** * Actions list. */ private static final int AddNotificationListener = 0x00001; private static final int GetAttribute = 0x00002; private static final int GetClassLoader = 0x00004; private static final int GetClassLoaderFor = 0x00008; private static final int GetClassLoaderRepository = 0x00010; private static final int GetDomains = 0x00020; private static final int GetMBeanInfo = 0x00040; private static final int GetObjectInstance = 0x00080; private static final int Instantiate = 0x00100; private static final int Invoke = 0x00200; private static final int IsInstanceOf = 0x00400; private static final int QueryMBeans = 0x00800; private static final int QueryNames = 0x01000; private static final int RegisterMBean = 0x02000; private static final int RemoveNotificationListener = 0x04000; private static final int SetAttribute = 0x08000; private static final int UnregisterMBean = 0x10000; /** * No actions. */ private static final int NONE = 0x00000; /** * All actions. */ private static final int ALL = AddNotificationListener | GetAttribute | GetClassLoader | GetClassLoaderFor | GetClassLoaderRepository | GetDomains | GetMBeanInfo | GetObjectInstance | Instantiate | Invoke | IsInstanceOf | QueryMBeans | QueryNames | RegisterMBean | RemoveNotificationListener | SetAttribute | UnregisterMBean; /** * The actions string. */ private String actions; /** * The actions mask. */ private transient int mask; /** * The classname prefix that must match. If null, is implied by any * classNamePrefix but does not imply any non-null classNamePrefix. */ private transient String classNamePrefix; /** * True if classNamePrefix must match exactly. Otherwise, the * className being matched must start with classNamePrefix. */ private transient boolean classNameExactMatch; /** * The member that must match. If null, is implied by any member * but does not imply any non-null member. */ private transient String member; /** * The objectName that must match. If null, is implied by any * objectName but does not imply any non-null objectName. */ private transient ObjectName objectName; /** * Parse <code>actions</code> parameter. */ private void parseActions() { int mask; if (actions == null) throw new IllegalArgumentException("MBeanPermission: " + "actions can't be null"); if (actions.equals("")) throw new IllegalArgumentException("MBeanPermission: " + "actions can't be empty"); mask = getMask(actions); if ((mask & ALL) != mask) throw new IllegalArgumentException("Invalid actions mask"); if (mask == NONE) throw new IllegalArgumentException("Invalid actions mask"); this.mask = mask; } /** * Parse <code>name</code> parameter. */ private void parseName() { String name = getName(); if (name == null) throw new IllegalArgumentException("MBeanPermission name " + "cannot be null"); if (name.equals("")) throw new IllegalArgumentException("MBeanPermission name " + "cannot be empty"); /* The name looks like "class#member[objectname]". We subtract elements from the right as we parse, so after parsing the objectname we have "class#member" and after parsing the member we have "class". Each element is optional. */ // Parse ObjectName int openingBracket = name.indexOf("["); if (openingBracket == -1) { // If "[on]" missing then ObjectName("*:*") // objectName = ObjectName.WILDCARD; } else { if (!name.endsWith("]")) { throw new IllegalArgumentException("MBeanPermission: " + "The ObjectName in the " + "target name must be " + "included in square " + "brackets"); } else { // Create ObjectName // try { // If "[]" then ObjectName("*:*") // String on = name.substring(openingBracket + 1, name.length() - 1); if (on.equals("")) objectName = ObjectName.WILDCARD; else if (on.equals("-")) objectName = null; else objectName = new ObjectName(on); } catch (MalformedObjectNameException e) { throw new IllegalArgumentException("MBeanPermission: " + "The target name does " + "not specify a valid " + "ObjectName"); } } name = name.substring(0, openingBracket); } // Parse member int poundSign = name.indexOf("#"); if (poundSign == -1) setMember("*"); else { String memberName = name.substring(poundSign + 1); setMember(memberName); name = name.substring(0, poundSign); } // Parse className setClassName(name); } /** * Assign fields based on className, member, and objectName * parameters. */ private void initName(String className, String member, ObjectName objectName) { setClassName(className); setMember(member); this.objectName = objectName; } private void setClassName(String className) { if (className == null || className.equals("-")) { classNamePrefix = null; classNameExactMatch = false; } else if (className.equals("") || className.equals("*")) { classNamePrefix = ""; classNameExactMatch = false; } else if (className.endsWith(".*")) { // Note that we include the "." in the required prefix classNamePrefix = className.substring(0, className.length() - 1); classNameExactMatch = false; } else { classNamePrefix = className; classNameExactMatch = true; } } private void setMember(String member) { if (member == null || member.equals("-")) this.member = null; else if (member.equals("")) this.member = "*"; else this.member = member; } /** * <p>Create a new MBeanPermission object with the specified target name * and actions.</p> * * <p>The target name is of the form * "<code>className#member[objectName]</code>" where each part is * optional. It must not be empty or null.</p> * * <p>The actions parameter contains a comma-separated list of the * desired actions granted on the target name. It must not be * empty or null.</p> * * @param name the triplet "className#member[objectName]". * @param actions the action string. * * @exception IllegalArgumentException if the <code>name</code> or * <code>actions</code> is invalid. */ public MBeanPermission(String name, String actions) { super(name); parseName(); this.actions = actions; parseActions(); } /** * <p>Create a new MBeanPermission object with the specified target name * (class name, member, object name) and actions.</p> * * <p>The class name, member and object name parameters define a * target name of the form * "<code>className#member[objectName]</code>" where each part is * optional. This will be the result of {@link #getName()} on the * resultant MBeanPermission.</p> * * <p>The actions parameter contains a comma-separated list of the * desired actions granted on the target name. It must not be * empty or null.</p> * * @param className the class name to which this permission applies. * May be null or <code>"-"</code>, 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 <code>"-"</code>, 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(makeName(className, member, objectName)); initName(className, member, objectName); this.actions = actions; parseActions(); } private static String makeName(String className, String member, ObjectName objectName) { final StringBuilder name = new StringBuilder(); if (className == null) className = "-"; name.append(className); if (member == null) member = "-"; name.append("#" + member); if (objectName == null) name.append("[-]"); else name.append("[").append(objectName.getCanonicalName()).append("]"); /* In the interests of legibility for Permission.toString(), we transform the empty string into "*". */ if (name.length() == 0) return "*"; else return name.toString(); } /** * 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() { if (actions == null) actions = getActions(this.mask); return actions; } /** * Returns the "canonical string representation" * of the actions from the mask. */ private static String getActions(int mask) { final StringBuilder sb = new StringBuilder(); boolean comma = false; if ((mask & AddNotificationListener) == AddNotificationListener) { comma = true; sb.append("addNotificationListener"); } if ((mask & GetAttribute) == GetAttribute) { if (comma) sb.append(','); else comma = true; sb.append("getAttribute"); } if ((mask & GetClassLoader) == GetClassLoader) { if (comma) sb.append(','); else comma = true; sb.append("getClassLoader"); } if ((mask & GetClassLoaderFor) == GetClassLoaderFor) { if (comma) sb.append(','); else comma = true; sb.append("getClassLoaderFor"); } if ((mask & GetClassLoaderRepository) == GetClassLoaderRepository) { if (comma) sb.append(','); else comma = true; sb.append("getClassLoaderRepository"); } if ((mask & GetDomains) == GetDomains) { if (comma) sb.append(','); else comma = true; sb.append("getDomains"); } if ((mask & GetMBeanInfo) == GetMBeanInfo) { if (comma) sb.append(','); else comma = true; sb.append("getMBeanInfo"); } if ((mask & GetObjectInstance) == GetObjectInstance) { if (comma) sb.append(','); else comma = true; sb.append("getObjectInstance"); } if ((mask & Instantiate) == Instantiate) { if (comma) sb.append(','); else comma = true; sb.append("instantiate"); } if ((mask & Invoke) == Invoke) { if (comma) sb.append(','); else comma = true; sb.append("invoke"); } if ((mask & IsInstanceOf) == IsInstanceOf) { if (comma) sb.append(','); else comma = true; sb.append("isInstanceOf"); } if ((mask & QueryMBeans) == QueryMBeans) { if (comma) sb.append(','); else comma = true; sb.append("queryMBeans"); } if ((mask & QueryNames) == QueryNames) { if (comma) sb.append(','); else comma = true; sb.append("queryNames"); } if ((mask & RegisterMBean) == RegisterMBean) { if (comma) sb.append(','); else comma = true; sb.append("registerMBean"); } if ((mask & RemoveNotificationListener) == RemoveNotificationListener) { if (comma) sb.append(','); else comma = true; sb.append("removeNotificationListener"); } if ((mask & SetAttribute) == SetAttribute) { if (comma) sb.append(','); else comma = true; sb.append("setAttribute"); } if ((mask & UnregisterMBean) == UnregisterMBean) { if (comma) sb.append(','); else comma = true; sb.append("unregisterMBean"); } return sb.toString(); } /** * Returns the hash code value for this object. * * @return a hash code value for this object. */ public int hashCode() { return this.getName().hashCode() + this.getActions().hashCode(); } /** * Converts an action String to an integer action mask. * * @param action the action string. * @return the action mask. */ private static int getMask(String action) { /* * BE CAREFUL HERE! PARSING ORDER IS IMPORTANT IN THIS ALGORITHM. * * The 'string length' test must be performed for the lengthiest * strings first. * * In this permission if the "unregisterMBean" string length test is * performed after the "registerMBean" string length test the algorithm * considers the 'unregisterMBean' action as being the 'registerMBean' * action and a parsing error is returned. */ int mask = NONE; if (action == null) { return mask; } if (action.equals("*")) { return ALL; } char[] a = action.toCharArray(); int i = a.length - 1; if (i < 0) return mask; while (i != -1) { char c; // skip whitespace while ((i!=-1) && ((c = a[i]) == ' ' || c == '\r' || c == '\n' || c == '\f' || c == '\t')) i--; // check for the known strings int matchlen; if (i >= 25 && /* removeNotificationListener */ (a[i-25] == 'r') && (a[i-24] == 'e') && (a[i-23] == 'm') && (a[i-22] == 'o') && (a[i-21] == 'v') && (a[i-20] == 'e') && (a[i-19] == 'N') && (a[i-18] == 'o') && (a[i-17] == 't') && (a[i-16] == 'i') && (a[i-15] == 'f') && (a[i-14] == 'i') && (a[i-13] == 'c') && (a[i-12] == 'a') && (a[i-11] == 't') && (a[i-10] == 'i') && (a[i-9] == 'o') && (a[i-8] == 'n') && (a[i-7] == 'L') && (a[i-6] == 'i') && (a[i-5] == 's') && (a[i-4] == 't') && (a[i-3] == 'e') && (a[i-2] == 'n') && (a[i-1] == 'e') && (a[i] == 'r')) { matchlen = 26; mask |= RemoveNotificationListener; } else if (i >= 23 && /* getClassLoaderRepository */ (a[i-23] == 'g') && (a[i-22] == 'e') && (a[i-21] == 't') && (a[i-20] == 'C') && (a[i-19] == 'l') && (a[i-18] == 'a') && (a[i-17] == 's') && (a[i-16] == 's') && (a[i-15] == 'L') && (a[i-14] == 'o') && (a[i-13] == 'a') && (a[i-12] == 'd') && (a[i-11] == 'e') && (a[i-10] == 'r') && (a[i-9] == 'R') && (a[i-8] == 'e') && (a[i-7] == 'p') && (a[i-6] == 'o') && (a[i-5] == 's') && (a[i-4] == 'i') && (a[i-3] == 't') && (a[i-2] == 'o') && (a[i-1] == 'r') && (a[i] == 'y')) { matchlen = 24; mask |= GetClassLoaderRepository; } else if (i >= 22 && /* addNotificationListener */ (a[i-22] == 'a') && (a[i-21] == 'd') && (a[i-20] == 'd') && (a[i-19] == 'N') && (a[i-18] == 'o') && (a[i-17] == 't') && (a[i-16] == 'i') && (a[i-15] == 'f') && (a[i-14] == 'i') && (a[i-13] == 'c') && (a[i-12] == 'a') && (a[i-11] == 't') && (a[i-10] == 'i') && (a[i-9] == 'o') && (a[i-8] == 'n') && (a[i-7] == 'L') && (a[i-6] == 'i') && (a[i-5] == 's') && (a[i-4] == 't') && (a[i-3] == 'e') && (a[i-2] == 'n') && (a[i-1] == 'e') && (a[i] == 'r')) { matchlen = 23; mask |= AddNotificationListener; } else if (i >= 16 && /* getClassLoaderFor */ (a[i-16] == 'g') && (a[i-15] == 'e') && (a[i-14] == 't') && (a[i-13] == 'C') && (a[i-12] == 'l') && (a[i-11] == 'a') && (a[i-10] == 's') && (a[i-9] == 's') && (a[i-8] == 'L') && (a[i-7] == 'o') && (a[i-6] == 'a') && (a[i-5] == 'd') && (a[i-4] == 'e') && (a[i-3] == 'r') && (a[i-2] == 'F') && (a[i-1] == 'o') && (a[i] == 'r')) { matchlen = 17; mask |= GetClassLoaderFor; } else if (i >= 16 && /* getObjectInstance */ (a[i-16] == 'g') && (a[i-15] == 'e') && (a[i-14] == 't') && (a[i-13] == 'O') && (a[i-12] == 'b') && (a[i-11] == 'j') && (a[i-10] == 'e') && (a[i-9] == 'c') && (a[i-8] == 't') && (a[i-7] == 'I') && (a[i-6] == 'n') && (a[i-5] == 's') && (a[i-4] == 't') && (a[i-3] == 'a') && (a[i-2] == 'n') && (a[i-1] == 'c') && (a[i] == 'e')) { matchlen = 17; mask |= GetObjectInstance; } else if (i >= 14 && /* unregisterMBean */ (a[i-14] == 'u') && (a[i-13] == 'n') && (a[i-12] == 'r') && (a[i-11] == 'e') && (a[i-10] == 'g') && (a[i-9] == 'i') && (a[i-8] == 's') && (a[i-7] == 't') && (a[i-6] == 'e') && (a[i-5] == 'r') && (a[i-4] == 'M') && (a[i-3] == 'B') && (a[i-2] == 'e') && (a[i-1] == 'a') && (a[i] == 'n')) { matchlen = 15; mask |= UnregisterMBean; } else if (i >= 13 && /* getClassLoader */ (a[i-13] == 'g') && (a[i-12] == 'e') && (a[i-11] == 't') && (a[i-10] == 'C') && (a[i-9] == 'l') && (a[i-8] == 'a') && (a[i-7] == 's') && (a[i-6] == 's') && (a[i-5] == 'L') && (a[i-4] == 'o') && (a[i-3] == 'a') && (a[i-2] == 'd') && (a[i-1] == 'e') && (a[i] == 'r')) { matchlen = 14; mask |= GetClassLoader; } else if (i >= 12 && /* registerMBean */ (a[i-12] == 'r') && (a[i-11] == 'e') && (a[i-10] == 'g') && (a[i-9] == 'i') && (a[i-8] == 's') && (a[i-7] == 't') && (a[i-6] == 'e') && (a[i-5] == 'r') && (a[i-4] == 'M') && (a[i-3] == 'B') && (a[i-2] == 'e') && (a[i-1] == 'a') && (a[i] == 'n')) { matchlen = 13; mask |= RegisterMBean; } else if (i >= 11 && /* getAttribute */ (a[i-11] == 'g') && (a[i-10] == 'e') && (a[i-9] == 't') && (a[i-8] == 'A') && (a[i-7] == 't') && (a[i-6] == 't') && (a[i-5] == 'r') && (a[i-4] == 'i') && (a[i-3] == 'b') && (a[i-2] == 'u') && (a[i-1] == 't') && (a[i] == 'e')) { matchlen = 12; mask |= GetAttribute; } else if (i >= 11 && /* getMBeanInfo */ (a[i-11] == 'g') && (a[i-10] == 'e') && (a[i-9] == 't') && (a[i-8] == 'M') && (a[i-7] == 'B') && (a[i-6] == 'e') && (a[i-5] == 'a') && (a[i-4] == 'n') && (a[i-3] == 'I') && (a[i-2] == 'n') && (a[i-1] == 'f') && (a[i] == 'o')) { matchlen = 12; mask |= GetMBeanInfo; } else if (i >= 11 && /* isInstanceOf */ (a[i-11] == 'i') && (a[i-10] == 's') && (a[i-9] == 'I') && (a[i-8] == 'n') && (a[i-7] == 's') && (a[i-6] == 't') && (a[i-5] == 'a') && (a[i-4] == 'n') && (a[i-3] == 'c') && (a[i-2] == 'e') && (a[i-1] == 'O') && (a[i] == 'f')) { matchlen = 12; mask |= IsInstanceOf; } else if (i >= 11 && /* setAttribute */ (a[i-11] == 's') && (a[i-10] == 'e') && (a[i-9] == 't') && (a[i-8] == 'A') && (a[i-7] == 't') && (a[i-6] == 't') && (a[i-5] == 'r') && (a[i-4] == 'i') && (a[i-3] == 'b') && (a[i-2] == 'u') && (a[i-1] == 't') && (a[i] == 'e')) { matchlen = 12; mask |= SetAttribute; } else if (i >= 10 && /* instantiate */ (a[i-10] == 'i') && (a[i-9] == 'n') && (a[i-8] == 's') && (a[i-7] == 't') && (a[i-6] == 'a') && (a[i-5] == 'n') && (a[i-4] == 't') && (a[i-3] == 'i') && (a[i-2] == 'a') && (a[i-1] == 't') && (a[i] == 'e')) { matchlen = 11; mask |= Instantiate; } else if (i >= 10 && /* queryMBeans */ (a[i-10] == 'q') && (a[i-9] == 'u') && (a[i-8] == 'e') && (a[i-7] == 'r') && (a[i-6] == 'y') && (a[i-5] == 'M') && (a[i-4] == 'B') && (a[i-3] == 'e') && (a[i-2] == 'a') && (a[i-1] == 'n') && (a[i] == 's')) { matchlen = 11; mask |= QueryMBeans; } else if (i >= 9 && /* getDomains */ (a[i-9] == 'g') && (a[i-8] == 'e') && (a[i-7] == 't') && (a[i-6] == 'D') && (a[i-5] == 'o') && (a[i-4] == 'm') && (a[i-3] == 'a') && (a[i-2] == 'i') && (a[i-1] == 'n') && (a[i] == 's')) { matchlen = 10; mask |= GetDomains; } else if (i >= 9 && /* queryNames */ (a[i-9] == 'q') && (a[i-8] == 'u') && (a[i-7] == 'e') && (a[i-6] == 'r') && (a[i-5] == 'y') && (a[i-4] == 'N') && (a[i-3] == 'a') && (a[i-2] == 'm') && (a[i-1] == 'e') && (a[i] == 's')) { matchlen = 10; mask |= QueryNames; } else if (i >= 5 && /* invoke */ (a[i-5] == 'i') && (a[i-4] == 'n') && (a[i-3] == 'v') && (a[i-2] == 'o') && (a[i-1] == 'k') && (a[i] == 'e')) { matchlen = 6; mask |= Invoke; } else { // parse error throw new IllegalArgumentException("Invalid permission: " + action); } // make sure we didn't just match the tail of a word // like "ackbarfaccept". Also, skip to the comma. boolean seencomma = false; while (i >= matchlen && !seencomma) { switch(a[i-matchlen]) { case ',': seencomma = true; break; case ' ': case '\r': case '\n': case '\f': case '\t': break; default: throw new IllegalArgumentException("Invalid permission: " + action); } i--; } // point i at the location of the comma minus one (or -1). i -= matchlen; } return mask; } /** * <p>Checks if this MBeanPermission object "implies" the * specified permission.</p> * * <p>More specifically, this method returns true if:</p> * * <ul> * * <li> <i>p</i> is an instance of MBeanPermission; and</li> * * <li> <i>p</i> has a null className or <i>p</i>'s className * matches this object's className; and</li> * * <li> <i>p</i> has a null member or <i>p</i>'s member matches this * object's member; and</li> * * <li> <i>p</i> has a null object name or <i>p</i>'s * object name matches this object's object name; and</li> * * <li> <i>p</i>'s actions are a subset of this object's actions</li> * * </ul> * * <p>If this object's className is "<code>*</code>", <i>p</i>'s * className always matches it. If it is "<code>a.*</code>", <i>p</i>'s * className matches it if it begins with "<code>a.</code>".</p> * * <p>If this object's member is "<code>*</code>", <i>p</i>'s * member always matches it.</p> * * <p>If this object's objectName <i>n1</i> is an object name pattern, * <i>p</i>'s objectName <i>n2</i> matches it if * {@link ObjectName#equals <i>n1</i>.equals(<i>n2</i>)} or if * {@link ObjectName#apply <i>n1</i>.apply(<i>n2</i>)}.</p> * * <p>A permission that includes the <code>queryMBeans</code> action * is considered to include <code>queryNames</code> as well.</p> * * @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 instanceof MBeanPermission)) return false; MBeanPermission that = (MBeanPermission) p; // Actions // // The actions in 'this' permission must be a // superset of the actions in 'that' permission // /* "queryMBeans" implies "queryNames" */ if ((this.mask & QueryMBeans) == QueryMBeans) { if (((this.mask | QueryNames) & that.mask) != that.mask) { //System.out.println("action [with QueryNames] does not imply"); return false; } } else { if ((this.mask & that.mask) != that.mask) { //System.out.println("action does not imply"); return false; } } // Target name // // The 'className' check is true iff: // 1) the className in 'this' permission is omitted or "*", or // 2) the className in 'that' permission is omitted or "*", or // 3) the className in 'this' permission does pattern // matching with the className in 'that' permission. // // The 'member' check is true iff: // 1) the member in 'this' permission is omitted or "*", or // 2) the member in 'that' permission is omitted or "*", or // 3) the member in 'this' permission equals the member in // 'that' permission. // // The 'object name' check is true iff: // 1) the object name in 'this' permission is omitted or "*:*", or // 2) the object name in 'that' permission is omitted or "*:*", or // 3) the object name in 'this' permission does pattern // matching with the object name in 'that' permission. // /* Check if this.className implies that.className. If that.classNamePrefix is empty that means the className is irrelevant for this permission check. Otherwise, we do not expect that "that" contains a wildcard, since it is a needed permission. So we assume that.classNameExactMatch. */ if (that.classNamePrefix == null) { // bottom is implied } else if (this.classNamePrefix == null) { // bottom implies nothing but itself return false; } else if (this.classNameExactMatch) { if (!that.classNameExactMatch) return false; // exact never implies wildcard if (!that.classNamePrefix.equals(this.classNamePrefix)) return false; // exact match fails } else { // prefix match, works even if "that" is also a wildcard // e.g. a.* implies a.* and a.b.* if (!that.classNamePrefix.startsWith(this.classNamePrefix)) return false; } /* Check if this.member implies that.member */ if (that.member == null) { // bottom is implied } else if (this.member == null) { // bottom implies nothing but itself return false; } else if (this.member.equals("*")) { // wildcard implies everything (including itself) } else if (!this.member.equals(that.member)) { return false; } /* Check if this.objectName implies that.objectName */ if (that.objectName == null) { // bottom is implied } else if (this.objectName == null) { // bottom implies nothing but itself return false; } else if (!this.objectName.apply(that.objectName)) { /* ObjectName.apply returns false if that.objectName is a wildcard so we also allow equals for that case. This never happens during real permission checks, but means the implies relation is reflexive. */ if (!this.objectName.equals(that.objectName)) return false; } return true; } /** * Checks two MBeanPermission objects for equality. Checks * that <i>obj</i> is an MBeanPermission, and has the same * name and actions as this object. * <P> * @param obj 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 obj) { if (obj == this) return true; if (! (obj instanceof MBeanPermission)) return false; MBeanPermission that = (MBeanPermission) obj; return (this.mask == that.mask) && (this.getName().equals(that.getName())); } /** * Deserialize this object based on its name and actions. */ private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { in.defaultReadObject(); parseName(); parseActions(); } }