package javax.security.auth;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.security.AccessControlContext;
import java.security.AccessController;
import java.security.DomainCombiner;
import java.security.Principal;
import java.security.PrivilegedAction;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
import java.util.AbstractSet;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Set;
public final class Subject implements Serializable
{
private static final long serialVersionUID = -8308522755600156056L;
private final Set principals;
private boolean readOnly;
private final transient SecureSet pubCred;
private final transient SecureSet privCred;
public Subject()
{
principals = new SecureSet (this, SecureSet.PRINCIPALS);
pubCred = new SecureSet (this, SecureSet.PUBLIC_CREDENTIALS);
privCred = new SecureSet (this, SecureSet.PRIVATE_CREDENTIALS);
readOnly = false;
}
public Subject (final boolean readOnly, final Set principals,
final Set pubCred, final Set privCred)
{
if (principals == null || pubCred == null || privCred == null)
{
throw new NullPointerException();
}
this.principals = new SecureSet (this, SecureSet.PRINCIPALS, principals);
this.pubCred = new SecureSet (this, SecureSet.PUBLIC_CREDENTIALS, pubCred);
this.privCred = new SecureSet (this, SecureSet.PRIVATE_CREDENTIALS, privCred);
this.readOnly = readOnly;
}
public static Subject getSubject (final AccessControlContext context)
{
final SecurityManager sm = System.getSecurityManager();
if (sm != null)
{
sm.checkPermission (new AuthPermission ("getSubject"));
}
DomainCombiner dc = context.getDomainCombiner();
if (!(dc instanceof SubjectDomainCombiner))
{
return null;
}
return ((SubjectDomainCombiner) dc).getSubject();
}
public static Object doAs (final Subject subject, final PrivilegedAction action)
{
final SecurityManager sm = System.getSecurityManager();
if (sm != null)
{
sm.checkPermission (new AuthPermission ("doAs"));
}
AccessControlContext context =
new AccessControlContext (AccessController.getContext(),
new SubjectDomainCombiner (subject));
return AccessController.doPrivileged (action, context);
}
public static Object doAs (final Subject subject,
final PrivilegedExceptionAction action)
throws PrivilegedActionException
{
final SecurityManager sm = System.getSecurityManager();
if (sm != null)
{
sm.checkPermission (new AuthPermission ("doAs"));
}
AccessControlContext context =
new AccessControlContext (AccessController.getContext(),
new SubjectDomainCombiner(subject));
return AccessController.doPrivileged (action, context);
}
public static Object doAsPrivileged (final Subject subject,
final PrivilegedAction action,
final AccessControlContext acc)
{
final SecurityManager sm = System.getSecurityManager();
if (sm != null)
{
sm.checkPermission (new AuthPermission ("doAsPrivileged"));
}
AccessControlContext context =
new AccessControlContext (acc, new SubjectDomainCombiner (subject));
return AccessController.doPrivileged (action, context);
}
public static Object doAsPrivileged (final Subject subject,
final PrivilegedExceptionAction action,
AccessControlContext acc)
throws PrivilegedActionException
{
final SecurityManager sm = System.getSecurityManager();
if (sm != null)
{
sm.checkPermission (new AuthPermission ("doAsPrivileged"));
}
if (acc == null)
acc = new AccessControlContext (new java.security.ProtectionDomain[0]);
AccessControlContext context =
new AccessControlContext (acc, new SubjectDomainCombiner (subject));
return AccessController.doPrivileged (action, context);
}
public boolean equals (Object o)
{
if (!(o instanceof Subject))
{
return false;
}
Subject that = (Subject) o;
return principals.containsAll (that.getPrincipals()) &&
pubCred.containsAll (that.getPublicCredentials()) &&
privCred.containsAll (that.getPrivateCredentials());
}
public Set getPrincipals()
{
return principals;
}
public Set getPrincipals(Class clazz)
{
HashSet result = new HashSet (principals.size());
for (Iterator it = principals.iterator(); it.hasNext(); )
{
Object o = it.next();
if (o != null && clazz.isAssignableFrom (o.getClass()))
{
result.add(o);
}
}
return Collections.unmodifiableSet (result);
}
public Set getPrivateCredentials()
{
return privCred;
}
public Set getPrivateCredentials (Class clazz)
{
HashSet result = new HashSet (privCred.size());
for (Iterator it = privCred.iterator(); it.hasNext(); )
{
Object o = it.next();
if (o != null && clazz.isAssignableFrom (o.getClass()))
{
result.add(o);
}
}
return Collections.unmodifiableSet (result);
}
public Set getPublicCredentials()
{
return pubCred;
}
public Set getPublicCredentials (Class clazz)
{
HashSet result = new HashSet (pubCred.size());
for (Iterator it = pubCred.iterator(); it.hasNext(); )
{
Object o = it.next();
if (o != null && clazz.isAssignableFrom (o.getClass()))
{
result.add(o);
}
}
return Collections.unmodifiableSet (result);
}
public int hashCode()
{
return principals.hashCode() + privCred.hashCode() + pubCred.hashCode();
}
public boolean isReadOnly()
{
return readOnly;
}
public void setReadOnly()
{
final SecurityManager sm = System.getSecurityManager();
if (sm != null)
{
sm.checkPermission (new AuthPermission ("setReadOnly"));
}
readOnly = true;
}
public String toString()
{
return Subject.class.getName() + " [ principals=" + principals +
", private credentials=" + privCred + ", public credentials=" +
pubCred + ", read-only=" + readOnly + " ]";
}
private static class SecureSet extends AbstractSet implements Serializable
{
private static final long serialVersionUID = 7911754171111800359L;
static final int PRINCIPALS = 0;
static final int PUBLIC_CREDENTIALS = 1;
static final int PRIVATE_CREDENTIALS = 2;
private final Subject subject;
private final LinkedList elements;
private final transient int type;
SecureSet (final Subject subject, final int type, final Collection elements)
{
this (subject, type);
for (Iterator it = elements.iterator(); it.hasNext(); )
{
Object o = it.next();
if (type == PRINCIPALS && !(o instanceof Principal))
{
throw new IllegalArgumentException(o+" is not a Principal");
}
if (!elements.contains (o))
{
elements.add (o);
}
}
}
SecureSet (final Subject subject, final int type)
{
this.subject = subject;
this.type = type;
this.elements = new LinkedList();
}
public synchronized int size()
{
return elements.size();
}
public Iterator iterator()
{
return elements.iterator();
}
public synchronized boolean add(Object element)
{
if (subject.isReadOnly())
{
throw new IllegalStateException ("subject is read-only");
}
final SecurityManager sm = System.getSecurityManager();
switch (type)
{
case PRINCIPALS:
if (sm != null)
{
sm.checkPermission (new AuthPermission ("modifyPrincipals"));
}
if (!(element instanceof Principal))
{
throw new IllegalArgumentException ("element is not a Principal");
}
break;
case PUBLIC_CREDENTIALS:
if (sm != null)
{
sm.checkPermission (new AuthPermission ("modifyPublicCredentials"));
}
break;
case PRIVATE_CREDENTIALS:
if (sm != null)
{
sm.checkPermission (new AuthPermission ("modifyPrivateCredentials"));
}
break;
default:
throw new Error ("this statement should be unreachable");
}
if (elements.contains (element))
{
return false;
}
return elements.add (element);
}
public synchronized boolean remove (final Object element)
{
if (subject.isReadOnly())
{
throw new IllegalStateException ("subject is read-only");
}
final SecurityManager sm = System.getSecurityManager();
switch (type)
{
case PRINCIPALS:
if (sm != null)
{
sm.checkPermission (new AuthPermission ("modifyPrincipals"));
}
if (!(element instanceof Principal))
{
throw new IllegalArgumentException ("element is not a Principal");
}
break;
case PUBLIC_CREDENTIALS:
if (sm != null)
{
sm.checkPermission (new AuthPermission ("modifyPublicCredentials"));
}
break;
case PRIVATE_CREDENTIALS:
if (sm != null)
{
sm.checkPermission (new AuthPermission ("modifyPrivateCredentials"));
}
break;
default:
throw new Error("this statement should be unreachable");
}
return elements.remove(element);
}
public synchronized boolean contains (final Object element)
{
return elements.remove (element);
}
public boolean removeAll (final Collection c)
{
if (subject.isReadOnly())
{
throw new IllegalStateException ("subject is read-only");
}
return super.removeAll (c);
}
public boolean retainAll (final Collection c)
{
if (subject.isReadOnly())
{
throw new IllegalStateException ("subject is read-only");
}
return super.retainAll (c);
}
public void clear()
{
if (subject.isReadOnly())
{
throw new IllegalStateException ("subject is read-only");
}
elements.clear();
}
private synchronized void writeObject (ObjectOutputStream out)
throws IOException
{
throw new UnsupportedOperationException ("FIXME: determine serialization");
}
private void readObject (ObjectInputStream in)
throws ClassNotFoundException, IOException
{
throw new UnsupportedOperationException ("FIXME: determine serialization");
}
}
}