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