123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782 |
- /*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- 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.Permission;
- import java.security.Principal;
- import java.security.PrivilegedAction;
- import java.security.PrivilegedActionException;
- import java.security.PrivilegedExceptionAction;
- import java.security.ProtectionDomain;
- import java.util.AbstractSet;
- import java.util.Collection;
- import java.util.Iterator;
- import java.util.LinkedList;
- import java.util.Set;
- import org.apache.harmony.auth.internal.nls.Messages;
- /**
- * The central class of the {@code javax.security.auth} package representing an
- * authenticated user or entity (both referred to as "subject"). IT defines also
- * the static methods that allow code to be run, and do modifications according
- * to the subject's permissions.
- * <p>
- * A subject has the following features:
- * <ul>
- * <li>A set of {@code Principal} objects specifying the identities bound to a
- * {@code Subject} that distinguish it.</li>
- * <li>Credentials (public and private) such as certificates, keys, or
- * authentication proofs such as tickets</li>
- * </ul>
- */
- public final class Subject implements Serializable {
- private static final long serialVersionUID = -8308522755600156056L;
-
- private static final AuthPermission _AS = new AuthPermission("doAs"); //$NON-NLS-1$
- private static final AuthPermission _AS_PRIVILEGED = new AuthPermission(
- "doAsPrivileged"); //$NON-NLS-1$
- private static final AuthPermission _SUBJECT = new AuthPermission(
- "getSubject"); //$NON-NLS-1$
- private static final AuthPermission _PRINCIPALS = new AuthPermission(
- "modifyPrincipals"); //$NON-NLS-1$
- private static final AuthPermission _PRIVATE_CREDENTIALS = new AuthPermission(
- "modifyPrivateCredentials"); //$NON-NLS-1$
- private static final AuthPermission _PUBLIC_CREDENTIALS = new AuthPermission(
- "modifyPublicCredentials"); //$NON-NLS-1$
- private static final AuthPermission _READ_ONLY = new AuthPermission(
- "setReadOnly"); //$NON-NLS-1$
- private final Set<Principal> principals;
- private boolean readOnly;
-
- // set of private credentials
- private transient SecureSet<Object> privateCredentials;
- // set of public credentials
- private transient SecureSet<Object> publicCredentials;
-
- /**
- * The default constructor initializing the sets of public and private
- * credentials and principals with the empty set.
- */
- public Subject() {
- super();
- principals = new SecureSet<Principal>(_PRINCIPALS);
- publicCredentials = new SecureSet<Object>(_PUBLIC_CREDENTIALS);
- privateCredentials = new SecureSet<Object>(_PRIVATE_CREDENTIALS);
- readOnly = false;
- }
- /**
- * The constructor for the subject, setting its public and private
- * credentials and principals according to the arguments.
- *
- * @param readOnly
- * {@code true} if this {@code Subject} is read-only, thus
- * preventing any modifications to be done.
- * @param subjPrincipals
- * the set of Principals that are attributed to this {@code
- * Subject}.
- * @param pubCredentials
- * the set of public credentials that distinguish this {@code
- * Subject}.
- * @param privCredentials
- * the set of private credentials that distinguish this {@code
- * Subject}.
- */
- public Subject(boolean readOnly, Set<? extends Principal> subjPrincipals,
- Set<?> pubCredentials, Set<?> privCredentials) {
- if (subjPrincipals == null || pubCredentials == null || privCredentials == null) {
- throw new NullPointerException();
- }
- principals = new SecureSet<Principal>(_PRINCIPALS, subjPrincipals);
- publicCredentials = new SecureSet<Object>(_PUBLIC_CREDENTIALS, pubCredentials);
- privateCredentials = new SecureSet<Object>(_PRIVATE_CREDENTIALS, privCredentials);
- this.readOnly = readOnly;
- }
- /**
- * Runs the code defined by {@code action} using the permissions granted to
- * the {@code Subject} itself and to the code as well.
- *
- * @param subject
- * the distinguished {@code Subject}.
- * @param action
- * the code to be run.
- * @return the {@code Object} returned when running the {@code action}.
- */
- @SuppressWarnings("unchecked")
- public static Object doAs(Subject subject, PrivilegedAction action) {
- checkPermission(_AS);
- return doAs_PrivilegedAction(subject, action, AccessController.getContext());
- }
- /**
- * Run the code defined by {@code action} using the permissions granted to
- * the {@code Subject} and to the code itself, additionally providing a more
- * specific context.
- *
- * @param subject
- * the distinguished {@code Subject}.
- * @param action
- * the code to be run.
- * @param context
- * the specific context in which the {@code action} is invoked.
- * if {@code null} a new {@link AccessControlContext} is
- * instantiated.
- * @return the {@code Object} returned when running the {@code action}.
- */
- @SuppressWarnings("unchecked")
- public static Object doAsPrivileged(Subject subject, PrivilegedAction action,
- AccessControlContext context) {
- checkPermission(_AS_PRIVILEGED);
- if (context == null) {
- return doAs_PrivilegedAction(subject, action, new AccessControlContext(
- new ProtectionDomain[0]));
- }
- return doAs_PrivilegedAction(subject, action, context);
- }
- // instantiates a new context and passes it to AccessController
- @SuppressWarnings("unchecked")
- private static Object doAs_PrivilegedAction(Subject subject, PrivilegedAction action,
- final AccessControlContext context) {
- AccessControlContext newContext;
- final SubjectDomainCombiner combiner;
- if (subject == null) {
- // performance optimization
- // if subject is null there is nothing to combine
- combiner = null;
- } else {
- combiner = new SubjectDomainCombiner(subject);
- }
- PrivilegedAction dccAction = new PrivilegedAction() {
- public Object run() {
- return new AccessControlContext(context, combiner);
- }
- };
- newContext = (AccessControlContext) AccessController.doPrivileged(dccAction);
- return AccessController.doPrivileged(action, newContext);
- }
- /**
- * Runs the code defined by {@code action} using the permissions granted to
- * the subject and to the code itself.
- *
- * @param subject
- * the distinguished {@code Subject}.
- * @param action
- * the code to be run.
- * @return the {@code Object} returned when running the {@code action}.
- * @throws PrivilegedActionException
- * if running the {@code action} throws an exception.
- */
- @SuppressWarnings("unchecked")
- public static Object doAs(Subject subject, PrivilegedExceptionAction action)
- throws PrivilegedActionException {
- checkPermission(_AS);
- return doAs_PrivilegedExceptionAction(subject, action, AccessController.getContext());
- }
- /**
- * Runs the code defined by {@code action} using the permissions granted to
- * the subject and to the code itself, additionally providing a more
- * specific context.
- *
- * @param subject
- * the distinguished {@code Subject}.
- * @param action
- * the code to be run.
- * @param context
- * the specific context in which the {@code action} is invoked.
- * if {@code null} a new {@link AccessControlContext} is
- * instantiated.
- * @return the {@code Object} returned when running the {@code action}.
- * @throws PrivilegedActionException
- * if running the {@code action} throws an exception.
- */
- @SuppressWarnings("unchecked")
- public static Object doAsPrivileged(Subject subject,
- PrivilegedExceptionAction action, AccessControlContext context)
- throws PrivilegedActionException {
- checkPermission(_AS_PRIVILEGED);
- if (context == null) {
- return doAs_PrivilegedExceptionAction(subject, action,
- new AccessControlContext(new ProtectionDomain[0]));
- }
- return doAs_PrivilegedExceptionAction(subject, action, context);
- }
- // instantiates a new context and passes it to AccessController
- @SuppressWarnings("unchecked")
- private static Object doAs_PrivilegedExceptionAction(Subject subject,
- PrivilegedExceptionAction action, final AccessControlContext context)
- throws PrivilegedActionException {
- AccessControlContext newContext;
- final SubjectDomainCombiner combiner;
- if (subject == null) {
- // performance optimization
- // if subject is null there is nothing to combine
- combiner = null;
- } else {
- combiner = new SubjectDomainCombiner(subject);
- }
- PrivilegedAction<AccessControlContext> dccAction = new PrivilegedAction<AccessControlContext>() {
- public AccessControlContext run() {
- return new AccessControlContext(context, combiner);
- }
- };
- newContext = AccessController.doPrivileged(dccAction);
- return AccessController.doPrivileged(action, newContext);
- }
- /**
- * Checks two Subjects for equality. More specifically if the principals,
- * public and private credentials are equal, equality for two {@code
- * Subjects} is implied.
- *
- * @param obj
- * the {@code Object} checked for equality with this {@code
- * Subject}.
- * @return {@code true} if the specified {@code Subject} is equal to this
- * one.
- */
- @Override
- public boolean equals(Object obj) {
- if (this == obj) {
- return true;
- }
- if (obj == null || this.getClass() != obj.getClass()) {
- return false;
- }
- Subject that = (Subject) obj;
- if (principals.equals(that.principals)
- && publicCredentials.equals(that.publicCredentials)
- && privateCredentials.equals(that.privateCredentials)) {
- return true;
- }
- return false;
- }
- /**
- * Returns this {@code Subject}'s {@link Principal}.
- *
- * @return this {@code Subject}'s {@link Principal}.
- */
- public Set<Principal> getPrincipals() {
- return principals;
- }
- /**
- * Returns this {@code Subject}'s {@link Principal} which is a subclass of
- * the {@code Class} provided.
- *
- * @param c
- * the {@code Class} as a criteria which the {@code Principal}
- * returned must satisfy.
- * @return this {@code Subject}'s {@link Principal}. Modifications to the
- * returned set of {@code Principal}s do not affect this {@code
- * Subject}'s set.
- */
- public <T extends Principal> Set<T> getPrincipals(Class<T> c) {
- return ((SecureSet<Principal>) principals).get(c);
- }
- /**
- * Returns the private credentials associated with this {@code Subject}.
- *
- * @return the private credentials associated with this {@code Subject}.
- */
- public Set<Object> getPrivateCredentials() {
- return privateCredentials;
- }
- /**
- * Returns this {@code Subject}'s private credentials which are a subclass
- * of the {@code Class} provided.
- *
- * @param c
- * the {@code Class} as a criteria which the private credentials
- * returned must satisfy.
- * @return this {@code Subject}'s private credentials. Modifications to the
- * returned set of credentials do not affect this {@code Subject}'s
- * credentials.
- */
- public <T> Set<T> getPrivateCredentials(Class<T> c) {
- return privateCredentials.get(c);
- }
- /**
- * Returns the public credentials associated with this {@code Subject}.
- *
- * @return the public credentials associated with this {@code Subject}.
- */
- public Set<Object> getPublicCredentials() {
- return publicCredentials;
- }
- /**
- * Returns this {@code Subject}'s public credentials which are a subclass of
- * the {@code Class} provided.
- *
- * @param c
- * the {@code Class} as a criteria which the public credentials
- * returned must satisfy.
- * @return this {@code Subject}'s public credentials. Modifications to the
- * returned set of credentials do not affect this {@code Subject}'s
- * credentials.
- */
- public <T> Set<T> getPublicCredentials(Class<T> c) {
- return publicCredentials.get(c);
- }
- /**
- * Returns a hash code of this {@code Subject}.
- *
- * @return a hash code of this {@code Subject}.
- */
- @Override
- public int hashCode() {
- return principals.hashCode() + privateCredentials.hashCode()
- + publicCredentials.hashCode();
- }
- /**
- * Prevents from modifications being done to the credentials and {@link
- * Principal} sets. After setting it to read-only this {@code Subject} can
- * not be made writable again. The destroy method on the credentials still
- * works though.
- */
- public void setReadOnly() {
- checkPermission(_READ_ONLY);
- readOnly = true;
- }
- /**
- * Returns whether this {@code Subject} is read-only or not.
- *
- * @return whether this {@code Subject} is read-only or not.
- */
- public boolean isReadOnly() {
- return readOnly;
- }
- /**
- * Returns a {@code String} representation of this {@code Subject}.
- *
- * @return a {@code String} representation of this {@code Subject}.
- */
- @Override
- public String toString() {
- StringBuilder buf = new StringBuilder("Subject:\n"); //$NON-NLS-1$
- Iterator<?> it = principals.iterator();
- while (it.hasNext()) {
- buf.append("\tPrincipal: "); //$NON-NLS-1$
- buf.append(it.next());
- buf.append('\n');
- }
- it = publicCredentials.iterator();
- while (it.hasNext()) {
- buf.append("\tPublic Credential: "); //$NON-NLS-1$
- buf.append(it.next());
- buf.append('\n');
- }
- int offset = buf.length() - 1;
- it = privateCredentials.iterator();
- try {
- while (it.hasNext()) {
- buf.append("\tPrivate Credential: "); //$NON-NLS-1$
- buf.append(it.next());
- buf.append('\n');
- }
- } catch (SecurityException e) {
- buf.delete(offset, buf.length());
- buf.append("\tPrivate Credentials: no accessible information\n"); //$NON-NLS-1$
- }
- return buf.toString();
- }
- private void readObject(ObjectInputStream in) throws IOException,
- ClassNotFoundException {
- in.defaultReadObject();
- publicCredentials = new SecureSet<Object>(_PUBLIC_CREDENTIALS);
- privateCredentials = new SecureSet<Object>(_PRIVATE_CREDENTIALS);
- }
- private void writeObject(ObjectOutputStream out) throws IOException {
- out.defaultWriteObject();
- }
- /**
- * Returns the {@code Subject} that was last associated with the {@code
- * context} provided as argument.
- *
- * @param context
- * the {@code context} that was associated with the
- * {@code Subject}.
- * @return the {@code Subject} that was last associated with the {@code
- * context} provided as argument.
- */
- public static Subject getSubject(final AccessControlContext context) {
- checkPermission(_SUBJECT);
- if (context == null) {
- throw new NullPointerException(Messages.getString("auth.09")); //$NON-NLS-1$
- }
- PrivilegedAction<DomainCombiner> action = new PrivilegedAction<DomainCombiner>() {
- public DomainCombiner run() {
- return context.getDomainCombiner();
- }
- };
- DomainCombiner combiner = AccessController.doPrivileged(action);
- if ((combiner == null) || !(combiner instanceof SubjectDomainCombiner)) {
- return null;
- }
- return ((SubjectDomainCombiner) combiner).getSubject();
- }
- // checks passed permission
- private static void checkPermission(Permission p) {
- SecurityManager sm = System.getSecurityManager();
- if (sm != null) {
- sm.checkPermission(p);
- }
- }
- // FIXME is used only in two places. remove?
- private void checkState() {
- if (readOnly) {
- throw new IllegalStateException(Messages.getString("auth.0A")); //$NON-NLS-1$
- }
- }
- private final class SecureSet<SST> extends AbstractSet<SST> implements Serializable {
- /**
- * Compatibility issue: see comments for setType variable
- */
- private static final long serialVersionUID = 7911754171111800359L;
- private LinkedList<SST> elements;
- /*
- * Is used to define a set type for serialization.
- *
- * A type can be principal, priv. or pub. credential set. The spec.
- * doesn't clearly says that priv. and pub. credential sets can be
- * serialized and what classes they are. It is only possible to figure
- * out from writeObject method comments that priv. credential set is
- * serializable and it is an instance of SecureSet class. So pub.
- * credential was implemented by analogy
- *
- * Compatibility issue: the class follows its specified serial form.
- * Also according to the serialization spec. adding new field is a
- * compatible change. So is ok for principal set (because the default
- * value for integer is zero). But priv. or pub. credential set it is
- * not compatible because most probably other implementations resolve
- * this issue in other way
- */
- private int setType;
- // Defines principal set for serialization.
- private static final int SET_Principal = 0;
- // Defines private credential set for serialization.
- private static final int SET_PrivCred = 1;
- // Defines public credential set for serialization.
- private static final int SET_PubCred = 2;
- // permission required to modify set
- private transient AuthPermission permission;
- protected SecureSet(AuthPermission perm) {
- permission = perm;
- elements = new LinkedList<SST>();
- }
- // creates set from specified collection with specified permission
- // all collection elements are verified before adding
- protected SecureSet(AuthPermission perm, Collection<? extends SST> s) {
- this(perm);
- // Subject's constructor receives a Set, we can trusts if a set is from bootclasspath,
- // and not to check whether it contains duplicates or not
- boolean trust = s.getClass().getClassLoader() == null;
-
- Iterator<? extends SST> it = s.iterator();
- while (it.hasNext()) {
- SST o = it.next();
- verifyElement(o);
- if (trust || !elements.contains(o)) {
- elements.add(o);
- }
- }
- }
- // verifies new set element
- private void verifyElement(Object o) {
- if (o == null) {
- throw new NullPointerException();
- }
- if (permission == _PRINCIPALS && !(Principal.class.isAssignableFrom(o.getClass()))) {
- throw new IllegalArgumentException(Messages.getString("auth.0B")); //$NON-NLS-1$
- }
- }
- /*
- * verifies specified element, checks set state, and security permission
- * to modify set before adding new element
- */
- @Override
- public boolean add(SST o) {
- verifyElement(o);
- checkState();
- checkPermission(permission);
- if (!elements.contains(o)) {
- elements.add(o);
- return true;
- }
- return false;
- }
- // returns an instance of SecureIterator
- @Override
- public Iterator<SST> iterator() {
- if (permission == _PRIVATE_CREDENTIALS) {
- /*
- * private credential set requires iterator with additional
- * security check (PrivateCredentialPermission)
- */
- return new SecureIterator(elements.iterator()) {
- /*
- * checks permission to access next private credential moves
- * to the next element even SecurityException was thrown
- */
- @Override
- public SST next() {
- SST obj = iterator.next();
- checkPermission(new PrivateCredentialPermission(obj
- .getClass().getName(), principals));
- return obj;
- }
- };
- }
- return new SecureIterator(elements.iterator());
- }
- @Override
- public boolean retainAll(Collection<?> c) {
- if (c == null) {
- throw new NullPointerException();
- }
- return super.retainAll(c);
- }
- @Override
- public int size() {
- return elements.size();
- }
- /**
- * return set with elements that are instances or subclasses of the
- * specified class
- */
- protected final <E> Set<E> get(final Class<E> c) {
- if (c == null) {
- throw new NullPointerException();
- }
- AbstractSet<E> s = new AbstractSet<E>() {
- private LinkedList<E> elements = new LinkedList<E>();
- @Override
- public boolean add(E o) {
- if (!c.isAssignableFrom(o.getClass())) {
- throw new IllegalArgumentException(
- Messages.getString("auth.0C", c.getName())); //$NON-NLS-1$
- }
- if (elements.contains(o)) {
- return false;
- }
- elements.add(o);
- return true;
- }
- @Override
- public Iterator<E> iterator() {
- return elements.iterator();
- }
- @Override
- public boolean retainAll(Collection<?> c) {
- if (c == null) {
- throw new NullPointerException();
- }
- return super.retainAll(c);
- }
- @Override
- public int size() {
- return elements.size();
- }
- };
- // FIXME must have permissions for requested priv. credentials
- for (Iterator<SST> it = iterator(); it.hasNext();) {
- SST o = it.next();
- if (c.isAssignableFrom(o.getClass())) {
- s.add(c.cast(o));
- }
- }
- return s;
- }
- private void readObject(ObjectInputStream in) throws IOException,
- ClassNotFoundException {
- in.defaultReadObject();
- switch (setType) {
- case SET_Principal:
- permission = _PRINCIPALS;
- break;
- case SET_PrivCred:
- permission = _PRIVATE_CREDENTIALS;
- break;
- case SET_PubCred:
- permission = _PUBLIC_CREDENTIALS;
- break;
- default:
- throw new IllegalArgumentException();
- }
- Iterator<SST> it = elements.iterator();
- while (it.hasNext()) {
- verifyElement(it.next());
- }
- }
- private void writeObject(ObjectOutputStream out) throws IOException {
- if (permission == _PRIVATE_CREDENTIALS) {
- // does security check for each private credential
- for (Iterator<SST> it = iterator(); it.hasNext();) {
- it.next();
- }
- setType = SET_PrivCred;
- } else if (permission == _PRINCIPALS) {
- setType = SET_Principal;
- } else {
- setType = SET_PubCred;
- }
- out.defaultWriteObject();
- }
- /**
- * Represents iterator for subject's secure set
- */
- private class SecureIterator implements Iterator<SST> {
- protected Iterator<SST> iterator;
- protected SecureIterator(Iterator<SST> iterator) {
- this.iterator = iterator;
- }
- public boolean hasNext() {
- return iterator.hasNext();
- }
- public SST next() {
- return iterator.next();
- }
- /**
- * checks set state, and security permission to modify set before
- * removing current element
- */
- public void remove() {
- checkState();
- checkPermission(permission);
- iterator.remove();
- }
- }
- }
- }
|