1 /* 2 * Copyright (c) 1998, 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.security.auth; 27 28 import java.util.*; 29 import java.io.*; 30 import java.lang.reflect.*; 31 import java.text.MessageFormat; 32 import java.security.AccessController; 33 import java.security.AccessControlContext; 34 import java.security.DomainCombiner; 35 import java.security.Permission; 36 import java.security.PermissionCollection; 37 import java.security.Principal; 38 import java.security.PrivilegedAction; 39 import java.security.PrivilegedExceptionAction; 40 import java.security.PrivilegedActionException; 41 import java.security.ProtectionDomain; 42 import sun.security.util.ResourcesMgr; 43 44 /** 45 * <p> A {@code Subject} represents a grouping of related information 46 * for a single entity, such as a person. 47 * Such information includes the Subject's identities as well as 48 * its security-related attributes 49 * (passwords and cryptographic keys, for example). 50 * 51 * <p> Subjects may potentially have multiple identities. 52 * Each identity is represented as a {@code Principal} 53 * within the {@code Subject}. Principals simply bind names to a 54 * {@code Subject}. For example, a {@code Subject} that happens 55 * to be a person, Alice, might have two Principals: 56 * one which binds "Alice Bar", the name on her driver license, 57 * to the {@code Subject}, and another which binds, 58 * "999-99-9999", the number on her student identification card, 59 * to the {@code Subject}. Both Principals refer to the same 60 * {@code Subject} even though each has a different name. 61 * 62 * <p> A {@code Subject} may also own security-related attributes, 63 * which are referred to as credentials. 64 * Sensitive credentials that require special protection, such as 65 * private cryptographic keys, are stored within a private credential 66 * {@code Set}. Credentials intended to be shared, such as 67 * public key certificates or Kerberos server tickets are stored 68 * within a public credential {@code Set}. Different permissions 69 * are required to access and modify the different credential Sets. 70 * 71 * <p> To retrieve all the Principals associated with a {@code Subject}, 72 * invoke the {@code getPrincipals} method. To retrieve 73 * all the public or private credentials belonging to a {@code Subject}, 74 * invoke the {@code getPublicCredentials} method or 75 * {@code getPrivateCredentials} method, respectively. 76 * To modify the returned {@code Set} of Principals and credentials, 77 * use the methods defined in the {@code Set} class. 78 * For example: 79 * <pre> 80 * Subject subject; 81 * Principal principal; 82 * Object credential; 83 * 84 * // add a Principal and credential to the Subject 85 * subject.getPrincipals().add(principal); 86 * subject.getPublicCredentials().add(credential); 87 * </pre> 88 * 89 * <p> This {@code Subject} class implements {@code Serializable}. 90 * While the Principals associated with the {@code Subject} are serialized, 91 * the credentials associated with the {@code Subject} are not. 92 * Note that the {@code java.security.Principal} class 93 * does not implement {@code Serializable}. Therefore all concrete 94 * {@code Principal} implementations associated with Subjects 95 * must implement {@code Serializable}. 96 * 97 * @see java.security.Principal 98 * @see java.security.DomainCombiner 99 */ 100 public final class Subject implements java.io.Serializable { 101 102 private static final long serialVersionUID = -8308522755600156056L; 103 104 /** 105 * A {@code Set} that provides a view of all of this 106 * Subject's Principals 107 * 108 * <p> 109 * 110 * @serial Each element in this set is a 111 * {@code java.security.Principal}. 112 * The set is a {@code Subject.SecureSet}. 113 */ 114 Set<Principal> principals; 115 116 /** 117 * Sets that provide a view of all of this 118 * Subject's Credentials 119 */ 120 transient Set<Object> pubCredentials; 121 transient Set<Object> privCredentials; 122 123 /** 124 * Whether this Subject is read-only 125 * 126 * @serial 127 */ 128 private volatile boolean readOnly = false; 129 130 private static final int PRINCIPAL_SET = 1; 131 private static final int PUB_CREDENTIAL_SET = 2; 132 private static final int PRIV_CREDENTIAL_SET = 3; 133 134 private static final ProtectionDomain[] NULL_PD_ARRAY 135 = new ProtectionDomain[0]; 136 137 /** 138 * Create an instance of a {@code Subject} 139 * with an empty {@code Set} of Principals and empty 140 * Sets of public and private credentials. 141 * 142 * <p> The newly constructed Sets check whether this {@code Subject} 143 * has been set read-only before permitting subsequent modifications. 144 * The newly created Sets also prevent illegal modifications 145 * by ensuring that callers have sufficient permissions. 146 * 147 * <p> To modify the Principals Set, the caller must have 148 * {@code AuthPermission("modifyPrincipals")}. 149 * To modify the public credential Set, the caller must have 150 * {@code AuthPermission("modifyPublicCredentials")}. 151 * To modify the private credential Set, the caller must have 152 * {@code AuthPermission("modifyPrivateCredentials")}. 153 */ 154 public Subject() { 155 156 this.principals = Collections.synchronizedSet 157 (new SecureSet<Principal>(this, PRINCIPAL_SET)); 158 this.pubCredentials = Collections.synchronizedSet 159 (new SecureSet<Object>(this, PUB_CREDENTIAL_SET)); 160 this.privCredentials = Collections.synchronizedSet 161 (new SecureSet<Object>(this, PRIV_CREDENTIAL_SET)); 162 } 163 164 /** 165 * Create an instance of a {@code Subject} with 166 * Principals and credentials. 167 * 168 * <p> The Principals and credentials from the specified Sets 169 * are copied into newly constructed Sets. 170 * These newly created Sets check whether this {@code Subject} 171 * has been set read-only before permitting subsequent modifications. 172 * The newly created Sets also prevent illegal modifications 173 * by ensuring that callers have sufficient permissions. 174 * 175 * <p> To modify the Principals Set, the caller must have 176 * {@code AuthPermission("modifyPrincipals")}. 177 * To modify the public credential Set, the caller must have 178 * {@code AuthPermission("modifyPublicCredentials")}. 179 * To modify the private credential Set, the caller must have 180 * {@code AuthPermission("modifyPrivateCredentials")}. 181 * <p> 182 * 183 * @param readOnly true if the {@code Subject} is to be read-only, 184 * and false otherwise. <p> 185 * 186 * @param principals the {@code Set} of Principals 187 * to be associated with this {@code Subject}. <p> 188 * 189 * @param pubCredentials the {@code Set} of public credentials 190 * to be associated with this {@code Subject}. <p> 191 * 192 * @param privCredentials the {@code Set} of private credentials 193 * to be associated with this {@code Subject}. 194 * 195 * @exception NullPointerException if the specified 196 * {@code principals}, {@code pubCredentials}, 197 * or {@code privCredentials} are {@code null}, 198 * or a null value exists within any of these three 199 * Sets. 200 */ 201 public Subject(boolean readOnly, Set<? extends Principal> principals, 202 Set<?> pubCredentials, Set<?> privCredentials) 203 { 204 if (collectionNullClean(principals) == false || 205 collectionNullClean(pubCredentials) == false || 206 collectionNullClean(privCredentials) == false) { 207 throw new NullPointerException 208 (ResourcesMgr.getString("invalid.null.input.s.")); 209 } 210 211 this.principals = Collections.synchronizedSet(new SecureSet<Principal> 212 (this, PRINCIPAL_SET, principals)); 213 this.pubCredentials = Collections.synchronizedSet(new SecureSet<Object> 214 (this, PUB_CREDENTIAL_SET, pubCredentials)); 215 this.privCredentials = Collections.synchronizedSet(new SecureSet<Object> 216 (this, PRIV_CREDENTIAL_SET, privCredentials)); 217 this.readOnly = readOnly; 218 } 219 220 /** 221 * Set this {@code Subject} to be read-only. 222 * 223 * <p> Modifications (additions and removals) to this Subject's 224 * {@code Principal} {@code Set} and 225 * credential Sets will be disallowed. 226 * The {@code destroy} operation on this Subject's credentials will 227 * still be permitted. 228 * 229 * <p> Subsequent attempts to modify the Subject's {@code Principal} 230 * and credential Sets will result in an 231 * {@code IllegalStateException} being thrown. 232 * Also, once a {@code Subject} is read-only, 233 * it can not be reset to being writable again. 234 * 235 * <p> 236 * 237 * @exception SecurityException if the caller does not have permission 238 * to set this {@code Subject} to be read-only. 239 */ 240 public void setReadOnly() { 241 java.lang.SecurityManager sm = System.getSecurityManager(); 242 if (sm != null) { 243 sm.checkPermission(AuthPermissionHolder.SET_READ_ONLY_PERMISSION); 244 } 245 246 this.readOnly = true; 247 } 248 249 /** 250 * Query whether this {@code Subject} is read-only. 251 * 252 * <p> 253 * 254 * @return true if this {@code Subject} is read-only, false otherwise. 255 */ 256 public boolean isReadOnly() { 257 return this.readOnly; 258 } 259 260 /** 261 * Get the {@code Subject} associated with the provided 262 * {@code AccessControlContext}. 263 * 264 * <p> The {@code AccessControlContext} may contain many 265 * Subjects (from nested {@code doAs} calls). 266 * In this situation, the most recent {@code Subject} associated 267 * with the {@code AccessControlContext} is returned. 268 * 269 * <p> 270 * 271 * @param acc the {@code AccessControlContext} from which to retrieve 272 * the {@code Subject}. 273 * 274 * @return the {@code Subject} associated with the provided 275 * {@code AccessControlContext}, or {@code null} 276 * if no {@code Subject} is associated 277 * with the provided {@code AccessControlContext}. 278 * 279 * @exception SecurityException if the caller does not have permission 280 * to get the {@code Subject}. <p> 281 * 282 * @exception NullPointerException if the provided 283 * {@code AccessControlContext} is {@code null}. 284 */ 285 public static Subject getSubject(final AccessControlContext acc) { 286 287 java.lang.SecurityManager sm = System.getSecurityManager(); 288 if (sm != null) { 289 sm.checkPermission(AuthPermissionHolder.GET_SUBJECT_PERMISSION); 290 } 291 292 if (acc == null) { 293 throw new NullPointerException(ResourcesMgr.getString 294 ("invalid.null.AccessControlContext.provided")); 295 } 296 297 // return the Subject from the DomainCombiner of the provided context 298 return AccessController.doPrivileged 299 (new java.security.PrivilegedAction<Subject>() { 300 public Subject run() { 301 DomainCombiner dc = acc.getDomainCombiner(); 302 if (!(dc instanceof SubjectDomainCombiner)) 303 return null; 304 SubjectDomainCombiner sdc = (SubjectDomainCombiner)dc; 305 return sdc.getSubject(); 306 } 307 }); 308 } 309 310 /** 311 * Perform work as a particular {@code Subject}. 312 * 313 * <p> This method first retrieves the current Thread's 314 * {@code AccessControlContext} via 315 * {@code AccessController.getContext}, 316 * and then instantiates a new {@code AccessControlContext} 317 * using the retrieved context along with a new 318 * {@code SubjectDomainCombiner} (constructed using 319 * the provided {@code Subject}). 320 * Finally, this method invokes {@code AccessController.doPrivileged}, 321 * passing it the provided {@code PrivilegedAction}, 322 * as well as the newly constructed {@code AccessControlContext}. 323 * 324 * <p> 325 * 326 * @param subject the {@code Subject} that the specified 327 * {@code action} will run as. This parameter 328 * may be {@code null}. <p> 329 * 330 * @param <T> the type of the value returned by the PrivilegedAction's 331 * {@code run} method. 332 * 333 * @param action the code to be run as the specified 334 * {@code Subject}. <p> 335 * 336 * @return the value returned by the PrivilegedAction's 337 * {@code run} method. 338 * 339 * @exception NullPointerException if the {@code PrivilegedAction} 340 * is {@code null}. <p> 341 * 342 * @exception SecurityException if the caller does not have permission 343 * to invoke this method. 344 */ 345 public static <T> T doAs(final Subject subject, 346 final java.security.PrivilegedAction<T> action) { 347 348 java.lang.SecurityManager sm = System.getSecurityManager(); 349 if (sm != null) { 350 sm.checkPermission(AuthPermissionHolder.DO_AS_PERMISSION); 351 } 352 if (action == null) 353 throw new NullPointerException 354 (ResourcesMgr.getString("invalid.null.action.provided")); 355 356 // set up the new Subject-based AccessControlContext 357 // for doPrivileged 358 final AccessControlContext currentAcc = AccessController.getContext(); 359 360 // call doPrivileged and push this new context on the stack 361 return java.security.AccessController.doPrivileged 362 (action, 363 createContext(subject, currentAcc)); 364 } 365 366 /** 367 * Perform work as a particular {@code Subject}. 368 * 369 * <p> This method first retrieves the current Thread's 370 * {@code AccessControlContext} via 371 * {@code AccessController.getContext}, 372 * and then instantiates a new {@code AccessControlContext} 373 * using the retrieved context along with a new 374 * {@code SubjectDomainCombiner} (constructed using 375 * the provided {@code Subject}). 376 * Finally, this method invokes {@code AccessController.doPrivileged}, 377 * passing it the provided {@code PrivilegedExceptionAction}, 378 * as well as the newly constructed {@code AccessControlContext}. 379 * 380 * <p> 381 * 382 * @param subject the {@code Subject} that the specified 383 * {@code action} will run as. This parameter 384 * may be {@code null}. <p> 385 * 386 * @param <T> the type of the value returned by the 387 * PrivilegedExceptionAction's {@code run} method. 388 * 389 * @param action the code to be run as the specified 390 * {@code Subject}. <p> 391 * 392 * @return the value returned by the 393 * PrivilegedExceptionAction's {@code run} method. 394 * 395 * @exception PrivilegedActionException if the 396 * {@code PrivilegedExceptionAction.run} 397 * method throws a checked exception. <p> 398 * 399 * @exception NullPointerException if the specified 400 * {@code PrivilegedExceptionAction} is 401 * {@code null}. <p> 402 * 403 * @exception SecurityException if the caller does not have permission 404 * to invoke this method. 405 */ 406 public static <T> T doAs(final Subject subject, 407 final java.security.PrivilegedExceptionAction<T> action) 408 throws java.security.PrivilegedActionException { 409 410 java.lang.SecurityManager sm = System.getSecurityManager(); 411 if (sm != null) { 412 sm.checkPermission(AuthPermissionHolder.DO_AS_PERMISSION); 413 } 414 415 if (action == null) 416 throw new NullPointerException 417 (ResourcesMgr.getString("invalid.null.action.provided")); 418 419 // set up the new Subject-based AccessControlContext for doPrivileged 420 final AccessControlContext currentAcc = AccessController.getContext(); 421 422 // call doPrivileged and push this new context on the stack 423 return java.security.AccessController.doPrivileged 424 (action, 425 createContext(subject, currentAcc)); 426 } 427 428 /** 429 * Perform privileged work as a particular {@code Subject}. 430 * 431 * <p> This method behaves exactly as {@code Subject.doAs}, 432 * except that instead of retrieving the current Thread's 433 * {@code AccessControlContext}, it uses the provided 434 * {@code AccessControlContext}. If the provided 435 * {@code AccessControlContext} is {@code null}, 436 * this method instantiates a new {@code AccessControlContext} 437 * with an empty collection of ProtectionDomains. 438 * 439 * <p> 440 * 441 * @param subject the {@code Subject} that the specified 442 * {@code action} will run as. This parameter 443 * may be {@code null}. <p> 444 * 445 * @param <T> the type of the value returned by the PrivilegedAction's 446 * {@code run} method. 447 * 448 * @param action the code to be run as the specified 449 * {@code Subject}. <p> 450 * 451 * @param acc the {@code AccessControlContext} to be tied to the 452 * specified <i>subject</i> and <i>action</i>. <p> 453 * 454 * @return the value returned by the PrivilegedAction's 455 * {@code run} method. 456 * 457 * @exception NullPointerException if the {@code PrivilegedAction} 458 * is {@code null}. <p> 459 * 460 * @exception SecurityException if the caller does not have permission 461 * to invoke this method. 462 */ 463 public static <T> T doAsPrivileged(final Subject subject, 464 final java.security.PrivilegedAction<T> action, 465 final java.security.AccessControlContext acc) { 466 467 java.lang.SecurityManager sm = System.getSecurityManager(); 468 if (sm != null) { 469 sm.checkPermission(AuthPermissionHolder.DO_AS_PRIVILEGED_PERMISSION); 470 } 471 472 if (action == null) 473 throw new NullPointerException 474 (ResourcesMgr.getString("invalid.null.action.provided")); 475 476 // set up the new Subject-based AccessControlContext 477 // for doPrivileged 478 final AccessControlContext callerAcc = 479 (acc == null ? 480 new AccessControlContext(NULL_PD_ARRAY) : 481 acc); 482 483 // call doPrivileged and push this new context on the stack 484 return java.security.AccessController.doPrivileged 485 (action, 486 createContext(subject, callerAcc)); 487 } 488 489 /** 490 * Perform privileged work as a particular {@code Subject}. 491 * 492 * <p> This method behaves exactly as {@code Subject.doAs}, 493 * except that instead of retrieving the current Thread's 494 * {@code AccessControlContext}, it uses the provided 495 * {@code AccessControlContext}. If the provided 496 * {@code AccessControlContext} is {@code null}, 497 * this method instantiates a new {@code AccessControlContext} 498 * with an empty collection of ProtectionDomains. 499 * 500 * <p> 501 * 502 * @param subject the {@code Subject} that the specified 503 * {@code action} will run as. This parameter 504 * may be {@code null}. <p> 505 * 506 * @param <T> the type of the value returned by the 507 * PrivilegedExceptionAction's {@code run} method. 508 * 509 * @param action the code to be run as the specified 510 * {@code Subject}. <p> 511 * 512 * @param acc the {@code AccessControlContext} to be tied to the 513 * specified <i>subject</i> and <i>action</i>. <p> 514 * 515 * @return the value returned by the 516 * PrivilegedExceptionAction's {@code run} method. 517 * 518 * @exception PrivilegedActionException if the 519 * {@code PrivilegedExceptionAction.run} 520 * method throws a checked exception. <p> 521 * 522 * @exception NullPointerException if the specified 523 * {@code PrivilegedExceptionAction} is 524 * {@code null}. <p> 525 * 526 * @exception SecurityException if the caller does not have permission 527 * to invoke this method. 528 */ 529 public static <T> T doAsPrivileged(final Subject subject, 530 final java.security.PrivilegedExceptionAction<T> action, 531 final java.security.AccessControlContext acc) 532 throws java.security.PrivilegedActionException { 533 534 java.lang.SecurityManager sm = System.getSecurityManager(); 535 if (sm != null) { 536 sm.checkPermission(AuthPermissionHolder.DO_AS_PRIVILEGED_PERMISSION); 537 } 538 539 if (action == null) 540 throw new NullPointerException 541 (ResourcesMgr.getString("invalid.null.action.provided")); 542 543 // set up the new Subject-based AccessControlContext for doPrivileged 544 final AccessControlContext callerAcc = 545 (acc == null ? 546 new AccessControlContext(NULL_PD_ARRAY) : 547 acc); 548 549 // call doPrivileged and push this new context on the stack 550 return java.security.AccessController.doPrivileged 551 (action, 552 createContext(subject, callerAcc)); 553 } 554 555 private static AccessControlContext createContext(final Subject subject, 556 final AccessControlContext acc) { 557 558 559 return java.security.AccessController.doPrivileged 560 (new java.security.PrivilegedAction<AccessControlContext>() { 561 public AccessControlContext run() { 562 if (subject == null) 563 return new AccessControlContext(acc, null); 564 else 565 return new AccessControlContext 566 (acc, 567 new SubjectDomainCombiner(subject)); 568 } 569 }); 570 } 571 572 /** 573 * Return the {@code Set} of Principals associated with this 574 * {@code Subject}. Each {@code Principal} represents 575 * an identity for this {@code Subject}. 576 * 577 * <p> The returned {@code Set} is backed by this Subject's 578 * internal {@code Principal} {@code Set}. Any modification 579 * to the returned {@code Set} affects the internal 580 * {@code Principal} {@code Set} as well. 581 * 582 * <p> 583 * 584 * @return The {@code Set} of Principals associated with this 585 * {@code Subject}. 586 */ 587 public Set<Principal> getPrincipals() { 588 589 // always return an empty Set instead of null 590 // so LoginModules can add to the Set if necessary 591 return principals; 592 } 593 594 /** 595 * Return a {@code Set} of Principals associated with this 596 * {@code Subject} that are instances or subclasses of the specified 597 * {@code Class}. 598 * 599 * <p> The returned {@code Set} is not backed by this Subject's 600 * internal {@code Principal} {@code Set}. A new 601 * {@code Set} is created and returned for each method invocation. 602 * Modifications to the returned {@code Set} 603 * will not affect the internal {@code Principal} {@code Set}. 604 * 605 * <p> 606 * 607 * @param <T> the type of the class modeled by {@code c} 608 * 609 * @param c the returned {@code Set} of Principals will all be 610 * instances of this class. 611 * 612 * @return a {@code Set} of Principals that are instances of the 613 * specified {@code Class}. 614 * 615 * @exception NullPointerException if the specified {@code Class} 616 * is {@code null}. 617 */ 618 public <T extends Principal> Set<T> getPrincipals(Class<T> c) { 619 620 if (c == null) 621 throw new NullPointerException 622 (ResourcesMgr.getString("invalid.null.Class.provided")); 623 624 // always return an empty Set instead of null 625 // so LoginModules can add to the Set if necessary 626 return new ClassSet<T>(PRINCIPAL_SET, c); 627 } 628 629 /** 630 * Return the {@code Set} of public credentials held by this 631 * {@code Subject}. 632 * 633 * <p> The returned {@code Set} is backed by this Subject's 634 * internal public Credential {@code Set}. Any modification 635 * to the returned {@code Set} affects the internal public 636 * Credential {@code Set} as well. 637 * 638 * <p> 639 * 640 * @return A {@code Set} of public credentials held by this 641 * {@code Subject}. 642 */ 643 public Set<Object> getPublicCredentials() { 644 645 // always return an empty Set instead of null 646 // so LoginModules can add to the Set if necessary 647 return pubCredentials; 648 } 649 650 /** 651 * Return the {@code Set} of private credentials held by this 652 * {@code Subject}. 653 * 654 * <p> The returned {@code Set} is backed by this Subject's 655 * internal private Credential {@code Set}. Any modification 656 * to the returned {@code Set} affects the internal private 657 * Credential {@code Set} as well. 658 * 659 * <p> A caller requires permissions to access the Credentials 660 * in the returned {@code Set}, or to modify the 661 * {@code Set} itself. A {@code SecurityException} 662 * is thrown if the caller does not have the proper permissions. 663 * 664 * <p> While iterating through the {@code Set}, 665 * a {@code SecurityException} is thrown 666 * if the caller does not have permission to access a 667 * particular Credential. The {@code Iterator} 668 * is nevertheless advanced to next element in the {@code Set}. 669 * 670 * <p> 671 * 672 * @return A {@code Set} of private credentials held by this 673 * {@code Subject}. 674 */ 675 public Set<Object> getPrivateCredentials() { 676 677 // XXX 678 // we do not need a security check for 679 // AuthPermission(getPrivateCredentials) 680 // because we already restrict access to private credentials 681 // via the PrivateCredentialPermission. all the extra AuthPermission 682 // would do is protect the set operations themselves 683 // (like size()), which don't seem security-sensitive. 684 685 // always return an empty Set instead of null 686 // so LoginModules can add to the Set if necessary 687 return privCredentials; 688 } 689 690 /** 691 * Return a {@code Set} of public credentials associated with this 692 * {@code Subject} that are instances or subclasses of the specified 693 * {@code Class}. 694 * 695 * <p> The returned {@code Set} is not backed by this Subject's 696 * internal public Credential {@code Set}. A new 697 * {@code Set} is created and returned for each method invocation. 698 * Modifications to the returned {@code Set} 699 * will not affect the internal public Credential {@code Set}. 700 * 701 * <p> 702 * 703 * @param <T> the type of the class modeled by {@code c} 704 * 705 * @param c the returned {@code Set} of public credentials will all be 706 * instances of this class. 707 * 708 * @return a {@code Set} of public credentials that are instances 709 * of the specified {@code Class}. 710 * 711 * @exception NullPointerException if the specified {@code Class} 712 * is {@code null}. 713 */ 714 public <T> Set<T> getPublicCredentials(Class<T> c) { 715 716 if (c == null) 717 throw new NullPointerException 718 (ResourcesMgr.getString("invalid.null.Class.provided")); 719 720 // always return an empty Set instead of null 721 // so LoginModules can add to the Set if necessary 722 return new ClassSet<T>(PUB_CREDENTIAL_SET, c); 723 } 724 725 /** 726 * Return a {@code Set} of private credentials associated with this 727 * {@code Subject} that are instances or subclasses of the specified 728 * {@code Class}. 729 * 730 * <p> The caller must have permission to access all of the 731 * requested Credentials, or a {@code SecurityException} 732 * will be thrown. 733 * 734 * <p> The returned {@code Set} is not backed by this Subject's 735 * internal private Credential {@code Set}. A new 736 * {@code Set} is created and returned for each method invocation. 737 * Modifications to the returned {@code Set} 738 * will not affect the internal private Credential {@code Set}. 739 * 740 * <p> 741 * 742 * @param <T> the type of the class modeled by {@code c} 743 * 744 * @param c the returned {@code Set} of private credentials will all be 745 * instances of this class. 746 * 747 * @return a {@code Set} of private credentials that are instances 748 * of the specified {@code Class}. 749 * 750 * @exception NullPointerException if the specified {@code Class} 751 * is {@code null}. 752 */ 753 public <T> Set<T> getPrivateCredentials(Class<T> c) { 754 755 // XXX 756 // we do not need a security check for 757 // AuthPermission(getPrivateCredentials) 758 // because we already restrict access to private credentials 759 // via the PrivateCredentialPermission. all the extra AuthPermission 760 // would do is protect the set operations themselves 761 // (like size()), which don't seem security-sensitive. 762 763 if (c == null) 764 throw new NullPointerException 765 (ResourcesMgr.getString("invalid.null.Class.provided")); 766 767 // always return an empty Set instead of null 768 // so LoginModules can add to the Set if necessary 769 return new ClassSet<T>(PRIV_CREDENTIAL_SET, c); 770 } 771 772 /** 773 * Compares the specified Object with this {@code Subject} 774 * for equality. Returns true if the given object is also a Subject 775 * and the two {@code Subject} instances are equivalent. 776 * More formally, two {@code Subject} instances are 777 * equal if their {@code Principal} and {@code Credential} 778 * Sets are equal. 779 * 780 * <p> 781 * 782 * @param o Object to be compared for equality with this 783 * {@code Subject}. 784 * 785 * @return true if the specified Object is equal to this 786 * {@code Subject}. 787 * 788 * @exception SecurityException if the caller does not have permission 789 * to access the private credentials for this {@code Subject}, 790 * or if the caller does not have permission to access the 791 * private credentials for the provided {@code Subject}. 792 */ 793 public boolean equals(Object o) { 794 795 if (o == null) 796 return false; 797 798 if (this == o) 799 return true; 800 801 if (o instanceof Subject) { 802 803 final Subject that = (Subject)o; 804 805 // check the principal and credential sets 806 Set<Principal> thatPrincipals; 807 synchronized(that.principals) { 808 // avoid deadlock from dual locks 809 thatPrincipals = new HashSet<Principal>(that.principals); 810 } 811 if (!principals.equals(thatPrincipals)) { 812 return false; 813 } 814 815 Set<Object> thatPubCredentials; 816 synchronized(that.pubCredentials) { 817 // avoid deadlock from dual locks 818 thatPubCredentials = new HashSet<Object>(that.pubCredentials); 819 } 820 if (!pubCredentials.equals(thatPubCredentials)) { 821 return false; 822 } 823 824 Set<Object> thatPrivCredentials; 825 synchronized(that.privCredentials) { 826 // avoid deadlock from dual locks 827 thatPrivCredentials = new HashSet<Object>(that.privCredentials); 828 } 829 if (!privCredentials.equals(thatPrivCredentials)) { 830 return false; 831 } 832 return true; 833 } 834 return false; 835 } 836 837 /** 838 * Return the String representation of this {@code Subject}. 839 * 840 * <p> 841 * 842 * @return the String representation of this {@code Subject}. 843 */ 844 public String toString() { 845 return toString(true); 846 } 847 848 /** 849 * package private convenience method to print out the Subject 850 * without firing off a security check when trying to access 851 * the Private Credentials 852 */ 853 String toString(boolean includePrivateCredentials) { 854 855 String s = ResourcesMgr.getString("Subject."); 856 String suffix = ""; 857 858 synchronized(principals) { 859 Iterator<Principal> pI = principals.iterator(); 860 while (pI.hasNext()) { 861 Principal p = pI.next(); 862 suffix = suffix + ResourcesMgr.getString(".Principal.") + 863 p.toString() + ResourcesMgr.getString("NEWLINE"); 864 } 865 } 866 867 synchronized(pubCredentials) { 868 Iterator<Object> pI = pubCredentials.iterator(); 869 while (pI.hasNext()) { 870 Object o = pI.next(); 871 suffix = suffix + 872 ResourcesMgr.getString(".Public.Credential.") + 873 o.toString() + ResourcesMgr.getString("NEWLINE"); 874 } 875 } 876 877 if (includePrivateCredentials) { 878 synchronized(privCredentials) { 879 Iterator<Object> pI = privCredentials.iterator(); 880 while (pI.hasNext()) { 881 try { 882 Object o = pI.next(); 883 suffix += ResourcesMgr.getString 884 (".Private.Credential.") + 885 o.toString() + 886 ResourcesMgr.getString("NEWLINE"); 887 } catch (SecurityException se) { 888 suffix += ResourcesMgr.getString 889 (".Private.Credential.inaccessible."); 890 break; 891 } 892 } 893 } 894 } 895 return s + suffix; 896 } 897 898 /** 899 * Returns a hashcode for this {@code Subject}. 900 * 901 * <p> 902 * 903 * @return a hashcode for this {@code Subject}. 904 * 905 * @exception SecurityException if the caller does not have permission 906 * to access this Subject's private credentials. 907 */ 908 public int hashCode() { 909 910 /** 911 * The hashcode is derived exclusive or-ing the 912 * hashcodes of this Subject's Principals and credentials. 913 * 914 * If a particular credential was destroyed 915 * ({@code credential.hashCode()} throws an 916 * {@code IllegalStateException}), 917 * the hashcode for that credential is derived via: 918 * {@code credential.getClass().toString().hashCode()}. 919 */ 920 921 int hashCode = 0; 922 923 synchronized(principals) { 924 Iterator<Principal> pIterator = principals.iterator(); 925 while (pIterator.hasNext()) { 926 Principal p = pIterator.next(); 927 hashCode ^= p.hashCode(); 928 } 929 } 930 931 synchronized(pubCredentials) { 932 Iterator<Object> pubCIterator = pubCredentials.iterator(); 933 while (pubCIterator.hasNext()) { 934 hashCode ^= getCredHashCode(pubCIterator.next()); 935 } 936 } 937 return hashCode; 938 } 939 940 /** 941 * get a credential's hashcode 942 */ 943 private int getCredHashCode(Object o) { 944 try { 945 return o.hashCode(); 946 } catch (IllegalStateException ise) { 947 return o.getClass().toString().hashCode(); 948 } 949 } 950 951 /** 952 * Writes this object out to a stream (i.e., serializes it). 953 */ 954 private void writeObject(java.io.ObjectOutputStream oos) 955 throws java.io.IOException { 956 synchronized(principals) { 957 oos.defaultWriteObject(); 958 } 959 } 960 961 /** 962 * Reads this object from a stream (i.e., deserializes it) 963 */ 964 @SuppressWarnings("unchecked") 965 private void readObject(java.io.ObjectInputStream s) 966 throws java.io.IOException, ClassNotFoundException { 967 968 ObjectInputStream.GetField gf = s.readFields(); 969 970 readOnly = gf.get("readOnly", false); 971 972 Set<Principal> inputPrincs = (Set<Principal>)gf.get("principals", null); 973 974 // Rewrap the principals into a SecureSet 975 try { 976 principals = Collections.synchronizedSet(new SecureSet<Principal> 977 (this, PRINCIPAL_SET, inputPrincs)); 978 } catch (NullPointerException npe) { 979 // Sometimes people deserialize the principals set only. 980 // Subject is not accessible, so just don't fail. 981 principals = Collections.synchronizedSet 982 (new SecureSet<Principal>(this, PRINCIPAL_SET)); 983 } 984 985 // The Credential {@code Set} is not serialized, but we do not 986 // want the default deserialization routine to set it to null. 987 this.pubCredentials = Collections.synchronizedSet 988 (new SecureSet<Object>(this, PUB_CREDENTIAL_SET)); 989 this.privCredentials = Collections.synchronizedSet 990 (new SecureSet<Object>(this, PRIV_CREDENTIAL_SET)); 991 } 992 993 /** 994 * Tests for null-clean collections (both non-null reference and 995 * no null elements) 996 * 997 * @param coll A {@code Collection} to be tested for null references 998 * 999 * @return true if {@code coll} is non-null and contains no null 1000 * elements, false otherwise. 1001 */ 1002 private static boolean collectionNullClean(Collection<?> coll) { 1003 boolean isClean = false; 1004 1005 try { 1006 isClean = (coll != null) && !coll.contains(null); 1007 } catch (NullPointerException npe) { 1008 // A null-hostile collection may choose to return null if 1009 // contains(null) is called on it rather than returning false. 1010 // If so then we know no nulls are present. 1011 isClean = true; 1012 } 1013 1014 return isClean; 1015 } 1016 1017 /** 1018 * Prevent modifications unless caller has permission. 1019 * 1020 * @serial include 1021 */ 1022 private static class SecureSet<E> 1023 extends AbstractSet<E> 1024 implements java.io.Serializable { 1025 1026 private static final long serialVersionUID = 7911754171111800359L; 1027 1028 /** 1029 * @serialField this$0 Subject The outer Subject instance. 1030 * @serialField elements LinkedList The elements in this set. 1031 */ 1032 private static final ObjectStreamField[] serialPersistentFields = { 1033 new ObjectStreamField("this$0", Subject.class), 1034 new ObjectStreamField("elements", LinkedList.class), 1035 new ObjectStreamField("which", int.class) 1036 }; 1037 1038 Subject subject; 1039 LinkedList<E> elements; 1040 1041 /** 1042 * @serial An integer identifying the type of objects contained 1043 * in this set. If {@code which == 1}, 1044 * this is a Principal set and all the elements are 1045 * of type {@code java.security.Principal}. 1046 * If {@code which == 2}, this is a public credential 1047 * set and all the elements are of type {@code Object}. 1048 * If {@code which == 3}, this is a private credential 1049 * set and all the elements are of type {@code Object}. 1050 */ 1051 private int which; 1052 1053 SecureSet(Subject subject, int which) { 1054 this.subject = subject; 1055 this.which = which; 1056 this.elements = new LinkedList<E>(); 1057 } 1058 1059 SecureSet(Subject subject, int which, Set<? extends E> set) { 1060 this.subject = subject; 1061 this.which = which; 1062 this.elements = new LinkedList<E>(set); 1063 } 1064 1065 public int size() { 1066 return elements.size(); 1067 } 1068 1069 public Iterator<E> iterator() { 1070 final LinkedList<E> list = elements; 1071 return new Iterator<E>() { 1072 ListIterator<E> i = list.listIterator(0); 1073 1074 public boolean hasNext() {return i.hasNext();} 1075 1076 public E next() { 1077 if (which != Subject.PRIV_CREDENTIAL_SET) { 1078 return i.next(); 1079 } 1080 1081 SecurityManager sm = System.getSecurityManager(); 1082 if (sm != null) { 1083 try { 1084 sm.checkPermission(new PrivateCredentialPermission 1085 (list.get(i.nextIndex()).getClass().getName(), 1086 subject.getPrincipals())); 1087 } catch (SecurityException se) { 1088 i.next(); 1089 throw (se); 1090 } 1091 } 1092 return i.next(); 1093 } 1094 1095 public void remove() { 1096 1097 if (subject.isReadOnly()) { 1098 throw new IllegalStateException(ResourcesMgr.getString 1099 ("Subject.is.read.only")); 1100 } 1101 1102 java.lang.SecurityManager sm = System.getSecurityManager(); 1103 if (sm != null) { 1104 switch (which) { 1105 case Subject.PRINCIPAL_SET: 1106 sm.checkPermission(AuthPermissionHolder.MODIFY_PRINCIPALS_PERMISSION); 1107 break; 1108 case Subject.PUB_CREDENTIAL_SET: 1109 sm.checkPermission(AuthPermissionHolder.MODIFY_PUBLIC_CREDENTIALS_PERMISSION); 1110 break; 1111 default: 1112 sm.checkPermission(AuthPermissionHolder.MODIFY_PRIVATE_CREDENTIALS_PERMISSION); 1113 break; 1114 } 1115 } 1116 i.remove(); 1117 } 1118 }; 1119 } 1120 1121 public boolean add(E o) { 1122 1123 if (o == null) { 1124 throw new NullPointerException 1125 (ResourcesMgr.getString("invalid.null.input.s.")); 1126 } 1127 1128 if (subject.isReadOnly()) { 1129 throw new IllegalStateException 1130 (ResourcesMgr.getString("Subject.is.read.only")); 1131 } 1132 1133 java.lang.SecurityManager sm = System.getSecurityManager(); 1134 if (sm != null) { 1135 switch (which) { 1136 case Subject.PRINCIPAL_SET: 1137 sm.checkPermission(AuthPermissionHolder.MODIFY_PRINCIPALS_PERMISSION); 1138 break; 1139 case Subject.PUB_CREDENTIAL_SET: 1140 sm.checkPermission(AuthPermissionHolder.MODIFY_PUBLIC_CREDENTIALS_PERMISSION); 1141 break; 1142 default: 1143 sm.checkPermission(AuthPermissionHolder.MODIFY_PRIVATE_CREDENTIALS_PERMISSION); 1144 break; 1145 } 1146 } 1147 1148 switch (which) { 1149 case Subject.PRINCIPAL_SET: 1150 if (!(o instanceof Principal)) { 1151 throw new SecurityException(ResourcesMgr.getString 1152 ("attempting.to.add.an.object.which.is.not.an.instance.of.java.security.Principal.to.a.Subject.s.Principal.Set")); 1153 } 1154 break; 1155 default: 1156 // ok to add Objects of any kind to credential sets 1157 break; 1158 } 1159 1160 // check for duplicates 1161 if (!elements.contains(o)) 1162 return elements.add(o); 1163 else 1164 return false; 1165 } 1166 1167 public boolean remove(Object o) { 1168 1169 if (o == null) { 1170 throw new NullPointerException 1171 (ResourcesMgr.getString("invalid.null.input.s.")); 1172 } 1173 1174 final Iterator<E> e = iterator(); 1175 while (e.hasNext()) { 1176 E next; 1177 if (which != Subject.PRIV_CREDENTIAL_SET) { 1178 next = e.next(); 1179 } else { 1180 next = java.security.AccessController.doPrivileged 1181 (new java.security.PrivilegedAction<E>() { 1182 public E run() { 1183 return e.next(); 1184 } 1185 }); 1186 } 1187 1188 if (next.equals(o)) { 1189 e.remove(); 1190 return true; 1191 } 1192 } 1193 return false; 1194 } 1195 1196 public boolean contains(Object o) { 1197 1198 if (o == null) { 1199 throw new NullPointerException 1200 (ResourcesMgr.getString("invalid.null.input.s.")); 1201 } 1202 1203 final Iterator<E> e = iterator(); 1204 while (e.hasNext()) { 1205 E next; 1206 if (which != Subject.PRIV_CREDENTIAL_SET) { 1207 next = e.next(); 1208 } else { 1209 1210 // For private credentials: 1211 // If the caller does not have read permission for 1212 // for o.getClass(), we throw a SecurityException. 1213 // Otherwise we check the private cred set to see whether 1214 // it contains the Object 1215 1216 SecurityManager sm = System.getSecurityManager(); 1217 if (sm != null) { 1218 sm.checkPermission(new PrivateCredentialPermission 1219 (o.getClass().getName(), 1220 subject.getPrincipals())); 1221 } 1222 next = java.security.AccessController.doPrivileged 1223 (new java.security.PrivilegedAction<E>() { 1224 public E run() { 1225 return e.next(); 1226 } 1227 }); 1228 } 1229 1230 if (next.equals(o)) { 1231 return true; 1232 } 1233 } 1234 return false; 1235 } 1236 1237 public boolean addAll(Collection<? extends E> c) { 1238 if (collectionNullClean(c) == false) { 1239 throw new NullPointerException 1240 (ResourcesMgr.getString("invalid.null.input.s.")); 1241 } 1242 1243 return (super.addAll(c)); 1244 } 1245 1246 public boolean removeAll(Collection<?> c) { 1247 if (collectionNullClean(c) == false) { 1248 throw new NullPointerException 1249 (ResourcesMgr.getString("invalid.null.input.s.")); 1250 } 1251 1252 boolean modified = false; 1253 final Iterator<E> e = iterator(); 1254 while (e.hasNext()) { 1255 E next; 1256 if (which != Subject.PRIV_CREDENTIAL_SET) { 1257 next = e.next(); 1258 } else { 1259 next = java.security.AccessController.doPrivileged 1260 (new java.security.PrivilegedAction<E>() { 1261 public E run() { 1262 return e.next(); 1263 } 1264 }); 1265 } 1266 1267 Iterator<?> ce = c.iterator(); 1268 while (ce.hasNext()) { 1269 if (next.equals(ce.next())) { 1270 e.remove(); 1271 modified = true; 1272 break; 1273 } 1274 } 1275 } 1276 return modified; 1277 } 1278 1279 public boolean containsAll(Collection<?> c) { 1280 if (collectionNullClean(c) == false) { 1281 throw new NullPointerException 1282 (ResourcesMgr.getString("invalid.null.input.s.")); 1283 } 1284 1285 return super.containsAll(c); 1286 } 1287 1288 public boolean retainAll(Collection<?> c) { 1289 if (collectionNullClean(c) == false) { 1290 throw new NullPointerException 1291 (ResourcesMgr.getString("invalid.null.input.s.")); 1292 } 1293 1294 boolean modified = false; 1295 final Iterator<E> e = iterator(); 1296 while (e.hasNext()) { 1297 E next; 1298 if (which != Subject.PRIV_CREDENTIAL_SET) { 1299 next = e.next(); 1300 } else { 1301 next = java.security.AccessController.doPrivileged 1302 (new java.security.PrivilegedAction<E>() { 1303 public E run() { 1304 return e.next(); 1305 } 1306 }); 1307 } 1308 1309 if (c.contains(next) == false) { 1310 e.remove(); 1311 modified = true; 1312 } 1313 } 1314 1315 return modified; 1316 } 1317 1318 public void clear() { 1319 final Iterator<E> e = iterator(); 1320 while (e.hasNext()) { 1321 E next; 1322 if (which != Subject.PRIV_CREDENTIAL_SET) { 1323 next = e.next(); 1324 } else { 1325 next = java.security.AccessController.doPrivileged 1326 (new java.security.PrivilegedAction<E>() { 1327 public E run() { 1328 return e.next(); 1329 } 1330 }); 1331 } 1332 e.remove(); 1333 } 1334 } 1335 1336 /** 1337 * Writes this object out to a stream (i.e., serializes it). 1338 * 1339 * <p> 1340 * 1341 * @serialData If this is a private credential set, 1342 * a security check is performed to ensure that 1343 * the caller has permission to access each credential 1344 * in the set. If the security check passes, 1345 * the set is serialized. 1346 */ 1347 private void writeObject(java.io.ObjectOutputStream oos) 1348 throws java.io.IOException { 1349 1350 if (which == Subject.PRIV_CREDENTIAL_SET) { 1351 // check permissions before serializing 1352 Iterator<E> i = iterator(); 1353 while (i.hasNext()) { 1354 i.next(); 1355 } 1356 } 1357 ObjectOutputStream.PutField fields = oos.putFields(); 1358 fields.put("this$0", subject); 1359 fields.put("elements", elements); 1360 fields.put("which", which); 1361 oos.writeFields(); 1362 } 1363 1364 @SuppressWarnings("unchecked") 1365 private void readObject(ObjectInputStream ois) 1366 throws IOException, ClassNotFoundException 1367 { 1368 ObjectInputStream.GetField fields = ois.readFields(); 1369 subject = (Subject) fields.get("this$0", null); 1370 which = fields.get("which", 0); 1371 1372 LinkedList<E> tmp = (LinkedList<E>) fields.get("elements", null); 1373 1374 if (Subject.collectionNullClean(tmp) == false) { 1375 throw new NullPointerException 1376 (ResourcesMgr.getString("invalid.null.input.s.")); 1377 } 1378 1379 if (tmp.getClass() != LinkedList.class) { 1380 elements = new LinkedList<E>(tmp); 1381 } else { 1382 elements = tmp; 1383 } 1384 } 1385 1386 } 1387 1388 /** 1389 * This class implements a {@code Set} which returns only 1390 * members that are an instance of a specified Class. 1391 */ 1392 private class ClassSet<T> extends AbstractSet<T> { 1393 1394 private int which; 1395 private Class<T> c; 1396 private Set<T> set; 1397 1398 ClassSet(int which, Class<T> c) { 1399 this.which = which; 1400 this.c = c; 1401 set = new HashSet<T>(); 1402 1403 switch (which) { 1404 case Subject.PRINCIPAL_SET: 1405 synchronized(principals) { populateSet(); } 1406 break; 1407 case Subject.PUB_CREDENTIAL_SET: 1408 synchronized(pubCredentials) { populateSet(); } 1409 break; 1410 default: 1411 synchronized(privCredentials) { populateSet(); } 1412 break; 1413 } 1414 } 1415 1416 @SuppressWarnings("unchecked") /*To suppress warning from line 1374*/ 1417 private void populateSet() { 1418 final Iterator<?> iterator; 1419 switch(which) { 1420 case Subject.PRINCIPAL_SET: 1421 iterator = Subject.this.principals.iterator(); 1422 break; 1423 case Subject.PUB_CREDENTIAL_SET: 1424 iterator = Subject.this.pubCredentials.iterator(); 1425 break; 1426 default: 1427 iterator = Subject.this.privCredentials.iterator(); 1428 break; 1429 } 1430 1431 // Check whether the caller has permisson to get 1432 // credentials of Class c 1433 1434 while (iterator.hasNext()) { 1435 Object next; 1436 if (which == Subject.PRIV_CREDENTIAL_SET) { 1437 next = java.security.AccessController.doPrivileged 1438 (new java.security.PrivilegedAction<Object>() { 1439 public Object run() { 1440 return iterator.next(); 1441 } 1442 }); 1443 } else { 1444 next = iterator.next(); 1445 } 1446 if (c.isAssignableFrom(next.getClass())) { 1447 if (which != Subject.PRIV_CREDENTIAL_SET) { 1448 set.add((T)next); 1449 } else { 1450 // Check permission for private creds 1451 SecurityManager sm = System.getSecurityManager(); 1452 if (sm != null) { 1453 sm.checkPermission(new PrivateCredentialPermission 1454 (next.getClass().getName(), 1455 Subject.this.getPrincipals())); 1456 } 1457 set.add((T)next); 1458 } 1459 } 1460 } 1461 } 1462 1463 public int size() { 1464 return set.size(); 1465 } 1466 1467 public Iterator<T> iterator() { 1468 return set.iterator(); 1469 } 1470 1471 public boolean add(T o) { 1472 1473 if (!o.getClass().isAssignableFrom(c)) { 1474 MessageFormat form = new MessageFormat(ResourcesMgr.getString 1475 ("attempting.to.add.an.object.which.is.not.an.instance.of.class")); 1476 Object[] source = {c.toString()}; 1477 throw new SecurityException(form.format(source)); 1478 } 1479 1480 return set.add(o); 1481 } 1482 } 1483 1484 static class AuthPermissionHolder { 1485 static final AuthPermission DO_AS_PERMISSION = 1486 new AuthPermission("doAs"); 1487 1488 static final AuthPermission DO_AS_PRIVILEGED_PERMISSION = 1489 new AuthPermission("doAsPrivileged"); 1490 1491 static final AuthPermission SET_READ_ONLY_PERMISSION = 1492 new AuthPermission("setReadOnly"); 1493 1494 static final AuthPermission GET_SUBJECT_PERMISSION = 1495 new AuthPermission("getSubject"); 1496 1497 static final AuthPermission MODIFY_PRINCIPALS_PERMISSION = 1498 new AuthPermission("modifyPrincipals"); 1499 1500 static final AuthPermission MODIFY_PUBLIC_CREDENTIALS_PERMISSION = 1501 new AuthPermission("modifyPublicCredentials"); 1502 1503 static final AuthPermission MODIFY_PRIVATE_CREDENTIALS_PERMISSION = 1504 new AuthPermission("modifyPrivateCredentials"); 1505 } 1506 }