Home | History | Annotate | Download | only in auth
      1 /*
      2  *  Licensed to the Apache Software Foundation (ASF) under one or more
      3  *  contributor license agreements.  See the NOTICE file distributed with
      4  *  this work for additional information regarding copyright ownership.
      5  *  The ASF licenses this file to You under the Apache License, Version 2.0
      6  *  (the "License"); you may not use this file except in compliance with
      7  *  the License.  You may obtain a copy of the License at
      8  *
      9  *     http://www.apache.org/licenses/LICENSE-2.0
     10  *
     11  *  Unless required by applicable law or agreed to in writing, software
     12  *  distributed under the License is distributed on an "AS IS" BASIS,
     13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14  *  See the License for the specific language governing permissions and
     15  *  limitations under the License.
     16  */
     17 
     18 package org.apache.harmony.javax.security.auth;
     19 
     20 import java.io.IOException;
     21 import java.io.ObjectInputStream;
     22 import java.io.ObjectOutputStream;
     23 import java.io.Serializable;
     24 import java.security.AccessControlContext;
     25 import java.security.AccessController;
     26 import java.security.DomainCombiner;
     27 import java.security.Permission;
     28 import java.security.Principal;
     29 import java.security.PrivilegedAction;
     30 import java.security.PrivilegedActionException;
     31 import java.security.PrivilegedExceptionAction;
     32 import java.security.ProtectionDomain;
     33 import java.util.AbstractSet;
     34 import java.util.Collection;
     35 import java.util.Iterator;
     36 import java.util.LinkedList;
     37 import java.util.Set;
     38 
     39 
     40 
     41 /**
     42  * The central class of the {@code javax.security.auth} package representing an
     43  * authenticated user or entity (both referred to as "subject"). IT defines also
     44  * the static methods that allow code to be run, and do modifications according
     45  * to the subject's permissions.
     46  * <p>
     47  * A subject has the following features:
     48  * <ul>
     49  * <li>A set of {@code Principal} objects specifying the identities bound to a
     50  * {@code Subject} that distinguish it.</li>
     51  * <li>Credentials (public and private) such as certificates, keys, or
     52  * authentication proofs such as tickets</li>
     53  * </ul>
     54  */
     55 public final class Subject implements Serializable {
     56 
     57     private static final long serialVersionUID = -8308522755600156056L;
     58 
     59     private static final AuthPermission _AS = new AuthPermission("doAs"); //$NON-NLS-1$
     60 
     61     private static final AuthPermission _AS_PRIVILEGED = new AuthPermission(
     62             "doAsPrivileged"); //$NON-NLS-1$
     63 
     64     private static final AuthPermission _SUBJECT = new AuthPermission(
     65             "getSubject"); //$NON-NLS-1$
     66 
     67     private static final AuthPermission _PRINCIPALS = new AuthPermission(
     68             "modifyPrincipals"); //$NON-NLS-1$
     69 
     70     private static final AuthPermission _PRIVATE_CREDENTIALS = new AuthPermission(
     71             "modifyPrivateCredentials"); //$NON-NLS-1$
     72 
     73     private static final AuthPermission _PUBLIC_CREDENTIALS = new AuthPermission(
     74             "modifyPublicCredentials"); //$NON-NLS-1$
     75 
     76     private static final AuthPermission _READ_ONLY = new AuthPermission(
     77             "setReadOnly"); //$NON-NLS-1$
     78 
     79     private final Set<Principal> principals;
     80 
     81     private boolean readOnly;
     82 
     83     // set of private credentials
     84     private transient SecureSet<Object> privateCredentials;
     85 
     86     // set of public credentials
     87     private transient SecureSet<Object> publicCredentials;
     88 
     89     /**
     90      * The default constructor initializing the sets of public and private
     91      * credentials and principals with the empty set.
     92      */
     93     public Subject() {
     94         super();
     95         principals = new SecureSet<Principal>(_PRINCIPALS);
     96         publicCredentials = new SecureSet<Object>(_PUBLIC_CREDENTIALS);
     97         privateCredentials = new SecureSet<Object>(_PRIVATE_CREDENTIALS);
     98 
     99         readOnly = false;
    100     }
    101 
    102     /**
    103      * The constructor for the subject, setting its public and private
    104      * credentials and principals according to the arguments.
    105      *
    106      * @param readOnly
    107      *            {@code true} if this {@code Subject} is read-only, thus
    108      *            preventing any modifications to be done.
    109      * @param subjPrincipals
    110      *            the set of Principals that are attributed to this {@code
    111      *            Subject}.
    112      * @param pubCredentials
    113      *            the set of public credentials that distinguish this {@code
    114      *            Subject}.
    115      * @param privCredentials
    116      *            the set of private credentials that distinguish this {@code
    117      *            Subject}.
    118      */
    119     public Subject(boolean readOnly, Set<? extends Principal> subjPrincipals,
    120             Set<?> pubCredentials, Set<?> privCredentials) {
    121 
    122         if (subjPrincipals == null || pubCredentials == null || privCredentials == null) {
    123             throw new NullPointerException();
    124         }
    125 
    126         principals = new SecureSet<Principal>(_PRINCIPALS, subjPrincipals);
    127         publicCredentials = new SecureSet<Object>(_PUBLIC_CREDENTIALS, pubCredentials);
    128         privateCredentials = new SecureSet<Object>(_PRIVATE_CREDENTIALS, privCredentials);
    129 
    130         this.readOnly = readOnly;
    131     }
    132 
    133     /**
    134      * Runs the code defined by {@code action} using the permissions granted to
    135      * the {@code Subject} itself and to the code as well.
    136      *
    137      * @param subject
    138      *            the distinguished {@code Subject}.
    139      * @param action
    140      *            the code to be run.
    141      * @return the {@code Object} returned when running the {@code action}.
    142      */
    143     @SuppressWarnings("unchecked")
    144     public static Object doAs(Subject subject, PrivilegedAction action) {
    145 
    146         checkPermission(_AS);
    147 
    148         return doAs_PrivilegedAction(subject, action, AccessController.getContext());
    149     }
    150 
    151     /**
    152      * Run the code defined by {@code action} using the permissions granted to
    153      * the {@code Subject} and to the code itself, additionally providing a more
    154      * specific context.
    155      *
    156      * @param subject
    157      *            the distinguished {@code Subject}.
    158      * @param action
    159      *            the code to be run.
    160      * @param context
    161      *            the specific context in which the {@code action} is invoked.
    162      *            if {@code null} a new {@link AccessControlContext} is
    163      *            instantiated.
    164      * @return the {@code Object} returned when running the {@code action}.
    165      */
    166     @SuppressWarnings("unchecked")
    167     public static Object doAsPrivileged(Subject subject, PrivilegedAction action,
    168             AccessControlContext context) {
    169 
    170         checkPermission(_AS_PRIVILEGED);
    171 
    172         if (context == null) {
    173             return doAs_PrivilegedAction(subject, action, new AccessControlContext(
    174                     new ProtectionDomain[0]));
    175         }
    176         return doAs_PrivilegedAction(subject, action, context);
    177     }
    178 
    179     // instantiates a new context and passes it to AccessController
    180     @SuppressWarnings("unchecked")
    181     private static Object doAs_PrivilegedAction(Subject subject, PrivilegedAction action,
    182             final AccessControlContext context) {
    183 
    184         AccessControlContext newContext;
    185 
    186         final SubjectDomainCombiner combiner;
    187         if (subject == null) {
    188             // performance optimization
    189             // if subject is null there is nothing to combine
    190             combiner = null;
    191         } else {
    192             combiner = new SubjectDomainCombiner(subject);
    193         }
    194 
    195         PrivilegedAction dccAction = new PrivilegedAction() {
    196             public Object run() {
    197 
    198                 return new AccessControlContext(context, combiner);
    199             }
    200         };
    201 
    202         newContext = (AccessControlContext) AccessController.doPrivileged(dccAction);
    203 
    204         return AccessController.doPrivileged(action, newContext);
    205     }
    206 
    207     /**
    208      * Runs the code defined by {@code action} using the permissions granted to
    209      * the subject and to the code itself.
    210      *
    211      * @param subject
    212      *            the distinguished {@code Subject}.
    213      * @param action
    214      *            the code to be run.
    215      * @return the {@code Object} returned when running the {@code action}.
    216      * @throws PrivilegedActionException
    217      *             if running the {@code action} throws an exception.
    218      */
    219     @SuppressWarnings("unchecked")
    220     public static Object doAs(Subject subject, PrivilegedExceptionAction action)
    221             throws PrivilegedActionException {
    222 
    223         checkPermission(_AS);
    224 
    225         return doAs_PrivilegedExceptionAction(subject, action, AccessController.getContext());
    226     }
    227 
    228     /**
    229      * Runs the code defined by {@code action} using the permissions granted to
    230      * the subject and to the code itself, additionally providing a more
    231      * specific context.
    232      *
    233      * @param subject
    234      *            the distinguished {@code Subject}.
    235      * @param action
    236      *            the code to be run.
    237      * @param context
    238      *            the specific context in which the {@code action} is invoked.
    239      *            if {@code null} a new {@link AccessControlContext} is
    240      *            instantiated.
    241      * @return the {@code Object} returned when running the {@code action}.
    242      * @throws PrivilegedActionException
    243      *             if running the {@code action} throws an exception.
    244      */
    245     @SuppressWarnings("unchecked")
    246     public static Object doAsPrivileged(Subject subject,
    247             PrivilegedExceptionAction action, AccessControlContext context)
    248             throws PrivilegedActionException {
    249 
    250         checkPermission(_AS_PRIVILEGED);
    251 
    252         if (context == null) {
    253             return doAs_PrivilegedExceptionAction(subject, action,
    254                     new AccessControlContext(new ProtectionDomain[0]));
    255         }
    256         return doAs_PrivilegedExceptionAction(subject, action, context);
    257     }
    258 
    259     // instantiates a new context and passes it to AccessController
    260     @SuppressWarnings("unchecked")
    261     private static Object doAs_PrivilegedExceptionAction(Subject subject,
    262             PrivilegedExceptionAction action, final AccessControlContext context)
    263             throws PrivilegedActionException {
    264 
    265         AccessControlContext newContext;
    266 
    267         final SubjectDomainCombiner combiner;
    268         if (subject == null) {
    269             // performance optimization
    270             // if subject is null there is nothing to combine
    271             combiner = null;
    272         } else {
    273             combiner = new SubjectDomainCombiner(subject);
    274         }
    275 
    276         PrivilegedAction<AccessControlContext> dccAction = new PrivilegedAction<AccessControlContext>() {
    277             public AccessControlContext run() {
    278                 return new AccessControlContext(context, combiner);
    279             }
    280         };
    281 
    282         newContext = AccessController.doPrivileged(dccAction);
    283 
    284         return AccessController.doPrivileged(action, newContext);
    285     }
    286 
    287     /**
    288      * Checks two Subjects for equality. More specifically if the principals,
    289      * public and private credentials are equal, equality for two {@code
    290      * Subjects} is implied.
    291      *
    292      * @param obj
    293      *            the {@code Object} checked for equality with this {@code
    294      *            Subject}.
    295      * @return {@code true} if the specified {@code Subject} is equal to this
    296      *         one.
    297      */
    298     @Override
    299     public boolean equals(Object obj) {
    300 
    301         if (this == obj) {
    302             return true;
    303         }
    304 
    305         if (obj == null || this.getClass() != obj.getClass()) {
    306             return false;
    307         }
    308 
    309         Subject that = (Subject) obj;
    310 
    311         if (principals.equals(that.principals)
    312                 && publicCredentials.equals(that.publicCredentials)
    313                 && privateCredentials.equals(that.privateCredentials)) {
    314             return true;
    315         }
    316         return false;
    317     }
    318 
    319     /**
    320      * Returns this {@code Subject}'s {@link Principal}.
    321      *
    322      * @return this {@code Subject}'s {@link Principal}.
    323      */
    324     public Set<Principal> getPrincipals() {
    325         return principals;
    326     }
    327 
    328 
    329     /**
    330      * Returns this {@code Subject}'s {@link Principal} which is a subclass of
    331      * the {@code Class} provided.
    332      *
    333      * @param c
    334      *            the {@code Class} as a criteria which the {@code Principal}
    335      *            returned must satisfy.
    336      * @return this {@code Subject}'s {@link Principal}. Modifications to the
    337      *         returned set of {@code Principal}s do not affect this {@code
    338      *         Subject}'s set.
    339      */
    340     public <T extends Principal> Set<T> getPrincipals(Class<T> c) {
    341         return ((SecureSet<Principal>) principals).get(c);
    342     }
    343 
    344     /**
    345      * Returns the private credentials associated with this {@code Subject}.
    346      *
    347      * @return the private credentials associated with this {@code Subject}.
    348      */
    349     public Set<Object> getPrivateCredentials() {
    350         return privateCredentials;
    351     }
    352 
    353     /**
    354      * Returns this {@code Subject}'s private credentials which are a subclass
    355      * of the {@code Class} provided.
    356      *
    357      * @param c
    358      *            the {@code Class} as a criteria which the private credentials
    359      *            returned must satisfy.
    360      * @return this {@code Subject}'s private credentials. Modifications to the
    361      *         returned set of credentials do not affect this {@code Subject}'s
    362      *         credentials.
    363      */
    364     public <T> Set<T> getPrivateCredentials(Class<T> c) {
    365         return privateCredentials.get(c);
    366     }
    367 
    368     /**
    369      * Returns the public credentials associated with this {@code Subject}.
    370      *
    371      * @return the public credentials associated with this {@code Subject}.
    372      */
    373     public Set<Object> getPublicCredentials() {
    374         return publicCredentials;
    375     }
    376 
    377 
    378     /**
    379      * Returns this {@code Subject}'s public credentials which are a subclass of
    380      * the {@code Class} provided.
    381      *
    382      * @param c
    383      *            the {@code Class} as a criteria which the public credentials
    384      *            returned must satisfy.
    385      * @return this {@code Subject}'s public credentials. Modifications to the
    386      *         returned set of credentials do not affect this {@code Subject}'s
    387      *         credentials.
    388      */
    389     public <T> Set<T> getPublicCredentials(Class<T> c) {
    390         return publicCredentials.get(c);
    391     }
    392 
    393     /**
    394      * Returns a hash code of this {@code Subject}.
    395      *
    396      * @return a hash code of this {@code Subject}.
    397      */
    398     @Override
    399     public int hashCode() {
    400         return principals.hashCode() + privateCredentials.hashCode()
    401                 + publicCredentials.hashCode();
    402     }
    403 
    404     /**
    405      * Prevents from modifications being done to the credentials and {@link
    406      * Principal} sets. After setting it to read-only this {@code Subject} can
    407      * not be made writable again. The destroy method on the credentials still
    408      * works though.
    409      */
    410     public void setReadOnly() {
    411         checkPermission(_READ_ONLY);
    412 
    413         readOnly = true;
    414     }
    415 
    416     /**
    417      * Returns whether this {@code Subject} is read-only or not.
    418      *
    419      * @return whether this {@code Subject} is read-only or not.
    420      */
    421     public boolean isReadOnly() {
    422         return readOnly;
    423     }
    424 
    425     /**
    426      * Returns a {@code String} representation of this {@code Subject}.
    427      *
    428      * @return a {@code String} representation of this {@code Subject}.
    429      */
    430     @Override
    431     public String toString() {
    432 
    433         StringBuilder buf = new StringBuilder("Subject:\n"); //$NON-NLS-1$
    434 
    435         Iterator<?> it = principals.iterator();
    436         while (it.hasNext()) {
    437             buf.append("\tPrincipal: "); //$NON-NLS-1$
    438             buf.append(it.next());
    439             buf.append('\n');
    440         }
    441 
    442         it = publicCredentials.iterator();
    443         while (it.hasNext()) {
    444             buf.append("\tPublic Credential: "); //$NON-NLS-1$
    445             buf.append(it.next());
    446             buf.append('\n');
    447         }
    448 
    449         int offset = buf.length() - 1;
    450         it = privateCredentials.iterator();
    451         try {
    452             while (it.hasNext()) {
    453                 buf.append("\tPrivate Credential: "); //$NON-NLS-1$
    454                 buf.append(it.next());
    455                 buf.append('\n');
    456             }
    457         } catch (SecurityException e) {
    458             buf.delete(offset, buf.length());
    459             buf.append("\tPrivate Credentials: no accessible information\n"); //$NON-NLS-1$
    460         }
    461         return buf.toString();
    462     }
    463 
    464     private void readObject(ObjectInputStream in) throws IOException,
    465             ClassNotFoundException {
    466 
    467         in.defaultReadObject();
    468 
    469         publicCredentials = new SecureSet<Object>(_PUBLIC_CREDENTIALS);
    470         privateCredentials = new SecureSet<Object>(_PRIVATE_CREDENTIALS);
    471     }
    472 
    473     private void writeObject(ObjectOutputStream out) throws IOException {
    474         out.defaultWriteObject();
    475     }
    476 
    477     /**
    478      * Returns the {@code Subject} that was last associated with the {@code
    479      * context} provided as argument.
    480      *
    481      * @param context
    482      *            the {@code context} that was associated with the
    483      *            {@code Subject}.
    484      * @return the {@code Subject} that was last associated with the {@code
    485      *         context} provided as argument.
    486      */
    487     public static Subject getSubject(final AccessControlContext context) {
    488         checkPermission(_SUBJECT);
    489         if (context == null) {
    490             throw new NullPointerException("auth.09"); //$NON-NLS-1$
    491         }
    492         PrivilegedAction<DomainCombiner> action = new PrivilegedAction<DomainCombiner>() {
    493             public DomainCombiner run() {
    494                 return context.getDomainCombiner();
    495             }
    496         };
    497         DomainCombiner combiner = AccessController.doPrivileged(action);
    498 
    499         if ((combiner == null) || !(combiner instanceof SubjectDomainCombiner)) {
    500             return null;
    501         }
    502         return ((SubjectDomainCombiner) combiner).getSubject();
    503     }
    504 
    505     // checks passed permission
    506     private static void checkPermission(Permission p) {
    507         SecurityManager sm = System.getSecurityManager();
    508         if (sm != null) {
    509             sm.checkPermission(p);
    510         }
    511     }
    512 
    513     // FIXME is used only in two places. remove?
    514     private void checkState() {
    515         if (readOnly) {
    516             throw new IllegalStateException("auth.0A"); //$NON-NLS-1$
    517         }
    518     }
    519 
    520     private final class SecureSet<SST> extends AbstractSet<SST> implements Serializable {
    521 
    522         /**
    523          * Compatibility issue: see comments for setType variable
    524          */
    525         private static final long serialVersionUID = 7911754171111800359L;
    526 
    527         private LinkedList<SST> elements;
    528 
    529         /*
    530          * Is used to define a set type for serialization.
    531          *
    532          * A type can be principal, priv. or pub. credential set. The spec.
    533          * doesn't clearly says that priv. and pub. credential sets can be
    534          * serialized and what classes they are. It is only possible to figure
    535          * out from writeObject method comments that priv. credential set is
    536          * serializable and it is an instance of SecureSet class. So pub.
    537          * credential was implemented by analogy
    538          *
    539          * Compatibility issue: the class follows its specified serial form.
    540          * Also according to the serialization spec. adding new field is a
    541          * compatible change. So is ok for principal set (because the default
    542          * value for integer is zero). But priv. or pub. credential set it is
    543          * not compatible because most probably other implementations resolve
    544          * this issue in other way
    545          */
    546         private int setType;
    547 
    548         // Defines principal set for serialization.
    549         private static final int SET_Principal = 0;
    550 
    551         // Defines private credential set for serialization.
    552         private static final int SET_PrivCred = 1;
    553 
    554         // Defines public credential set for serialization.
    555         private static final int SET_PubCred = 2;
    556 
    557         // permission required to modify set
    558         private transient AuthPermission permission;
    559 
    560         protected SecureSet(AuthPermission perm) {
    561             permission = perm;
    562             elements = new LinkedList<SST>();
    563         }
    564 
    565         // creates set from specified collection with specified permission
    566         // all collection elements are verified before adding
    567         protected SecureSet(AuthPermission perm, Collection<? extends SST> s) {
    568             this(perm);
    569 
    570             // Subject's constructor receives a Set, we can trusts if a set is from bootclasspath,
    571             // and not to check whether it contains duplicates or not
    572             boolean trust = s.getClass().getClassLoader() == null;
    573 
    574             Iterator<? extends SST> it = s.iterator();
    575             while (it.hasNext()) {
    576                 SST o = it.next();
    577                 verifyElement(o);
    578                 if (trust || !elements.contains(o)) {
    579                     elements.add(o);
    580                 }
    581             }
    582         }
    583 
    584         // verifies new set element
    585         private void verifyElement(Object o) {
    586 
    587             if (o == null) {
    588                 throw new NullPointerException();
    589             }
    590             if (permission == _PRINCIPALS && !(Principal.class.isAssignableFrom(o.getClass()))) {
    591                 throw new IllegalArgumentException("auth.0B"); //$NON-NLS-1$
    592             }
    593         }
    594 
    595         /*
    596          * verifies specified element, checks set state, and security permission
    597          * to modify set before adding new element
    598          */
    599         @Override
    600         public boolean add(SST o) {
    601 
    602             verifyElement(o);
    603 
    604             checkState();
    605             checkPermission(permission);
    606 
    607             if (!elements.contains(o)) {
    608                 elements.add(o);
    609                 return true;
    610             }
    611             return false;
    612         }
    613 
    614         // returns an instance of SecureIterator
    615         @Override
    616         public Iterator<SST> iterator() {
    617 
    618             if (permission == _PRIVATE_CREDENTIALS) {
    619                 /*
    620                  * private credential set requires iterator with additional
    621                  * security check (PrivateCredentialPermission)
    622                  */
    623                 return new SecureIterator(elements.iterator()) {
    624                     /*
    625                      * checks permission to access next private credential moves
    626                      * to the next element even SecurityException was thrown
    627                      */
    628                     @Override
    629                     public SST next() {
    630                         SST obj = iterator.next();
    631                         checkPermission(new PrivateCredentialPermission(obj
    632                                 .getClass().getName(), principals));
    633                         return obj;
    634                     }
    635                 };
    636             }
    637             return new SecureIterator(elements.iterator());
    638         }
    639 
    640         @Override
    641         public boolean retainAll(Collection<?> c) {
    642 
    643             if (c == null) {
    644                 throw new NullPointerException();
    645             }
    646             return super.retainAll(c);
    647         }
    648 
    649         @Override
    650         public int size() {
    651             return elements.size();
    652         }
    653 
    654         /**
    655          * return set with elements that are instances or subclasses of the
    656          * specified class
    657          */
    658         protected final <E> Set<E> get(final Class<E> c) {
    659 
    660             if (c == null) {
    661                 throw new NullPointerException();
    662             }
    663 
    664             AbstractSet<E> s = new AbstractSet<E>() {
    665                 private LinkedList<E> elements = new LinkedList<E>();
    666 
    667                 @Override
    668                 public boolean add(E o) {
    669 
    670                     if (!c.isAssignableFrom(o.getClass())) {
    671                         throw new IllegalArgumentException(
    672                                 "auth.0C " + c.getName()); //$NON-NLS-1$
    673                     }
    674 
    675                     if (elements.contains(o)) {
    676                         return false;
    677                     }
    678                     elements.add(o);
    679                     return true;
    680                 }
    681 
    682                 @Override
    683                 public Iterator<E> iterator() {
    684                     return elements.iterator();
    685                 }
    686 
    687                 @Override
    688                 public boolean retainAll(Collection<?> c) {
    689 
    690                     if (c == null) {
    691                         throw new NullPointerException();
    692                     }
    693                     return super.retainAll(c);
    694                 }
    695 
    696                 @Override
    697                 public int size() {
    698                     return elements.size();
    699                 }
    700             };
    701 
    702             // FIXME must have permissions for requested priv. credentials
    703             for (Iterator<SST> it = iterator(); it.hasNext();) {
    704                 SST o = it.next();
    705                 if (c.isAssignableFrom(o.getClass())) {
    706                     s.add(c.cast(o));
    707                 }
    708             }
    709             return s;
    710         }
    711 
    712         private void readObject(ObjectInputStream in) throws IOException,
    713                 ClassNotFoundException {
    714             in.defaultReadObject();
    715 
    716             switch (setType) {
    717             case SET_Principal:
    718                 permission = _PRINCIPALS;
    719                 break;
    720             case SET_PrivCred:
    721                 permission = _PRIVATE_CREDENTIALS;
    722                 break;
    723             case SET_PubCred:
    724                 permission = _PUBLIC_CREDENTIALS;
    725                 break;
    726             default:
    727                 throw new IllegalArgumentException();
    728             }
    729 
    730             Iterator<SST> it = elements.iterator();
    731             while (it.hasNext()) {
    732                 verifyElement(it.next());
    733             }
    734         }
    735 
    736         private void writeObject(ObjectOutputStream out) throws IOException {
    737 
    738             if (permission == _PRIVATE_CREDENTIALS) {
    739                 // does security check for each private credential
    740                 for (Iterator<SST> it = iterator(); it.hasNext();) {
    741                     it.next();
    742                 }
    743                 setType = SET_PrivCred;
    744             } else if (permission == _PRINCIPALS) {
    745                 setType = SET_Principal;
    746             } else {
    747                 setType = SET_PubCred;
    748             }
    749 
    750             out.defaultWriteObject();
    751         }
    752 
    753         /**
    754          * Represents iterator for subject's secure set
    755          */
    756         private class SecureIterator implements Iterator<SST> {
    757             protected Iterator<SST> iterator;
    758 
    759             protected SecureIterator(Iterator<SST> iterator) {
    760                 this.iterator = iterator;
    761             }
    762 
    763             public boolean hasNext() {
    764                 return iterator.hasNext();
    765             }
    766 
    767             public SST next() {
    768                 return iterator.next();
    769             }
    770 
    771             /**
    772              * checks set state, and security permission to modify set before
    773              * removing current element
    774              */
    775             public void remove() {
    776                 checkState();
    777                 checkPermission(permission);
    778                 iterator.remove();
    779             }
    780         }
    781     }
    782 }
    783