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