diff options
author | The Android Open Source Project <initial-contribution@android.com> | 2009-03-03 19:28:47 -0800 |
---|---|---|
committer | The Android Open Source Project <initial-contribution@android.com> | 2009-03-03 19:28:47 -0800 |
commit | adc854b798c1cfe3bfd4c27d68d5cee38ca617da (patch) | |
tree | 6aed8b4923ca428942cbaa7e848d50237a3d31e0 /auth | |
parent | 1c0fed63c71ddb230f3b304aac12caffbedf2f21 (diff) | |
download | libcore-adc854b798c1cfe3bfd4c27d68d5cee38ca617da.zip libcore-adc854b798c1cfe3bfd4c27d68d5cee38ca617da.tar.gz libcore-adc854b798c1cfe3bfd4c27d68d5cee38ca617da.tar.bz2 |
auto import from //depot/cupcake/@135843
Diffstat (limited to 'auth')
19 files changed, 2352 insertions, 0 deletions
diff --git a/auth/MODULE_LICENSE_APACHE2 b/auth/MODULE_LICENSE_APACHE2 new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/auth/MODULE_LICENSE_APACHE2 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..06ea3fb --- /dev/null +++ b/auth/src/main/java/javax/security/auth/AuthPermission.java @@ -0,0 +1,99 @@ +/* + * 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; + +/** + * Governs the use of methods in this package and also its subpackages. A + * <i>target name</i> of the permission specifies which methods are allowed + * without specifying the concrete action lists. Possible target names and + * associated authentication permissions are: + * + * <pre> + * doAs invoke Subject.doAs methods. + * doAsPrivileged invoke the Subject.doAsPrivileged methods. + * getSubject invoke Subject.getSubject(). + * getSubjectFromDomainCombiner invoke SubjectDomainCombiner.getSubject(). + * setReadOnly invoke Subject.setReadonly(). + * modifyPrincipals modify the set of principals + * associated with a Subject. + * modifyPublicCredentials modify the set of public credentials + * associated with a Subject. + * modifyPrivateCredentials modify the set of private credentials + * associated with a Subject. + * refreshCredential invoke the refresh method on a credential of a + * refreshable credential class. + * destroyCredential invoke the destroy method on a credential of a + * destroyable credential class. + * createLoginContext.<i>name</i> instantiate a LoginContext with the + * specified name. The wildcard name ('*') + * allows to a LoginContext of any name. + * getLoginConfiguration invoke the getConfiguration method of + * javax.security.auth.login.Configuration. + * refreshLoginConfiguration Invoke the refresh method of + * javax.security.auth.login.Configuration. + * </pre> + * + * @since Android 1.0 + */ +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; + } + + /** + * Creates an authentication permission with the specified target name. + * + * @param name + * the target name of this authentication permission. + */ + public AuthPermission(String name) { + super(init(name)); + } + + /** + * Creates an authentication permission with the specified target name. + * + * @param name + * the target name of this authentication permission. + * @param actions + * this parameter is ignored and should be {@code null}. + */ + 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..a5438a6 --- /dev/null +++ b/auth/src/main/java/javax/security/auth/DestroyFailedException.java @@ -0,0 +1,46 @@ +/* + * 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; + +/** + * Signals that the {@link Destroyable#destroy()} method failed. + * + * @since Android 1.0 + */ +public class DestroyFailedException extends Exception { + + private static final long serialVersionUID = -7790152857282749162L; + + /** + * Creates an exception of type {@code DestroyFailedException}. + */ + public DestroyFailedException() { + super(); + } + + /** + * Creates an exception of type {@code DestroyFailedException}. + * + * @param message + * A detail message that describes the reason for this exception. + */ + 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..6194db6 --- /dev/null +++ b/auth/src/main/java/javax/security/auth/Destroyable.java @@ -0,0 +1,45 @@ +/* + * 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; + +/** + * Allows for special treatment of sensitive information, when it comes to + * destroying or clearing of the data. + * + * @since Android 1.0 + */ +public interface Destroyable { + + /** + * Erases the sensitive information. Once an object is destroyed any calls + * to its methods will throw an {@code IllegalStateException}. If it does + * not succeed a DestroyFailedException is thrown. + * + * @throws DestroyFailedException + * if the information cannot be erased. + */ + void destroy() throws DestroyFailedException; + + /** + * Returns {@code true} once an object has been safely destroyed. + * + * @return whether the object has been safely destroyed. + */ + 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..d92ede5 --- /dev/null +++ b/auth/src/main/java/javax/security/auth/PrivateCredentialPermission.java @@ -0,0 +1,389 @@ +/* + * 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; + +/** + * Protects private credential objects belonging to a {@code Subject}. It has + * only one action which is "read". The target name of this permission has a + * special syntax: + * + * <pre> + * targetName = CredentialClass {PrincipalClass "PrincipalName"}* + * </pre> + * + * First it states a credential class and is followed then by a list of one or + * more principals identifying the subject. + * <p> + * The principals on their part are specified as the name of the {@code + * Principal} class followed by the principal name in quotes. For example, the + * following file may define permission to read the private credentials of a + * principal named "Bob": "com.sun.PrivateCredential com.sun.Principal \"Bob\"" + * </p> + * The syntax also allows the use of the wildcard "*" in place of {@code + * CredentialClass} or {@code PrincipalClass} and/or {@code PrincipalName}. + * + * @see Principal + * @since Android 1.0 + */ +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; + + /** + * Creates a new permission for private credentials specified by the target + * name {@code name} and an {@code action}. The action is always + * {@code "read"}. + * + * @param name + * the target name of the permission. + * @param action + * the action {@code "read"}. + */ + 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} from the {@code Credential} + * class and set of principals. + * + * @param credentialClass + * the credential class name. + * @param principals + * the set of principals. + */ + 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()); + } + + /** + * Returns the principal's classes and names associated with this {@code + * PrivateCredentialPermission} as a two dimensional array. The first + * dimension of the array corresponds to the number of principals. The + * second dimension defines either the name of the {@code PrincipalClass} + * [x][0] or the value of {@code PrincipalName} [x][1]. + * + * This corresponds to the the target name's syntax: + * + * <pre> + * targetName = CredentialClass {PrincipalClass "PrincipalName"}* + * </pre> + * + * @return the principal classes and names associated with this {@code + * PrivateCredentialPermission}. + */ + 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; + } + + /** + * Returns the class name of the credential associated with this permission. + * + * @return the class name of the credential associated with this permission. + */ + 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..5a4cceb --- /dev/null +++ b/auth/src/main/java/javax/security/auth/Subject.java @@ -0,0 +1,784 @@ +/* + * 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> + * </p> + * @since Android 1.0 + */ +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() { + + 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(); + } + + /** + * 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(); + } + } + } +} 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..6a8f00b --- /dev/null +++ b/auth/src/main/java/javax/security/auth/SubjectDomainCombiner.java @@ -0,0 +1,123 @@ +/* + * 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; + +/** + * Merges permissions based on code source and code signers with permissions + * granted to the specified {@link Subject}. + * + * @since Android 1.0 + */ +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$ + + /** + * Creates a domain combiner for the entity provided in {@code subject}. + * + * @param subject + * the entity to which this domain combiner is associated. + */ + public SubjectDomainCombiner(Subject subject) { + super(); + if (subject == null) { + throw new NullPointerException(); + } + this.subject = subject; + } + + /** + * Returns the entity to which this domain combiner is associated. + * + * @return the entity to which this domain combiner is associated. + */ + public Subject getSubject() { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + sm.checkPermission(_GET); + } + + return subject; + } + + /** + * Merges the {@code ProtectionDomain} with the {@code Principal}s + * associated with the subject of this {@code SubjectDomainCombiner}. + * + * @param currentDomains + * the {@code ProtectionDomain}s associated with the context of + * the current thread. The domains must be sorted according to + * the execution order, the most recent residing at the + * beginning. + * @param assignedDomains + * the {@code ProtectionDomain}s from the parent thread based on + * code source and signers. + * @return a single {@code ProtectionDomain} array computed from the two + * provided arrays, or {@code null}. + * @see ProtectionDomain + */ + 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..6cf46b8 --- /dev/null +++ b/auth/src/main/java/javax/security/auth/callback/Callback.java @@ -0,0 +1,27 @@ +/* + * 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; + +/** + * Defines an empty base interface for all {@code Callback}s used during + * authentication. + * + * @since Android 1.0 + */ +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..a71c558 --- /dev/null +++ b/auth/src/main/java/javax/security/auth/callback/CallbackHandler.java @@ -0,0 +1,54 @@ +/* + * 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; + +/** + * Needs to be implemented by classes that want to handle authentication + * {@link Callback}s. A single method {@link #handle(Callback[])} must be + * provided that checks the type of the incoming {@code Callback}s and reacts + * accordingly. {@code CallbackHandler}s can be installed per application. It is + * also possible to configure a system-default {@code CallbackHandler} by + * setting the {@code auth.login.defaultCallbackHandler} property in the + * standard {@code security.properties} file. + * + * @since Android 1.0 + */ +public interface CallbackHandler { + + /** + * Handles the actual {@link Callback}. A {@code CallbackHandler} needs to + * implement this method. In the method, it is free to select which {@code + * Callback}s it actually wants to handle and in which way. For example, a + * console-based {@code CallbackHandler} might choose to sequentially ask + * the user for login and password, if it implements these {@code Callback} + * s, whereas a GUI-based one might open a single dialog window for both + * values. If a {@code CallbackHandler} is not able to handle a specific + * {@code Callback}, it needs to throw an + * {@link UnsupportedCallbackException}. + * + * @param callbacks + * the array of {@code Callback}s that need handling + * @throws IOException + * if an I/O related error occurs + * @throws UnsupportedCallbackException + * if the {@code CallbackHandler} is not able to handle a + * specific {@code Callback} + */ + 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..00020fe --- /dev/null +++ b/auth/src/main/java/javax/security/auth/callback/PasswordCallback.java @@ -0,0 +1,126 @@ +/* + * 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; + +/** + * Is used in conjunction with a {@link CallbackHandler} to retrieve a password + * when needed. + * + * @since Android 1.0 + */ +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; + } + + /** + * Creates a new {@code PasswordCallback} instance. + * + * @param prompt + * the message that should be displayed to the user + * @param echoOn + * determines whether the user input should be echoed + */ + public PasswordCallback(String prompt, boolean echoOn) { + super(); + setPrompt(prompt); + this.echoOn = echoOn; + } + + /** + * Returns the prompt that was specified when creating this {@code + * PasswordCallback} + * + * @return the prompt + */ + public String getPrompt() { + return prompt; + } + + /** + * Queries whether this {@code PasswordCallback} expects user input to be + * echoed, which is specified during the creation of the object. + * + * @return {@code true} if (and only if) user input should be echoed + */ + public boolean isEchoOn() { + return echoOn; + } + + /** + * Sets the password. The {@link CallbackHandler} that performs the actual + * provisioning or input of the password needs to call this method to hand + * back the password to the security service that requested it. + * + * @param password + * the password. A copy of this is stored, so subsequent changes + * to the input array do not affect the {@code PasswordCallback}. + */ + 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); + } + } + + /** + * Returns the password. The security service that needs the password + * usually calls this method once the {@link CallbackHandler} has finished + * its work. + * + * @return the password. A copy of the internal password is created and + * returned, so subsequent changes to the internal password do not + * affect the result. + */ + public char[] getPassword() { + if (inputPassword != null) { + char[] tmp = new char[inputPassword.length]; + System.arraycopy(inputPassword, 0, tmp, 0, tmp.length); + return tmp; + } + return null; + } + + /** + * Clears the password stored in this {@code PasswordCallback}. + */ + 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..d40ff45 --- /dev/null +++ b/auth/src/main/java/javax/security/auth/callback/UnsupportedCallbackException.java @@ -0,0 +1,66 @@ +/* + * 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; + +/** + * Thrown when a {@link CallbackHandler} does not support a particular {@link + * Callback}. + * + * @since Android 1.0 + */ +public class UnsupportedCallbackException extends Exception { + + private static final long serialVersionUID = -6873556327655666839L; + + private Callback callback; + + /** + * Creates a new exception instance and initializes it with just the + * unsupported {@code Callback}, but no error message. + * + * @param callback + * the {@code Callback} + */ + public UnsupportedCallbackException(Callback callback) { + super(); + this.callback = callback; + } + + /** + * Creates a new exception instance and initializes it with both the + * unsupported {@code Callback} and an error message. + * + * @param callback + * the {@code Callback} + * @param message + * the error message + */ + public UnsupportedCallbackException(Callback callback, String message) { + super(message); + this.callback = callback; + } + + /** + * Returns the unsupported {@code Callback} that triggered this exception. + * + * @return the {@code 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..5446ab8 --- /dev/null +++ b/auth/src/main/java/javax/security/auth/callback/package.html @@ -0,0 +1,22 @@ +<html> +<head> +<meta http-equiv="Content-Type" content="text/html; charset=us-ascii"> +</head> +<html> +<body> +<p> +This package provides 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> +<p> +Note that the current implementation of this package is not complete, that is, +not compatible with desktop implementations of the Java programming language. +It contains only what was needed to make the compiler happy, that is, classes +required by other packages. +</p> +@since Android 1.0 +</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..a1d6ec0 --- /dev/null +++ b/auth/src/main/java/javax/security/auth/login/LoginException.java @@ -0,0 +1,47 @@ +/* + * 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; + +/** + * Base class for exceptions that are thrown when a login error occurs. + * + * @since Android 1.0 + */ +public class LoginException extends GeneralSecurityException { + + private static final long serialVersionUID = -4679091624035232488L; + + /** + * Creates a new exception instance and initializes it with default values. + */ + public LoginException() { + super(); + } + + /** + * Creates a new exception instance and initializes it with a given message. + * + * @param message the error message + */ + 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..382b487 --- /dev/null +++ b/auth/src/main/java/javax/security/auth/login/package.html @@ -0,0 +1,20 @@ +<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> +Note that the current implementation of this package is not complete, that is, +not compatible with desktop implementations of the Java programming language. +It contains only what was needed to make the compiler happy, that is, classes +required by other packages. +</p> +@since Android 1.0 +</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..2bca2db --- /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 the classes and interfaces needed to implemenet and program +different methods of users' authentification and role based users' authorization. + +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 Android. +For example the class <i>javax.security.auth.SubjectDomainCombiner</i> updates the +ProtectionDomains associated with the actual class with the subjects defined therein. +</p> +@since Android 1.0 +</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..fa9dfe8 --- /dev/null +++ b/auth/src/main/java/javax/security/auth/x500/X500Principal.java @@ -0,0 +1,220 @@ +/* + * 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; + +/** + * Represents an X.500 principal, which holds the distinguished name of some + * network entity. An example of a distinguished name is {@code "O=Google, + * OU=Android, C=US"}. The class can be instantiated from a byte representation + * of an object identifier (OID), an ASN.1 DER-encoded version, or a simple + * string holding the distinguished name. The representations must follow either + * RFC 2253, RFC 1779, or RFC2459. + * + * @since Android 1.0 + */ +public final class X500Principal implements Serializable, Principal { + + private static final long serialVersionUID = -500463348111345721L; + + /** + * Defines a constant for the canonical string format of distinguished + * names. + */ + public static final String CANONICAL = "CANONICAL"; //$NON-NLS-1$ + + /** + * Defines a constant for the RFC 1779 string format of distinguished + * names. + */ + public static final String RFC1779 = "RFC1779"; //$NON-NLS-1$ + + /** + * Defines a constant for the RFC 2253 string format of distinguished + * names. + */ + public static final String RFC2253 = "RFC2253"; //$NON-NLS-1$ + + //Distinguished Name + private transient Name dn; + + /** + * Creates a new X500Principal from a given ASN.1 DER encoding of a + * distinguished name. + * + * @param name + * the ASN.1 DER-encoded distinguished name + * + * @throws IllegalArgumentException + * if the ASN.1 DER-encoded distinguished name is incorrect + */ + 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; + } + } + + /** + * Creates a new X500Principal from a given ASN.1 DER encoding of a + * distinguished name. + * + * @param in + * an {@code InputStream} holding the ASN.1 DER-encoded + * distinguished name + * + * @throws IllegalArgumentException + * if the ASN.1 DER-encoded distinguished name is incorrect + */ + 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; + } + } + + /** + * Creates a new X500Principal from a string representation of a + * distinguished name. + * + * @param name + * the string representation of the distinguished name + * + * @throws IllegalArgumentException + * if the string representation of the distinguished name is + * incorrect + */ + 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)); + } + + /** + * Returns an ASN.1 DER-encoded representation of the distinguished name + * contained in this X.500 principal. + * + * @return the ASN.1 DER-encoded representation + */ + public byte[] getEncoded() { + byte[] src = dn.getEncoded(); + byte[] dst = new byte[src.length]; + System.arraycopy(src, 0, dst, 0, dst.length); + return dst; + } + + /** + * Returns a human-readable string representation of the distinguished name + * contained in this X.500 principal. + * + * @return the string representation + */ + public String getName() { + return dn.getName(RFC2253); + } + + /** + * Returns a string representation of the distinguished name contained in + * this X.500 principal. The format of the representation can be chosen. + * Valid arguments are {@link #RFC1779}, {@link #RFC2253}, and + * {@link #CANONICAL}. The representations are specified in RFC 1779 and RFC + * 2253, respectively. The canonical form is based on RFC 2253, but adds + * some canonicalizing operations like removing leading and trailing + * whitespace, lower-casing the whole name, and bringing it into a + * normalized Unicode representation. + * + * @param format + * the name of the format to use for the representation + * + * @return the string representation + * + * @throws IllegalArgumentException + * if the {@code format} argument is not one of the three + * mentioned above + */ + 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..58d27ac --- /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 classes needed to store X.500 principals and their +credentials. +</p> +Note that the current implementation of this package is not complete, that is, +not compatible with desktop implementations of the Java programming language. +It contains only what was needed to make the compiler happy, that is, classes +required by other packages. +</p> +@since Android 1.0 +</body> +</html> diff --git a/auth/src/main/java/org/apache/harmony/auth/internal/nls/Messages.java b/auth/src/main/java/org/apache/harmony/auth/internal/nls/Messages.java new file mode 100644 index 0000000..511aa7a --- /dev/null +++ b/auth/src/main/java/org/apache/harmony/auth/internal/nls/Messages.java @@ -0,0 +1,147 @@ +/* + * 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. + */ + +/* + * THE FILE HAS BEEN AUTOGENERATED BY MSGTOOL TOOL. + * All changes made to this file manually will be overwritten + * if this tool runs again. Better make changes in the template file. + */ + +// BEGIN android-note +// Redundant code has been removed and is now called from MsgHelp. +// END android-note + +package org.apache.harmony.auth.internal.nls; + + +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.util.Locale; +import java.util.MissingResourceException; +import java.util.ResourceBundle; + +// BEGIN android-changed +import org.apache.harmony.luni.util.MsgHelp; +// END android-changed + +/** + * This class retrieves strings from a resource bundle and returns them, + * formatting them with MessageFormat when required. + * <p> + * It is used by the system classes to provide national language support, by + * looking up messages in the <code> + * org.apache.harmony.auth.internal.nls.messages + * </code> + * resource bundle. Note that if this file is not available, or an invalid key + * is looked up, or resource bundle support is not available, the key itself + * will be returned as the associated message. This means that the <em>KEY</em> + * should a reasonable human-readable (english) string. + * + */ +public class Messages { + + // BEGIN android-changed + private static final String sResource = + "org.apache.harmony.auth.internal.nls.messages"; + // END android-changed + + /** + * Retrieves a message which has no arguments. + * + * @param msg + * String the key to look up. + * @return String the message for that key in the system message bundle. + */ + static public String getString(String msg) { + // BEGIN android-changed + return MsgHelp.getString(sResource, msg); + // END android-changed + } + + /** + * Retrieves a message which takes 1 argument. + * + * @param msg + * String the key to look up. + * @param arg + * Object the object to insert in the formatted output. + * @return String the message for that key in the system message bundle. + */ + static public String getString(String msg, Object arg) { + return getString(msg, new Object[] { arg }); + } + + /** + * Retrieves a message which takes 1 integer argument. + * + * @param msg + * String the key to look up. + * @param arg + * int the integer to insert in the formatted output. + * @return String the message for that key in the system message bundle. + */ + static public String getString(String msg, int arg) { + return getString(msg, new Object[] { Integer.toString(arg) }); + } + + /** + * Retrieves a message which takes 1 character argument. + * + * @param msg + * String the key to look up. + * @param arg + * char the character to insert in the formatted output. + * @return String the message for that key in the system message bundle. + */ + static public String getString(String msg, char arg) { + return getString(msg, new Object[] { String.valueOf(arg) }); + } + + /** + * Retrieves a message which takes 2 arguments. + * + * @param msg + * String the key to look up. + * @param arg1 + * Object an object to insert in the formatted output. + * @param arg2 + * Object another object to insert in the formatted output. + * @return String the message for that key in the system message bundle. + */ + static public String getString(String msg, Object arg1, Object arg2) { + return getString(msg, new Object[] { arg1, arg2 }); + } + + /** + * Retrieves a message which takes several arguments. + * + * @param msg + * String the key to look up. + * @param args + * Object[] the objects to insert in the formatted output. + * @return String the message for that key in the system message bundle. + */ + static public String getString(String msg, Object[] args) { + // BEGIN android-changed + return MsgHelp.getString(sResource, msg, args); + // END android-changed + } + + // BEGIN android-note + // Duplicate code was dropped in favor of using MsgHelp. + // END android-note +} diff --git a/auth/src/main/java/org/apache/harmony/auth/internal/nls/messages.properties b/auth/src/main/java/org/apache/harmony/auth/internal/nls/messages.properties new file mode 100644 index 0000000..c8d1b0f --- /dev/null +++ b/auth/src/main/java/org/apache/harmony/auth/internal/nls/messages.properties @@ -0,0 +1,101 @@ +# 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. +# + +# messages for EN locale +auth.00=Name can not be null +auth.01=sid can not be null +auth.02=sid can not be empty +auth.03=Subject can not be null +auth.04=options can not be null +auth.05=Read-only Subject +auth.06=uid can not be null +auth.07=gid can not be null +auth.08=Failed to load Subject-based policy +auth.09=invalid AccessControlContext +auth.0A=Set is read only +auth.0B=Element is not instance of java.security.Principal +auth.0C=Invalid argument class. MUST be instance of {0} +auth.0D=Null oids were provided +auth.0E=target name is null +auth.0F=target name has a length of 0 +auth.10=Target name MUST have the following syntax: CredentialClass 1*(PrincipalClass "PrincipalName") +auth.11=Action must be "read" only +auth.12=invalid syntax: Principal Class can not be a wildcard (*) value if Principal Name is not a wildcard (*) value +auth.13=name is null +auth.14=Invalid prompt +auth.15=Invalid default text +auth.16=Invalid message type +auth.17=invalid defaultOption +auth.18=Invalid option type +auth.19=invalid selection +auth.1A=Invalid options +auth.1B=specified selection is out of bounds +auth.1C=Invalid choices +auth.1D=Invalid default choices +auth.1E=Invalid default name +auth.1F=Invalid message +auth.20=Name must have the following syntax: "subordinate service" "target service" +auth.21=collection is read-only +auth.22=invalid permission: {0} +auth.23=Invalid principal name +auth.24=Illegal character in realm name; one of: '/', ':', null +auth.25=Invalid name type +auth.26=name of the LoginModule is null or has a length of 0 +auth.27=invalid control flag +auth.28=X509 certificate is null +auth.29=Private key is null +auth.2A=Alias is null +auth.2B=Incorrect input encoding +auth.2C=Input stream can not be null +auth.2D=Incorrect input name +auth.2E=Invalid actions mask +auth.2F=service principal is null +auth.30=service principal is empty +auth.31=Implementation was not found for: +auth.32=mechanism is null +auth.33=mechanisms is null +auth.34=CallbackHandler can not be null +auth.35=There is no "{0}" in Configuration or it's empty. +auth.36=Could not get default callback handler. +auth.37=Login attempt failed. +auth.38=This LoginContext is not logged. +auth.39=Could not load module {0} +auth.3A=Could not instantiate module {0} +auth.3B=ASN.1 encoding of this ticket is null +auth.3C=client is null +auth.3D=server is null +auth.3E=session key is null +auth.3F=authentication time is null +auth.40=expiration time is null +auth.41=An absolute expiration time can not be null for renewable tickets +auth.42=Incorrect start or end time +auth.43=This ticket is already destroyed +auth.44=The ticket is not renewable +auth.45=The allowable renew time is passed for this ticket +auth.46=InetAddress is null +auth.47=key is null +auth.48=The key is destroyed +auth.49=Unsupported algorithm +auth.4A=Failed to generate DES key from password. +auth.4B=\n\tApplication name [{0}] already exists +auth.4C=\n\tInvalid application name {0} +auth.4D=\nAppname: {0} +auth.4E=\n\tInvalid LoginModule name {0} +auth.4F=\n\tInvalid control flag: {0} +auth.50=\n\tInvalid options format {0} +auth.51=\n\tInvalid token: {0} +auth.52=Error code: {0} +auth.53=Unable to locate a login configuration |