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