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