Merge from the pain train
[official-gcc.git] / libjava / javax / security / auth / Subject.java
blob37baecc8aedd3faa0b84de00910bd9426bc936a8
1 /* Subject.java -- a single entity in the system.
2 Copyright (C) 2004 Free Software Foundation, Inc.
4 This file is part of GNU Classpath.
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING. If not, write to the
18 Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
19 02111-1307 USA.
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library. Thus, the terms and
23 conditions of the GNU General Public License cover the whole
24 combination.
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module. An independent module is a module which is not derived from
33 or based on this library. If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so. If you do not wish to do so, delete this
36 exception statement from your version. */
39 package javax.security.auth;
41 import java.io.IOException;
42 import java.io.ObjectInputStream;
43 import java.io.ObjectOutputStream;
44 import java.io.Serializable;
46 import java.security.AccessControlContext;
47 import java.security.AccessController;
48 import java.security.DomainCombiner;
49 import java.security.Principal;
50 import java.security.PrivilegedAction;
51 import java.security.PrivilegedActionException;
52 import java.security.PrivilegedExceptionAction;
54 import java.util.AbstractSet;
55 import java.util.Collection;
56 import java.util.Collections;
57 import java.util.HashSet;
58 import java.util.Iterator;
59 import java.util.LinkedList;
60 import java.util.Set;
62 public final class Subject implements Serializable
64 // Fields.
65 // -------------------------------------------------------------------------
67 private static final long serialVersionUID = -8308522755600156056L;
69 /**
70 * @serial The set of principals. The type of this field is SecureSet, a
71 * private inner class.
73 private final Set principals;
75 /**
76 * @serial The read-only flag.
78 private boolean readOnly;
80 private final transient SecureSet pubCred;
81 private final transient SecureSet privCred;
83 // Constructors.
84 // -------------------------------------------------------------------------
86 public Subject()
88 principals = new SecureSet (this, SecureSet.PRINCIPALS);
89 pubCred = new SecureSet (this, SecureSet.PUBLIC_CREDENTIALS);
90 privCred = new SecureSet (this, SecureSet.PRIVATE_CREDENTIALS);
91 readOnly = false;
94 public Subject (final boolean readOnly, final Set principals,
95 final Set pubCred, final Set privCred)
97 if (principals == null || pubCred == null || privCred == null)
99 throw new NullPointerException();
101 this.principals = new SecureSet (this, SecureSet.PRINCIPALS, principals);
102 this.pubCred = new SecureSet (this, SecureSet.PUBLIC_CREDENTIALS, pubCred);
103 this.privCred = new SecureSet (this, SecureSet.PRIVATE_CREDENTIALS, privCred);
104 this.readOnly = readOnly;
107 // Class methods.
108 // -------------------------------------------------------------------------
111 * <p>Returns the subject associated with the given {@link
112 * AccessControlContext}.</p>
114 * <p>All this method does is retrieve the Subject object from the supplied
115 * context's {@link DomainCombiner}, if any, and if it is an instance of
116 * a {@link SubjectDomainCombiner}.
118 * @param context The context to retrieve the subject from.
119 * @return The subject assoctiated with the context, or <code>null</code>
120 * if there is none.
121 * @throws NullPointerException If <i>subject</i> is null.
122 * @throws SecurityException If the caller does not have permission to get
123 * the subject (<code>"getSubject"</code> target of {@link AuthPermission}.
125 public static Subject getSubject (final AccessControlContext context)
127 final SecurityManager sm = System.getSecurityManager();
128 if (sm != null)
130 sm.checkPermission (new AuthPermission ("getSubject"));
132 DomainCombiner dc = context.getDomainCombiner();
133 if (!(dc instanceof SubjectDomainCombiner))
135 return null;
137 return ((SubjectDomainCombiner) dc).getSubject();
141 * <p>Run a method as another subject. This method will obtain the current
142 * {@link AccessControlContext} for this thread, then creates another with
143 * a {@link SubjectDomainCombiner} with the given subject. The supplied
144 * action will then be run with the modified context.</p>
146 * @param subject The subject to run as.
147 * @param action The action to run.
148 * @return The value returned by the privileged action.
149 * @throws SecurityException If the caller is not allowed to run under a
150 * different identity (<code>"doAs"</code> target of {@link AuthPermission}.
152 public static Object doAs (final Subject subject, final PrivilegedAction action)
154 final SecurityManager sm = System.getSecurityManager();
155 if (sm != null)
157 sm.checkPermission (new AuthPermission ("doAs"));
159 AccessControlContext context =
160 new AccessControlContext (AccessController.getContext(),
161 new SubjectDomainCombiner (subject));
162 return AccessController.doPrivileged (action, context);
166 * <p>Run a method as another subject. This method will obtain the current
167 * {@link AccessControlContext} for this thread, then creates another with
168 * a {@link SubjectDomainCombiner} with the given subject. The supplied
169 * action will then be run with the modified context.</p>
171 * @param subject The subject to run as.
172 * @param action The action to run.
173 * @return The value returned by the privileged action.
174 * @throws SecurityException If the caller is not allowed to run under a
175 * different identity (<code>"doAs"</code> target of {@link AuthPermission}.
176 * @throws PrivilegedActionException If the action throws an exception.
178 public static Object doAs (final Subject subject,
179 final PrivilegedExceptionAction action)
180 throws PrivilegedActionException
182 final SecurityManager sm = System.getSecurityManager();
183 if (sm != null)
185 sm.checkPermission (new AuthPermission ("doAs"));
187 AccessControlContext context =
188 new AccessControlContext (AccessController.getContext(),
189 new SubjectDomainCombiner(subject));
190 return AccessController.doPrivileged (action, context);
194 * <p>Run a method as another subject. This method will create a new
195 * {@link AccessControlContext} derived from the given one, with a
196 * {@link SubjectDomainCombiner} with the given subject. The supplied
197 * action will then be run with the modified context.</p>
199 * @param subject The subject to run as.
200 * @param action The action to run.
201 * @param acc The context to use.
202 * @return The value returned by the privileged action.
203 * @throws SecurityException If the caller is not allowed to run under a
204 * different identity (<code>"doAsPrivileged"</code> target of {@link
205 * AuthPermission}.
207 public static Object doAsPrivileged (final Subject subject,
208 final PrivilegedAction action,
209 final AccessControlContext acc)
211 final SecurityManager sm = System.getSecurityManager();
212 if (sm != null)
214 sm.checkPermission (new AuthPermission ("doAsPrivileged"));
216 AccessControlContext context =
217 new AccessControlContext (acc, new SubjectDomainCombiner (subject));
218 return AccessController.doPrivileged (action, context);
222 * <p>Run a method as another subject. This method will create a new
223 * {@link AccessControlContext} derived from the given one, with a
224 * {@link SubjectDomainCombiner} with the given subject. The supplied
225 * action will then be run with the modified context.</p>
227 * @param subject The subject to run as.
228 * @param action The action to run.
229 * @param acc The context to use.
230 * @return The value returned by the privileged action.
231 * @throws SecurityException If the caller is not allowed to run under a
232 * different identity (<code>"doAsPrivileged"</code> target of
233 * {@link AuthPermission}.
234 * @throws PrivilegedActionException If the action throws an exception.
236 public static Object doAsPrivileged (final Subject subject,
237 final PrivilegedExceptionAction action,
238 AccessControlContext acc)
239 throws PrivilegedActionException
241 final SecurityManager sm = System.getSecurityManager();
242 if (sm != null)
244 sm.checkPermission (new AuthPermission ("doAsPrivileged"));
246 if (acc == null)
247 acc = new AccessControlContext (new java.security.ProtectionDomain[0]);
248 AccessControlContext context =
249 new AccessControlContext (acc, new SubjectDomainCombiner (subject));
250 return AccessController.doPrivileged (action, context);
253 // Instance methods.
254 // -------------------------------------------------------------------------
256 public boolean equals (Object o)
258 if (!(o instanceof Subject))
260 return false;
262 Subject that = (Subject) o;
263 return principals.containsAll (that.getPrincipals()) &&
264 pubCred.containsAll (that.getPublicCredentials()) &&
265 privCred.containsAll (that.getPrivateCredentials());
268 public Set getPrincipals()
270 return principals;
273 public Set getPrincipals(Class clazz)
275 HashSet result = new HashSet (principals.size());
276 for (Iterator it = principals.iterator(); it.hasNext(); )
278 Object o = it.next();
279 if (o != null && clazz.isAssignableFrom (o.getClass()))
281 result.add(o);
284 return Collections.unmodifiableSet (result);
287 public Set getPrivateCredentials()
289 return privCred;
292 public Set getPrivateCredentials (Class clazz)
294 HashSet result = new HashSet (privCred.size());
295 for (Iterator it = privCred.iterator(); it.hasNext(); )
297 Object o = it.next();
298 if (o != null && clazz.isAssignableFrom (o.getClass()))
300 result.add(o);
303 return Collections.unmodifiableSet (result);
306 public Set getPublicCredentials()
308 return pubCred;
311 public Set getPublicCredentials (Class clazz)
313 HashSet result = new HashSet (pubCred.size());
314 for (Iterator it = pubCred.iterator(); it.hasNext(); )
316 Object o = it.next();
317 if (o != null && clazz.isAssignableFrom (o.getClass()))
319 result.add(o);
322 return Collections.unmodifiableSet (result);
325 public int hashCode()
327 return principals.hashCode() + privCred.hashCode() + pubCred.hashCode();
331 * <p>Returns whether or not this subject is read-only.</p>
333 * @return True is this subject is read-only.
335 public boolean isReadOnly()
337 return readOnly;
341 * <p>Marks this subject as read-only.</p>
343 * @throws SecurityException If the caller does not have permission to
344 * set this subject as read-only (<code>"setReadOnly"</code> target of
345 * {@link AuthPermission}.
347 public void setReadOnly()
349 final SecurityManager sm = System.getSecurityManager();
350 if (sm != null)
352 sm.checkPermission (new AuthPermission ("setReadOnly"));
354 readOnly = true;
357 public String toString()
359 return Subject.class.getName() + " [ principals=" + principals +
360 ", private credentials=" + privCred + ", public credentials=" +
361 pubCred + ", read-only=" + readOnly + " ]";
364 \f// Inner class.
365 // -------------------------------------------------------------------------
368 * An undocumented inner class that is used for sets in the parent class.
370 private static class SecureSet extends AbstractSet implements Serializable
372 // Fields.
373 // -----------------------------------------------------------------------
375 private static final long serialVersionUID = 7911754171111800359L;
377 static final int PRINCIPALS = 0;
378 static final int PUBLIC_CREDENTIALS = 1;
379 static final int PRIVATE_CREDENTIALS = 2;
381 private final Subject subject;
382 private final LinkedList elements;
383 private final transient int type;
385 // Constructors.
386 // -----------------------------------------------------------------------
388 SecureSet (final Subject subject, final int type, final Collection elements)
390 this (subject, type);
391 for (Iterator it = elements.iterator(); it.hasNext(); )
393 Object o = it.next();
394 if (type == PRINCIPALS && !(o instanceof Principal))
396 throw new IllegalArgumentException(o+" is not a Principal");
398 if (!elements.contains (o))
400 elements.add (o);
405 SecureSet (final Subject subject, final int type)
407 this.subject = subject;
408 this.type = type;
409 this.elements = new LinkedList();
412 // Instance methods.
413 // -----------------------------------------------------------------------
415 public synchronized int size()
417 return elements.size();
420 public Iterator iterator()
422 return elements.iterator();
425 public synchronized boolean add(Object element)
427 if (subject.isReadOnly())
429 throw new IllegalStateException ("subject is read-only");
431 final SecurityManager sm = System.getSecurityManager();
432 switch (type)
434 case PRINCIPALS:
435 if (sm != null)
437 sm.checkPermission (new AuthPermission ("modifyPrincipals"));
439 if (!(element instanceof Principal))
441 throw new IllegalArgumentException ("element is not a Principal");
443 break;
445 case PUBLIC_CREDENTIALS:
446 if (sm != null)
448 sm.checkPermission (new AuthPermission ("modifyPublicCredentials"));
450 break;
452 case PRIVATE_CREDENTIALS:
453 if (sm != null)
455 sm.checkPermission (new AuthPermission ("modifyPrivateCredentials"));
457 break;
459 default:
460 throw new Error ("this statement should be unreachable");
463 if (elements.contains (element))
465 return false;
468 return elements.add (element);
471 public synchronized boolean remove (final Object element)
473 if (subject.isReadOnly())
475 throw new IllegalStateException ("subject is read-only");
477 final SecurityManager sm = System.getSecurityManager();
478 switch (type)
480 case PRINCIPALS:
481 if (sm != null)
483 sm.checkPermission (new AuthPermission ("modifyPrincipals"));
485 if (!(element instanceof Principal))
487 throw new IllegalArgumentException ("element is not a Principal");
489 break;
491 case PUBLIC_CREDENTIALS:
492 if (sm != null)
494 sm.checkPermission (new AuthPermission ("modifyPublicCredentials"));
496 break;
498 case PRIVATE_CREDENTIALS:
499 if (sm != null)
501 sm.checkPermission (new AuthPermission ("modifyPrivateCredentials"));
503 break;
505 default:
506 throw new Error("this statement should be unreachable");
509 return elements.remove(element);
512 public synchronized boolean contains (final Object element)
514 return elements.remove (element);
517 public boolean removeAll (final Collection c)
519 if (subject.isReadOnly())
521 throw new IllegalStateException ("subject is read-only");
523 return super.removeAll (c);
526 public boolean retainAll (final Collection c)
528 if (subject.isReadOnly())
530 throw new IllegalStateException ("subject is read-only");
532 return super.retainAll (c);
535 public void clear()
537 if (subject.isReadOnly())
539 throw new IllegalStateException ("subject is read-only");
541 elements.clear();
544 private synchronized void writeObject (ObjectOutputStream out)
545 throws IOException
547 throw new UnsupportedOperationException ("FIXME: determine serialization");
550 private void readObject (ObjectInputStream in)
551 throws ClassNotFoundException, IOException
553 throw new UnsupportedOperationException ("FIXME: determine serialization");