113 * The actions mask. 114 * 115 */ 116 private transient int mask; 117 118 /** 119 * The actions string. 120 * 121 * @serial 122 */ 123 private String actions; // Left null as long as possible, then 124 // created and re-used in the getAction function. 125 126 /** 127 * initialize a PropertyPermission object. Common to all constructors. 128 * Also called during de-serialization. 129 * 130 * @param mask the actions mask to use. 131 * 132 */ 133 134 private void init(int mask) 135 { 136 137 if ((mask & ALL) != mask) 138 throw new IllegalArgumentException("invalid actions mask"); 139 140 if (mask == NONE) 141 throw new IllegalArgumentException("invalid actions mask"); 142 143 if (getName() == null) 144 throw new NullPointerException("name can't be null"); 145 146 this.mask = mask; 147 } 148 149 /** 150 * Creates a new PropertyPermission object with the specified name. 151 * The name is the name of the system property, and 152 * <i>actions</i> contains a comma-separated list of the 153 * desired actions granted on the property. Possible actions are 154 * "read" and "write". 155 * 156 * @param name the name of the PropertyPermission. 157 * @param actions the actions string. 158 * 159 * @throws NullPointerException if <code>name</code> is <code>null</code>. 160 * @throws IllegalArgumentException if <code>name</code> is empty or if 161 * <code>actions</code> is invalid. 162 */ 163 164 public PropertyPermission(String name, String actions) 165 { 166 super(name,actions); 167 init(getMask(actions)); 168 } 169 170 /** 171 * Checks if this PropertyPermission object "implies" the specified 172 * permission. 173 * <P> 174 * More specifically, this method returns true if:<p> 175 * <ul> 176 * <li> <i>p</i> is an instanceof PropertyPermission,<p> 177 * <li> <i>p</i>'s actions are a subset of this 178 * object's actions, and <p> 179 * <li> <i>p</i>'s name is implied by this object's 180 * name. For example, "java.*" implies "java.home". 181 * </ul> 182 * @param p the permission to check against. 183 * 184 * @return true if the specified permission is implied by this object, 185 * false if not. 186 */ 187 public boolean implies(Permission p) { 188 if (!(p instanceof PropertyPermission)) 189 return false; 190 191 PropertyPermission that = (PropertyPermission) p; 192 193 // we get the effective mask. i.e., the "and" of this and that. 194 // They must be equal to that.mask for implies to return true. 195 196 return ((this.mask & that.mask) == that.mask) && super.implies(that); 197 } 198 199 200 /** 201 * Checks two PropertyPermission objects for equality. Checks that <i>obj</i> is 202 * a PropertyPermission, and has the same name and actions as this object. 203 * <P> 204 * @param obj the object we are testing for equality with this object. 205 * @return true if obj is a PropertyPermission, and has the same name and 206 * actions as this PropertyPermission object. 207 */ 208 public boolean equals(Object obj) { 209 if (obj == this) 210 return true; 211 212 if (! (obj instanceof PropertyPermission)) 213 return false; 214 215 PropertyPermission that = (PropertyPermission) obj; 216 217 return (this.mask == that.mask) && 218 (this.getName().equals(that.getName())); 219 } 220 221 /** 222 * Returns the hash code value for this object. 223 * The hash code used is the hash code of this permissions name, that is, 224 * <code>getName().hashCode()</code>, where <code>getName</code> is 225 * from the Permission superclass. 226 * 227 * @return a hash code value for this object. 228 */ 229 230 public int hashCode() { 231 return this.getName().hashCode(); 232 } 233 234 235 /** 236 * Converts an actions String to an actions mask. 237 * 238 * @param action the action string. 239 * @return the actions mask. 240 */ 241 private static int getMask(String actions) { 242 243 int mask = NONE; 244 245 if (actions == null) { 246 return mask; 247 } 248 249 // Use object identity comparison against known-interned strings for 250 // performance benefit (these values are used heavily within the JDK). 251 if (actions == SecurityConstants.PROPERTY_READ_ACTION) { 252 return READ; 253 } if (actions == SecurityConstants.PROPERTY_WRITE_ACTION) { 254 return WRITE; 255 } else if (actions == SecurityConstants.PROPERTY_RW_ACTION) { 256 return READ|WRITE; 257 } 258 315 "invalid permission: " + actions); 316 } 317 i--; 318 } 319 320 // point i at the location of the comma minus one (or -1). 321 i -= matchlen; 322 } 323 324 return mask; 325 } 326 327 328 /** 329 * Return the canonical string representation of the actions. 330 * Always returns present actions in the following order: 331 * read, write. 332 * 333 * @return the canonical string representation of the actions. 334 */ 335 static String getActions(int mask) 336 { 337 StringBuilder sb = new StringBuilder(); 338 boolean comma = false; 339 340 if ((mask & READ) == READ) { 341 comma = true; 342 sb.append("read"); 343 } 344 345 if ((mask & WRITE) == WRITE) { 346 if (comma) sb.append(','); 347 else comma = true; 348 sb.append("write"); 349 } 350 return sb.toString(); 351 } 352 353 /** 354 * Returns the "canonical string representation" of the actions. 355 * That is, this method always returns present actions in the following order: 356 * read, write. For example, if this PropertyPermission object 357 * allows both write and read actions, a call to <code>getActions</code> 358 * will return the string "read,write". 359 * 360 * @return the canonical string representation of the actions. 361 */ 362 public String getActions() 363 { 364 if (actions == null) 365 actions = getActions(this.mask); 366 367 return actions; 368 } 369 370 /** 371 * Return the current action mask. 372 * Used by the PropertyPermissionCollection 373 * 374 * @return the actions mask. 375 */ 376 377 int getMask() { 378 return mask; 379 } 380 381 /** 382 * Returns a new PermissionCollection object for storing 383 * PropertyPermission objects. 384 * <p> 385 * 386 * @return a new PermissionCollection object suitable for storing 387 * PropertyPermissions. 388 */ 389 390 public PermissionCollection newPermissionCollection() { 391 return new PropertyPermissionCollection(); 392 } 393 394 395 private static final long serialVersionUID = 885438825399942851L; 396 397 /** 398 * WriteObject is called to save the state of the PropertyPermission 399 * to a stream. The actions are serialized, and the superclass 400 * takes care of the name. 401 */ 402 private synchronized void writeObject(java.io.ObjectOutputStream s) 403 throws IOException 404 { 405 // Write out the actions. The superclass takes care of the name 406 // call getActions to make sure actions field is initialized 407 if (actions == null) 408 getActions(); 409 s.defaultWriteObject(); 419 // Read in the action, then initialize the rest 420 s.defaultReadObject(); 421 init(getMask(actions)); 422 } 423 } 424 425 /** 426 * A PropertyPermissionCollection stores a set of PropertyPermission 427 * permissions. 428 * 429 * @see java.security.Permission 430 * @see java.security.Permissions 431 * @see java.security.PermissionCollection 432 * 433 * 434 * @author Roland Schemers 435 * 436 * @serial include 437 */ 438 final class PropertyPermissionCollection extends PermissionCollection 439 implements Serializable 440 { 441 442 /** 443 * Key is property name; value is PropertyPermission. 444 * Not serialized; see serialization section at end of class. 445 */ 446 private transient Map<String, PropertyPermission> perms; 447 448 /** 449 * Boolean saying if "*" is in the collection. 450 * 451 * @see #serialPersistentFields 452 */ 453 // No sync access; OK for this to be stale. 454 private boolean all_allowed; 455 456 /** 457 * Create an empty PropertyPermissions object. 458 * 459 */ 460 461 public PropertyPermissionCollection() { 462 perms = new HashMap<>(32); // Capacity for default policy 463 all_allowed = false; 464 } 465 466 /** 467 * Adds a permission to the PropertyPermissions. The key for the hash is 468 * the name. 469 * 470 * @param permission the Permission object to add. 471 * 472 * @exception IllegalArgumentException - if the permission is not a 473 * PropertyPermission 474 * 475 * @exception SecurityException - if this PropertyPermissionCollection 476 * object has been marked readonly 477 */ 478 479 public void add(Permission permission) 480 { 481 if (! (permission instanceof PropertyPermission)) 482 throw new IllegalArgumentException("invalid permission: "+ 483 permission); 484 if (isReadOnly()) 485 throw new SecurityException( 486 "attempt to add a Permission to a readonly PermissionCollection"); 487 488 PropertyPermission pp = (PropertyPermission) permission; 489 String propName = pp.getName(); 490 491 synchronized (this) { 492 PropertyPermission existing = perms.get(propName); 493 494 if (existing != null) { 495 int oldMask = existing.getMask(); 496 int newMask = pp.getMask(); 497 if (oldMask != newMask) { 498 int effective = oldMask | newMask; 499 String actions = PropertyPermission.getActions(effective); 500 perms.put(propName, new PropertyPermission(propName, actions)); 501 } 502 } else { 503 perms.put(propName, pp); 504 } 505 } 506 507 if (!all_allowed) { 508 if (propName.equals("*")) 509 all_allowed = true; 510 } 511 } 512 513 /** 514 * Check and see if this set of permissions implies the permissions 515 * expressed in "permission". 516 * 517 * @param p the Permission object to compare 518 * 519 * @return true if "permission" is a proper subset of a permission in 520 * the set, false if not. 521 */ 522 523 public boolean implies(Permission permission) 524 { 525 if (! (permission instanceof PropertyPermission)) 526 return false; 527 528 PropertyPermission pp = (PropertyPermission) permission; 529 PropertyPermission x; 530 531 int desired = pp.getMask(); 532 int effective = 0; 533 534 // short circuit if the "*" Permission was added 535 if (all_allowed) { 536 synchronized (this) { 537 x = perms.get("*"); 538 } 539 if (x != null) { 540 effective |= x.getMask(); 541 if ((effective & desired) == desired) 542 return true; 543 } 544 } 638 // Don't call out.defaultWriteObject() 639 640 // Copy perms into a Hashtable 641 Hashtable<String, Permission> permissions = 642 new Hashtable<>(perms.size()*2); 643 synchronized (this) { 644 permissions.putAll(perms); 645 } 646 647 // Write out serializable fields 648 ObjectOutputStream.PutField pfields = out.putFields(); 649 pfields.put("all_allowed", all_allowed); 650 pfields.put("permissions", permissions); 651 out.writeFields(); 652 } 653 654 /* 655 * Reads in a Hashtable of PropertyPermissions and saves them in the 656 * perms field. Reads in all_allowed. 657 */ 658 private void readObject(ObjectInputStream in) throws IOException, 659 ClassNotFoundException { 660 // Don't call defaultReadObject() 661 662 // Read in serialized fields 663 ObjectInputStream.GetField gfields = in.readFields(); 664 665 // Get all_allowed 666 all_allowed = gfields.get("all_allowed", false); 667 668 // Get permissions 669 @SuppressWarnings("unchecked") 670 Hashtable<String, PropertyPermission> permissions = 671 (Hashtable<String, PropertyPermission>)gfields.get("permissions", null); 672 perms = new HashMap<>(permissions.size()*2); 673 perms.putAll(permissions); 674 } 675 } | 113 * The actions mask. 114 * 115 */ 116 private transient int mask; 117 118 /** 119 * The actions string. 120 * 121 * @serial 122 */ 123 private String actions; // Left null as long as possible, then 124 // created and re-used in the getAction function. 125 126 /** 127 * initialize a PropertyPermission object. Common to all constructors. 128 * Also called during de-serialization. 129 * 130 * @param mask the actions mask to use. 131 * 132 */ 133 private void init(int mask) { 134 if ((mask & ALL) != mask) 135 throw new IllegalArgumentException("invalid actions mask"); 136 137 if (mask == NONE) 138 throw new IllegalArgumentException("invalid actions mask"); 139 140 if (getName() == null) 141 throw new NullPointerException("name can't be null"); 142 143 this.mask = mask; 144 } 145 146 /** 147 * Creates a new PropertyPermission object with the specified name. 148 * The name is the name of the system property, and 149 * <i>actions</i> contains a comma-separated list of the 150 * desired actions granted on the property. Possible actions are 151 * "read" and "write". 152 * 153 * @param name the name of the PropertyPermission. 154 * @param actions the actions string. 155 * 156 * @throws NullPointerException if <code>name</code> is <code>null</code>. 157 * @throws IllegalArgumentException if <code>name</code> is empty or if 158 * <code>actions</code> is invalid. 159 */ 160 public PropertyPermission(String name, String actions) { 161 super(name,actions); 162 init(getMask(actions)); 163 } 164 165 /** 166 * Checks if this PropertyPermission object "implies" the specified 167 * permission. 168 * <P> 169 * More specifically, this method returns true if:<p> 170 * <ul> 171 * <li> <i>p</i> is an instanceof PropertyPermission,<p> 172 * <li> <i>p</i>'s actions are a subset of this 173 * object's actions, and <p> 174 * <li> <i>p</i>'s name is implied by this object's 175 * name. For example, "java.*" implies "java.home". 176 * </ul> 177 * @param p the permission to check against. 178 * 179 * @return true if the specified permission is implied by this object, 180 * false if not. 181 */ 182 public boolean implies(Permission p) { 183 if (!(p instanceof PropertyPermission)) 184 return false; 185 186 PropertyPermission that = (PropertyPermission) p; 187 188 // we get the effective mask. i.e., the "and" of this and that. 189 // They must be equal to that.mask for implies to return true. 190 191 return ((this.mask & that.mask) == that.mask) && super.implies(that); 192 } 193 194 /** 195 * Checks two PropertyPermission objects for equality. Checks that <i>obj</i> is 196 * a PropertyPermission, and has the same name and actions as this object. 197 * <P> 198 * @param obj the object we are testing for equality with this object. 199 * @return true if obj is a PropertyPermission, and has the same name and 200 * actions as this PropertyPermission object. 201 */ 202 public boolean equals(Object obj) { 203 if (obj == this) 204 return true; 205 206 if (! (obj instanceof PropertyPermission)) 207 return false; 208 209 PropertyPermission that = (PropertyPermission) obj; 210 211 return (this.mask == that.mask) && 212 (this.getName().equals(that.getName())); 213 } 214 215 /** 216 * Returns the hash code value for this object. 217 * The hash code used is the hash code of this permissions name, that is, 218 * <code>getName().hashCode()</code>, where <code>getName</code> is 219 * from the Permission superclass. 220 * 221 * @return a hash code value for this object. 222 */ 223 public int hashCode() { 224 return this.getName().hashCode(); 225 } 226 227 /** 228 * Converts an actions String to an actions mask. 229 * 230 * @param actions the action string. 231 * @return the actions mask. 232 */ 233 private static int getMask(String actions) { 234 235 int mask = NONE; 236 237 if (actions == null) { 238 return mask; 239 } 240 241 // Use object identity comparison against known-interned strings for 242 // performance benefit (these values are used heavily within the JDK). 243 if (actions == SecurityConstants.PROPERTY_READ_ACTION) { 244 return READ; 245 } if (actions == SecurityConstants.PROPERTY_WRITE_ACTION) { 246 return WRITE; 247 } else if (actions == SecurityConstants.PROPERTY_RW_ACTION) { 248 return READ|WRITE; 249 } 250 307 "invalid permission: " + actions); 308 } 309 i--; 310 } 311 312 // point i at the location of the comma minus one (or -1). 313 i -= matchlen; 314 } 315 316 return mask; 317 } 318 319 320 /** 321 * Return the canonical string representation of the actions. 322 * Always returns present actions in the following order: 323 * read, write. 324 * 325 * @return the canonical string representation of the actions. 326 */ 327 static String getActions(int mask) { 328 StringBuilder sb = new StringBuilder(); 329 boolean comma = false; 330 331 if ((mask & READ) == READ) { 332 comma = true; 333 sb.append("read"); 334 } 335 336 if ((mask & WRITE) == WRITE) { 337 if (comma) sb.append(','); 338 else comma = true; 339 sb.append("write"); 340 } 341 return sb.toString(); 342 } 343 344 /** 345 * Returns the "canonical string representation" of the actions. 346 * That is, this method always returns present actions in the following order: 347 * read, write. For example, if this PropertyPermission object 348 * allows both write and read actions, a call to <code>getActions</code> 349 * will return the string "read,write". 350 * 351 * @return the canonical string representation of the actions. 352 */ 353 public String getActions() { 354 if (actions == null) 355 actions = getActions(this.mask); 356 357 return actions; 358 } 359 360 /** 361 * Return the current action mask. 362 * Used by the PropertyPermissionCollection 363 * 364 * @return the actions mask. 365 */ 366 int getMask() { 367 return mask; 368 } 369 370 /** 371 * Returns a new PermissionCollection object for storing 372 * PropertyPermission objects. 373 * <p> 374 * 375 * @return a new PermissionCollection object suitable for storing 376 * PropertyPermissions. 377 */ 378 public PermissionCollection newPermissionCollection() { 379 return new PropertyPermissionCollection(); 380 } 381 382 383 private static final long serialVersionUID = 885438825399942851L; 384 385 /** 386 * WriteObject is called to save the state of the PropertyPermission 387 * to a stream. The actions are serialized, and the superclass 388 * takes care of the name. 389 */ 390 private synchronized void writeObject(java.io.ObjectOutputStream s) 391 throws IOException 392 { 393 // Write out the actions. The superclass takes care of the name 394 // call getActions to make sure actions field is initialized 395 if (actions == null) 396 getActions(); 397 s.defaultWriteObject(); 407 // Read in the action, then initialize the rest 408 s.defaultReadObject(); 409 init(getMask(actions)); 410 } 411 } 412 413 /** 414 * A PropertyPermissionCollection stores a set of PropertyPermission 415 * permissions. 416 * 417 * @see java.security.Permission 418 * @see java.security.Permissions 419 * @see java.security.PermissionCollection 420 * 421 * 422 * @author Roland Schemers 423 * 424 * @serial include 425 */ 426 final class PropertyPermissionCollection extends PermissionCollection 427 implements Serializable 428 { 429 430 /** 431 * Key is property name; value is PropertyPermission. 432 * Not serialized; see serialization section at end of class. 433 */ 434 private transient Map<String, PropertyPermission> perms; 435 436 /** 437 * Boolean saying if "*" is in the collection. 438 * 439 * @see #serialPersistentFields 440 */ 441 // No sync access; OK for this to be stale. 442 private boolean all_allowed; 443 444 /** 445 * Create an empty PropertyPermissionCollection object. 446 */ 447 public PropertyPermissionCollection() { 448 perms = new HashMap<>(32); // Capacity for default policy 449 all_allowed = false; 450 } 451 452 /** 453 * Adds a permission to the PropertyPermissions. The key for the hash is 454 * the name. 455 * 456 * @param permission the Permission object to add. 457 * 458 * @exception IllegalArgumentException - if the permission is not a 459 * PropertyPermission 460 * 461 * @exception SecurityException - if this PropertyPermissionCollection 462 * object has been marked readonly 463 */ 464 public void add(Permission permission) { 465 if (! (permission instanceof PropertyPermission)) 466 throw new IllegalArgumentException("invalid permission: "+ 467 permission); 468 if (isReadOnly()) 469 throw new SecurityException( 470 "attempt to add a Permission to a readonly PermissionCollection"); 471 472 PropertyPermission pp = (PropertyPermission) permission; 473 String propName = pp.getName(); 474 475 synchronized (this) { 476 PropertyPermission existing = perms.get(propName); 477 478 if (existing != null) { 479 int oldMask = existing.getMask(); 480 int newMask = pp.getMask(); 481 if (oldMask != newMask) { 482 int effective = oldMask | newMask; 483 String actions = PropertyPermission.getActions(effective); 484 perms.put(propName, new PropertyPermission(propName, actions)); 485 } 486 } else { 487 perms.put(propName, pp); 488 } 489 } 490 491 if (!all_allowed) { 492 if (propName.equals("*")) 493 all_allowed = true; 494 } 495 } 496 497 /** 498 * Check and see if this set of permissions implies the permissions 499 * expressed in "permission". 500 * 501 * @param permission the Permission object to compare 502 * 503 * @return true if "permission" is a proper subset of a permission in 504 * the set, false if not. 505 */ 506 public boolean implies(Permission permission) { 507 if (! (permission instanceof PropertyPermission)) 508 return false; 509 510 PropertyPermission pp = (PropertyPermission) permission; 511 PropertyPermission x; 512 513 int desired = pp.getMask(); 514 int effective = 0; 515 516 // short circuit if the "*" Permission was added 517 if (all_allowed) { 518 synchronized (this) { 519 x = perms.get("*"); 520 } 521 if (x != null) { 522 effective |= x.getMask(); 523 if ((effective & desired) == desired) 524 return true; 525 } 526 } 620 // Don't call out.defaultWriteObject() 621 622 // Copy perms into a Hashtable 623 Hashtable<String, Permission> permissions = 624 new Hashtable<>(perms.size()*2); 625 synchronized (this) { 626 permissions.putAll(perms); 627 } 628 629 // Write out serializable fields 630 ObjectOutputStream.PutField pfields = out.putFields(); 631 pfields.put("all_allowed", all_allowed); 632 pfields.put("permissions", permissions); 633 out.writeFields(); 634 } 635 636 /* 637 * Reads in a Hashtable of PropertyPermissions and saves them in the 638 * perms field. Reads in all_allowed. 639 */ 640 private void readObject(ObjectInputStream in) 641 throws IOException, ClassNotFoundException 642 { 643 // Don't call defaultReadObject() 644 645 // Read in serialized fields 646 ObjectInputStream.GetField gfields = in.readFields(); 647 648 // Get all_allowed 649 all_allowed = gfields.get("all_allowed", false); 650 651 // Get permissions 652 @SuppressWarnings("unchecked") 653 Hashtable<String, PropertyPermission> permissions = 654 (Hashtable<String, PropertyPermission>)gfields.get("permissions", null); 655 perms = new HashMap<>(permissions.size()*2); 656 perms.putAll(permissions); 657 } 658 } |