1 /* MBeanServerPermission.java -- Permissions controlling server creation. 2 Copyright (C) 2006 Free Software Foundation, Inc. 3 4 This file is part of GNU Classpath. 5 6 GNU Classpath is free software; you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published by 8 the Free Software Foundation; either version 2, or (at your option) 9 any later version. 10 11 GNU Classpath is distributed in the hope that it will be useful, but 12 WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 General Public License for more details. 15 16 You should have received a copy of the GNU General Public License 17 along with GNU Classpath; see the file COPYING. If not, write to the 18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 19 02110-1301 USA. 20 21 Linking this library statically or dynamically with other modules is 22 making a combined work based on this library. Thus, the terms and 23 conditions of the GNU General Public License cover the whole 24 combination. 25 26 As a special exception, the copyright holders of this library give you 27 permission to link this library with independent modules to produce an 28 executable, regardless of the license terms of these independent 29 modules, and to copy and distribute the resulting executable under 30 terms of your choice, provided that you also meet, for each linked 31 independent module, the terms and conditions of the license of that 32 module. An independent module is a module which is not derived from 33 or based on this library. If you modify this library, you may extend 34 this exception to your version of the library, but you are not 35 obligated to do so. If you do not wish to do so, delete this 36 exception statement from your version. */ 37 38 package javax.management; 39 40 import java.security.BasicPermission; 41 import java.security.Permission; 42 import java.security.PermissionCollection; 43 44 import java.util.Enumeration; 45 import java.util.NoSuchElementException; 46 47 /** 48 * <p> 49 * Represents the permissions required to perform 50 * operations provided by the {@link MBeanServerFactory}. 51 * As with all {@link java.security.Permission} objects, an 52 * instance of this class either represents a permission 53 * already held or one that is required to access a 54 * particular service. In the case of {@link MBeanServerPermission}s, 55 * implication checks are made using an instance of this class 56 * when a user requests an operation from the factory, and a 57 * {@link SecurityManager} is in place. 58 * </p> 59 * <p> 60 * The permission is defined by its name, which may be 61 * either a <code>'*'</code> (to allow all) or one or 62 * more of the following, separated by a <code>','</code>: 63 * </p> 64 * <ul> 65 * <li><code>createMBeanServer</code> -- allows a registered 66 * instance of a server to be obtained from the factory.</li> 67 * <li><code>findMBeanServer</code> -- allows all or one 68 * particular server instance to be retrieved from the factory.</li> 69 * <li><code>newMBeanServer</code> -- allows an unregistered 70 * instance of a server to be obtained from the factory.</li> 71 * <li><code>releaseMBeanServer</code> -- allows a reference to 72 * a server instance to be removed from the factory.</li> 73 * </ul> 74 * <p> 75 * The names may be surrounded by arbitrary amounts of whitespace. 76 * <code>createMBeanServer</code> implies <code>newMBeanServer</code>. 77 * </p> 78 * 79 * @author Andrew John Hughes (gnu_andrew@member.fsf.org) 80 * @since 1.5 81 */ 82 public class MBeanServerPermission 83 extends BasicPermission 84 { 85 86 /** 87 * Compatible with JDK 1.5 88 */ 89 private static final long serialVersionUID = -5661980843569388590L; 90 91 /** 92 * <p> 93 * Constructs a new {@link MBeanServerPermission} with 94 * the given name. The name must not be <code>null</code> 95 * and must be equal to either <code>"*"</code> or a 96 * comma-separated list of valid permissions. The four 97 * valid constraints are: 98 * </p> 99 * <ol> 100 * <li><code>createMBeanServer</code></li> 101 * <li><code>findMBeanServer</code></li> 102 * <li><code>newMBeanServer</code></li> 103 * <li><code>releaseMBeanServer</code></li> 104 * </ol> 105 * <p> 106 * Calling this constructor is equivalent to calling 107 * <code>MBeanPermission(name, null)</code>. 108 * </p> 109 * 110 * @param name the name of this permission. 111 * @throws NullPointerException if <code>name</code> 112 * is <code>null</code>. 113 * @throws IllegalArgumentException if <code>name</code> 114 * is not either equal to 115 * <code>"*"</code> or forms 116 * a comma-separated list of 117 * valid constraints. 118 * @see #MBeanServerPermission(String,String) 119 */ MBeanServerPermission(String name)120 public MBeanServerPermission(String name) 121 { 122 this(name, null); 123 } 124 125 /** 126 * <p> 127 * Constructs a new {@link MBeanServerPermission} with 128 * the given name and actions. The actions are unused, 129 * and must be either <code>null</code> or the empty 130 * string. The name must not be <code>null</code> 131 * and must be equal to either <code>"*"</code> or a 132 * comma-separated list of valid permissions. The four 133 * valid constraints are: 134 * </p> 135 * <ol> 136 * <li><code>createMBeanServer</code></li> 137 * <li><code>findMBeanServer</code></li> 138 * <li><code>newMBeanServer</code></li> 139 * <li><code>releaseMBeanServer</code></li> 140 * </ol> 141 * <p> 142 * Calling this constructor is equivalent to calling 143 * <code>MBeanPermission(name, null)</code>. 144 * </p> 145 * 146 * @param name the name of this permission. 147 * @throws NullPointerException if <code>name</code> 148 * is <code>null</code>. 149 * @throws IllegalArgumentException if <code>name</code> 150 * is not either equal to 151 * <code>"*"</code> or forms 152 * a comma-separated list of 153 * valid constraints, or if 154 * <code>actions</code> is not 155 * <code>null</code> or the 156 * empty string. 157 * @see #MBeanServerPermission(String,String) 158 */ MBeanServerPermission(String name, String actions)159 public MBeanServerPermission(String name, String actions) 160 { 161 super(checkName(name), actions); 162 if (actions != null && actions.length() > 0) 163 throw new IllegalArgumentException("The supplied action list " + 164 "was not equal to null or the " + 165 "empty string."); 166 } 167 168 /** 169 * Returns true if the given object is also an {@link MBeanServerPermission} 170 * with the same name. 171 * 172 * @param obj the object to compare with this one. 173 * @return true if the object is an {@link MBeanPermission} 174 * with the same name. 175 */ equals(Object obj)176 public boolean equals(Object obj) 177 { 178 if (obj instanceof MBeanServerPermission) 179 { 180 MBeanServerPermission o = (MBeanServerPermission) obj; 181 return o.getName().equals(getName()); 182 } 183 return false; 184 } 185 186 /** 187 * Returns a unique hash code for this permission. 188 * This is simply the hashcode of {@link BasicPermission#getName()}. 189 * 190 * @return the hashcode of this permission. 191 */ hashCode()192 public int hashCode() 193 { 194 return getName().hashCode(); 195 } 196 197 /** 198 * Returns true if this {@link MBeanServerPermission} implies 199 * the given permission. This occurs if the given permission 200 * is also an {@link MBeanServerPermission} and its target names 201 * are a subset of the target names of this permission. Note that 202 * the name <code>createMBeanServer</code> implies 203 * <code>newMBeanServer</code>. 204 * 205 * @param p the permission to check for implication. 206 * @return true if this permission implies <code>p</code>. 207 */ implies(Permission p)208 public boolean implies(Permission p) 209 { 210 if (p instanceof MBeanServerPermission) 211 { 212 if (getName().equals("*")) 213 return true; 214 MBeanServerPermission msp = (MBeanServerPermission) p; 215 String[] thisCaps = getName().split(","); 216 String[] mspCaps = msp.getName().split(","); 217 for (int a = 0; a < mspCaps.length; ++a) 218 { 219 boolean found = false; 220 String mc = mspCaps[a].trim(); 221 for (int b = 0; b < thisCaps.length; ++b) 222 { 223 String tc = thisCaps[b].trim(); 224 if (tc.equals(mc)) 225 found = true; 226 if (tc.equals("createMBeanServer") && 227 mc.equals("newMBeanServer")) 228 found = true; 229 } 230 if (!found) 231 return false; 232 } 233 return true; 234 } 235 return false; 236 } 237 238 /** 239 * Returns a {@link PermissionCollection} which stores 240 * a series of {@link MBeanServerPermission}s as the union 241 * of their capabilities. 242 * 243 * @return a collection for {@link MBeanServerPermission}s. 244 */ newPermissionCollection()245 public PermissionCollection newPermissionCollection() 246 { 247 return new MBeanServerPermissionCollection(); 248 } 249 250 /** 251 * A collection of {@link MBeanServerPermission}s, stored 252 * as a single permission with the union of the capabilities 253 * as its capabilities. 254 * 255 * @author Andrew John Hughes (gnu_andrew@member.fsf.org) 256 * @since 1.5 257 */ 258 private class MBeanServerPermissionCollection 259 extends PermissionCollection 260 { 261 262 /** 263 * Compatible with JDK 1.5 264 */ 265 private static final long serialVersionUID = -5661980843569388590L; 266 267 /** 268 * The collected permission. This is <code>null</code> or 269 * the union of the permissions held by all the collected 270 * permissions. 271 */ 272 private MBeanServerPermission collectionPermission; 273 274 /** 275 * Adds a new permission by unifying it with the existing 276 * collection permission. 277 * 278 * @param p the permission to add. 279 * @throws SecurityException if the collection is read only. 280 * @see #isReadOnly() 281 * @see #setReadOnly(boolean) 282 */ 283 @Override add(Permission p)284 public void add(Permission p) 285 { 286 if (isReadOnly()) 287 throw new SecurityException("This collection is read only."); 288 if (p instanceof MBeanServerPermission) 289 { 290 MBeanServerPermission msp = (MBeanServerPermission) p; 291 if (collectionPermission == null) 292 collectionPermission = msp; 293 else 294 { 295 String finalString = collectionPermission.getName(); 296 String[] cp = finalString.split(","); 297 String[] np = msp.getName().split(","); 298 int createms = finalString.indexOf("createMBeanServer"); 299 int newms = finalString.indexOf("newMBeanServer"); 300 for (int a = 0; a < np.length; ++a) 301 { 302 boolean found = false; 303 String nps = np[a].trim(); 304 for (int b = 0; b < cp.length; ++b) 305 { 306 String cps = cp[b].trim(); 307 if (cps.equals(nps)) 308 found = true; 309 if (nps.equals("newMBeanServer") 310 && createms != -1) 311 found = true; 312 if (nps.equals("createMBeanServer") 313 && newms != -1) 314 finalString = 315 finalString.replace("newMBeanServer", 316 "createMBeanServer"); 317 } 318 if (!found) 319 finalString += "," + nps; 320 } 321 collectionPermission = 322 new MBeanServerPermission(finalString); 323 } 324 } 325 } 326 327 /** 328 * Returns an enumeration over the single permission. 329 * 330 * @return an enumeration over the collection permission. 331 */ 332 @Override elements()333 public Enumeration<Permission> elements() 334 { 335 return new 336 MBeanServerPermissionEnumeration(collectionPermission); 337 } 338 339 /** 340 * Provides an enumeration over a comma-separated list 341 * of capabilities. 342 * 343 * @author Andrew John Hughes (gnu_andrew@member.fsf.org) 344 * @since 1.5 345 */ 346 private class MBeanServerPermissionEnumeration 347 implements Enumeration<Permission> 348 { 349 350 /** 351 * The collected permission. 352 */ 353 private MBeanServerPermission p; 354 355 /** 356 * True if we have returned the permission. 357 */ 358 private boolean done; 359 360 /** 361 * Constructs a new {@link MBeanServerPermissionEnumeration} 362 * using the given collected permission. 363 * 364 * @param p the collected permission. 365 */ MBeanServerPermissionEnumeration(MBeanServerPermission p)366 public MBeanServerPermissionEnumeration(MBeanServerPermission p) 367 { 368 this.p = p; 369 done = false; 370 } 371 372 /** 373 * Returns true if there are more capabilities to return. 374 * 375 * @return true if there are more capabilities available. 376 */ hasMoreElements()377 public boolean hasMoreElements() 378 { 379 return !done; 380 } 381 382 /** 383 * Returns the next capability. 384 * 385 * @return the next capability. 386 */ nextElement()387 public Permission nextElement() 388 { 389 if (hasMoreElements()) 390 { 391 done = true; 392 return p; 393 } 394 else 395 throw new NoSuchElementException("No more elements are available."); 396 } 397 398 } 399 400 /** 401 * Returns true if the collected {@link MBeanServerPermission} 402 * implies the given permission. This occurs if the given permission 403 * is also an {@link MBeanServerPermission} and its target names 404 * are a subset of the target names of this permission. Note that 405 * the name <code>createMBeanServer</code> implies 406 * <code>newMBeanServer</code>. 407 * 408 * @param p the permission to check for implication. 409 * @return true if this permission implies <code>p</code>. 410 */ 411 @Override implies(Permission p)412 public boolean implies(Permission p) 413 { 414 return collectionPermission.implies(p); 415 } 416 } 417 418 /** 419 * Checks the name is valid, including removing 420 * the <code>newMBeanServer</code> permission when 421 * <code>createMBeanServer</code> is present. 422 * 423 * @param name the name to check. 424 * @throws NullPointerException if <code>name</code> 425 * is <code>null</code>. 426 * @throws IllegalArgumentException if <code>name</code> 427 * is not either equal to 428 * <code>"*"</code> or forms 429 * a comma-separated list of 430 * valid constraints. 431 */ checkName(String name)432 private static String checkName(String name) 433 { 434 if (!(name.equals("*"))) 435 { 436 String[] constraints = name.split(","); 437 name = ""; 438 boolean seenCreate = false; 439 boolean seenNew = false; 440 boolean start = true; 441 for (int a = 0; a < constraints.length; ++a) 442 { 443 String next = constraints[a].trim(); 444 if (!(next.equals("createMBeanServer") || 445 next.equals("findMBeanServer") || 446 next.equals("newMBeanServer") || 447 next.equals("releaseMBeanServer"))) 448 throw new IllegalArgumentException("An invalid constraint, " + 449 next + ", was specified."); 450 if (next.equals("newMBeanServer")) 451 seenNew = true; 452 else if (next.equals("createMBeanServer")) 453 seenCreate = true; 454 else 455 { 456 if (!start) 457 name += ","; 458 name += next; 459 start = false; 460 } 461 } 462 if (seenNew && !seenCreate) 463 name += (start ? "" : ",") + "newMBeanServer"; 464 else if (seenCreate) 465 name += (start ? "" : ",") + "createMBeanServer"; 466 } 467 return name; 468 } 469 470 } 471