1 /* 2 * Copyright (c) 2002, 2014, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package javax.management; 27 28 import java.io.IOException; 29 import java.io.ObjectInputStream; 30 import java.security.Permission; 31 32 /** 33 * <p>Permission controlling access to MBeanServer operations. If a 34 * security manager has been set using {@link 35 * System#setSecurityManager}, most operations on the MBean Server 36 * require that the caller's permissions imply an MBeanPermission 37 * appropriate for the operation. This is described in detail in the 38 * documentation for the {@link MBeanServer} interface.</p> 39 * 40 * <p>As with other {@link Permission} objects, an MBeanPermission can 41 * represent either a permission that you <em>have</em> or a 42 * permission that you <em>need</em>. When a sensitive operation is 43 * being checked for permission, an MBeanPermission is constructed 44 * representing the permission you need. The operation is only 45 * allowed if the permissions you have {@linkplain #implies imply} the 46 * permission you need.</p> 47 * 48 * <p>An MBeanPermission contains four items of information:</p> 49 * 50 * <ul> 51 * 52 * <li><p>The <em>action</em>. For a permission you need, 53 * this is one of the actions in the list <a 54 * href="#action-list">below</a>. For a permission you have, this is 55 * a comma-separated list of those actions, or <code>*</code>, 56 * representing all actions.</p> 57 * 58 * <p>The action is returned by {@link #getActions()}.</p> 59 * 60 * <li><p>The <em>class name</em>.</p> 61 * 62 * <p>For a permission you need, this is the class name of an MBean 63 * you are accessing, as returned by {@link 64 * MBeanServer#getMBeanInfo(ObjectName) 65 * MBeanServer.getMBeanInfo(name)}.{@link MBeanInfo#getClassName() 66 * getClassName()}. Certain operations do not reference a class name, 67 * in which case the class name is null.</p> 68 * 69 * <p>For a permission you have, this is either empty or a <em>class 70 * name pattern</em>. A class name pattern is a string following the 71 * Java conventions for dot-separated class names. It may end with 72 * "<code>.*</code>" meaning that the permission grants access to any 73 * class that begins with the string preceding "<code>.*</code>". For 74 * instance, "<code>javax.management.*</code>" grants access to 75 * <code>javax.management.MBeanServerDelegate</code> and 76 * <code>javax.management.timer.Timer</code>, among other classes.</p> 77 * 78 * <p>A class name pattern can also be empty or the single character 79 * "<code>*</code>", both of which grant access to any class.</p> 80 * 81 * <li><p>The <em>member</em>.</p> 82 * 83 * <p>For a permission you need, this is the name of the attribute or 84 * operation you are accessing. For operations that do not reference 85 * an attribute or operation, the member is null.</p> 86 * 87 * <p>For a permission you have, this is either the name of an attribute 88 * or operation you can access, or it is empty or the single character 89 * "<code>*</code>", both of which grant access to any member.</p> 90 * 91 * <li id="MBeanName"><p>The <em>object name</em>.</p> 92 * 93 * <p>For a permission you need, this is the {@link ObjectName} of the 94 * MBean you are accessing. For operations that do not reference a 95 * single MBean, it is null. It is never an object name pattern.</p> 96 * 97 * <p>For a permission you have, this is the {@link ObjectName} of the 98 * MBean or MBeans you can access. It may be an object name pattern 99 * to grant access to all MBeans whose names match the pattern. It 100 * may also be empty, which grants access to all MBeans whatever their 101 * name.</p> 102 * 103 * </ul> 104 * 105 * <p>If you have an MBeanPermission, it allows operations only if all 106 * four of the items match.</p> 107 * 108 * <p>The class name, member, and object name can be written together 109 * as a single string, which is the <em>name</em> of this permission. 110 * The name of the permission is the string returned by {@link 111 * Permission#getName() getName()}. The format of the string is:</p> 112 * 113 * <blockquote> 114 * <code>className#member[objectName]</code> 115 * </blockquote> 116 * 117 * <p>The object name is written using the usual syntax for {@link 118 * ObjectName}. It may contain any legal characters, including 119 * <code>]</code>. It is terminated by a <code>]</code> character 120 * that is the last character in the string.</p> 121 * 122 * <p>One or more of the <code>className</code>, <code>member</code>, 123 * or <code>objectName</code> may be omitted. If the 124 * <code>member</code> is omitted, the <code>#</code> may be too (but 125 * does not have to be). If the <code>objectName</code> is omitted, 126 * the <code>[]</code> may be too (but does not have to be). It is 127 * not legal to omit all three items, that is to have a <em>name</em> 128 * that is the empty string.</p> 129 * 130 * <p>One or more of the <code>className</code>, <code>member</code>, 131 * or <code>objectName</code> may be the character "<code>-</code>", 132 * which is equivalent to a null value. A null value is implied by 133 * any value (including another null value) but does not imply any 134 * other value.</p> 135 * 136 * <p><a name="action-list">The possible actions are these:</a></p> 137 * 138 * <ul> 139 * <li>addNotificationListener</li> 140 * <li>getAttribute</li> 141 * <li>getClassLoader</li> 142 * <li>getClassLoaderFor</li> 143 * <li>getClassLoaderRepository</li> 144 * <li>getDomains</li> 145 * <li>getMBeanInfo</li> 146 * <li>getObjectInstance</li> 147 * <li>instantiate</li> 148 * <li>invoke</li> 149 * <li>isInstanceOf</li> 150 * <li>queryMBeans</li> 151 * <li>queryNames</li> 152 * <li>registerMBean</li> 153 * <li>removeNotificationListener</li> 154 * <li>setAttribute</li> 155 * <li>unregisterMBean</li> 156 * </ul> 157 * 158 * <p>In a comma-separated list of actions, spaces are allowed before 159 * and after each action. 160 * 161 * @since 1.5 162 */ 163 public class MBeanPermission extends Permission { 164 165 private static final long serialVersionUID = -2416928705275160661L; 166 167 /** 168 * Actions list. 169 */ 170 private static final int AddNotificationListener = 0x00001; 171 private static final int GetAttribute = 0x00002; 172 private static final int GetClassLoader = 0x00004; 173 private static final int GetClassLoaderFor = 0x00008; 174 private static final int GetClassLoaderRepository = 0x00010; 175 private static final int GetDomains = 0x00020; 176 private static final int GetMBeanInfo = 0x00040; 177 private static final int GetObjectInstance = 0x00080; 178 private static final int Instantiate = 0x00100; 179 private static final int Invoke = 0x00200; 180 private static final int IsInstanceOf = 0x00400; 181 private static final int QueryMBeans = 0x00800; 182 private static final int QueryNames = 0x01000; 183 private static final int RegisterMBean = 0x02000; 184 private static final int RemoveNotificationListener = 0x04000; 185 private static final int SetAttribute = 0x08000; 186 private static final int UnregisterMBean = 0x10000; 187 188 /** 189 * No actions. 190 */ 191 private static final int NONE = 0x00000; 192 193 /** 194 * All actions. 195 */ 196 private static final int ALL = 197 AddNotificationListener | 198 GetAttribute | 199 GetClassLoader | 200 GetClassLoaderFor | 201 GetClassLoaderRepository | 202 GetDomains | 203 GetMBeanInfo | 204 GetObjectInstance | 205 Instantiate | 206 Invoke | 207 IsInstanceOf | 208 QueryMBeans | 209 QueryNames | 210 RegisterMBean | 211 RemoveNotificationListener | 212 SetAttribute | 213 UnregisterMBean; 214 215 /** 216 * The actions string. 217 */ 218 private String actions; 219 220 /** 221 * The actions mask. 222 */ 223 private transient int mask; 224 225 /** 226 * The classname prefix that must match. If null, is implied by any 227 * classNamePrefix but does not imply any non-null classNamePrefix. 228 */ 229 private transient String classNamePrefix; 230 231 /** 232 * True if classNamePrefix must match exactly. Otherwise, the 233 * className being matched must start with classNamePrefix. 234 */ 235 private transient boolean classNameExactMatch; 236 237 /** 238 * The member that must match. If null, is implied by any member 239 * but does not imply any non-null member. 240 */ 241 private transient String member; 242 243 /** 244 * The objectName that must match. If null, is implied by any 245 * objectName but does not imply any non-null objectName. 246 */ 247 private transient ObjectName objectName; 248 249 /** 250 * Parse <code>actions</code> parameter. 251 */ 252 private void parseActions() { 253 254 int mask; 255 256 if (actions == null) 257 throw new IllegalArgumentException("MBeanPermission: " + 258 "actions can't be null"); 259 if (actions.equals("")) 260 throw new IllegalArgumentException("MBeanPermission: " + 261 "actions can't be empty"); 262 263 mask = getMask(actions); 264 265 if ((mask & ALL) != mask) 266 throw new IllegalArgumentException("Invalid actions mask"); 267 if (mask == NONE) 268 throw new IllegalArgumentException("Invalid actions mask"); 269 this.mask = mask; 270 } 271 272 /** 273 * Parse <code>name</code> parameter. 274 */ 275 private void parseName() { 276 String name = getName(); 277 278 if (name == null) 279 throw new IllegalArgumentException("MBeanPermission name " + 280 "cannot be null"); 281 282 if (name.equals("")) 283 throw new IllegalArgumentException("MBeanPermission name " + 284 "cannot be empty"); 285 286 /* The name looks like "class#member[objectname]". We subtract 287 elements from the right as we parse, so after parsing the 288 objectname we have "class#member" and after parsing the 289 member we have "class". Each element is optional. */ 290 291 // Parse ObjectName 292 293 int openingBracket = name.indexOf('['); 294 if (openingBracket == -1) { 295 // If "[on]" missing then ObjectName("*:*") 296 // 297 objectName = ObjectName.WILDCARD; 298 } else { 299 if (!name.endsWith("]")) { 300 throw new IllegalArgumentException("MBeanPermission: " + 301 "The ObjectName in the " + 302 "target name must be " + 303 "included in square " + 304 "brackets"); 305 } else { 306 // Create ObjectName 307 // 308 try { 309 // If "[]" then ObjectName("*:*") 310 // 311 String on = name.substring(openingBracket + 1, 312 name.length() - 1); 313 if (on.equals("")) 314 objectName = ObjectName.WILDCARD; 315 else if (on.equals("-")) 316 objectName = null; 317 else 318 objectName = new ObjectName(on); 319 } catch (MalformedObjectNameException e) { 320 throw new IllegalArgumentException("MBeanPermission: " + 321 "The target name does " + 322 "not specify a valid " + 323 "ObjectName", e); 324 } 325 } 326 327 name = name.substring(0, openingBracket); 328 } 329 330 // Parse member 331 332 int poundSign = name.indexOf('#'); 333 334 if (poundSign == -1) 335 setMember("*"); 336 else { 337 String memberName = name.substring(poundSign + 1); 338 setMember(memberName); 339 name = name.substring(0, poundSign); 340 } 341 342 // Parse className 343 344 setClassName(name); 345 } 346 347 /** 348 * Assign fields based on className, member, and objectName 349 * parameters. 350 */ 351 private void initName(String className, String member, 352 ObjectName objectName) { 353 setClassName(className); 354 setMember(member); 355 this.objectName = objectName; 356 } 357 358 private void setClassName(String className) { 359 if (className == null || className.equals("-")) { 360 classNamePrefix = null; 361 classNameExactMatch = false; 362 } else if (className.equals("") || className.equals("*")) { 363 classNamePrefix = ""; 364 classNameExactMatch = false; 365 } else if (className.endsWith(".*")) { 366 // Note that we include the "." in the required prefix 367 classNamePrefix = className.substring(0, className.length() - 1); 368 classNameExactMatch = false; 369 } else { 370 classNamePrefix = className; 371 classNameExactMatch = true; 372 } 373 } 374 375 private void setMember(String member) { 376 if (member == null || member.equals("-")) 377 this.member = null; 378 else if (member.equals("")) 379 this.member = "*"; 380 else 381 this.member = member; 382 } 383 384 /** 385 * <p>Create a new MBeanPermission object with the specified target name 386 * and actions.</p> 387 * 388 * <p>The target name is of the form 389 * "<code>className#member[objectName]</code>" where each part is 390 * optional. It must not be empty or null.</p> 391 * 392 * <p>The actions parameter contains a comma-separated list of the 393 * desired actions granted on the target name. It must not be 394 * empty or null.</p> 395 * 396 * @param name the triplet "className#member[objectName]". 397 * @param actions the action string. 398 * 399 * @exception IllegalArgumentException if the <code>name</code> or 400 * <code>actions</code> is invalid. 401 */ 402 public MBeanPermission(String name, String actions) { 403 super(name); 404 405 parseName(); 406 407 this.actions = actions; 408 parseActions(); 409 } 410 411 /** 412 * <p>Create a new MBeanPermission object with the specified target name 413 * (class name, member, object name) and actions.</p> 414 * 415 * <p>The class name, member and object name parameters define a 416 * target name of the form 417 * "<code>className#member[objectName]</code>" where each part is 418 * optional. This will be the result of {@link #getName()} on the 419 * resultant MBeanPermission.</p> 420 * 421 * <p>The actions parameter contains a comma-separated list of the 422 * desired actions granted on the target name. It must not be 423 * empty or null.</p> 424 * 425 * @param className the class name to which this permission applies. 426 * May be null or <code>"-"</code>, which represents a class name 427 * that is implied by any class name but does not imply any other 428 * class name. 429 * @param member the member to which this permission applies. May 430 * be null or <code>"-"</code>, which represents a member that is 431 * implied by any member but does not imply any other member. 432 * @param objectName the object name to which this permission 433 * applies. May be null, which represents an object name that is 434 * implied by any object name but does not imply any other object 435 * name. 436 * @param actions the action string. 437 */ 438 public MBeanPermission(String className, 439 String member, 440 ObjectName objectName, 441 String actions) { 442 443 super(makeName(className, member, objectName)); 444 initName(className, member, objectName); 445 446 this.actions = actions; 447 parseActions(); 448 } 449 450 private static String makeName(String className, String member, 451 ObjectName objectName) { 452 final StringBuilder name = new StringBuilder(); 453 if (className == null) 454 className = "-"; 455 name.append(className); 456 if (member == null) 457 member = "-"; 458 name.append("#" + member); 459 if (objectName == null) 460 name.append("[-]"); 461 else 462 name.append("[").append(objectName.getCanonicalName()).append("]"); 463 464 /* In the interests of legibility for Permission.toString(), we 465 transform the empty string into "*". */ 466 if (name.length() == 0) 467 return "*"; 468 else 469 return name.toString(); 470 } 471 472 /** 473 * Returns the "canonical string representation" of the actions. That is, 474 * this method always returns present actions in alphabetical order. 475 * 476 * @return the canonical string representation of the actions. 477 */ 478 public String getActions() { 479 480 if (actions == null) 481 actions = getActions(this.mask); 482 483 return actions; 484 } 485 486 /** 487 * Returns the "canonical string representation" 488 * of the actions from the mask. 489 */ 490 private static String getActions(int mask) { 491 final StringBuilder sb = new StringBuilder(); 492 boolean comma = false; 493 494 if ((mask & AddNotificationListener) == AddNotificationListener) { 495 comma = true; 496 sb.append("addNotificationListener"); 497 } 498 499 if ((mask & GetAttribute) == GetAttribute) { 500 if (comma) sb.append(','); 501 else comma = true; 502 sb.append("getAttribute"); 503 } 504 505 if ((mask & GetClassLoader) == GetClassLoader) { 506 if (comma) sb.append(','); 507 else comma = true; 508 sb.append("getClassLoader"); 509 } 510 511 if ((mask & GetClassLoaderFor) == GetClassLoaderFor) { 512 if (comma) sb.append(','); 513 else comma = true; 514 sb.append("getClassLoaderFor"); 515 } 516 517 if ((mask & GetClassLoaderRepository) == GetClassLoaderRepository) { 518 if (comma) sb.append(','); 519 else comma = true; 520 sb.append("getClassLoaderRepository"); 521 } 522 523 if ((mask & GetDomains) == GetDomains) { 524 if (comma) sb.append(','); 525 else comma = true; 526 sb.append("getDomains"); 527 } 528 529 if ((mask & GetMBeanInfo) == GetMBeanInfo) { 530 if (comma) sb.append(','); 531 else comma = true; 532 sb.append("getMBeanInfo"); 533 } 534 535 if ((mask & GetObjectInstance) == GetObjectInstance) { 536 if (comma) sb.append(','); 537 else comma = true; 538 sb.append("getObjectInstance"); 539 } 540 541 if ((mask & Instantiate) == Instantiate) { 542 if (comma) sb.append(','); 543 else comma = true; 544 sb.append("instantiate"); 545 } 546 547 if ((mask & Invoke) == Invoke) { 548 if (comma) sb.append(','); 549 else comma = true; 550 sb.append("invoke"); 551 } 552 553 if ((mask & IsInstanceOf) == IsInstanceOf) { 554 if (comma) sb.append(','); 555 else comma = true; 556 sb.append("isInstanceOf"); 557 } 558 559 if ((mask & QueryMBeans) == QueryMBeans) { 560 if (comma) sb.append(','); 561 else comma = true; 562 sb.append("queryMBeans"); 563 } 564 565 if ((mask & QueryNames) == QueryNames) { 566 if (comma) sb.append(','); 567 else comma = true; 568 sb.append("queryNames"); 569 } 570 571 if ((mask & RegisterMBean) == RegisterMBean) { 572 if (comma) sb.append(','); 573 else comma = true; 574 sb.append("registerMBean"); 575 } 576 577 if ((mask & RemoveNotificationListener) == RemoveNotificationListener) { 578 if (comma) sb.append(','); 579 else comma = true; 580 sb.append("removeNotificationListener"); 581 } 582 583 if ((mask & SetAttribute) == SetAttribute) { 584 if (comma) sb.append(','); 585 else comma = true; 586 sb.append("setAttribute"); 587 } 588 589 if ((mask & UnregisterMBean) == UnregisterMBean) { 590 if (comma) sb.append(','); 591 else comma = true; 592 sb.append("unregisterMBean"); 593 } 594 595 return sb.toString(); 596 } 597 598 /** 599 * Returns the hash code value for this object. 600 * 601 * @return a hash code value for this object. 602 */ 603 public int hashCode() { 604 return this.getName().hashCode() + this.getActions().hashCode(); 605 } 606 607 /** 608 * Converts an action String to an integer action mask. 609 * 610 * @param action the action string. 611 * @return the action mask. 612 */ 613 private static int getMask(String action) { 614 615 /* 616 * BE CAREFUL HERE! PARSING ORDER IS IMPORTANT IN THIS ALGORITHM. 617 * 618 * The 'string length' test must be performed for the lengthiest 619 * strings first. 620 * 621 * In this permission if the "unregisterMBean" string length test is 622 * performed after the "registerMBean" string length test the algorithm 623 * considers the 'unregisterMBean' action as being the 'registerMBean' 624 * action and a parsing error is returned. 625 */ 626 627 int mask = NONE; 628 629 if (action == null) { 630 return mask; 631 } 632 633 if (action.equals("*")) { 634 return ALL; 635 } 636 637 char[] a = action.toCharArray(); 638 639 int i = a.length - 1; 640 if (i < 0) 641 return mask; 642 643 while (i != -1) { 644 char c; 645 646 // skip whitespace 647 while ((i!=-1) && ((c = a[i]) == ' ' || 648 c == '\r' || 649 c == '\n' || 650 c == '\f' || 651 c == '\t')) 652 i--; 653 654 // check for the known strings 655 int matchlen; 656 657 if (i >= 25 && /* removeNotificationListener */ 658 (a[i-25] == 'r') && 659 (a[i-24] == 'e') && 660 (a[i-23] == 'm') && 661 (a[i-22] == 'o') && 662 (a[i-21] == 'v') && 663 (a[i-20] == 'e') && 664 (a[i-19] == 'N') && 665 (a[i-18] == 'o') && 666 (a[i-17] == 't') && 667 (a[i-16] == 'i') && 668 (a[i-15] == 'f') && 669 (a[i-14] == 'i') && 670 (a[i-13] == 'c') && 671 (a[i-12] == 'a') && 672 (a[i-11] == 't') && 673 (a[i-10] == 'i') && 674 (a[i-9] == 'o') && 675 (a[i-8] == 'n') && 676 (a[i-7] == 'L') && 677 (a[i-6] == 'i') && 678 (a[i-5] == 's') && 679 (a[i-4] == 't') && 680 (a[i-3] == 'e') && 681 (a[i-2] == 'n') && 682 (a[i-1] == 'e') && 683 (a[i] == 'r')) { 684 matchlen = 26; 685 mask |= RemoveNotificationListener; 686 } else if (i >= 23 && /* getClassLoaderRepository */ 687 (a[i-23] == 'g') && 688 (a[i-22] == 'e') && 689 (a[i-21] == 't') && 690 (a[i-20] == 'C') && 691 (a[i-19] == 'l') && 692 (a[i-18] == 'a') && 693 (a[i-17] == 's') && 694 (a[i-16] == 's') && 695 (a[i-15] == 'L') && 696 (a[i-14] == 'o') && 697 (a[i-13] == 'a') && 698 (a[i-12] == 'd') && 699 (a[i-11] == 'e') && 700 (a[i-10] == 'r') && 701 (a[i-9] == 'R') && 702 (a[i-8] == 'e') && 703 (a[i-7] == 'p') && 704 (a[i-6] == 'o') && 705 (a[i-5] == 's') && 706 (a[i-4] == 'i') && 707 (a[i-3] == 't') && 708 (a[i-2] == 'o') && 709 (a[i-1] == 'r') && 710 (a[i] == 'y')) { 711 matchlen = 24; 712 mask |= GetClassLoaderRepository; 713 } else if (i >= 22 && /* addNotificationListener */ 714 (a[i-22] == 'a') && 715 (a[i-21] == 'd') && 716 (a[i-20] == 'd') && 717 (a[i-19] == 'N') && 718 (a[i-18] == 'o') && 719 (a[i-17] == 't') && 720 (a[i-16] == 'i') && 721 (a[i-15] == 'f') && 722 (a[i-14] == 'i') && 723 (a[i-13] == 'c') && 724 (a[i-12] == 'a') && 725 (a[i-11] == 't') && 726 (a[i-10] == 'i') && 727 (a[i-9] == 'o') && 728 (a[i-8] == 'n') && 729 (a[i-7] == 'L') && 730 (a[i-6] == 'i') && 731 (a[i-5] == 's') && 732 (a[i-4] == 't') && 733 (a[i-3] == 'e') && 734 (a[i-2] == 'n') && 735 (a[i-1] == 'e') && 736 (a[i] == 'r')) { 737 matchlen = 23; 738 mask |= AddNotificationListener; 739 } else if (i >= 16 && /* getClassLoaderFor */ 740 (a[i-16] == 'g') && 741 (a[i-15] == 'e') && 742 (a[i-14] == 't') && 743 (a[i-13] == 'C') && 744 (a[i-12] == 'l') && 745 (a[i-11] == 'a') && 746 (a[i-10] == 's') && 747 (a[i-9] == 's') && 748 (a[i-8] == 'L') && 749 (a[i-7] == 'o') && 750 (a[i-6] == 'a') && 751 (a[i-5] == 'd') && 752 (a[i-4] == 'e') && 753 (a[i-3] == 'r') && 754 (a[i-2] == 'F') && 755 (a[i-1] == 'o') && 756 (a[i] == 'r')) { 757 matchlen = 17; 758 mask |= GetClassLoaderFor; 759 } else if (i >= 16 && /* getObjectInstance */ 760 (a[i-16] == 'g') && 761 (a[i-15] == 'e') && 762 (a[i-14] == 't') && 763 (a[i-13] == 'O') && 764 (a[i-12] == 'b') && 765 (a[i-11] == 'j') && 766 (a[i-10] == 'e') && 767 (a[i-9] == 'c') && 768 (a[i-8] == 't') && 769 (a[i-7] == 'I') && 770 (a[i-6] == 'n') && 771 (a[i-5] == 's') && 772 (a[i-4] == 't') && 773 (a[i-3] == 'a') && 774 (a[i-2] == 'n') && 775 (a[i-1] == 'c') && 776 (a[i] == 'e')) { 777 matchlen = 17; 778 mask |= GetObjectInstance; 779 } else if (i >= 14 && /* unregisterMBean */ 780 (a[i-14] == 'u') && 781 (a[i-13] == 'n') && 782 (a[i-12] == 'r') && 783 (a[i-11] == 'e') && 784 (a[i-10] == 'g') && 785 (a[i-9] == 'i') && 786 (a[i-8] == 's') && 787 (a[i-7] == 't') && 788 (a[i-6] == 'e') && 789 (a[i-5] == 'r') && 790 (a[i-4] == 'M') && 791 (a[i-3] == 'B') && 792 (a[i-2] == 'e') && 793 (a[i-1] == 'a') && 794 (a[i] == 'n')) { 795 matchlen = 15; 796 mask |= UnregisterMBean; 797 } else if (i >= 13 && /* getClassLoader */ 798 (a[i-13] == 'g') && 799 (a[i-12] == 'e') && 800 (a[i-11] == 't') && 801 (a[i-10] == 'C') && 802 (a[i-9] == 'l') && 803 (a[i-8] == 'a') && 804 (a[i-7] == 's') && 805 (a[i-6] == 's') && 806 (a[i-5] == 'L') && 807 (a[i-4] == 'o') && 808 (a[i-3] == 'a') && 809 (a[i-2] == 'd') && 810 (a[i-1] == 'e') && 811 (a[i] == 'r')) { 812 matchlen = 14; 813 mask |= GetClassLoader; 814 } else if (i >= 12 && /* registerMBean */ 815 (a[i-12] == 'r') && 816 (a[i-11] == 'e') && 817 (a[i-10] == 'g') && 818 (a[i-9] == 'i') && 819 (a[i-8] == 's') && 820 (a[i-7] == 't') && 821 (a[i-6] == 'e') && 822 (a[i-5] == 'r') && 823 (a[i-4] == 'M') && 824 (a[i-3] == 'B') && 825 (a[i-2] == 'e') && 826 (a[i-1] == 'a') && 827 (a[i] == 'n')) { 828 matchlen = 13; 829 mask |= RegisterMBean; 830 } else if (i >= 11 && /* getAttribute */ 831 (a[i-11] == 'g') && 832 (a[i-10] == 'e') && 833 (a[i-9] == 't') && 834 (a[i-8] == 'A') && 835 (a[i-7] == 't') && 836 (a[i-6] == 't') && 837 (a[i-5] == 'r') && 838 (a[i-4] == 'i') && 839 (a[i-3] == 'b') && 840 (a[i-2] == 'u') && 841 (a[i-1] == 't') && 842 (a[i] == 'e')) { 843 matchlen = 12; 844 mask |= GetAttribute; 845 } else if (i >= 11 && /* getMBeanInfo */ 846 (a[i-11] == 'g') && 847 (a[i-10] == 'e') && 848 (a[i-9] == 't') && 849 (a[i-8] == 'M') && 850 (a[i-7] == 'B') && 851 (a[i-6] == 'e') && 852 (a[i-5] == 'a') && 853 (a[i-4] == 'n') && 854 (a[i-3] == 'I') && 855 (a[i-2] == 'n') && 856 (a[i-1] == 'f') && 857 (a[i] == 'o')) { 858 matchlen = 12; 859 mask |= GetMBeanInfo; 860 } else if (i >= 11 && /* isInstanceOf */ 861 (a[i-11] == 'i') && 862 (a[i-10] == 's') && 863 (a[i-9] == 'I') && 864 (a[i-8] == 'n') && 865 (a[i-7] == 's') && 866 (a[i-6] == 't') && 867 (a[i-5] == 'a') && 868 (a[i-4] == 'n') && 869 (a[i-3] == 'c') && 870 (a[i-2] == 'e') && 871 (a[i-1] == 'O') && 872 (a[i] == 'f')) { 873 matchlen = 12; 874 mask |= IsInstanceOf; 875 } else if (i >= 11 && /* setAttribute */ 876 (a[i-11] == 's') && 877 (a[i-10] == 'e') && 878 (a[i-9] == 't') && 879 (a[i-8] == 'A') && 880 (a[i-7] == 't') && 881 (a[i-6] == 't') && 882 (a[i-5] == 'r') && 883 (a[i-4] == 'i') && 884 (a[i-3] == 'b') && 885 (a[i-2] == 'u') && 886 (a[i-1] == 't') && 887 (a[i] == 'e')) { 888 matchlen = 12; 889 mask |= SetAttribute; 890 } else if (i >= 10 && /* instantiate */ 891 (a[i-10] == 'i') && 892 (a[i-9] == 'n') && 893 (a[i-8] == 's') && 894 (a[i-7] == 't') && 895 (a[i-6] == 'a') && 896 (a[i-5] == 'n') && 897 (a[i-4] == 't') && 898 (a[i-3] == 'i') && 899 (a[i-2] == 'a') && 900 (a[i-1] == 't') && 901 (a[i] == 'e')) { 902 matchlen = 11; 903 mask |= Instantiate; 904 } else if (i >= 10 && /* queryMBeans */ 905 (a[i-10] == 'q') && 906 (a[i-9] == 'u') && 907 (a[i-8] == 'e') && 908 (a[i-7] == 'r') && 909 (a[i-6] == 'y') && 910 (a[i-5] == 'M') && 911 (a[i-4] == 'B') && 912 (a[i-3] == 'e') && 913 (a[i-2] == 'a') && 914 (a[i-1] == 'n') && 915 (a[i] == 's')) { 916 matchlen = 11; 917 mask |= QueryMBeans; 918 } else if (i >= 9 && /* getDomains */ 919 (a[i-9] == 'g') && 920 (a[i-8] == 'e') && 921 (a[i-7] == 't') && 922 (a[i-6] == 'D') && 923 (a[i-5] == 'o') && 924 (a[i-4] == 'm') && 925 (a[i-3] == 'a') && 926 (a[i-2] == 'i') && 927 (a[i-1] == 'n') && 928 (a[i] == 's')) { 929 matchlen = 10; 930 mask |= GetDomains; 931 } else if (i >= 9 && /* queryNames */ 932 (a[i-9] == 'q') && 933 (a[i-8] == 'u') && 934 (a[i-7] == 'e') && 935 (a[i-6] == 'r') && 936 (a[i-5] == 'y') && 937 (a[i-4] == 'N') && 938 (a[i-3] == 'a') && 939 (a[i-2] == 'm') && 940 (a[i-1] == 'e') && 941 (a[i] == 's')) { 942 matchlen = 10; 943 mask |= QueryNames; 944 } else if (i >= 5 && /* invoke */ 945 (a[i-5] == 'i') && 946 (a[i-4] == 'n') && 947 (a[i-3] == 'v') && 948 (a[i-2] == 'o') && 949 (a[i-1] == 'k') && 950 (a[i] == 'e')) { 951 matchlen = 6; 952 mask |= Invoke; 953 } else { 954 // parse error 955 throw new IllegalArgumentException("Invalid permission: " + 956 action); 957 } 958 959 // make sure we didn't just match the tail of a word 960 // like "ackbarfaccept". Also, skip to the comma. 961 boolean seencomma = false; 962 while (i >= matchlen && !seencomma) { 963 switch(a[i-matchlen]) { 964 case ',': 965 seencomma = true; 966 break; 967 case ' ': case '\r': case '\n': 968 case '\f': case '\t': 969 break; 970 default: 971 throw new IllegalArgumentException("Invalid permission: " + 972 action); 973 } 974 i--; 975 } 976 977 // point i at the location of the comma minus one (or -1). 978 i -= matchlen; 979 } 980 981 return mask; 982 } 983 984 /** 985 * <p>Checks if this MBeanPermission object "implies" the 986 * specified permission.</p> 987 * 988 * <p>More specifically, this method returns true if:</p> 989 * 990 * <ul> 991 * 992 * <li> <i>p</i> is an instance of MBeanPermission; and</li> 993 * 994 * <li> <i>p</i> has a null className or <i>p</i>'s className 995 * matches this object's className; and</li> 996 * 997 * <li> <i>p</i> has a null member or <i>p</i>'s member matches this 998 * object's member; and</li> 999 * 1000 * <li> <i>p</i> has a null object name or <i>p</i>'s 1001 * object name matches this object's object name; and</li> 1002 * 1003 * <li> <i>p</i>'s actions are a subset of this object's actions</li> 1004 * 1005 * </ul> 1006 * 1007 * <p>If this object's className is "<code>*</code>", <i>p</i>'s 1008 * className always matches it. If it is "<code>a.*</code>", <i>p</i>'s 1009 * className matches it if it begins with "<code>a.</code>".</p> 1010 * 1011 * <p>If this object's member is "<code>*</code>", <i>p</i>'s 1012 * member always matches it.</p> 1013 * 1014 * <p>If this object's objectName <i>n1</i> is an object name pattern, 1015 * <i>p</i>'s objectName <i>n2</i> matches it if 1016 * {@link ObjectName#equals <i>n1</i>.equals(<i>n2</i>)} or if 1017 * {@link ObjectName#apply <i>n1</i>.apply(<i>n2</i>)}.</p> 1018 * 1019 * <p>A permission that includes the <code>queryMBeans</code> action 1020 * is considered to include <code>queryNames</code> as well.</p> 1021 * 1022 * @param p the permission to check against. 1023 * @return true if the specified permission is implied by this object, 1024 * false if not. 1025 */ 1026 public boolean implies(Permission p) { 1027 if (!(p instanceof MBeanPermission)) 1028 return false; 1029 1030 MBeanPermission that = (MBeanPermission) p; 1031 1032 // Actions 1033 // 1034 // The actions in 'this' permission must be a 1035 // superset of the actions in 'that' permission 1036 // 1037 1038 /* "queryMBeans" implies "queryNames" */ 1039 if ((this.mask & QueryMBeans) == QueryMBeans) { 1040 if (((this.mask | QueryNames) & that.mask) != that.mask) { 1041 //System.out.println("action [with QueryNames] does not imply"); 1042 return false; 1043 } 1044 } else { 1045 if ((this.mask & that.mask) != that.mask) { 1046 //System.out.println("action does not imply"); 1047 return false; 1048 } 1049 } 1050 1051 // Target name 1052 // 1053 // The 'className' check is true iff: 1054 // 1) the className in 'this' permission is omitted or "*", or 1055 // 2) the className in 'that' permission is omitted or "*", or 1056 // 3) the className in 'this' permission does pattern 1057 // matching with the className in 'that' permission. 1058 // 1059 // The 'member' check is true iff: 1060 // 1) the member in 'this' permission is omitted or "*", or 1061 // 2) the member in 'that' permission is omitted or "*", or 1062 // 3) the member in 'this' permission equals the member in 1063 // 'that' permission. 1064 // 1065 // The 'object name' check is true iff: 1066 // 1) the object name in 'this' permission is omitted or "*:*", or 1067 // 2) the object name in 'that' permission is omitted or "*:*", or 1068 // 3) the object name in 'this' permission does pattern 1069 // matching with the object name in 'that' permission. 1070 // 1071 1072 /* Check if this.className implies that.className. 1073 1074 If that.classNamePrefix is empty that means the className is 1075 irrelevant for this permission check. Otherwise, we do not 1076 expect that "that" contains a wildcard, since it is a 1077 needed permission. So we assume that.classNameExactMatch. */ 1078 1079 if (that.classNamePrefix == null) { 1080 // bottom is implied 1081 } else if (this.classNamePrefix == null) { 1082 // bottom implies nothing but itself 1083 return false; 1084 } else if (this.classNameExactMatch) { 1085 if (!that.classNameExactMatch) 1086 return false; // exact never implies wildcard 1087 if (!that.classNamePrefix.equals(this.classNamePrefix)) 1088 return false; // exact match fails 1089 } else { 1090 // prefix match, works even if "that" is also a wildcard 1091 // e.g. a.* implies a.* and a.b.* 1092 if (!that.classNamePrefix.startsWith(this.classNamePrefix)) 1093 return false; 1094 } 1095 1096 /* Check if this.member implies that.member */ 1097 1098 if (that.member == null) { 1099 // bottom is implied 1100 } else if (this.member == null) { 1101 // bottom implies nothing but itself 1102 return false; 1103 } else if (this.member.equals("*")) { 1104 // wildcard implies everything (including itself) 1105 } else if (!this.member.equals(that.member)) { 1106 return false; 1107 } 1108 1109 /* Check if this.objectName implies that.objectName */ 1110 1111 if (that.objectName == null) { 1112 // bottom is implied 1113 } else if (this.objectName == null) { 1114 // bottom implies nothing but itself 1115 return false; 1116 } else if (!this.objectName.apply(that.objectName)) { 1117 /* ObjectName.apply returns false if that.objectName is a 1118 wildcard so we also allow equals for that case. This 1119 never happens during real permission checks, but means 1120 the implies relation is reflexive. */ 1121 if (!this.objectName.equals(that.objectName)) 1122 return false; 1123 } 1124 1125 return true; 1126 } 1127 1128 /** 1129 * Checks two MBeanPermission objects for equality. Checks 1130 * that <i>obj</i> is an MBeanPermission, and has the same 1131 * name and actions as this object. 1132 * 1133 * @param obj the object we are testing for equality with this object. 1134 * @return true if obj is an MBeanPermission, and has the 1135 * same name and actions as this MBeanPermission object. 1136 */ 1137 public boolean equals(Object obj) { 1138 if (obj == this) 1139 return true; 1140 1141 if (! (obj instanceof MBeanPermission)) 1142 return false; 1143 1144 MBeanPermission that = (MBeanPermission) obj; 1145 1146 return (this.mask == that.mask) && 1147 (this.getName().equals(that.getName())); 1148 } 1149 1150 /** 1151 * Deserialize this object based on its name and actions. 1152 */ 1153 private void readObject(ObjectInputStream in) 1154 throws IOException, ClassNotFoundException { 1155 in.defaultReadObject(); 1156 parseName(); 1157 parseActions(); 1158 } 1159 }