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