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