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