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)
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
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
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
;
62 public final class Subject
implements Serializable
65 // -------------------------------------------------------------------------
67 private static final long serialVersionUID
= -8308522755600156056L;
70 * @serial The set of principals. The type of this field is SecureSet, a
71 * private inner class.
73 private final Set principals
;
76 * @serial The read-only flag.
78 private boolean readOnly
;
80 private final transient SecureSet pubCred
;
81 private final transient SecureSet privCred
;
84 // -------------------------------------------------------------------------
88 principals
= new SecureSet (this, SecureSet
.PRINCIPALS
);
89 pubCred
= new SecureSet (this, SecureSet
.PUBLIC_CREDENTIALS
);
90 privCred
= new SecureSet (this, SecureSet
.PRIVATE_CREDENTIALS
);
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
;
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>
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();
130 sm
.checkPermission (new AuthPermission ("getSubject"));
132 DomainCombiner dc
= context
.getDomainCombiner();
133 if (!(dc
instanceof SubjectDomainCombiner
))
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();
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();
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
207 public static Object
doAsPrivileged (final Subject subject
,
208 final PrivilegedAction action
,
209 final AccessControlContext acc
)
211 final SecurityManager sm
= System
.getSecurityManager();
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();
244 sm
.checkPermission (new AuthPermission ("doAsPrivileged"));
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
);
254 // -------------------------------------------------------------------------
256 public boolean equals (Object o
)
258 if (!(o
instanceof Subject
))
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()
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()))
284 return Collections
.unmodifiableSet (result
);
287 public Set
getPrivateCredentials()
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()))
303 return Collections
.unmodifiableSet (result
);
306 public Set
getPublicCredentials()
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()))
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()
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();
352 sm
.checkPermission (new AuthPermission ("setReadOnly"));
357 public String
toString()
359 return Subject
.class.getName() + " [ principals=" + principals
+
360 ", private credentials=" + privCred
+ ", public credentials=" +
361 pubCred
+ ", read-only=" + readOnly
+ " ]";
365 // -------------------------------------------------------------------------
368 * An undocumented inner class that is used for sets in the parent class.
370 private static class SecureSet
extends AbstractSet
implements Serializable
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
;
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
))
405 SecureSet (final Subject subject
, final int type
)
407 this.subject
= subject
;
409 this.elements
= new LinkedList();
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();
437 sm
.checkPermission (new AuthPermission ("modifyPrincipals"));
439 if (!(element
instanceof Principal
))
441 throw new IllegalArgumentException ("element is not a Principal");
445 case PUBLIC_CREDENTIALS
:
448 sm
.checkPermission (new AuthPermission ("modifyPublicCredentials"));
452 case PRIVATE_CREDENTIALS
:
455 sm
.checkPermission (new AuthPermission ("modifyPrivateCredentials"));
460 throw new Error ("this statement should be unreachable");
463 if (elements
.contains (element
))
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();
483 sm
.checkPermission (new AuthPermission ("modifyPrincipals"));
485 if (!(element
instanceof Principal
))
487 throw new IllegalArgumentException ("element is not a Principal");
491 case PUBLIC_CREDENTIALS
:
494 sm
.checkPermission (new AuthPermission ("modifyPublicCredentials"));
498 case PRIVATE_CREDENTIALS
:
501 sm
.checkPermission (new AuthPermission ("modifyPrivateCredentials"));
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
);
537 if (subject
.isReadOnly())
539 throw new IllegalStateException ("subject is read-only");
544 private synchronized void writeObject (ObjectOutputStream out
)
547 throw new UnsupportedOperationException ("FIXME: determine serialization");
550 private void readObject (ObjectInputStream in
)
551 throws ClassNotFoundException
, IOException
553 throw new UnsupportedOperationException ("FIXME: determine serialization");