From d7955ce24d294fb2014c59d11fca184471056f44 Mon Sep 17 00:00:00 2001 From: Shuyi Chen Date: Wed, 22 May 2013 14:51:55 -0700 Subject: Add android smack source. Change-Id: I49ce97136c17173c4ae3965c694af6e7bc49897d --- .../javax/security/auth/AuthPermission.java | 97 +++ .../security/auth/DestroyFailedException.java | 44 ++ .../harmony/javax/security/auth/Destroyable.java | 43 ++ .../security/auth/PrivateCredentialPermission.java | 395 +++++++++++ .../security/auth/RefreshFailedException.java | 31 + .../harmony/javax/security/auth/Refreshable.java | 26 + .../harmony/javax/security/auth/Subject.java | 782 +++++++++++++++++++++ .../javax/security/auth/SubjectDomainCombiner.java | 123 ++++ .../javax/security/auth/callback/Callback.java | 25 + .../security/auth/callback/CallbackHandler.java | 54 ++ .../security/auth/callback/ChoiceCallback.java | 109 +++ .../auth/callback/ConfirmationCallback.java | 234 ++++++ .../security/auth/callback/LanguageCallback.java | 41 ++ .../javax/security/auth/callback/NameCallback.java | 74 ++ .../security/auth/callback/PasswordCallback.java | 124 ++++ .../security/auth/callback/TextInputCallback.java | 74 ++ .../security/auth/callback/TextOutputCallback.java | 56 ++ .../callback/UnsupportedCallbackException.java | 64 ++ .../security/auth/login/AccountException.java | 31 + .../auth/login/AccountExpiredException.java | 31 + .../auth/login/AccountLockedException.java | 32 + .../auth/login/AccountNotFoundException.java | 32 + .../security/auth/login/AppConfigurationEntry.java | 95 +++ .../javax/security/auth/login/Configuration.java | 102 +++ .../security/auth/login/CredentialException.java | 32 + .../auth/login/CredentialExpiredException.java | 32 + .../auth/login/CredentialNotFoundException.java | 32 + .../security/auth/login/FailedLoginException.java | 32 + .../javax/security/auth/login/LoginContext.java | 548 +++++++++++++++ .../javax/security/auth/login/LoginException.java | 45 ++ .../javax/security/auth/spi/LoginModule.java | 38 + .../security/sasl/AuthenticationException.java | 35 + .../javax/security/sasl/AuthorizeCallback.java | 79 +++ .../harmony/javax/security/sasl/RealmCallback.java | 33 + .../javax/security/sasl/RealmChoiceCallback.java | 30 + .../apache/harmony/javax/security/sasl/Sasl.java | 204 ++++++ .../harmony/javax/security/sasl/SaslClient.java | 37 + .../javax/security/sasl/SaslClientFactory.java | 30 + .../harmony/javax/security/sasl/SaslException.java | 69 ++ .../harmony/javax/security/sasl/SaslServer.java | 37 + .../javax/security/sasl/SaslServerFactory.java | 30 + .../sasl/CRAMMD5HashedSaslClientFactory.java | 59 ++ .../management/common/sasl/ClientSaslFactory.java | 53 ++ .../qpid/management/common/sasl/Constants.java | 33 + .../qpid/management/common/sasl/JCAProvider.java | 55 ++ .../management/common/sasl/PlainSaslClient.java | 210 ++++++ .../qpid/management/common/sasl/SaslProvider.java | 35 + .../common/sasl/UserPasswordCallbackHandler.java | 77 ++ .../UsernameHashedPasswordCallbackHandler.java | 107 +++ 49 files changed, 4691 insertions(+) create mode 100644 src/org/apache/harmony/javax/security/auth/AuthPermission.java create mode 100644 src/org/apache/harmony/javax/security/auth/DestroyFailedException.java create mode 100644 src/org/apache/harmony/javax/security/auth/Destroyable.java create mode 100644 src/org/apache/harmony/javax/security/auth/PrivateCredentialPermission.java create mode 100644 src/org/apache/harmony/javax/security/auth/RefreshFailedException.java create mode 100644 src/org/apache/harmony/javax/security/auth/Refreshable.java create mode 100644 src/org/apache/harmony/javax/security/auth/Subject.java create mode 100644 src/org/apache/harmony/javax/security/auth/SubjectDomainCombiner.java create mode 100644 src/org/apache/harmony/javax/security/auth/callback/Callback.java create mode 100644 src/org/apache/harmony/javax/security/auth/callback/CallbackHandler.java create mode 100644 src/org/apache/harmony/javax/security/auth/callback/ChoiceCallback.java create mode 100644 src/org/apache/harmony/javax/security/auth/callback/ConfirmationCallback.java create mode 100644 src/org/apache/harmony/javax/security/auth/callback/LanguageCallback.java create mode 100644 src/org/apache/harmony/javax/security/auth/callback/NameCallback.java create mode 100644 src/org/apache/harmony/javax/security/auth/callback/PasswordCallback.java create mode 100644 src/org/apache/harmony/javax/security/auth/callback/TextInputCallback.java create mode 100644 src/org/apache/harmony/javax/security/auth/callback/TextOutputCallback.java create mode 100644 src/org/apache/harmony/javax/security/auth/callback/UnsupportedCallbackException.java create mode 100644 src/org/apache/harmony/javax/security/auth/login/AccountException.java create mode 100644 src/org/apache/harmony/javax/security/auth/login/AccountExpiredException.java create mode 100644 src/org/apache/harmony/javax/security/auth/login/AccountLockedException.java create mode 100644 src/org/apache/harmony/javax/security/auth/login/AccountNotFoundException.java create mode 100644 src/org/apache/harmony/javax/security/auth/login/AppConfigurationEntry.java create mode 100644 src/org/apache/harmony/javax/security/auth/login/Configuration.java create mode 100644 src/org/apache/harmony/javax/security/auth/login/CredentialException.java create mode 100644 src/org/apache/harmony/javax/security/auth/login/CredentialExpiredException.java create mode 100644 src/org/apache/harmony/javax/security/auth/login/CredentialNotFoundException.java create mode 100644 src/org/apache/harmony/javax/security/auth/login/FailedLoginException.java create mode 100644 src/org/apache/harmony/javax/security/auth/login/LoginContext.java create mode 100644 src/org/apache/harmony/javax/security/auth/login/LoginException.java create mode 100644 src/org/apache/harmony/javax/security/auth/spi/LoginModule.java create mode 100644 src/org/apache/harmony/javax/security/sasl/AuthenticationException.java create mode 100644 src/org/apache/harmony/javax/security/sasl/AuthorizeCallback.java create mode 100644 src/org/apache/harmony/javax/security/sasl/RealmCallback.java create mode 100644 src/org/apache/harmony/javax/security/sasl/RealmChoiceCallback.java create mode 100644 src/org/apache/harmony/javax/security/sasl/Sasl.java create mode 100644 src/org/apache/harmony/javax/security/sasl/SaslClient.java create mode 100644 src/org/apache/harmony/javax/security/sasl/SaslClientFactory.java create mode 100644 src/org/apache/harmony/javax/security/sasl/SaslException.java create mode 100644 src/org/apache/harmony/javax/security/sasl/SaslServer.java create mode 100644 src/org/apache/harmony/javax/security/sasl/SaslServerFactory.java create mode 100644 src/org/apache/qpid/management/common/sasl/CRAMMD5HashedSaslClientFactory.java create mode 100644 src/org/apache/qpid/management/common/sasl/ClientSaslFactory.java create mode 100644 src/org/apache/qpid/management/common/sasl/Constants.java create mode 100644 src/org/apache/qpid/management/common/sasl/JCAProvider.java create mode 100644 src/org/apache/qpid/management/common/sasl/PlainSaslClient.java create mode 100644 src/org/apache/qpid/management/common/sasl/SaslProvider.java create mode 100644 src/org/apache/qpid/management/common/sasl/UserPasswordCallbackHandler.java create mode 100644 src/org/apache/qpid/management/common/sasl/UsernameHashedPasswordCallbackHandler.java (limited to 'src/org/apache') diff --git a/src/org/apache/harmony/javax/security/auth/AuthPermission.java b/src/org/apache/harmony/javax/security/auth/AuthPermission.java new file mode 100644 index 0000000..bb12554 --- /dev/null +++ b/src/org/apache/harmony/javax/security/auth/AuthPermission.java @@ -0,0 +1,97 @@ +/* + * 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 org.apache.harmony.javax.security.auth; + +import java.security.BasicPermission; + + + +/** + * Governs the use of methods in this package and also its subpackages. A + * target name of the permission specifies which methods are allowed + * without specifying the concrete action lists. Possible target names and + * associated authentication permissions are: + * + *
+ *    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.name   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.
+ * 
+ */ +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("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/src/org/apache/harmony/javax/security/auth/DestroyFailedException.java b/src/org/apache/harmony/javax/security/auth/DestroyFailedException.java new file mode 100644 index 0000000..7c7ea79 --- /dev/null +++ b/src/org/apache/harmony/javax/security/auth/DestroyFailedException.java @@ -0,0 +1,44 @@ +/* + * 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 org.apache.harmony.javax.security.auth; + +/** + * Signals that the {@link Destroyable#destroy()} method failed. + */ +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/src/org/apache/harmony/javax/security/auth/Destroyable.java b/src/org/apache/harmony/javax/security/auth/Destroyable.java new file mode 100644 index 0000000..12a107b --- /dev/null +++ b/src/org/apache/harmony/javax/security/auth/Destroyable.java @@ -0,0 +1,43 @@ +/* + * 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 org.apache.harmony.javax.security.auth; + +/** + * Allows for special treatment of sensitive information, when it comes to + * destroying or clearing of the data. + */ +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/src/org/apache/harmony/javax/security/auth/PrivateCredentialPermission.java b/src/org/apache/harmony/javax/security/auth/PrivateCredentialPermission.java new file mode 100644 index 0000000..d62bb24 --- /dev/null +++ b/src/org/apache/harmony/javax/security/auth/PrivateCredentialPermission.java @@ -0,0 +1,395 @@ +/* + * 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 org.apache.harmony.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; + + + +/** + * 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: + * + *
+ * targetName = CredentialClass {PrincipalClass "PrincipalName"}*
+ * 
+ * + * First it states a credential class and is followed then by a list of one or + * more principals identifying the subject. + *

+ * 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\"" + *

+ * The syntax also allows the use of the wildcard "*" in place of {@code + * CredentialClass} or {@code PrincipalClass} and/or {@code PrincipalName}. + * + * @see Principal + */ +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("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 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("auth.0E"); //$NON-NLS-1$ + } + + // check empty string + name = name.trim(); + if (name.length() == 0) { + throw new IllegalArgumentException("auth.0F"); //$NON-NLS-1$ + } + + // get CredentialClass + int beg = name.indexOf(' '); + if (beg == -1) { + throw new IllegalArgumentException("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("auth.10"); //$NON-NLS-1$ + } + } + + // name MUST have one pair at least + if (count < 1) { + throw new IllegalArgumentException("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: + * + *

+     * targetName = CredentialClass {PrincipalClass "PrincipalName"}*
+     * 
+ * + * @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("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) { + if (obj == this) { + return true; + } + if (obj instanceof CredOwner) { + CredOwner that = (CredOwner) obj; + return principalClass.equals(that.principalClass) + && principalName.equals(that.principalName); + } + return false; + } + + // Returns the hash code value for this object. + @Override + public int hashCode() { + return principalClass.hashCode() + principalName.hashCode(); + } + } +} diff --git a/src/org/apache/harmony/javax/security/auth/RefreshFailedException.java b/src/org/apache/harmony/javax/security/auth/RefreshFailedException.java new file mode 100644 index 0000000..71bcc6b --- /dev/null +++ b/src/org/apache/harmony/javax/security/auth/RefreshFailedException.java @@ -0,0 +1,31 @@ +/* + * 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 org.apache.harmony.javax.security.auth; + +public class RefreshFailedException extends Exception { + + private static final long serialVersionUID = 5058444488565265840L; + + public RefreshFailedException() { + super(); + } + + public RefreshFailedException(String message) { + super(message); + } +} diff --git a/src/org/apache/harmony/javax/security/auth/Refreshable.java b/src/org/apache/harmony/javax/security/auth/Refreshable.java new file mode 100644 index 0000000..90b00cb --- /dev/null +++ b/src/org/apache/harmony/javax/security/auth/Refreshable.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 org.apache.harmony.javax.security.auth; + +public interface Refreshable { + + void refresh() throws RefreshFailedException; + + boolean isCurrent(); + +} diff --git a/src/org/apache/harmony/javax/security/auth/Subject.java b/src/org/apache/harmony/javax/security/auth/Subject.java new file mode 100644 index 0000000..142686e --- /dev/null +++ b/src/org/apache/harmony/javax/security/auth/Subject.java @@ -0,0 +1,782 @@ +/* + * 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 org.apache.harmony.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; + + + +/** + * 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. + *

+ * A subject has the following features: + *

+ */ +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 principals; + + private boolean readOnly; + + // set of private credentials + private transient SecureSet privateCredentials; + + // set of public credentials + private transient SecureSet publicCredentials; + + /** + * The default constructor initializing the sets of public and private + * credentials and principals with the empty set. + */ + public Subject() { + super(); + principals = new SecureSet(_PRINCIPALS); + publicCredentials = new SecureSet(_PUBLIC_CREDENTIALS); + privateCredentials = new SecureSet(_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 subjPrincipals, + Set pubCredentials, Set privCredentials) { + + if (subjPrincipals == null || pubCredentials == null || privCredentials == null) { + throw new NullPointerException(); + } + + principals = new SecureSet(_PRINCIPALS, subjPrincipals); + publicCredentials = new SecureSet(_PUBLIC_CREDENTIALS, pubCredentials); + privateCredentials = new SecureSet(_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 dccAction = new PrivilegedAction() { + 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 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 Set getPrincipals(Class c) { + return ((SecureSet) principals).get(c); + } + + /** + * Returns the private credentials associated with this {@code Subject}. + * + * @return the private credentials associated with this {@code Subject}. + */ + public Set 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 Set getPrivateCredentials(Class 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 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 Set getPublicCredentials(Class c) { + return publicCredentials.get(c); + } + + /** + * Returns a hash code of this {@code Subject}. + * + * @return a hash code of this {@code Subject}. + */ + @Override + public int hashCode() { + return principals.hashCode() + privateCredentials.hashCode() + + publicCredentials.hashCode(); + } + + /** + * Prevents from modifications being done to the credentials and {@link + * Principal} sets. After setting it to read-only this {@code Subject} can + * not be made writable again. The destroy method on the credentials still + * works though. + */ + public void setReadOnly() { + checkPermission(_READ_ONLY); + + readOnly = true; + } + + /** + * Returns whether this {@code Subject} is read-only or not. + * + * @return whether this {@code Subject} is read-only or not. + */ + public boolean isReadOnly() { + return readOnly; + } + + /** + * Returns a {@code String} representation of this {@code Subject}. + * + * @return a {@code String} representation of this {@code Subject}. + */ + @Override + public String toString() { + + StringBuilder buf = new StringBuilder("Subject:\n"); //$NON-NLS-1$ + + Iterator it = principals.iterator(); + while (it.hasNext()) { + buf.append("\tPrincipal: "); //$NON-NLS-1$ + buf.append(it.next()); + buf.append('\n'); + } + + it = publicCredentials.iterator(); + while (it.hasNext()) { + buf.append("\tPublic Credential: "); //$NON-NLS-1$ + buf.append(it.next()); + buf.append('\n'); + } + + int offset = buf.length() - 1; + it = privateCredentials.iterator(); + try { + while (it.hasNext()) { + buf.append("\tPrivate Credential: "); //$NON-NLS-1$ + buf.append(it.next()); + buf.append('\n'); + } + } catch (SecurityException e) { + buf.delete(offset, buf.length()); + buf.append("\tPrivate Credentials: no accessible information\n"); //$NON-NLS-1$ + } + return buf.toString(); + } + + private void readObject(ObjectInputStream in) throws IOException, + ClassNotFoundException { + + in.defaultReadObject(); + + publicCredentials = new SecureSet(_PUBLIC_CREDENTIALS); + privateCredentials = new SecureSet(_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("auth.09"); //$NON-NLS-1$ + } + PrivilegedAction action = new PrivilegedAction() { + 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("auth.0A"); //$NON-NLS-1$ + } + } + + private final class SecureSet extends AbstractSet implements Serializable { + + /** + * Compatibility issue: see comments for setType variable + */ + private static final long serialVersionUID = 7911754171111800359L; + + private LinkedList 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(); + } + + // creates set from specified collection with specified permission + // all collection elements are verified before adding + protected SecureSet(AuthPermission perm, Collection 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 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("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 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 Set get(final Class c) { + + if (c == null) { + throw new NullPointerException(); + } + + AbstractSet s = new AbstractSet() { + private LinkedList elements = new LinkedList(); + + @Override + public boolean add(E o) { + + if (!c.isAssignableFrom(o.getClass())) { + throw new IllegalArgumentException( + "auth.0C " + c.getName()); //$NON-NLS-1$ + } + + if (elements.contains(o)) { + return false; + } + elements.add(o); + return true; + } + + @Override + public Iterator 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 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 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 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 { + protected Iterator iterator; + + protected SecureIterator(Iterator 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/src/org/apache/harmony/javax/security/auth/SubjectDomainCombiner.java b/src/org/apache/harmony/javax/security/auth/SubjectDomainCombiner.java new file mode 100644 index 0000000..edbb672 --- /dev/null +++ b/src/org/apache/harmony/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 org.apache.harmony.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}. + */ +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 s = subject.getPrincipals(); + Principal[] p = s.toArray(new Principal[s.size()]); + + for (cur = 0; cur < currentDomains.length; cur++) { + if (currentDomains[cur] != null) { + 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/src/org/apache/harmony/javax/security/auth/callback/Callback.java b/src/org/apache/harmony/javax/security/auth/callback/Callback.java new file mode 100644 index 0000000..8fd745c --- /dev/null +++ b/src/org/apache/harmony/javax/security/auth/callback/Callback.java @@ -0,0 +1,25 @@ +/* + * 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 org.apache.harmony.javax.security.auth.callback; + +/** + * Defines an empty base interface for all {@code Callback}s used during + * authentication. + */ +public interface Callback { +} \ No newline at end of file diff --git a/src/org/apache/harmony/javax/security/auth/callback/CallbackHandler.java b/src/org/apache/harmony/javax/security/auth/callback/CallbackHandler.java new file mode 100644 index 0000000..d09fafa --- /dev/null +++ b/src/org/apache/harmony/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 org.apache.harmony.javax.security.auth.callback; + +import java.io.IOException; + +/** + * 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. + */ +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 IOException, UnsupportedCallbackException; + +} diff --git a/src/org/apache/harmony/javax/security/auth/callback/ChoiceCallback.java b/src/org/apache/harmony/javax/security/auth/callback/ChoiceCallback.java new file mode 100644 index 0000000..1e53fb6 --- /dev/null +++ b/src/org/apache/harmony/javax/security/auth/callback/ChoiceCallback.java @@ -0,0 +1,109 @@ +/* + * 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 org.apache.harmony.javax.security.auth.callback; + +import java.io.Serializable; + + + +public class ChoiceCallback implements Callback, Serializable { + + private static final long serialVersionUID = -3975664071579892167L; + + private int defaultChoice; + + private String prompt; + + private boolean multipleSelectionsAllowed; + + private String[] choices; + + private int[] selections; + + private void setChoices(String[] choices) { + if (choices == null || choices.length == 0) { + throw new IllegalArgumentException("auth.1C"); //$NON-NLS-1$ + } + for (int i = 0; i < choices.length; i++) { + if (choices[i] == null || choices[i].length() == 0) { + throw new IllegalArgumentException("auth.1C"); //$NON-NLS-1$ + } + } + //FIXME: System.arraycopy(choices, 0 , new String[choices.length], 0, choices.length); + this.choices = choices; + + } + + private void setPrompt(String prompt) { + if (prompt == null || prompt.length() == 0) { + throw new IllegalArgumentException("auth.14"); //$NON-NLS-1$ + } + this.prompt = prompt; + } + + private void setDefaultChoice(int defaultChoice) { + if (0 > defaultChoice || defaultChoice >= choices.length) { + throw new IllegalArgumentException("auth.1D"); //$NON-NLS-1$ + } + this.defaultChoice = defaultChoice; + } + + public ChoiceCallback(String prompt, String[] choices, int defaultChoice, + boolean multipleSelectionsAllowed) { + super(); + setPrompt(prompt); + setChoices(choices); + setDefaultChoice(defaultChoice); + this.multipleSelectionsAllowed = multipleSelectionsAllowed; + } + + public boolean allowMultipleSelections() { + return multipleSelectionsAllowed; + } + + public String[] getChoices() { + return choices; + } + + public int getDefaultChoice() { + return defaultChoice; + } + + public String getPrompt() { + return prompt; + } + + public int[] getSelectedIndexes() { + return selections; + } + + public void setSelectedIndex(int selection) { + this.selections = new int[1]; + this.selections[0] = selection; + } + + public void setSelectedIndexes(int[] selections) { + if (!multipleSelectionsAllowed) { + throw new UnsupportedOperationException(); + } + this.selections = selections; + //FIXME: + // this.selections = new int[selections.length] + //System.arraycopy(selections, 0, this.selections, 0, this.selections.length); + } +} diff --git a/src/org/apache/harmony/javax/security/auth/callback/ConfirmationCallback.java b/src/org/apache/harmony/javax/security/auth/callback/ConfirmationCallback.java new file mode 100644 index 0000000..a1893f3 --- /dev/null +++ b/src/org/apache/harmony/javax/security/auth/callback/ConfirmationCallback.java @@ -0,0 +1,234 @@ +/* + * 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 org.apache.harmony.javax.security.auth.callback; + +import java.io.Serializable; + + + +public class ConfirmationCallback implements Callback, Serializable { + + private static final long serialVersionUID = -9095656433782481624L; + + public static final int YES = 0; // default options + + public static final int NO = 1; + + public static final int CANCEL = 2; + + public static final int OK = 3; + + public static final int YES_NO_OPTION = 0; // options type + + public static final int YES_NO_CANCEL_OPTION = 1; + + public static final int OK_CANCEL_OPTION = 2; + + public static final int UNSPECIFIED_OPTION = -1; + + public static final int INFORMATION = 0; // messages type + + public static final int WARNING = 1; + + public static final int ERROR = 2; + + private String prompt; + + private int messageType; + + private int optionType = UNSPECIFIED_OPTION; + + private int defaultOption; + + private String[] options; + + private int selection; + + public ConfirmationCallback(int messageType, int optionType, int defaultOption) { + super(); + if (messageType > ERROR || messageType < INFORMATION) { + throw new IllegalArgumentException("auth.16"); //$NON-NLS-1$ + } + + switch (optionType) { + case YES_NO_OPTION: + if (defaultOption != YES && defaultOption != NO) { + throw new IllegalArgumentException("auth.17"); //$NON-NLS-1$ + } + break; + case YES_NO_CANCEL_OPTION: + if (defaultOption != YES && defaultOption != NO && defaultOption != CANCEL) { + throw new IllegalArgumentException("auth.17"); //$NON-NLS-1$ + } + break; + case OK_CANCEL_OPTION: + if (defaultOption != OK && defaultOption != CANCEL) { + throw new IllegalArgumentException("auth.17"); //$NON-NLS-1$ + } + break; + default: + throw new IllegalArgumentException("auth.18"); //$NON-NLS-1$ + } + this.messageType = messageType; + this.optionType = optionType; + this.defaultOption = defaultOption; + } + + public ConfirmationCallback(int messageType, String[] options, int defaultOption) { + super(); + if (messageType > ERROR || messageType < INFORMATION) { + throw new IllegalArgumentException("auth.16"); //$NON-NLS-1$ + } + + if (options == null || options.length == 0) { + throw new IllegalArgumentException("auth.1A"); //$NON-NLS-1$ + } + for (int i = 0; i < options.length; i++) { + if (options[i] == null || options[i].length() == 0) { + throw new IllegalArgumentException("auth.1A"); //$NON-NLS-1$ + } + } + if (0 > defaultOption || defaultOption >= options.length) { + throw new IllegalArgumentException("auth.17"); //$NON-NLS-1$ + } + // FIXME:System.arraycopy(options, 0 , new String[this.options.length], + // 0, this.options.length); + this.options = options; + this.defaultOption = defaultOption; + this.messageType = messageType; + } + + public ConfirmationCallback(String prompt, int messageType, int optionType, + int defaultOption) { + super(); + if (prompt == null || prompt.length() == 0) { + throw new IllegalArgumentException("auth.14"); //$NON-NLS-1$ + } + + if (messageType > ERROR || messageType < INFORMATION) { + throw new IllegalArgumentException("auth.16"); //$NON-NLS-1$ + } + + switch (optionType) { + case YES_NO_OPTION: + if (defaultOption != YES && defaultOption != NO) { + throw new IllegalArgumentException("auth.17"); //$NON-NLS-1$ + } + break; + case YES_NO_CANCEL_OPTION: + if (defaultOption != YES && defaultOption != NO && defaultOption != CANCEL) { + throw new IllegalArgumentException("auth.17"); //$NON-NLS-1$ + } + break; + case OK_CANCEL_OPTION: + if (defaultOption != OK && defaultOption != CANCEL) { + throw new IllegalArgumentException("auth.17"); //$NON-NLS-1$ + } + break; + default: + throw new IllegalArgumentException("auth.18"); //$NON-NLS-1$ + } + this.prompt = prompt; + this.messageType = messageType; + this.optionType = optionType; + this.defaultOption = defaultOption; + } + + public ConfirmationCallback(String prompt, int messageType, String[] options, + int defaultOption) { + super(); + if (prompt == null || prompt.length() == 0) { + throw new IllegalArgumentException("auth.14"); //$NON-NLS-1$ + } + + if (messageType > ERROR || messageType < INFORMATION) { + throw new IllegalArgumentException("auth.16"); //$NON-NLS-1$ + } + + if (options == null || options.length == 0) { + throw new IllegalArgumentException("auth.1A"); //$NON-NLS-1$ + } + for (int i = 0; i < options.length; i++) { + if (options[i] == null || options[i].length() == 0) { + throw new IllegalArgumentException("auth.1A"); //$NON-NLS-1$ + } + } + if (0 > defaultOption || defaultOption >= options.length) { + throw new IllegalArgumentException("auth.17"); //$NON-NLS-1$ + } + // FIXME:System.arraycopy(options, 0 , new String[this.options.length], + // 0, this.options.length); + this.options = options; + this.defaultOption = defaultOption; + this.messageType = messageType; + this.prompt = prompt; + } + + public String getPrompt() { + return prompt; + } + + public int getMessageType() { + return messageType; + } + + public int getDefaultOption() { + return defaultOption; + } + + public String[] getOptions() { + return options; + } + + public int getOptionType() { + return optionType; + } + + public int getSelectedIndex() { + return selection; + } + + public void setSelectedIndex(int selection) { + if (options != null) { + if (0 <= selection && selection <= options.length) { + this.selection = selection; + } else { + throw new ArrayIndexOutOfBoundsException("auth.1B"); //$NON-NLS-1$ + } + } else { + switch (optionType) { + case YES_NO_OPTION: + if (selection != YES && selection != NO) { + throw new IllegalArgumentException("auth.19"); //$NON-NLS-1$ + } + break; + case YES_NO_CANCEL_OPTION: + if (selection != YES && selection != NO && selection != CANCEL) { + throw new IllegalArgumentException("auth.19"); //$NON-NLS-1$ + } + break; + case OK_CANCEL_OPTION: + if (selection != OK && selection != CANCEL) { + throw new IllegalArgumentException("auth.19"); //$NON-NLS-1$ + } + break; + } + this.selection = selection; + } + } +} diff --git a/src/org/apache/harmony/javax/security/auth/callback/LanguageCallback.java b/src/org/apache/harmony/javax/security/auth/callback/LanguageCallback.java new file mode 100644 index 0000000..729bb49 --- /dev/null +++ b/src/org/apache/harmony/javax/security/auth/callback/LanguageCallback.java @@ -0,0 +1,41 @@ +/* + * 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 org.apache.harmony.javax.security.auth.callback; + +import java.io.Serializable; +import java.util.Locale; + +public class LanguageCallback implements Callback, Serializable { + + private static final long serialVersionUID = 2019050433478903213L; + + private Locale locale; + + public LanguageCallback() { + super(); + } + + public Locale getLocale() { + return locale; + } + + public void setLocale(Locale locale) { + this.locale = locale; + } + +} diff --git a/src/org/apache/harmony/javax/security/auth/callback/NameCallback.java b/src/org/apache/harmony/javax/security/auth/callback/NameCallback.java new file mode 100644 index 0000000..97264ef --- /dev/null +++ b/src/org/apache/harmony/javax/security/auth/callback/NameCallback.java @@ -0,0 +1,74 @@ +/* + * 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 org.apache.harmony.javax.security.auth.callback; + +import java.io.Serializable; + + + +public class NameCallback implements Callback, Serializable { + + private static final long serialVersionUID = 3770938795909392253L; + + private String prompt; + + private String defaultName; + + private String inputName; + + private void setPrompt(String prompt) { + if (prompt == null || prompt.length() == 0) { + throw new IllegalArgumentException("auth.14"); //$NON-NLS-1$ + } + this.prompt = prompt; + } + + private void setDefaultName(String defaultName) { + if (defaultName == null || defaultName.length() == 0) { + throw new IllegalArgumentException("auth.1E"); //$NON-NLS-1$ + } + this.defaultName = defaultName; + } + + public NameCallback(String prompt) { + super(); + setPrompt(prompt); + } + + public NameCallback(String prompt, String defaultName) { + super(); + setPrompt(prompt); + setDefaultName(defaultName); + } + + public String getPrompt() { + return prompt; + } + + public String getDefaultName() { + return defaultName; + } + + public void setName(String name) { + this.inputName = name; + } + + public String getName() { + return inputName; + } +} diff --git a/src/org/apache/harmony/javax/security/auth/callback/PasswordCallback.java b/src/org/apache/harmony/javax/security/auth/callback/PasswordCallback.java new file mode 100644 index 0000000..bd142fc --- /dev/null +++ b/src/org/apache/harmony/javax/security/auth/callback/PasswordCallback.java @@ -0,0 +1,124 @@ +/* + * 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 org.apache.harmony.javax.security.auth.callback; + +import java.io.Serializable; +import java.util.Arrays; + + + +/** + * Is used in conjunction with a {@link CallbackHandler} to retrieve a password + * when needed. + */ +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("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/src/org/apache/harmony/javax/security/auth/callback/TextInputCallback.java b/src/org/apache/harmony/javax/security/auth/callback/TextInputCallback.java new file mode 100644 index 0000000..c7de222 --- /dev/null +++ b/src/org/apache/harmony/javax/security/auth/callback/TextInputCallback.java @@ -0,0 +1,74 @@ +/* + * 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 org.apache.harmony.javax.security.auth.callback; + +import java.io.Serializable; + + + +public class TextInputCallback implements Callback, Serializable { + + private static final long serialVersionUID = -8064222478852811804L; + + private String defaultText; + + private String prompt; + + private String inputText; + + private void setPrompt(String prompt) { + if (prompt == null || prompt.length() == 0) { + throw new IllegalArgumentException("auth.14"); //$NON-NLS-1$ + } + this.prompt = prompt; + } + + private void setDefaultText(String defaultText) { + if (defaultText == null || defaultText.length() == 0) { + throw new IllegalArgumentException("auth.15"); //$NON-NLS-1$ + } + this.defaultText = defaultText; + } + + public TextInputCallback(String prompt) { + super(); + setPrompt(prompt); + } + + public TextInputCallback(String prompt, String defaultText) { + super(); + setPrompt(prompt); + setDefaultText(defaultText); + } + + public String getDefaultText() { + return defaultText; + } + + public String getPrompt() { + return prompt; + } + + public String getText() { + return inputText; + } + + public void setText(String text) { + this.inputText = text; + } +} diff --git a/src/org/apache/harmony/javax/security/auth/callback/TextOutputCallback.java b/src/org/apache/harmony/javax/security/auth/callback/TextOutputCallback.java new file mode 100644 index 0000000..23a72fa --- /dev/null +++ b/src/org/apache/harmony/javax/security/auth/callback/TextOutputCallback.java @@ -0,0 +1,56 @@ +/* + * 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 org.apache.harmony.javax.security.auth.callback; + +import java.io.Serializable; + + + +public class TextOutputCallback implements Callback, Serializable { + + private static final long serialVersionUID = 1689502495511663102L; + + public static final int INFORMATION = 0; + + public static final int WARNING = 1; + + public static final int ERROR = 2; + + private String message; + + private int messageType; + + public TextOutputCallback(int messageType, String message) { + if (messageType > ERROR || messageType < INFORMATION) { + throw new IllegalArgumentException("auth.16"); //$NON-NLS-1$ + } + if (message == null || message.length() == 0) { + throw new IllegalArgumentException("auth.1F"); //$NON-NLS-1$ + } + this.messageType = messageType; + this.message = message; + } + + public String getMessage() { + return message; + } + + public int getMessageType() { + return messageType; + } +} diff --git a/src/org/apache/harmony/javax/security/auth/callback/UnsupportedCallbackException.java b/src/org/apache/harmony/javax/security/auth/callback/UnsupportedCallbackException.java new file mode 100644 index 0000000..19f6e40 --- /dev/null +++ b/src/org/apache/harmony/javax/security/auth/callback/UnsupportedCallbackException.java @@ -0,0 +1,64 @@ +/* + * 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 org.apache.harmony.javax.security.auth.callback; + +/** + * Thrown when a {@link CallbackHandler} does not support a particular {@link + * Callback}. + */ +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/src/org/apache/harmony/javax/security/auth/login/AccountException.java b/src/org/apache/harmony/javax/security/auth/login/AccountException.java new file mode 100644 index 0000000..c86e801 --- /dev/null +++ b/src/org/apache/harmony/javax/security/auth/login/AccountException.java @@ -0,0 +1,31 @@ +/* + * 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 org.apache.harmony.javax.security.auth.login; + +public class AccountException extends LoginException { + + private static final long serialVersionUID = -2112878680072211787L; + + public AccountException() { + super(); + } + + public AccountException(String message) { + super(message); + } +} diff --git a/src/org/apache/harmony/javax/security/auth/login/AccountExpiredException.java b/src/org/apache/harmony/javax/security/auth/login/AccountExpiredException.java new file mode 100644 index 0000000..1e0ce4d --- /dev/null +++ b/src/org/apache/harmony/javax/security/auth/login/AccountExpiredException.java @@ -0,0 +1,31 @@ +/* + * 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 org.apache.harmony.javax.security.auth.login; + +public class AccountExpiredException extends AccountException { + + private static final long serialVersionUID = -6064064890162661560L; + + public AccountExpiredException() { + super(); + } + + public AccountExpiredException(String message) { + super(message); + } +} diff --git a/src/org/apache/harmony/javax/security/auth/login/AccountLockedException.java b/src/org/apache/harmony/javax/security/auth/login/AccountLockedException.java new file mode 100644 index 0000000..47913a5 --- /dev/null +++ b/src/org/apache/harmony/javax/security/auth/login/AccountLockedException.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 org.apache.harmony.javax.security.auth.login; + +public class AccountLockedException extends AccountException { + + private static final long serialVersionUID = 8280345554014066334L; + + public AccountLockedException() { + super(); + } + + public AccountLockedException(String message) { + super(message); + } + +} diff --git a/src/org/apache/harmony/javax/security/auth/login/AccountNotFoundException.java b/src/org/apache/harmony/javax/security/auth/login/AccountNotFoundException.java new file mode 100644 index 0000000..8ca9b96 --- /dev/null +++ b/src/org/apache/harmony/javax/security/auth/login/AccountNotFoundException.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 org.apache.harmony.javax.security.auth.login; + +public class AccountNotFoundException extends AccountException { + + private static final long serialVersionUID = 1498349563916294614L; + + public AccountNotFoundException() { + super(); + } + + public AccountNotFoundException(String message) { + super(message); + } + +} diff --git a/src/org/apache/harmony/javax/security/auth/login/AppConfigurationEntry.java b/src/org/apache/harmony/javax/security/auth/login/AppConfigurationEntry.java new file mode 100644 index 0000000..2a735dc --- /dev/null +++ b/src/org/apache/harmony/javax/security/auth/login/AppConfigurationEntry.java @@ -0,0 +1,95 @@ +/* + * 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 org.apache.harmony.javax.security.auth.login; + +import java.util.Collections; +import java.util.Map; + + + +public class AppConfigurationEntry { + + // the login module options + private final Map options; + + // the control flag + private final AppConfigurationEntry.LoginModuleControlFlag controlFlag; + + // the login module name + private final String loginModuleName; + + public AppConfigurationEntry(String loginModuleName, + AppConfigurationEntry.LoginModuleControlFlag controlFlag, Map options) { + + if (loginModuleName == null || loginModuleName.length() == 0) { + throw new IllegalArgumentException("auth.26"); //$NON-NLS-1$ + } + + if (controlFlag == null) { + throw new IllegalArgumentException("auth.27"); //$NON-NLS-1$ + } + + if (options == null) { + throw new IllegalArgumentException("auth.1A"); //$NON-NLS-1$ + } + + this.loginModuleName = loginModuleName; + this.controlFlag = controlFlag; + this.options = Collections.unmodifiableMap(options); + } + + public String getLoginModuleName() { + return loginModuleName; + } + + public LoginModuleControlFlag getControlFlag() { + return controlFlag; + } + + public Map getOptions() { + return options; + } + + public static class LoginModuleControlFlag { + + // the control flag + private final String flag; + + public static final LoginModuleControlFlag REQUIRED = new LoginModuleControlFlag( + "LoginModuleControlFlag: required"); //$NON-NLS-1$ + + public static final LoginModuleControlFlag REQUISITE = new LoginModuleControlFlag( + "LoginModuleControlFlag: requisite"); //$NON-NLS-1$ + + public static final LoginModuleControlFlag OPTIONAL = new LoginModuleControlFlag( + "LoginModuleControlFlag: optional"); //$NON-NLS-1$ + + public static final LoginModuleControlFlag SUFFICIENT = new LoginModuleControlFlag( + "LoginModuleControlFlag: sufficient"); //$NON-NLS-1$ + + // Creates the LoginModuleControlFlag object with specified a flag + private LoginModuleControlFlag(String flag) { + this.flag = flag; + } + + @Override + public String toString() { + return flag; + } + } +} diff --git a/src/org/apache/harmony/javax/security/auth/login/Configuration.java b/src/org/apache/harmony/javax/security/auth/login/Configuration.java new file mode 100644 index 0000000..74c371f --- /dev/null +++ b/src/org/apache/harmony/javax/security/auth/login/Configuration.java @@ -0,0 +1,102 @@ +/* + * 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 org.apache.harmony.javax.security.auth.login; + +import java.security.AccessController; +import org.apache.harmony.javax.security.auth.AuthPermission; + +public abstract class Configuration { + + // the current configuration + private static Configuration configuration; + + // creates a AuthPermission object with a specify property + private static final AuthPermission GET_LOGIN_CONFIGURATION = new AuthPermission( + "getLoginConfiguration"); //$NON-NLS-1$ + + // creates a AuthPermission object with a specify property + private static final AuthPermission SET_LOGIN_CONFIGURATION = new AuthPermission( + "setLoginConfiguration"); //$NON-NLS-1$ + + // Key to security properties, defining default configuration provider. + private static final String LOGIN_CONFIGURATION_PROVIDER = "login.configuration.provider"; //$NON-NLS-1$ + + protected Configuration() { + super(); + } + + public static Configuration getConfiguration() { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + sm.checkPermission(GET_LOGIN_CONFIGURATION); + } + return getAccessibleConfiguration(); + } + + /** + * Reads name of default configuration provider from security.properties, + * loads the class and instantiates the provider.
In case of any + * exception, wraps it with SecurityException and throws further. + */ + private static final Configuration getDefaultProvider() { + return new Configuration() { + + @Override + public void refresh() { + } + + @Override + public AppConfigurationEntry[] getAppConfigurationEntry( + String applicationName) { + return new AppConfigurationEntry[0]; + } + }; + } + + /** + * Shortcut accessor for friendly classes, to skip security checks. + * If active configuration was set to null, tries to load a default + * provider, so this method never returns null.
+ * This method is synchronized with setConfiguration() + */ + static Configuration getAccessibleConfiguration() { + Configuration current = configuration; + if (current == null) { + synchronized (Configuration.class) { + if (configuration == null) { + configuration = getDefaultProvider(); + } + return configuration; + } + } + return current; + } + + public static void setConfiguration(Configuration configuration) { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + sm.checkPermission(SET_LOGIN_CONFIGURATION); + } + Configuration.configuration = configuration; + } + + public abstract AppConfigurationEntry[] getAppConfigurationEntry(String applicationName); + + public abstract void refresh(); + +} diff --git a/src/org/apache/harmony/javax/security/auth/login/CredentialException.java b/src/org/apache/harmony/javax/security/auth/login/CredentialException.java new file mode 100644 index 0000000..e74e866 --- /dev/null +++ b/src/org/apache/harmony/javax/security/auth/login/CredentialException.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 org.apache.harmony.javax.security.auth.login; + +public class CredentialException extends LoginException { + + private static final long serialVersionUID = -4772893876810601859L; + + public CredentialException() { + super(); + } + + public CredentialException(String message) { + super(message); + } + +} diff --git a/src/org/apache/harmony/javax/security/auth/login/CredentialExpiredException.java b/src/org/apache/harmony/javax/security/auth/login/CredentialExpiredException.java new file mode 100644 index 0000000..3ca3ad7 --- /dev/null +++ b/src/org/apache/harmony/javax/security/auth/login/CredentialExpiredException.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 org.apache.harmony.javax.security.auth.login; + +public class CredentialExpiredException extends CredentialException { + + private static final long serialVersionUID = -5344739593859737937L; + + public CredentialExpiredException() { + super(); + } + + public CredentialExpiredException(String message) { + super(message); + } + +} diff --git a/src/org/apache/harmony/javax/security/auth/login/CredentialNotFoundException.java b/src/org/apache/harmony/javax/security/auth/login/CredentialNotFoundException.java new file mode 100644 index 0000000..ffd529f --- /dev/null +++ b/src/org/apache/harmony/javax/security/auth/login/CredentialNotFoundException.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 org.apache.harmony.javax.security.auth.login; + +public class CredentialNotFoundException extends CredentialException { + + private static final long serialVersionUID = -7779934467214319475L; + + public CredentialNotFoundException() { + super(); + } + + public CredentialNotFoundException(String message) { + super(message); + } + +} diff --git a/src/org/apache/harmony/javax/security/auth/login/FailedLoginException.java b/src/org/apache/harmony/javax/security/auth/login/FailedLoginException.java new file mode 100644 index 0000000..f689d99 --- /dev/null +++ b/src/org/apache/harmony/javax/security/auth/login/FailedLoginException.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 org.apache.harmony.javax.security.auth.login; + +public class FailedLoginException extends LoginException { + + private static final long serialVersionUID = 802556922354616286L; + + public FailedLoginException() { + super(); + } + + public FailedLoginException(String message) { + super(message); + } + +} \ No newline at end of file diff --git a/src/org/apache/harmony/javax/security/auth/login/LoginContext.java b/src/org/apache/harmony/javax/security/auth/login/LoginContext.java new file mode 100644 index 0000000..7d46278 --- /dev/null +++ b/src/org/apache/harmony/javax/security/auth/login/LoginContext.java @@ -0,0 +1,548 @@ +/* + * 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 org.apache.harmony.javax.security.auth.login; + +import java.io.IOException; +import java.security.AccessController; +import java.security.AccessControlContext; +import java.security.PrivilegedExceptionAction; +import java.security.PrivilegedActionException; + +import java.security.Security; +import java.util.HashMap; +import java.util.Map; + +import org.apache.harmony.javax.security.auth.Subject; +import org.apache.harmony.javax.security.auth.callback.CallbackHandler; +import org.apache.harmony.javax.security.auth.callback.Callback; +import org.apache.harmony.javax.security.auth.callback.UnsupportedCallbackException; +import org.apache.harmony.javax.security.auth.spi.LoginModule; +import org.apache.harmony.javax.security.auth.AuthPermission; + +import org.apache.harmony.javax.security.auth.login.AppConfigurationEntry.LoginModuleControlFlag; + + + +public class LoginContext { + + private static final String DEFAULT_CALLBACK_HANDLER_PROPERTY = "auth.login.defaultCallbackHandler"; //$NON-NLS-1$ + + /* + * Integer constants which serve as a replacement for the corresponding + * LoginModuleControlFlag.* constants. These integers are used later as + * index in the arrays - see loginImpl() and logoutImpl() methods + */ + private static final int OPTIONAL = 0; + + private static final int REQUIRED = 1; + + private static final int REQUISITE = 2; + + private static final int SUFFICIENT = 3; + + // Subject to be used for this LoginContext's operations + private Subject subject; + + /* + * Shows whether the subject was specified by user (true) or was created by + * this LoginContext itself (false). + */ + private boolean userProvidedSubject; + + // Shows whether we use installed or user-provided Configuration + private boolean userProvidedConfig; + + // An user's AccessControlContext, used when user specifies + private AccessControlContext userContext; + + /* + * Either a callback handler passed by the user or a wrapper for the user's + * specified handler - see init() below. + */ + private CallbackHandler callbackHandler; + + /* + * An array which keeps the instantiated and init()-ialized login modules + * and their states + */ + private Module[] modules; + + // Stores a shared state + private Map sharedState; + + // A context class loader used to load [mainly] LoginModules + private ClassLoader contextClassLoader; + + // Shows overall status - whether this LoginContext was successfully logged + private boolean loggedIn; + + public LoginContext(String name) throws LoginException { + super(); + init(name, null, null, null); + } + + public LoginContext(String name, CallbackHandler cbHandler) throws LoginException { + super(); + if (cbHandler == null) { + throw new LoginException("auth.34"); //$NON-NLS-1$ + } + init(name, null, cbHandler, null); + } + + public LoginContext(String name, Subject subject) throws LoginException { + super(); + if (subject == null) { + throw new LoginException("auth.03"); //$NON-NLS-1$ + } + init(name, subject, null, null); + } + + public LoginContext(String name, Subject subject, CallbackHandler cbHandler) + throws LoginException { + super(); + if (subject == null) { + throw new LoginException("auth.03"); //$NON-NLS-1$ + } + if (cbHandler == null) { + throw new LoginException("auth.34"); //$NON-NLS-1$ + } + init(name, subject, cbHandler, null); + } + + public LoginContext(String name, Subject subject, CallbackHandler cbHandler, + Configuration config) throws LoginException { + super(); + init(name, subject, cbHandler, config); + } + + // Does all the machinery needed for the initialization. + private void init(String name, Subject subject, final CallbackHandler cbHandler, + Configuration config) throws LoginException { + userProvidedSubject = (this.subject = subject) != null; + + // + // Set config + // + if (name == null) { + throw new LoginException("auth.00"); //$NON-NLS-1$ + } + + if (config == null) { + config = Configuration.getAccessibleConfiguration(); + } else { + userProvidedConfig = true; + } + + SecurityManager sm = System.getSecurityManager(); + + if (sm != null && !userProvidedConfig) { + sm.checkPermission(new AuthPermission("createLoginContext." + name));//$NON-NLS-1$ + } + + AppConfigurationEntry[] entries = config.getAppConfigurationEntry(name); + if (entries == null) { + if (sm != null && !userProvidedConfig) { + sm.checkPermission(new AuthPermission("createLoginContext.other")); //$NON-NLS-1$ + } + entries = config.getAppConfigurationEntry("other"); //$NON-NLS-1$ + if (entries == null) { + throw new LoginException("auth.35 " + name); //$NON-NLS-1$ + } + } + + modules = new Module[entries.length]; + for (int i = 0; i < modules.length; i++) { + modules[i] = new Module(entries[i]); + } + // + // Set CallbackHandler and this.contextClassLoader + // + + /* + * as some of the operations to be executed (i.e. get*ClassLoader, + * getProperty, class loading) are security-checked, then combine all of + * them into a single doPrivileged() call. + */ + try { + AccessController.doPrivileged(new PrivilegedExceptionAction() { + public Void run() throws Exception { + // First, set the 'contextClassLoader' + contextClassLoader = Thread.currentThread().getContextClassLoader(); + if (contextClassLoader == null) { + contextClassLoader = ClassLoader.getSystemClassLoader(); + } + // then, checks whether the cbHandler is set + if (cbHandler == null) { + // well, let's try to find it + String klassName = Security + .getProperty(DEFAULT_CALLBACK_HANDLER_PROPERTY); + if (klassName == null || klassName.length() == 0) { + return null; + } + Class klass = Class.forName(klassName, true, contextClassLoader); + callbackHandler = (CallbackHandler) klass.newInstance(); + } else { + callbackHandler = cbHandler; + } + return null; + } + }); + } catch (PrivilegedActionException ex) { + Throwable cause = ex.getCause(); + throw (LoginException) new LoginException("auth.36").initCause(cause);//$NON-NLS-1$ + } + + if (userProvidedConfig) { + userContext = AccessController.getContext(); + } else if (callbackHandler != null) { + userContext = AccessController.getContext(); + callbackHandler = new ContextedCallbackHandler(callbackHandler); + } + } + + public Subject getSubject() { + if (userProvidedSubject || loggedIn) { + return subject; + } + return null; + } + + /** + * Warning: calling the method more than once may result in undefined + * behaviour if logout() method is not invoked before. + */ + public void login() throws LoginException { + PrivilegedExceptionAction action = new PrivilegedExceptionAction() { + public Void run() throws LoginException { + loginImpl(); + return null; + } + }; + try { + if (userProvidedConfig) { + AccessController.doPrivileged(action, userContext); + } else { + AccessController.doPrivileged(action); + } + } catch (PrivilegedActionException ex) { + throw (LoginException) ex.getException(); + } + } + + /** + * The real implementation of login() method whose calls are wrapped into + * appropriate doPrivileged calls in login(). + */ + private void loginImpl() throws LoginException { + if (subject == null) { + subject = new Subject(); + } + + if (sharedState == null) { + sharedState = new HashMap(); + } + + // PHASE 1: Calling login()-s + Throwable firstProblem = null; + + int[] logged = new int[4]; + int[] total = new int[4]; + + for (Module module : modules) { + try { + // if a module fails during Class.forName(), then it breaks overall + // attempt - see catch() below + module.create(subject, callbackHandler, sharedState); + + if (module.module.login()) { + ++total[module.getFlag()]; + ++logged[module.getFlag()]; + if (module.getFlag() == SUFFICIENT) { + break; + } + } + } catch (Throwable ex) { + if (firstProblem == null) { + firstProblem = ex; + } + if (module.klass == null) { + /* + * an exception occurred during class lookup - overall + * attempt must fail a little trick: increase the REQUIRED's + * number - this will look like a failed REQUIRED module + * later, so overall attempt will fail + */ + ++total[REQUIRED]; + break; + } + ++total[module.getFlag()]; + // something happened after the class was loaded + if (module.getFlag() == REQUISITE) { + // ... and no need to walk down anymore + break; + } + } + } + // end of PHASE1, + + // Let's decide whether we have either overall success or a total failure + boolean fail = true; + + /* + * Note: 'failed[xxx]!=0' is not enough to check. + * + * Use 'logged[xx] != total[xx]' instead. This is because some modules + * might not be counted as 'failed' if an exception occurred during + * preload()/Class.forName()-ing. But, such modules still get counted in + * the total[]. + */ + + // if any REQ* module failed - then it's failure + if (logged[REQUIRED] != total[REQUIRED] || logged[REQUISITE] != total[REQUISITE]) { + // fail = true; + } else { + if (total[REQUIRED] == 0 && total[REQUISITE] == 0) { + // neither REQUIRED nor REQUISITE was configured. + // must have at least one SUFFICIENT or OPTIONAL + if (logged[OPTIONAL] != 0 || logged[SUFFICIENT] != 0) { + fail = false; + } + //else { fail = true; } + } else { + fail = false; + } + } + + int commited[] = new int[4]; + // clear it + total[0] = total[1] = total[2] = total[3] = 0; + if (!fail) { + // PHASE 2: + + for (Module module : modules) { + if (module.klass != null) { + ++total[module.getFlag()]; + try { + module.module.commit(); + ++commited[module.getFlag()]; + } catch (Throwable ex) { + if (firstProblem == null) { + firstProblem = ex; + } + } + } + } + } + + // need to decide once again + fail = true; + if (commited[REQUIRED] != total[REQUIRED] || commited[REQUISITE] != total[REQUISITE]) { + //fail = true; + } else { + if (total[REQUIRED] == 0 && total[REQUISITE] == 0) { + /* + * neither REQUIRED nor REQUISITE was configured. must have at + * least one SUFFICIENT or OPTIONAL + */ + if (commited[OPTIONAL] != 0 || commited[SUFFICIENT] != 0) { + fail = false; + } else { + //fail = true; + } + } else { + fail = false; + } + } + + if (fail) { + // either login() or commit() failed. aborting... + + for (Module module : modules) { + try { + module.module.abort(); + } catch ( /*LoginException*/Throwable ex) { + if (firstProblem == null) { + firstProblem = ex; + } + } + } + if (firstProblem instanceof PrivilegedActionException + && firstProblem.getCause() != null) { + firstProblem = firstProblem.getCause(); + } + if (firstProblem instanceof LoginException) { + throw (LoginException) firstProblem; + } + throw (LoginException) new LoginException("auth.37").initCause(firstProblem); //$NON-NLS-1$ + } + loggedIn = true; + } + + public void logout() throws LoginException { + PrivilegedExceptionAction action = new PrivilegedExceptionAction() { + public Void run() throws LoginException { + logoutImpl(); + return null; + } + }; + try { + if (userProvidedConfig) { + AccessController.doPrivileged(action, userContext); + } else { + AccessController.doPrivileged(action); + } + } catch (PrivilegedActionException ex) { + throw (LoginException) ex.getException(); + } + } + + /** + * The real implementation of logout() method whose calls are wrapped into + * appropriate doPrivileged calls in logout(). + */ + private void logoutImpl() throws LoginException { + if (subject == null) { + throw new LoginException("auth.38"); //$NON-NLS-1$ + } + loggedIn = false; + Throwable firstProblem = null; + int total = 0; + for (Module module : modules) { + try { + module.module.logout(); + ++total; + } catch (Throwable ex) { + if (firstProblem == null) { + firstProblem = ex; + } + } + } + if (firstProblem != null || total == 0) { + if (firstProblem instanceof PrivilegedActionException + && firstProblem.getCause() != null) { + firstProblem = firstProblem.getCause(); + } + if (firstProblem instanceof LoginException) { + throw (LoginException) firstProblem; + } + throw (LoginException) new LoginException("auth.37").initCause(firstProblem); //$NON-NLS-1$ + } + } + + /** + *

A class that servers as a wrapper for the CallbackHandler when we use + * installed Configuration, but not a passed one. See API docs on the + * LoginContext.

+ * + *

Simply invokes the given handler with the given AccessControlContext.

+ */ + private class ContextedCallbackHandler implements CallbackHandler { + private final CallbackHandler hiddenHandlerRef; + + ContextedCallbackHandler(CallbackHandler handler) { + super(); + this.hiddenHandlerRef = handler; + } + + public void handle(final Callback[] callbacks) throws IOException, + UnsupportedCallbackException { + try { + AccessController.doPrivileged(new PrivilegedExceptionAction() { + public Void run() throws IOException, UnsupportedCallbackException { + hiddenHandlerRef.handle(callbacks); + return null; + } + }, userContext); + } catch (PrivilegedActionException ex) { + if (ex.getCause() instanceof UnsupportedCallbackException) { + throw (UnsupportedCallbackException) ex.getCause(); + } + throw (IOException) ex.getCause(); + } + } + } + + /** + * A private class that stores an instantiated LoginModule. + */ + private final class Module { + + // An initial info about the module to be used + AppConfigurationEntry entry; + + // A mapping of LoginModuleControlFlag onto a simple int constant + int flag; + + // The LoginModule itself + LoginModule module; + + // A class of the module + Class klass; + + Module(AppConfigurationEntry entry) { + this.entry = entry; + LoginModuleControlFlag flg = entry.getControlFlag(); + if (flg == LoginModuleControlFlag.OPTIONAL) { + flag = OPTIONAL; + } else if (flg == LoginModuleControlFlag.REQUISITE) { + flag = REQUISITE; + } else if (flg == LoginModuleControlFlag.SUFFICIENT) { + flag = SUFFICIENT; + } else { + flag = REQUIRED; + //if(flg!=LoginModuleControlFlag.REQUIRED) throw new Error() + } + } + + int getFlag() { + return flag; + } + + /** + * Loads class of the LoginModule, instantiates it and then calls + * initialize(). + */ + void create(Subject subject, CallbackHandler callbackHandler, Map sharedState) + throws LoginException { + String klassName = entry.getLoginModuleName(); + if (klass == null) { + try { + klass = Class.forName(klassName, false, contextClassLoader); + } catch (ClassNotFoundException ex) { + throw (LoginException) new LoginException( + "auth.39 " + klassName).initCause(ex); //$NON-NLS-1$ + } + } + + if (module == null) { + try { + module = (LoginModule) klass.newInstance(); + } catch (IllegalAccessException ex) { + throw (LoginException) new LoginException( + "auth.3A " + klassName) //$NON-NLS-1$ + .initCause(ex); + } catch (InstantiationException ex) { + throw (LoginException) new LoginException( + "auth.3A" + klassName) //$NON-NLS-1$ + .initCause(ex); + } + module.initialize(subject, callbackHandler, sharedState, entry.getOptions()); + } + } + } +} diff --git a/src/org/apache/harmony/javax/security/auth/login/LoginException.java b/src/org/apache/harmony/javax/security/auth/login/LoginException.java new file mode 100644 index 0000000..e9ea566 --- /dev/null +++ b/src/org/apache/harmony/javax/security/auth/login/LoginException.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 org.apache.harmony.javax.security.auth.login; + +import java.security.GeneralSecurityException; + +/** + * Base class for exceptions that are thrown when a login error occurs. + */ +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/src/org/apache/harmony/javax/security/auth/spi/LoginModule.java b/src/org/apache/harmony/javax/security/auth/spi/LoginModule.java new file mode 100644 index 0000000..3ed9eb2 --- /dev/null +++ b/src/org/apache/harmony/javax/security/auth/spi/LoginModule.java @@ -0,0 +1,38 @@ +/* + * 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 org.apache.harmony.javax.security.auth.spi; + +import java.util.Map; + +import org.apache.harmony.javax.security.auth.Subject; +import org.apache.harmony.javax.security.auth.callback.CallbackHandler; +import org.apache.harmony.javax.security.auth.login.LoginException; + +public interface LoginModule { + + void initialize(Subject subject, CallbackHandler callbackHandler, + Map sharedState, Map options); + + boolean login() throws LoginException; + + boolean commit() throws LoginException; + + boolean abort() throws LoginException; + + boolean logout() throws LoginException; +} diff --git a/src/org/apache/harmony/javax/security/sasl/AuthenticationException.java b/src/org/apache/harmony/javax/security/sasl/AuthenticationException.java new file mode 100644 index 0000000..38703ef --- /dev/null +++ b/src/org/apache/harmony/javax/security/sasl/AuthenticationException.java @@ -0,0 +1,35 @@ +/* + * 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 org.apache.harmony.javax.security.sasl; + +public class AuthenticationException extends SaslException { + + private static final long serialVersionUID = -3579708765071815007L; + + public AuthenticationException() { + super(); + } + + public AuthenticationException(String detail) { + super(detail); + } + + public AuthenticationException(String detail, Throwable ex) { + super(detail, ex); + } +} diff --git a/src/org/apache/harmony/javax/security/sasl/AuthorizeCallback.java b/src/org/apache/harmony/javax/security/sasl/AuthorizeCallback.java new file mode 100644 index 0000000..2ba90a2 --- /dev/null +++ b/src/org/apache/harmony/javax/security/sasl/AuthorizeCallback.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 org.apache.harmony.javax.security.sasl; + +import java.io.Serializable; +import org.apache.harmony.javax.security.auth.callback.Callback; + +public class AuthorizeCallback implements Callback, Serializable { + + private static final long serialVersionUID = -2353344186490470805L; + + /** + * Serialized field for storing authenticationID. + */ + private final String authenticationID; + + /** + * Serialized field for storing authorizationID. + */ + private final String authorizationID; + + /** + * Serialized field for storing authorizedID. + */ + private String authorizedID; + + /** + * Store authorized Serialized field. + */ + private boolean authorized; + + public AuthorizeCallback(String authnID, String authzID) { + super(); + authenticationID = authnID; + authorizationID = authzID; + authorizedID = authzID; + } + + public String getAuthenticationID() { + return authenticationID; + } + + public String getAuthorizationID() { + return authorizationID; + } + + public String getAuthorizedID() { + return (authorized ? authorizedID : null); + } + + public boolean isAuthorized() { + return authorized; + } + + public void setAuthorized(boolean ok) { + authorized = ok; + } + + public void setAuthorizedID(String id) { + if (id != null) { + authorizedID = id; + } + } +} diff --git a/src/org/apache/harmony/javax/security/sasl/RealmCallback.java b/src/org/apache/harmony/javax/security/sasl/RealmCallback.java new file mode 100644 index 0000000..65b5d15 --- /dev/null +++ b/src/org/apache/harmony/javax/security/sasl/RealmCallback.java @@ -0,0 +1,33 @@ +/* + * 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 org.apache.harmony.javax.security.sasl; + +import org.apache.harmony.javax.security.auth.callback.TextInputCallback; + +public class RealmCallback extends TextInputCallback { + + private static final long serialVersionUID = -4342673378785456908L; + + public RealmCallback(String prompt) { + super(prompt); + } + + public RealmCallback(String prompt, String defaultRealmInfo) { + super(prompt, defaultRealmInfo); + } +} diff --git a/src/org/apache/harmony/javax/security/sasl/RealmChoiceCallback.java b/src/org/apache/harmony/javax/security/sasl/RealmChoiceCallback.java new file mode 100644 index 0000000..079ea07 --- /dev/null +++ b/src/org/apache/harmony/javax/security/sasl/RealmChoiceCallback.java @@ -0,0 +1,30 @@ +/* + * 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 org.apache.harmony.javax.security.sasl; + +import org.apache.harmony.javax.security.auth.callback.ChoiceCallback; + +public class RealmChoiceCallback extends ChoiceCallback { + + private static final long serialVersionUID = -8588141348846281332L; + + public RealmChoiceCallback(String prompt, String[] choices, int defaultChoice, + boolean multiple) { + super(prompt, choices, defaultChoice, multiple); + } +} diff --git a/src/org/apache/harmony/javax/security/sasl/Sasl.java b/src/org/apache/harmony/javax/security/sasl/Sasl.java new file mode 100644 index 0000000..4d827f8 --- /dev/null +++ b/src/org/apache/harmony/javax/security/sasl/Sasl.java @@ -0,0 +1,204 @@ +/* + * 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 org.apache.harmony.javax.security.sasl; + +import java.security.Provider; +import java.security.Security; +import org.apache.harmony.javax.security.auth.callback.CallbackHandler; + + + +import java.util.Collection; +import java.util.Collections; +import java.util.Enumeration; +import java.util.Map; +import java.util.HashSet; +import java.util.Iterator; + +public class Sasl { + // SaslClientFactory service name + private static final String CLIENTFACTORYSRV = "SaslClientFactory"; //$NON-NLS-1$ + + // SaslServerFactory service name + private static final String SERVERFACTORYSRV = "SaslServerFactory"; //$NON-NLS-1$ + + public static final String POLICY_NOPLAINTEXT = "javax.security.sasl.policy.noplaintext"; //$NON-NLS-1$ + + public static final String POLICY_NOACTIVE = "javax.security.sasl.policy.noactive"; //$NON-NLS-1$ + + public static final String POLICY_NODICTIONARY = "javax.security.sasl.policy.nodictionary"; //$NON-NLS-1$ + + public static final String POLICY_NOANONYMOUS = "javax.security.sasl.policy.noanonymous"; //$NON-NLS-1$ + + public static final String POLICY_FORWARD_SECRECY = "javax.security.sasl.policy.forward"; //$NON-NLS-1$ + + public static final String POLICY_PASS_CREDENTIALS = "javax.security.sasl.policy.credentials"; //$NON-NLS-1$ + + public static final String MAX_BUFFER = "javax.security.sasl.maxbuffer"; //$NON-NLS-1$ + + public static final String RAW_SEND_SIZE = "javax.security.sasl.rawsendsize"; //$NON-NLS-1$ + + public static final String REUSE = "javax.security.sasl.reuse"; //$NON-NLS-1$ + + public static final String QOP = "javax.security.sasl.qop"; //$NON-NLS-1$ + + public static final String STRENGTH = "javax.security.sasl.strength"; //$NON-NLS-1$ + + public static final String SERVER_AUTH = "javax.security.sasl.server.authentication"; //$NON-NLS-1$ + + // Default public constructor is overridden + private Sasl() { + super(); + } + + // Forms new instance of factory + private static Object newInstance(String factoryName, Provider prv) throws SaslException { + String msg = "auth.31"; //$NON-NLS-1$ + Object factory; + ClassLoader cl = prv.getClass().getClassLoader(); + if (cl == null) { + cl = ClassLoader.getSystemClassLoader(); + } + try { + factory = (Class.forName(factoryName, true, cl)).newInstance(); + return factory; + } catch (IllegalAccessException e) { + throw new SaslException(msg + factoryName, e); + } catch (ClassNotFoundException e) { + throw new SaslException(msg + factoryName, e); + } catch (InstantiationException e) { + throw new SaslException(msg + factoryName, e); + } + } + + /** + * This method forms the list of SaslClient/SaslServer factories which are + * implemented in used providers + */ + private static Collection findFactories(String service) { + HashSet fact = new HashSet(); + Provider[] pp = Security.getProviders(); + if ((pp == null) || (pp.length == 0)) { + return fact; + } + HashSet props = new HashSet(); + for (int i = 0; i < pp.length; i++) { + String prName = pp[i].getName(); + Enumeration keys = pp[i].keys(); + while (keys.hasMoreElements()) { + String s = (String) keys.nextElement(); + if (s.startsWith(service)) { + String prop = pp[i].getProperty(s); + try { + if (props.add(prName.concat(prop))) { + fact.add(newInstance(prop, pp[i])); + } + } catch (SaslException e) { + // ignore this factory + e.printStackTrace(); + } + } + } + } + return fact; + } + + @SuppressWarnings("unchecked") + public static Enumeration getSaslClientFactories() { + Collection res = (Collection) findFactories(CLIENTFACTORYSRV); + return Collections.enumeration(res); + + } + + @SuppressWarnings("unchecked") + public static Enumeration getSaslServerFactories() { + Collection res = (Collection) findFactories(SERVERFACTORYSRV); + return Collections.enumeration(res); + } + + public static SaslServer createSaslServer(String mechanism, String protocol, + String serverName, Map prop, CallbackHandler cbh) throws SaslException { + if (mechanism == null) { + throw new NullPointerException("auth.32"); //$NON-NLS-1$ + } + Collection res = findFactories(SERVERFACTORYSRV); + if (res.isEmpty()) { + return null; + } + + Iterator iter = res.iterator(); + while (iter.hasNext()) { + SaslServerFactory fact = (SaslServerFactory) iter.next(); + String[] mech = fact.getMechanismNames(null); + boolean is = false; + if (mech != null) { + for (int j = 0; j < mech.length; j++) { + if (mech[j].equals(mechanism)) { + is = true; + break; + } + } + } + if (is) { + SaslServer saslS = fact.createSaslServer(mechanism, protocol, serverName, prop, + cbh); + if (saslS != null) { + return saslS; + } + } + } + return null; + } + + public static SaslClient createSaslClient(String[] mechanisms, String authanticationID, + String protocol, String serverName, Map prop, CallbackHandler cbh) + throws SaslException { + if (mechanisms == null) { + throw new NullPointerException("auth.33"); //$NON-NLS-1$ + } + Collection res = findFactories(CLIENTFACTORYSRV); + if (res.isEmpty()) { + return null; + } + + Iterator iter = res.iterator(); + while (iter.hasNext()) { + SaslClientFactory fact = (SaslClientFactory) iter.next(); + String[] mech = fact.getMechanismNames(null); + boolean is = false; + if (mech != null) { + for (int j = 0; j < mech.length; j++) { + for (int n = 0; n < mechanisms.length; n++) { + if (mech[j].equals(mechanisms[n])) { + is = true; + break; + } + } + } + } + if (is) { + SaslClient saslC = fact.createSaslClient(mechanisms, authanticationID, + protocol, serverName, prop, cbh); + if (saslC != null) { + return saslC; + } + } + } + return null; + } +} diff --git a/src/org/apache/harmony/javax/security/sasl/SaslClient.java b/src/org/apache/harmony/javax/security/sasl/SaslClient.java new file mode 100644 index 0000000..e07ff53 --- /dev/null +++ b/src/org/apache/harmony/javax/security/sasl/SaslClient.java @@ -0,0 +1,37 @@ +/* + * 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 org.apache.harmony.javax.security.sasl; + +public interface SaslClient { + + void dispose() throws SaslException; + + byte[] evaluateChallenge(byte[] challenge) throws SaslException; + + String getMechanismName(); + + Object getNegotiatedProperty(String propName); + + boolean hasInitialResponse(); + + boolean isComplete(); + + byte[] unwrap(byte[] incoming, int offset, int len) throws SaslException; + + byte[] wrap(byte[] outgoing, int offset, int len) throws SaslException; +} diff --git a/src/org/apache/harmony/javax/security/sasl/SaslClientFactory.java b/src/org/apache/harmony/javax/security/sasl/SaslClientFactory.java new file mode 100644 index 0000000..e567ed3 --- /dev/null +++ b/src/org/apache/harmony/javax/security/sasl/SaslClientFactory.java @@ -0,0 +1,30 @@ +/* + * 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 org.apache.harmony.javax.security.sasl; + +import java.util.Map; +import org.apache.harmony.javax.security.auth.callback.CallbackHandler; + +public interface SaslClientFactory { + + SaslClient createSaslClient(String[] mechanisms, String authorizationId, String protocol, + String serverName, Map props, CallbackHandler cbh) throws SaslException; + + String[] getMechanismNames(Map props); + +} diff --git a/src/org/apache/harmony/javax/security/sasl/SaslException.java b/src/org/apache/harmony/javax/security/sasl/SaslException.java new file mode 100644 index 0000000..1ab7b12 --- /dev/null +++ b/src/org/apache/harmony/javax/security/sasl/SaslException.java @@ -0,0 +1,69 @@ +/* + * 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 org.apache.harmony.javax.security.sasl; + +import java.io.IOException; + +public class SaslException extends IOException { + + private static final long serialVersionUID = 4579784287983423626L; + + /** + * Serialized field for storing initial cause + */ + private Throwable _exception; + + public SaslException() { + super(); + } + + public SaslException(String detail) { + super(detail); + } + + public SaslException(String detail, Throwable ex) { + super(detail); + if (ex != null) { + super.initCause(ex); + _exception = ex; + } + } + + @Override + public Throwable getCause() { + return _exception; + } + + @Override + public Throwable initCause(Throwable cause) { + super.initCause(cause); + _exception = cause; + return this; + } + + @Override + public String toString() { + if (_exception == null) { + return super.toString(); + } + StringBuilder sb = new StringBuilder(super.toString()); + sb.append(", caused by: "); //$NON-NLS-1$ + sb.append(_exception.toString()); + return sb.toString(); + } +} diff --git a/src/org/apache/harmony/javax/security/sasl/SaslServer.java b/src/org/apache/harmony/javax/security/sasl/SaslServer.java new file mode 100644 index 0000000..f057a4b --- /dev/null +++ b/src/org/apache/harmony/javax/security/sasl/SaslServer.java @@ -0,0 +1,37 @@ +/* + * 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 org.apache.harmony.javax.security.sasl; + +public interface SaslServer { + + void dispose() throws SaslException; + + byte[] evaluateResponse(byte[] response) throws SaslException; + + String getAuthorizationID(); + + String getMechanismName(); + + Object getNegotiatedProperty(String propName); + + boolean isComplete(); + + byte[] unwrap(byte[] incoming, int offset, int len) throws SaslException; + + byte[] wrap(byte[] outgoing, int offset, int len) throws SaslException; +} diff --git a/src/org/apache/harmony/javax/security/sasl/SaslServerFactory.java b/src/org/apache/harmony/javax/security/sasl/SaslServerFactory.java new file mode 100644 index 0000000..d59530e --- /dev/null +++ b/src/org/apache/harmony/javax/security/sasl/SaslServerFactory.java @@ -0,0 +1,30 @@ +/* + * 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 org.apache.harmony.javax.security.sasl; + +import java.util.Map; +import org.apache.harmony.javax.security.auth.callback.CallbackHandler; + +public interface SaslServerFactory { + + SaslServer createSaslServer(String mechanisms, String protocol, String serverName, + Map props, CallbackHandler cbh) throws SaslException; + + String[] getMechanismNames(Map props); + +} diff --git a/src/org/apache/qpid/management/common/sasl/CRAMMD5HashedSaslClientFactory.java b/src/org/apache/qpid/management/common/sasl/CRAMMD5HashedSaslClientFactory.java new file mode 100644 index 0000000..5c33e40 --- /dev/null +++ b/src/org/apache/qpid/management/common/sasl/CRAMMD5HashedSaslClientFactory.java @@ -0,0 +1,59 @@ +/* + * + * 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 org.apache.qpid.management.common.sasl; + +import org.apache.harmony.javax.security.auth.callback.CallbackHandler; +import de.measite.smack.Sasl; +import org.apache.harmony.javax.security.sasl.SaslClient; +import org.apache.harmony.javax.security.sasl.SaslClientFactory; +import org.apache.harmony.javax.security.sasl.SaslException; +import java.util.Map; + +public class CRAMMD5HashedSaslClientFactory implements SaslClientFactory +{ + /** The name of this mechanism */ + public static final String MECHANISM = "CRAM-MD5-HASHED"; + + public SaslClient createSaslClient(String[] mechanisms, String authorizationId, String protocol, + String serverName, Map props, CallbackHandler cbh) + throws SaslException + { + for (int i = 0; i < mechanisms.length; i++) + { + if (mechanisms[i].equals(MECHANISM)) + { + if (cbh == null) + { + throw new SaslException("CallbackHandler must not be null"); + } + + String[] mechs = {"CRAM-MD5"}; + return Sasl.createSaslClient(mechs, authorizationId, protocol, serverName, props, cbh); + } + } + return null; + } + + public String[] getMechanismNames(Map props) + { + return new String[]{MECHANISM}; + } +} diff --git a/src/org/apache/qpid/management/common/sasl/ClientSaslFactory.java b/src/org/apache/qpid/management/common/sasl/ClientSaslFactory.java new file mode 100644 index 0000000..19162d8 --- /dev/null +++ b/src/org/apache/qpid/management/common/sasl/ClientSaslFactory.java @@ -0,0 +1,53 @@ +/* + * + * 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 org.apache.qpid.management.common.sasl; + +import org.apache.harmony.javax.security.auth.callback.CallbackHandler; +import org.apache.harmony.javax.security.sasl.SaslClient; +import org.apache.harmony.javax.security.sasl.SaslClientFactory; +import org.apache.harmony.javax.security.sasl.SaslException; +import java.util.Map; + +public class ClientSaslFactory implements SaslClientFactory +{ + public SaslClient createSaslClient(String[] mechs, String authorizationId, String protocol, + String serverName, Map props, CallbackHandler cbh) + throws SaslException + { + for (int i = 0; i < mechs.length; i++) + { + if (mechs[i].equals("PLAIN")) + { + return new PlainSaslClient(authorizationId, cbh); + } + } + return null; + } + + /** + * Simple-minded implementation that ignores props + */ + public String[] getMechanismNames(Map props) + { + return new String[]{"PLAIN"}; + } + +} diff --git a/src/org/apache/qpid/management/common/sasl/Constants.java b/src/org/apache/qpid/management/common/sasl/Constants.java new file mode 100644 index 0000000..31010ba --- /dev/null +++ b/src/org/apache/qpid/management/common/sasl/Constants.java @@ -0,0 +1,33 @@ +/* + * + * 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 org.apache.qpid.management.common.sasl; + +public class Constants +{ + + public final static String MECH_CRAMMD5 = "CRAM-MD5"; + public final static String MECH_PLAIN = "PLAIN"; + public final static String SASL_CRAMMD5 = "SASL/CRAM-MD5"; + public final static String SASL_PLAIN = "SASL/PLAIN"; + +} + diff --git a/src/org/apache/qpid/management/common/sasl/JCAProvider.java b/src/org/apache/qpid/management/common/sasl/JCAProvider.java new file mode 100644 index 0000000..5793dae --- /dev/null +++ b/src/org/apache/qpid/management/common/sasl/JCAProvider.java @@ -0,0 +1,55 @@ +/* + * + * 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 org.apache.qpid.management.common.sasl; + +import org.apache.harmony.javax.security.sasl.SaslClientFactory; +import java.security.Provider; +import java.util.Map; + +public class JCAProvider extends Provider +{ + private static final long serialVersionUID = 1L; + + /** + * Creates the security provider with a map from SASL mechanisms to implementing factories. + * + * @param providerMap The map from SASL mechanims to implementing factory classes. + */ + public JCAProvider(Map> providerMap) + { + super("AMQSASLProvider", 1.0, "A JCA provider that registers all " + + "AMQ SASL providers that want to be registered"); + register(providerMap); + } + + /** + * Registers client factory classes for a map of mechanism names to client factory classes. + * + * @param providerMap The map from SASL mechanims to implementing factory classes. + */ + private void register(Map> providerMap) + { + for (Map.Entry> me : providerMap.entrySet()) + { + put("SaslClientFactory." + me.getKey(), me.getValue().getName()); + } + } +} diff --git a/src/org/apache/qpid/management/common/sasl/PlainSaslClient.java b/src/org/apache/qpid/management/common/sasl/PlainSaslClient.java new file mode 100644 index 0000000..99a1d43 --- /dev/null +++ b/src/org/apache/qpid/management/common/sasl/PlainSaslClient.java @@ -0,0 +1,210 @@ +/* + * + * 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 org.apache.qpid.management.common.sasl; + +import org.apache.harmony.javax.security.auth.callback.Callback; +import org.apache.harmony.javax.security.auth.callback.CallbackHandler; +import org.apache.harmony.javax.security.auth.callback.NameCallback; +import org.apache.harmony.javax.security.auth.callback.PasswordCallback; +import org.apache.harmony.javax.security.auth.callback.UnsupportedCallbackException; +import de.measite.smack.Sasl; +import org.apache.harmony.javax.security.sasl.SaslClient; +import org.apache.harmony.javax.security.sasl.SaslException; +import java.io.IOException; +import java.io.UnsupportedEncodingException; + +public class PlainSaslClient implements SaslClient +{ + + private boolean completed; + private CallbackHandler cbh; + private String authorizationID; + private String authenticationID; + private byte password[]; + private static byte SEPARATOR = 0; + + public PlainSaslClient(String authorizationID, CallbackHandler cbh) throws SaslException + { + completed = false; + this.cbh = cbh; + Object[] userInfo = getUserInfo(); + this.authorizationID = authorizationID; + this.authenticationID = (String) userInfo[0]; + this.password = (byte[]) userInfo[1]; + if (authenticationID == null || password == null) + { + throw new SaslException("PLAIN: authenticationID and password must be specified"); + } + } + + public byte[] evaluateChallenge(byte[] challenge) throws SaslException + { + if (completed) + { + throw new IllegalStateException("PLAIN: authentication already " + + "completed"); + } + completed = true; + try + { + byte authzid[] = + authorizationID == null ? null : authorizationID.getBytes("UTF8"); + byte authnid[] = authenticationID.getBytes("UTF8"); + byte response[] = + new byte[ + password.length + + authnid.length + + 2 + // SEPARATOR + (authzid != null ? authzid.length : 0) + ]; + int size = 0; + if (authzid != null) { + System.arraycopy(authzid, 0, response, 0, authzid.length); + size = authzid.length; + } + response[size++] = SEPARATOR; + System.arraycopy(authnid, 0, response, size, authnid.length); + size += authnid.length; + response[size++] = SEPARATOR; + System.arraycopy(password, 0, response, size, password.length); + clearPassword(); + return response; + } catch (UnsupportedEncodingException e) { + throw new SaslException("PLAIN: Cannot get UTF-8 encoding of ids", + e); + } + } + + public String getMechanismName() + { + return "PLAIN"; + } + + public boolean hasInitialResponse() + { + return true; + } + + public boolean isComplete() + { + return completed; + } + + public byte[] unwrap(byte[] incoming, int offset, int len) throws SaslException + { + if (completed) { + throw new IllegalStateException("PLAIN: this mechanism supports " + + "neither integrity nor privacy"); + } else { + throw new IllegalStateException("PLAIN: authentication not " + + "completed"); + } + } + + public byte[] wrap(byte[] outgoing, int offset, int len) throws SaslException + { + if (completed) + { + throw new IllegalStateException("PLAIN: this mechanism supports " + + "neither integrity nor privacy"); + } + else + { + throw new IllegalStateException("PLAIN: authentication not " + + "completed"); + } + } + + public Object getNegotiatedProperty(String propName) + { + if (completed) + { + if (propName.equals(Sasl.QOP)) + { + return "auth"; + } + else + { + return null; + } + } + else + { + throw new IllegalStateException("PLAIN: authentication not " + + "completed"); + } + } + + private void clearPassword() + { + if (password != null) + { + for (int i = 0 ; i < password.length ; i++) + { + password[i] = 0; + } + password = null; + } + } + + public void dispose() throws SaslException + { + clearPassword(); + } + + protected void finalize() + { + clearPassword(); + } + + private Object[] getUserInfo() throws SaslException + { + try + { + final String userPrompt = "PLAIN authentication id: "; + final String pwPrompt = "PLAIN password: "; + NameCallback nameCb = new NameCallback(userPrompt); + PasswordCallback passwordCb = new PasswordCallback(pwPrompt, false); + cbh.handle(new Callback[] { nameCb, passwordCb }); + String userid = nameCb.getName(); + char pwchars[] = passwordCb.getPassword(); + byte pwbytes[]; + if (pwchars != null) + { + pwbytes = (new String(pwchars)).getBytes("UTF8"); + passwordCb.clearPassword(); + } + else + { + pwbytes = null; + } + return (new Object[] { userid, pwbytes }); + } + catch (IOException e) + { + throw new SaslException("Cannot get password", e); + } + catch (UnsupportedCallbackException e) + { + throw new SaslException("Cannot get userid/password", e); + } + } +} diff --git a/src/org/apache/qpid/management/common/sasl/SaslProvider.java b/src/org/apache/qpid/management/common/sasl/SaslProvider.java new file mode 100644 index 0000000..1eb44e3 --- /dev/null +++ b/src/org/apache/qpid/management/common/sasl/SaslProvider.java @@ -0,0 +1,35 @@ +/* + * + * 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 org.apache.qpid.management.common.sasl; + +import java.security.Provider; + +public class SaslProvider extends Provider +{ + private static final long serialVersionUID = -6978096016899676466L; + + public SaslProvider() + { + super("SaslClientFactory", 1.0, "SASL PLAIN CLIENT MECHANISM"); + put("SaslClientFactory.PLAIN", "ClientSaslFactory"); + } + +} diff --git a/src/org/apache/qpid/management/common/sasl/UserPasswordCallbackHandler.java b/src/org/apache/qpid/management/common/sasl/UserPasswordCallbackHandler.java new file mode 100644 index 0000000..a7886cf --- /dev/null +++ b/src/org/apache/qpid/management/common/sasl/UserPasswordCallbackHandler.java @@ -0,0 +1,77 @@ +/* + * 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 org.apache.qpid.management.common.sasl; + +import org.apache.harmony.javax.security.auth.callback.Callback; +import org.apache.harmony.javax.security.auth.callback.CallbackHandler; +import org.apache.harmony.javax.security.auth.callback.NameCallback; +import org.apache.harmony.javax.security.auth.callback.PasswordCallback; +import org.apache.harmony.javax.security.auth.callback.UnsupportedCallbackException; +import java.io.IOException; + +public class UserPasswordCallbackHandler implements CallbackHandler +{ + private String user; + private char[] pwchars; + + public UserPasswordCallbackHandler(String user, String password) + { + this.user = user; + this.pwchars = password.toCharArray(); + } + + public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException + { + for (int i = 0; i < callbacks.length; i++) + { + if (callbacks[i] instanceof NameCallback) + { + NameCallback ncb = (NameCallback) callbacks[i]; + ncb.setName(user); + } + else if (callbacks[i] instanceof PasswordCallback) + { + PasswordCallback pcb = (PasswordCallback) callbacks[i]; + pcb.setPassword(pwchars); + } + else + { + throw new UnsupportedCallbackException(callbacks[i]); + } + } + } + + private void clearPassword() + { + if (pwchars != null) + { + for (int i = 0 ; i < pwchars.length ; i++) + { + pwchars[i] = 0; + } + pwchars = null; + } + } + + protected void finalize() + { + clearPassword(); + } +} diff --git a/src/org/apache/qpid/management/common/sasl/UsernameHashedPasswordCallbackHandler.java b/src/org/apache/qpid/management/common/sasl/UsernameHashedPasswordCallbackHandler.java new file mode 100644 index 0000000..54d7374 --- /dev/null +++ b/src/org/apache/qpid/management/common/sasl/UsernameHashedPasswordCallbackHandler.java @@ -0,0 +1,107 @@ +/* + * + * 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 org.apache.qpid.management.common.sasl; + +import org.apache.harmony.javax.security.auth.callback.Callback; +import org.apache.harmony.javax.security.auth.callback.CallbackHandler; +import org.apache.harmony.javax.security.auth.callback.NameCallback; +import org.apache.harmony.javax.security.auth.callback.PasswordCallback; +import org.apache.harmony.javax.security.auth.callback.UnsupportedCallbackException; +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; + + +public class UsernameHashedPasswordCallbackHandler implements CallbackHandler +{ + private String user; + private char[] pwchars; + + public UsernameHashedPasswordCallbackHandler(String user, String password) throws Exception + { + this.user = user; + this.pwchars = getHash(password); + } + + public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException + { + for (int i = 0; i < callbacks.length; i++) + { + if (callbacks[i] instanceof NameCallback) + { + NameCallback ncb = (NameCallback) callbacks[i]; + ncb.setName(user); + } + else if (callbacks[i] instanceof PasswordCallback) + { + PasswordCallback pcb = (PasswordCallback) callbacks[i]; + pcb.setPassword(pwchars); + } + else + { + throw new UnsupportedCallbackException(callbacks[i]); + } + } + } + + + private void clearPassword() + { + if (pwchars != null) + { + for (int i = 0 ; i < pwchars.length ; i++) + { + pwchars[i] = 0; + } + pwchars = null; + } + } + + protected void finalize() + { + clearPassword(); + } + + public static char[] getHash(String text) throws NoSuchAlgorithmException, UnsupportedEncodingException + { + byte[] data = text.getBytes("utf-8"); + + MessageDigest md = MessageDigest.getInstance("MD5"); + + for (byte b : data) + { + md.update(b); + } + + byte[] digest = md.digest(); + + char[] hash = new char[digest.length ]; + + int index = 0; + for (byte b : digest) + { + hash[index++] = (char) b; + } + + return hash; + } +} -- cgit v1.2.3