diff options
author | The Android Open Source Project <initial-contribution@android.com> | 2008-10-21 07:00:00 -0700 |
---|---|---|
committer | The Android Open Source Project <initial-contribution@android.com> | 2008-10-21 07:00:00 -0700 |
commit | fdb2704414a9ed92394ada0d1395e4db86889465 (patch) | |
tree | 9b591a4a50054274a197f02b3ccb51313681879f /auth/src/main/java/javax/security | |
download | libcore-fdb2704414a9ed92394ada0d1395e4db86889465.zip libcore-fdb2704414a9ed92394ada0d1395e4db86889465.tar.gz libcore-fdb2704414a9ed92394ada0d1395e4db86889465.tar.bz2 |
Initial Contribution
Diffstat (limited to 'auth/src/main/java/javax/security')
16 files changed, 1532 insertions, 0 deletions
diff --git a/auth/src/main/java/javax/security/auth/AuthPermission.java b/auth/src/main/java/javax/security/auth/AuthPermission.java new file mode 100644 index 0000000..31f5b50 --- /dev/null +++ b/auth/src/main/java/javax/security/auth/AuthPermission.java @@ -0,0 +1,52 @@ +/* + * 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.security.BasicPermission; + +import org.apache.harmony.auth.internal.nls.Messages; + +public final class AuthPermission extends BasicPermission { + + private static final long serialVersionUID = 5806031445061587174L; + + private static final String CREATE_LOGIN_CONTEXT = "createLoginContext"; //$NON-NLS-1$ + + private static final String CREATE_LOGIN_CONTEXT_ANY = "createLoginContext.*"; //$NON-NLS-1$ + + // inits permission name. + private static String init(String name) { + + if (name == null) { + throw new NullPointerException(Messages.getString("auth.13")); //$NON-NLS-1$ + } + + if (CREATE_LOGIN_CONTEXT.equals(name)) { + return CREATE_LOGIN_CONTEXT_ANY; + } + return name; + } + + public AuthPermission(String name) { + super(init(name)); + } + + public AuthPermission(String name, String actions) { + super(init(name), actions); + } +}
\ No newline at end of file diff --git a/auth/src/main/java/javax/security/auth/DestroyFailedException.java b/auth/src/main/java/javax/security/auth/DestroyFailedException.java new file mode 100644 index 0000000..16e9dfb --- /dev/null +++ b/auth/src/main/java/javax/security/auth/DestroyFailedException.java @@ -0,0 +1,32 @@ +/* + * 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; + +public class DestroyFailedException extends Exception { + + private static final long serialVersionUID = -7790152857282749162L; + + public DestroyFailedException() { + super(); + } + + public DestroyFailedException(String message) { + super(message); + } + +} diff --git a/auth/src/main/java/javax/security/auth/Destroyable.java b/auth/src/main/java/javax/security/auth/Destroyable.java new file mode 100644 index 0000000..a54cbe6 --- /dev/null +++ b/auth/src/main/java/javax/security/auth/Destroyable.java @@ -0,0 +1,26 @@ +/* + * 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; + +public interface Destroyable { + + void destroy() throws DestroyFailedException; + + boolean isDestroyed(); + +} diff --git a/auth/src/main/java/javax/security/auth/PrivateCredentialPermission.java b/auth/src/main/java/javax/security/auth/PrivateCredentialPermission.java new file mode 100644 index 0000000..1f5a560 --- /dev/null +++ b/auth/src/main/java/javax/security/auth/PrivateCredentialPermission.java @@ -0,0 +1,333 @@ +/* + * 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.Serializable; +import java.security.Permission; +import java.security.PermissionCollection; +import java.security.Principal; +import java.util.Set; + +import org.apache.harmony.auth.internal.nls.Messages; + +public final class PrivateCredentialPermission extends Permission { + + private static final long serialVersionUID = 5284372143517237068L; + + // allowed action + private static final String READ = "read"; //$NON-NLS-1$ + + private String credentialClass; + + // current offset + private transient int offset; + + // owners set + private transient CredOwner[] set; + + public PrivateCredentialPermission(String name, String action) { + super(name); + if (READ.equalsIgnoreCase(action)) { + initTargetName(name); + } else { + throw new IllegalArgumentException(Messages.getString("auth.11")); //$NON-NLS-1$ + } + } + + /** + * Creates a <code>PrivateCredentialPermission</code> from the Credential Class + * and Set of Principals + * + * @param credentialClass - credential class name + * @param principals - principal set + */ + PrivateCredentialPermission(String credentialClass, Set<Principal> principals) { + super(credentialClass); + this.credentialClass = credentialClass; + + set = new CredOwner[principals.size()]; + for (Principal p : principals) { + CredOwner element = new CredOwner(p.getClass().getName(), p.getName()); + // check for duplicate elements + boolean found = false; + for (int ii = 0; ii < offset; ii++) { + if (set[ii].equals(element)) { + found = true; + break; + } + } + if (!found) { + set[offset++] = element; + } + } + } + + /** + * Initialize a PrivateCredentialPermission object and checks that a target + * name has a correct format: CredentialClass 1*(PrincipalClass + * "PrincipalName") + */ + private void initTargetName(String name) { + + if (name == null) { + throw new NullPointerException(Messages.getString("auth.0E")); //$NON-NLS-1$ + } + + // check empty string + name = name.trim(); + if (name.length() == 0) { + throw new IllegalArgumentException(Messages.getString("auth.0F")); //$NON-NLS-1$ + } + + // get CredentialClass + int beg = name.indexOf(' '); + if (beg == -1) { + throw new IllegalArgumentException(Messages.getString("auth.10")); //$NON-NLS-1$ + } + credentialClass = name.substring(0, beg); + + // get a number of pairs: PrincipalClass "PrincipalName" + beg++; + int count = 0; + int nameLength = name.length(); + for (int i, j = 0; beg < nameLength; beg = j + 2, count++) { + i = name.indexOf(' ', beg); + j = name.indexOf('"', i + 2); + + if (i == -1 || j == -1 || name.charAt(i + 1) != '"') { + throw new IllegalArgumentException(Messages.getString("auth.10")); //$NON-NLS-1$ + } + } + + // name MUST have one pair at least + if (count < 1) { + throw new IllegalArgumentException(Messages.getString("auth.10")); //$NON-NLS-1$ + } + + beg = name.indexOf(' '); + beg++; + + // populate principal set with instances of CredOwner class + String principalClass; + String principalName; + + set = new CredOwner[count]; + for (int index = 0, i, j; index < count; beg = j + 2, index++) { + i = name.indexOf(' ', beg); + j = name.indexOf('"', i + 2); + + principalClass = name.substring(beg, i); + principalName = name.substring(i + 2, j); + + CredOwner element = new CredOwner(principalClass, principalName); + // check for duplicate elements + boolean found = false; + for (int ii = 0; ii < offset; ii++) { + if (set[ii].equals(element)) { + found = true; + break; + } + } + if (!found) { + set[offset++] = element; + } + } + } + + private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException { + ois.defaultReadObject(); + initTargetName(getName()); + } + + public String[][] getPrincipals() { + + String[][] s = new String[offset][2]; + + for (int i = 0; i < s.length; i++) { + s[i][0] = set[i].principalClass; + s[i][1] = set[i].principalName; + } + return s; + } + + @Override + public String getActions() { + return READ; + } + + public String getCredentialClass() { + return credentialClass; + } + + @Override + public int hashCode() { + int hash = 0; + for (int i = 0; i < offset; i++) { + hash = hash + set[i].hashCode(); + } + return getCredentialClass().hashCode() + hash; + } + + @Override + public boolean equals(Object obj) { + if (obj == this) { + return true; + } + + if (obj == null || this.getClass() != obj.getClass()) { + return false; + } + + PrivateCredentialPermission that = (PrivateCredentialPermission) obj; + + return credentialClass.equals(that.credentialClass) && (offset == that.offset) + && sameMembers(set, that.set, offset); + } + + @Override + public boolean implies(Permission permission) { + + if (permission == null || this.getClass() != permission.getClass()) { + return false; + } + + PrivateCredentialPermission that = (PrivateCredentialPermission) permission; + + if (!("*".equals(credentialClass) || credentialClass //$NON-NLS-1$ + .equals(that.getCredentialClass()))) { + return false; + } + + if (that.offset == 0) { + return true; + } + + CredOwner[] thisCo = set; + CredOwner[] thatCo = that.set; + int thisPrincipalsSize = offset; + int thatPrincipalsSize = that.offset; + for (int i = 0, j; i < thisPrincipalsSize; i++) { + for (j = 0; j < thatPrincipalsSize; j++) { + if (thisCo[i].implies(thatCo[j])) { + break; + } + } + if (j == thatCo.length) { + return false; + } + } + return true; + } + + @Override + public PermissionCollection newPermissionCollection() { + return null; + } + + /** + * Returns true if the two arrays have the same length, and every member of + * one array is contained in another array + */ + private boolean sameMembers(Object[] ar1, Object[] ar2, int length) { + if (ar1 == null && ar2 == null) { + return true; + } + if (ar1 == null || ar2 == null) { + return false; + } + boolean found; + for (int i = 0; i < length; i++) { + found = false; + for (int j = 0; j < length; j++) { + if (ar1[i].equals(ar2[j])) { + found = true; + break; + } + } + if (!found) { + return false; + } + } + return true; + } + + private static final class CredOwner implements Serializable { + + private static final long serialVersionUID = -5607449830436408266L; + + String principalClass; + + String principalName; + + // whether class name contains wildcards + private transient boolean isClassWildcard; + + // whether pname contains wildcards + private transient boolean isPNameWildcard; + + // Creates a new CredOwner with the specified Principal Class and Principal Name + CredOwner(String principalClass, String principalName) { + super(); + if ("*".equals(principalClass)) { //$NON-NLS-1$ + isClassWildcard = true; + } + + if ("*".equals(principalName)) { //$NON-NLS-1$ + isPNameWildcard = true; + } + + if (isClassWildcard && !isPNameWildcard) { + throw new IllegalArgumentException(Messages.getString("auth.12")); //$NON-NLS-1$ + } + + this.principalClass = principalClass; + this.principalName = principalName; + } + + // Checks if this CredOwner implies the specified Object. + boolean implies(Object obj) { + if (obj == this) { + return true; + } + + CredOwner co = (CredOwner) obj; + + if (isClassWildcard || principalClass.equals(co.principalClass)) { + if (isPNameWildcard || principalName.equals(co.principalName)) { + return true; + } + } + return false; + } + + // Checks two CredOwner objects for equality. + @Override + public boolean equals(Object obj) { + return principalClass.equals(((CredOwner) obj).principalClass) + && principalName.equals(((CredOwner) obj).principalName); + } + + // Returns the hash code value for this object. + @Override + public int hashCode() { + return principalClass.hashCode() + principalName.hashCode(); + } + } +} diff --git a/auth/src/main/java/javax/security/auth/Subject.java b/auth/src/main/java/javax/security/auth/Subject.java new file mode 100644 index 0000000..12c2ff6 --- /dev/null +++ b/auth/src/main/java/javax/security/auth/Subject.java @@ -0,0 +1,601 @@ +/* + * 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; + +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; + + public Subject() { + super(); + principals = new SecureSet<Principal>(_PRINCIPALS); + publicCredentials = new SecureSet<Object>(_PUBLIC_CREDENTIALS); + privateCredentials = new SecureSet<Object>(_PRIVATE_CREDENTIALS); + + readOnly = false; + } + + 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; + } + + @SuppressWarnings("unchecked") + public static Object doAs(Subject subject, PrivilegedAction action) { + + checkPermission(_AS); + + return doAs_PrivilegedAction(subject, action, AccessController.getContext()); + } + + @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); + } + + @SuppressWarnings("unchecked") + public static Object doAs(Subject subject, PrivilegedExceptionAction action) + throws PrivilegedActionException { + + checkPermission(_AS); + + return doAs_PrivilegedExceptionAction(subject, action, AccessController.getContext()); + } + + @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); + } + + @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; + } + + public Set<Principal> getPrincipals() { + return principals; + } + + public <T extends Principal> Set<T> getPrincipals(Class<T> c) { + return ((SecureSet<Principal>) principals).get(c); + } + + public Set<Object> getPrivateCredentials() { + return privateCredentials; + } + + public <T> Set<T> getPrivateCredentials(Class<T> c) { + return privateCredentials.get(c); + } + + public Set<Object> getPublicCredentials() { + return publicCredentials; + } + + public <T> Set<T> getPublicCredentials(Class<T> c) { + return publicCredentials.get(c); + } + + @Override + public int hashCode() { + return principals.hashCode() + privateCredentials.hashCode() + + publicCredentials.hashCode(); + } + + public void setReadOnly() { + checkPermission(_READ_ONLY); + + readOnly = true; + } + + public boolean isReadOnly() { + return readOnly; + } + + @Override + public String toString() { + + StringBuffer buf = new StringBuffer("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(); + } + + 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(); + } + } + } +}
\ No newline at end of file diff --git a/auth/src/main/java/javax/security/auth/SubjectDomainCombiner.java b/auth/src/main/java/javax/security/auth/SubjectDomainCombiner.java new file mode 100644 index 0000000..80f9d85 --- /dev/null +++ b/auth/src/main/java/javax/security/auth/SubjectDomainCombiner.java @@ -0,0 +1,90 @@ +/* + * 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.security.DomainCombiner; +import java.security.Principal; +import java.security.ProtectionDomain; +import java.util.Set; + +public class SubjectDomainCombiner implements DomainCombiner { + + // subject to be associated + private Subject subject; + + // permission required to get a subject object + private static final AuthPermission _GET = new AuthPermission( + "getSubjectFromDomainCombiner"); //$NON-NLS-1$ + + public SubjectDomainCombiner(Subject subject) { + super(); + if (subject == null) { + throw new NullPointerException(); + } + this.subject = subject; + } + + public Subject getSubject() { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + sm.checkPermission(_GET); + } + + return subject; + } + + public ProtectionDomain[] combine(ProtectionDomain[] currentDomains, + ProtectionDomain[] assignedDomains) { + // get array length for combining protection domains + int len = 0; + if (currentDomains != null) { + len += currentDomains.length; + } + if (assignedDomains != null) { + len += assignedDomains.length; + } + if (len == 0) { + return null; + } + + ProtectionDomain[] pd = new ProtectionDomain[len]; + + // for each current domain substitute set of principal with subject's + int cur = 0; + if (currentDomains != null) { + + Set<Principal> s = subject.getPrincipals(); + Principal[] p = s.toArray(new Principal[s.size()]); + + for (cur = 0; cur < currentDomains.length; cur++) { + ProtectionDomain newPD; + newPD = new ProtectionDomain(currentDomains[cur].getCodeSource(), + currentDomains[cur].getPermissions(), currentDomains[cur] + .getClassLoader(), p); + pd[cur] = newPD; + } + } + + // copy assigned domains + if (assignedDomains != null) { + System.arraycopy(assignedDomains, 0, pd, cur, assignedDomains.length); + } + + return pd; + } +} diff --git a/auth/src/main/java/javax/security/auth/callback/Callback.java b/auth/src/main/java/javax/security/auth/callback/Callback.java new file mode 100644 index 0000000..13e7574 --- /dev/null +++ b/auth/src/main/java/javax/security/auth/callback/Callback.java @@ -0,0 +1,21 @@ +/* + * 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.callback; + +public interface Callback { +}
\ No newline at end of file diff --git a/auth/src/main/java/javax/security/auth/callback/CallbackHandler.java b/auth/src/main/java/javax/security/auth/callback/CallbackHandler.java new file mode 100644 index 0000000..ceaeba4 --- /dev/null +++ b/auth/src/main/java/javax/security/auth/callback/CallbackHandler.java @@ -0,0 +1,24 @@ +/* + * 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.callback; + +public interface CallbackHandler { + + void handle(Callback[] callbacks) throws java.io.IOException, UnsupportedCallbackException; + +} diff --git a/auth/src/main/java/javax/security/auth/callback/PasswordCallback.java b/auth/src/main/java/javax/security/auth/callback/PasswordCallback.java new file mode 100644 index 0000000..e8191bf --- /dev/null +++ b/auth/src/main/java/javax/security/auth/callback/PasswordCallback.java @@ -0,0 +1,79 @@ +/* + * 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.callback; + +import java.io.Serializable; +import java.util.Arrays; + +import org.apache.harmony.auth.internal.nls.Messages; + +public class PasswordCallback implements Callback, Serializable { + + private static final long serialVersionUID = 2267422647454909926L; + + private String prompt; + + boolean echoOn; + + private char[] inputPassword; + + private void setPrompt(String prompt) throws IllegalArgumentException { + if (prompt == null || prompt.length() == 0) { + throw new IllegalArgumentException(Messages.getString("auth.14")); //$NON-NLS-1$ + } + this.prompt = prompt; + } + + public PasswordCallback(String prompt, boolean echoOn) { + super(); + setPrompt(prompt); + this.echoOn = echoOn; + } + + public String getPrompt() { + return prompt; + } + + public boolean isEchoOn() { + return echoOn; + } + + public void setPassword(char[] password) { + if (password == null) { + this.inputPassword = password; + } else { + inputPassword = new char[password.length]; + System.arraycopy(password, 0, inputPassword, 0, inputPassword.length); + } + } + + public char[] getPassword() { + if (inputPassword != null) { + char[] tmp = new char[inputPassword.length]; + System.arraycopy(inputPassword, 0, tmp, 0, tmp.length); + return tmp; + } + return null; + } + + public void clearPassword() { + if (inputPassword != null) { + Arrays.fill(inputPassword, '\u0000'); + } + } +} diff --git a/auth/src/main/java/javax/security/auth/callback/UnsupportedCallbackException.java b/auth/src/main/java/javax/security/auth/callback/UnsupportedCallbackException.java new file mode 100644 index 0000000..e814774 --- /dev/null +++ b/auth/src/main/java/javax/security/auth/callback/UnsupportedCallbackException.java @@ -0,0 +1,39 @@ +/* + * 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.callback; + +public class UnsupportedCallbackException extends Exception { + + private static final long serialVersionUID = -6873556327655666839L; + + private Callback callback; + + public UnsupportedCallbackException(Callback callback) { + super(); + this.callback = callback; + } + + public UnsupportedCallbackException(Callback callback, String message) { + super(message); + this.callback = callback; + } + + public Callback getCallback() { + return callback; + } +} diff --git a/auth/src/main/java/javax/security/auth/callback/package.html b/auth/src/main/java/javax/security/auth/callback/package.html new file mode 100644 index 0000000..50073c7 --- /dev/null +++ b/auth/src/main/java/javax/security/auth/callback/package.html @@ -0,0 +1,15 @@ +<html> +<head> +<meta http-equiv="Content-Type" content="text/html; charset=us-ascii"> +</head> +<html> +<body> +<p> +This package provides all the classes and interfaces needed to interact with the application +in order to execute the authentification and authorization processes. +It is a classical callback mechanism: one retrieves information (i.e. for authentification +purposes) and one display some messages (for example error messages). + +</p> +</body> +</html>
\ No newline at end of file diff --git a/auth/src/main/java/javax/security/auth/login/LoginException.java b/auth/src/main/java/javax/security/auth/login/LoginException.java new file mode 100644 index 0000000..993d5c1 --- /dev/null +++ b/auth/src/main/java/javax/security/auth/login/LoginException.java @@ -0,0 +1,34 @@ +/* + * 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.login; + +import java.security.GeneralSecurityException; + +public class LoginException extends GeneralSecurityException { + + private static final long serialVersionUID = -4679091624035232488L; + + public LoginException() { + super(); + } + + public LoginException(String message) { + super(message); + } + +} diff --git a/auth/src/main/java/javax/security/auth/login/package.html b/auth/src/main/java/javax/security/auth/login/package.html new file mode 100644 index 0000000..f8d7ab9 --- /dev/null +++ b/auth/src/main/java/javax/security/auth/login/package.html @@ -0,0 +1,15 @@ +<html> +<head> +<meta http-equiv="Content-Type" content="text/html; charset=us-ascii"> +</head> +<html> +<body> +<p> +This package provides a pluggable and stackable authentication system based on ideas and concepts +from the Unix-PAM module. +New authentication methods can be specified simply via a new LoginModule and chained together +with the existing ones. + +</p> +</body> +</html>
\ No newline at end of file diff --git a/auth/src/main/java/javax/security/auth/package.html b/auth/src/main/java/javax/security/auth/package.html new file mode 100644 index 0000000..3dd5344 --- /dev/null +++ b/auth/src/main/java/javax/security/auth/package.html @@ -0,0 +1,18 @@ +<html> +<head> +<meta http-equiv="Content-Type" content="text/html; charset=us-ascii"> +</head> +<html> +<body> +<p> +This package provides all the classes and interfaces needed to implemenet and program +different methods of users' authentification and role based users' authorization. +It integrates the previous separated JAAS package into the Java SDK. + +All subjects' authentification and role based authorization are strongly coupled with +the java.security file that, as always, is the ultimate arbiter of all matters secure in Java. +For example the class {@link javax.security.auth.SubjectDomainCombiner} updates the +ProtectionDomains associated with the actual class with the subjects defined therein. +</p> +</body> +</html> diff --git a/auth/src/main/java/javax/security/auth/x500/X500Principal.java b/auth/src/main/java/javax/security/auth/x500/X500Principal.java new file mode 100644 index 0000000..a168dae --- /dev/null +++ b/auth/src/main/java/javax/security/auth/x500/X500Principal.java @@ -0,0 +1,135 @@ +/* + * 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.x500; + +import java.io.IOException; +import java.io.InputStream; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; +import java.security.Principal; + +import org.apache.harmony.auth.internal.nls.Messages; +import org.apache.harmony.security.x501.Name; + +public final class X500Principal implements Serializable, Principal { + + private static final long serialVersionUID = -500463348111345721L; + + public static final String CANONICAL = "CANONICAL"; //$NON-NLS-1$ + + public static final String RFC1779 = "RFC1779"; //$NON-NLS-1$ + + public static final String RFC2253 = "RFC2253"; //$NON-NLS-1$ + + //Distinguished Name + private transient Name dn; + + public X500Principal(byte[] name) { + super(); + if (name == null) { + throw new IllegalArgumentException(Messages.getString("auth.00")); //$NON-NLS-1$ + } + try { + // FIXME dn = new Name(name); + dn = (Name) Name.ASN1.decode(name); + } catch (IOException e) { + IllegalArgumentException iae = new IllegalArgumentException(Messages + .getString("auth.2B")); //$NON-NLS-1$ + iae.initCause(e); + throw iae; + } + } + + public X500Principal(InputStream in) { + super(); + if (in == null) { + throw new NullPointerException(Messages.getString("auth.2C")); //$NON-NLS-1$ + } + try { + // FIXME dn = new Name(is); + dn = (Name) Name.ASN1.decode(in); + } catch (IOException e) { + IllegalArgumentException iae = new IllegalArgumentException(Messages + .getString("auth.2B")); //$NON-NLS-1$ + iae.initCause(e); + throw iae; + } + } + + public X500Principal(String name) { + super(); + if (name == null) { + throw new NullPointerException(Messages.getString("auth.00")); //$NON-NLS-1$ + } + try { + dn = new Name(name); + } catch (IOException e) { + IllegalArgumentException iae = new IllegalArgumentException(Messages + .getString("auth.2D")); //$NON-NLS-1$ + iae.initCause(e); + throw iae; + } + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || this.getClass() != o.getClass()) { + return false; + } + X500Principal principal = (X500Principal) o; + return dn.getName(CANONICAL).equals(principal.dn.getName(CANONICAL)); + } + + public byte[] getEncoded() { + byte[] src = dn.getEncoded(); + byte[] dst = new byte[src.length]; + System.arraycopy(src, 0, dst, 0, dst.length); + return dst; + } + + public String getName() { + return dn.getName(RFC2253); + } + + public String getName(String format) { + return dn.getName(format); + } + + @Override + public int hashCode() { + return dn.getName(CANONICAL).hashCode(); + } + + @Override + public String toString() { + return dn.getName(RFC1779); + } + + private void writeObject(ObjectOutputStream out) throws IOException { + out.writeObject(dn.getEncoded()); + } + + private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { + + dn = (Name) Name.ASN1.decode((byte[]) in.readObject()); + } +} diff --git a/auth/src/main/java/javax/security/auth/x500/package.html b/auth/src/main/java/javax/security/auth/x500/package.html new file mode 100644 index 0000000..3a7163e --- /dev/null +++ b/auth/src/main/java/javax/security/auth/x500/package.html @@ -0,0 +1,18 @@ +<html> +<head> +<meta http-equiv="Content-Type" content="text/html; charset=us-ascii"> +</head> +<html> +<body> +<p> +This package provides all the classes needed to store X.500 principals and their credentials. +The class {@link javax.security.auth.x500.X500Principal} represents such a principal. +Specifically, X500 principals are defined by such tokens (distinguished names) as O=Google, + OU=Android, C=US. + The class accepts string representations of distinguished names defined in both + specifications RFC2253 and (the older) RFC1779. OID (Object Identifiers used to encode with + the ASN.1 standard the extended attributes of distinguished name, algorithm etc.) must + follow the RFC2459 specification. +</p> +</body> +</html> |