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