• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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      */
Subject()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      */
Subject(boolean readOnly, Set<? extends Principal> subjPrincipals, Set<?> pubCredentials, Set<?> privCredentials)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")
doAs(Subject subject, PrivilegedAction action)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")
doAsPrivileged(Subject subject, PrivilegedAction action, AccessControlContext context)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")
doAs_PrivilegedAction(Subject subject, PrivilegedAction action, final AccessControlContext context)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")
doAs(Subject subject, PrivilegedExceptionAction action)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")
doAsPrivileged(Subject subject, PrivilegedExceptionAction action, AccessControlContext context)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")
doAs_PrivilegedExceptionAction(Subject subject, PrivilegedExceptionAction action, final AccessControlContext context)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
equals(Object obj)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      */
getPrincipals()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      */
getPrincipals(Class<T> c)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      */
getPrivateCredentials()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      */
getPrivateCredentials(Class<T> c)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      */
getPublicCredentials()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      */
getPublicCredentials(Class<T> c)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
hashCode()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      */
setReadOnly()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      */
isReadOnly()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
toString()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 
readObject(ObjectInputStream in)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 
writeObject(ObjectOutputStream out)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      */
getSubject(final AccessControlContext context)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
checkPermission(Permission p)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?
checkState()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 
SecureSet(AuthPermission perm)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
SecureSet(AuthPermission perm, Collection<? extends SST> s)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
verifyElement(Object o)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
add(SST o)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
iterator()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
retainAll(Collection<?> c)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
size()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          */
get(final Class<E> c)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 
readObject(ObjectInputStream in)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 
writeObject(ObjectOutputStream out)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 
SecureIterator(Iterator<SST> iterator)759             protected SecureIterator(Iterator<SST> iterator) {
760                 this.iterator = iterator;
761             }
762 
hasNext()763             public boolean hasNext() {
764                 return iterator.hasNext();
765             }
766 
next()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              */
remove()775             public void remove() {
776                 checkState();
777                 checkPermission(permission);
778                 iterator.remove();
779             }
780         }
781     }
782 }
783