001 /* MBeanServerPermission.java -- Permissions controlling server creation. 002 Copyright (C) 2006 Free Software Foundation, Inc. 003 004 This file is part of GNU Classpath. 005 006 GNU Classpath is free software; you can redistribute it and/or modify 007 it under the terms of the GNU General Public License as published by 008 the Free Software Foundation; either version 2, or (at your option) 009 any later version. 010 011 GNU Classpath is distributed in the hope that it will be useful, but 012 WITHOUT ANY WARRANTY; without even the implied warranty of 013 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 014 General Public License for more details. 015 016 You should have received a copy of the GNU General Public License 017 along with GNU Classpath; see the file COPYING. If not, write to the 018 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 019 02110-1301 USA. 020 021 Linking this library statically or dynamically with other modules is 022 making a combined work based on this library. Thus, the terms and 023 conditions of the GNU General Public License cover the whole 024 combination. 025 026 As a special exception, the copyright holders of this library give you 027 permission to link this library with independent modules to produce an 028 executable, regardless of the license terms of these independent 029 modules, and to copy and distribute the resulting executable under 030 terms of your choice, provided that you also meet, for each linked 031 independent module, the terms and conditions of the license of that 032 module. An independent module is a module which is not derived from 033 or based on this library. If you modify this library, you may extend 034 this exception to your version of the library, but you are not 035 obligated to do so. If you do not wish to do so, delete this 036 exception statement from your version. */ 037 038 package javax.management; 039 040 import java.security.BasicPermission; 041 import java.security.Permission; 042 import java.security.PermissionCollection; 043 044 import java.util.Enumeration; 045 import java.util.NoSuchElementException; 046 047 /** 048 * <p> 049 * Represents the permissions required to perform 050 * operations provided by the {@link MBeanServerFactory}. 051 * As with all {@link java.security.Permission} objects, an 052 * instance of this class either represents a permission 053 * already held or one that is required to access a 054 * particular service. In the case of {@link MBeanServerPermission}s, 055 * implication checks are made using an instance of this class 056 * when a user requests an operation from the factory, and a 057 * {@link SecurityManager} is in place. 058 * </p> 059 * <p> 060 * The permission is defined by its name, which may be 061 * either a <code>'*'</code> (to allow all) or one or 062 * more of the following, separated by a <code>','</code>: 063 * </p> 064 * <ul> 065 * <li><code>createMBeanServer</code> -- allows a registered 066 * instance of a server to be obtained from the factory.</li> 067 * <li><code>findMBeanServer</code> -- allows all or one 068 * particular server instance to be retrieved from the factory.</li> 069 * <li><code>newMBeanServer</code> -- allows an unregistered 070 * instance of a server to be obtained from the factory.</li> 071 * <li><code>releaseMBeanServer</code> -- allows a reference to 072 * a server instance to be removed from the factory.</li> 073 * </ul> 074 * <p> 075 * The names may be surrounded by arbitrary amounts of whitespace. 076 * <code>createMBeanServer</code> implies <code>newMBeanServer</code>. 077 * </p> 078 * 079 * @author Andrew John Hughes (gnu_andrew@member.fsf.org) 080 * @since 1.5 081 */ 082 public class MBeanServerPermission 083 extends BasicPermission 084 { 085 086 /** 087 * Compatible with JDK 1.5 088 */ 089 private static final long serialVersionUID = -5661980843569388590L; 090 091 /** 092 * <p> 093 * Constructs a new {@link MBeanServerPermission} with 094 * the given name. The name must not be <code>null</code> 095 * and must be equal to either <code>"*"</code> or a 096 * comma-separated list of valid permissions. The four 097 * valid constraints are: 098 * </p> 099 * <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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 public void add(Permission p) 284 { 285 if (isReadOnly()) 286 throw new SecurityException("This collection is read only."); 287 if (p instanceof MBeanServerPermission) 288 { 289 MBeanServerPermission msp = (MBeanServerPermission) p; 290 if (collectionPermission == null) 291 collectionPermission = msp; 292 else 293 { 294 String finalString = collectionPermission.getName(); 295 String[] cp = finalString.split(","); 296 String[] np = msp.getName().split(","); 297 int createms = finalString.indexOf("createMBeanServer"); 298 int newms = finalString.indexOf("newMBeanServer"); 299 for (int a = 0; a < np.length; ++a) 300 { 301 boolean found = false; 302 String nps = np[a].trim(); 303 for (int b = 0; b < cp.length; ++b) 304 { 305 String cps = cp[b].trim(); 306 if (cps.equals(nps)) 307 found = true; 308 if (np.equals("newMBeanServer") 309 && createms != -1) 310 found = true; 311 if (np.equals("createMBeanServer") 312 && newms != -1) 313 finalString.replace("newMBeanServer", 314 "createMBeanServer"); 315 } 316 if (!found) 317 finalString += "," + nps; 318 } 319 collectionPermission = 320 new MBeanServerPermission(finalString); 321 } 322 } 323 } 324 325 /** 326 * Returns an enumeration over the single permission. 327 * 328 * @return an enumeration over the collection permission. 329 */ 330 public Enumeration elements() 331 { 332 return new 333 MBeanServerPermissionEnumeration(collectionPermission); 334 } 335 336 /** 337 * Provides an enumeration over a comma-separated list 338 * of capabilities. 339 * 340 * @author Andrew John Hughes (gnu_andrew@member.fsf.org) 341 * @since 1.5 342 */ 343 private class MBeanServerPermissionEnumeration 344 implements Enumeration 345 { 346 347 /** 348 * The collected permission. 349 */ 350 private MBeanServerPermission p; 351 352 /** 353 * True if we have returned the permission. 354 */ 355 private boolean done; 356 357 /** 358 * Constructs a new {@link MBeanServerPermissionEnumeration} 359 * using the given collected permission. 360 * 361 * @param p the collected permission. 362 */ 363 public MBeanServerPermissionEnumeration(MBeanServerPermission p) 364 { 365 this.p = p; 366 done = false; 367 } 368 369 /** 370 * Returns true if there are more capabilities to return. 371 * 372 * @return true if there are more capabilities available. 373 */ 374 public boolean hasMoreElements() 375 { 376 return !done; 377 } 378 379 /** 380 * Returns the next capability. 381 * 382 * @return the next capability. 383 */ 384 public Object nextElement() 385 { 386 if (hasMoreElements()) 387 { 388 done = true; 389 return p; 390 } 391 else 392 throw new NoSuchElementException("No more elements are available."); 393 } 394 395 } 396 397 /** 398 * Returns true if the collected {@link MBeanServerPermission} 399 * implies the given permission. This occurs if the given permission 400 * is also an {@link MBeanServerPermission} and its target names 401 * are a subset of the target names of this permission. Note that 402 * the name <code>createMBeanServer</code> implies 403 * <code>newMBeanServer</code>. 404 * 405 * @param p the permission to check for implication. 406 * @return true if this permission implies <code>p</code>. 407 */ 408 public boolean implies(Permission p) 409 { 410 return collectionPermission.implies(p); 411 } 412 } 413 414 /** 415 * Checks the name is valid, including removing 416 * the <code>newMBeanServer</code> permission when 417 * <code>createMBeanServer</code> is present. 418 * 419 * @param name the name to check. 420 * @throws NullPointerException if <code>name</code> 421 * is <code>null</code>. 422 * @throws IllegalArgumentException if <code>name</code> 423 * is not either equal to 424 * <code>"*"</code> or forms 425 * a comma-separated list of 426 * valid constraints. 427 */ 428 private static String checkName(String name) 429 { 430 if (!(name.equals("*"))) 431 { 432 String[] constraints = name.split(","); 433 name = ""; 434 boolean seenCreate = false; 435 boolean seenNew = false; 436 boolean start = true; 437 for (int a = 0; a < constraints.length; ++a) 438 { 439 String next = constraints[a].trim(); 440 if (!(next.equals("createMBeanServer") || 441 next.equals("findMBeanServer") || 442 next.equals("newMBeanServer") || 443 next.equals("releaseMBeanServer"))) 444 throw new IllegalArgumentException("An invalid constraint, " + 445 next + ", was specified."); 446 if (next.equals("newMBeanServer")) 447 seenNew = true; 448 else if (next.equals("createMBeanServer")) 449 seenCreate = true; 450 else 451 { 452 if (!start) 453 name += ","; 454 name += next; 455 start = false; 456 } 457 } 458 if (seenNew && !seenCreate) 459 name += (start ? "" : ",") + "newMBeanServer"; 460 else if (seenCreate) 461 name += (start ? "" : ",") + "createMBeanServer"; 462 } 463 return name; 464 } 465 466 } 467 468 469 470