diff options
| author | Martin Ritchie <ritchiem@apache.org> | 2007-04-05 09:29:22 +0000 |
|---|---|---|
| committer | Martin Ritchie <ritchiem@apache.org> | 2007-04-05 09:29:22 +0000 |
| commit | 11e02d37fedbb0bb847bcfe2f7929416340cd98b (patch) | |
| tree | 61435475e8f9d47c2c3546253f4360c1b95d9389 /java/client/src | |
| parent | 2057518593b06f4bbb3d99e817332f784f786c6e (diff) | |
| download | qpid-python-11e02d37fedbb0bb847bcfe2f7929416340cd98b.tar.gz | |
QPID-414 : Addition of CRAM-MD5-HASHED authentication. Same as CRAM-MD5 but the client uses the hash of the password rather than the original password. This allows the broker to store the hash not the original password.
Added initial tool for generation passwords.
Broker:
Renamed MD5PasswordFilePrincipalDatabase.java to Base64MD5PasswordFilePrincipalDatabase.java as that more accurately represents the file contents.
PlainPasswordVhostFilePrincipalDatabase.java - import tidy up
PrincipalDatabaseAuthenticationManager.java - Changed to add our SASL providers at the start of the SASL list.
CRAMMD5Hashed* - New SASL mechanism that delegates to CRAM-MD5 but understands that the password to use is the hash of the users password.
JCAProvider - Removed the addProvider() line as this is done after the construction in PrincipalDatabaseAuthenticationManager.
PlainSaslServerFactory - White Space
Passwd.java - New util stub for managing passwords ala htpasswd.
Client
Added CRAM-MD5-HASHED to CallbackHandlerRegistry
Added ClientFactory for CRAMMD5Hashed that returns the first CRAM-MD5 SaslClient.
DynamicSaslRegistrar.java - Tidied imports added new JCAProviders at the start of the Sasl lists.
DynamicSaslRegistrar.properties - Added CRAM-MD5-HASHED handler.
JCAProvider.java - as with broker stopped JCAProvider.java adding itself as the DynamicSaslRegistrar.java does this on the client.
UsernameHashedPasswordCallbackHandler.java - New callback handler that is used by CRAM-MD5-HASHED. It hashes the client's password and uses that in the CRAM-MD5 algorithm.
git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/branches/M2@525777 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'java/client/src')
6 files changed, 190 insertions, 22 deletions
diff --git a/java/client/src/main/java/org/apache/qpid/client/security/CallbackHandlerRegistry.properties b/java/client/src/main/java/org/apache/qpid/client/security/CallbackHandlerRegistry.properties index 50e6f1efaa..89ee8337f8 100644 --- a/java/client/src/main/java/org/apache/qpid/client/security/CallbackHandlerRegistry.properties +++ b/java/client/src/main/java/org/apache/qpid/client/security/CallbackHandlerRegistry.properties @@ -16,5 +16,6 @@ # specific language governing permissions and limitations # under the License. # +CallbackHandler.CRAM-MD5-HASHED=org.apache.qpid.client.security.UsernameHashedPasswordCallbackHandler CallbackHandler.CRAM-MD5=org.apache.qpid.client.security.UsernamePasswordCallbackHandler CallbackHandler.PLAIN=org.apache.qpid.client.security.UsernamePasswordCallbackHandler diff --git a/java/client/src/main/java/org/apache/qpid/client/security/DynamicSaslRegistrar.java b/java/client/src/main/java/org/apache/qpid/client/security/DynamicSaslRegistrar.java index f8ee22a5d9..04db8044de 100644 --- a/java/client/src/main/java/org/apache/qpid/client/security/DynamicSaslRegistrar.java +++ b/java/client/src/main/java/org/apache/qpid/client/security/DynamicSaslRegistrar.java @@ -20,10 +20,6 @@ */ package org.apache.qpid.client.security; -import java.io.BufferedInputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.security.Security; @@ -34,6 +30,7 @@ import java.util.TreeMap; import javax.security.sasl.SaslClientFactory; + import org.apache.log4j.Logger; import org.apache.qpid.util.FileUtils; @@ -50,14 +47,11 @@ import org.apache.qpid.util.FileUtils; * mechanism=fully.qualified.class.name * </pre> * - * <p/>Where mechanism is an IANA-registered mechanism name and the fully qualified class name refers to a - * class that implements javax.security.sasl.SaslClientFactory and provides the specified mechanism. + * <p/>Where mechanism is an IANA-registered mechanism name and the fully qualified class name refers to a class that + * implements javax.security.sasl.SaslClientFactory and provides the specified mechanism. * - * <p><table id="crc"><caption>CRC Card</caption> - * <tr><th> Responsibilities <th> Collaborations - * <tr><td> Parse SASL mechanism properties. - * <tr><td> Create and register security provider for SASL mechanisms. - * </table> + * <p><table id="crc"><caption>CRC Card</caption> <tr><th> Responsibilities <th> Collaborations <tr><td> Parse SASL + * mechanism properties. <tr><td> Create and register security provider for SASL mechanisms. </table> */ public class DynamicSaslRegistrar { @@ -69,10 +63,7 @@ public class DynamicSaslRegistrar /** The default name of the SASL properties file resource. */ public static final String DEFAULT_RESOURCE_NAME = "org/apache/qpid/client/security/DynamicSaslRegistrar.properties"; - /** - * Reads the properties file, and creates a dynamic security provider to register the SASL implementations - * with. - */ + /** Reads the properties file, and creates a dynamic security provider to register the SASL implementations with. */ public static void registerSaslProviders() { _logger.debug("public static void registerSaslProviders(): called"); @@ -80,8 +71,8 @@ public class DynamicSaslRegistrar // Open the SASL properties file, using the default name is one is not specified. String filename = System.getProperty(FILE_PROPERTY); InputStream is = - FileUtils.openFileOrDefaultResource(filename, DEFAULT_RESOURCE_NAME, - DynamicSaslRegistrar.class.getClassLoader()); + FileUtils.openFileOrDefaultResource(filename, DEFAULT_RESOURCE_NAME, + DynamicSaslRegistrar.class.getClassLoader()); try { @@ -94,7 +85,7 @@ public class DynamicSaslRegistrar if (factories.size() > 0) { - Security.addProvider(new JCAProvider(factories)); + Security.insertProviderAt(new JCAProvider(factories), 0); _logger.debug("Dynamic SASL provider added as a security provider"); } } @@ -170,15 +161,15 @@ public class DynamicSaslRegistrar * @return A map from SASL mechanism names to implementing client factory classes. * * @todo Why tree map here? Do really want mechanisms in alphabetical order? Seems more likely that the declared - * order of the mechanisms is intended to be preserved, so that they are registered in the declared order - * of preference. Consider LinkedHashMap instead. + * order of the mechanisms is intended to be preserved, so that they are registered in the declared order of + * preference. Consider LinkedHashMap instead. */ private static Map<String, Class<? extends SaslClientFactory>> parseProperties(Properties props) { Enumeration e = props.propertyNames(); TreeMap<String, Class<? extends SaslClientFactory>> factoriesToRegister = - new TreeMap<String, Class<? extends SaslClientFactory>>(); + new TreeMap<String, Class<? extends SaslClientFactory>>(); while (e.hasMoreElements()) { diff --git a/java/client/src/main/java/org/apache/qpid/client/security/DynamicSaslRegistrar.properties b/java/client/src/main/java/org/apache/qpid/client/security/DynamicSaslRegistrar.properties index c2a7d7928c..1bff43142b 100644 --- a/java/client/src/main/java/org/apache/qpid/client/security/DynamicSaslRegistrar.properties +++ b/java/client/src/main/java/org/apache/qpid/client/security/DynamicSaslRegistrar.properties @@ -17,3 +17,4 @@ # under the License. # AMQPLAIN=org.apache.qpid.client.security.amqplain.AmqPlainSaslClientFactory +CRAM-MD5-HASHED=org.apache.qpid.client.security.crammd5hashed.CRAMMD5HashedSaslClientFactory diff --git a/java/client/src/main/java/org/apache/qpid/client/security/JCAProvider.java b/java/client/src/main/java/org/apache/qpid/client/security/JCAProvider.java index 2fa8dcddde..5bf120454e 100644 --- a/java/client/src/main/java/org/apache/qpid/client/security/JCAProvider.java +++ b/java/client/src/main/java/org/apache/qpid/client/security/JCAProvider.java @@ -52,7 +52,7 @@ public class JCAProvider extends Provider super("AMQSASLProvider", 1.0, "A JCA provider that registers all " + "AMQ SASL providers that want to be registered"); register(providerMap); - Security.addProvider(this); +// Security.addProvider(this); } /** diff --git a/java/client/src/main/java/org/apache/qpid/client/security/UsernameHashedPasswordCallbackHandler.java b/java/client/src/main/java/org/apache/qpid/client/security/UsernameHashedPasswordCallbackHandler.java new file mode 100644 index 0000000000..4504498308 --- /dev/null +++ b/java/client/src/main/java/org/apache/qpid/client/security/UsernameHashedPasswordCallbackHandler.java @@ -0,0 +1,103 @@ +/* + * + * 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.client.security; + +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; + +import javax.security.auth.callback.Callback; +import javax.security.auth.callback.NameCallback; +import javax.security.auth.callback.PasswordCallback; +import javax.security.auth.callback.UnsupportedCallbackException; +import javax.security.sasl.RealmCallback; + +import org.apache.qpid.client.protocol.AMQProtocolSession; +import org.apache.log4j.Logger; +import com.sun.crypto.provider.HmacMD5; + +public class UsernameHashedPasswordCallbackHandler implements AMQCallbackHandler +{ + private static final Logger _logger = Logger.getLogger(UsernameHashedPasswordCallbackHandler.class); + + + private AMQProtocolSession _protocolSession; + + public void initialise(AMQProtocolSession protocolSession) + { + _protocolSession = protocolSession; + } + + public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException + { + for (int i = 0; i < callbacks.length; i++) + { + Callback cb = callbacks[i]; + if (cb instanceof NameCallback) + { + ((NameCallback) cb).setName(_protocolSession.getUsername()); + } + else if (cb instanceof PasswordCallback) + { + + try + { + ((PasswordCallback) cb).setPassword(getHash(_protocolSession.getPassword())); + } + catch (Exception e) + { + throw new UnsupportedCallbackException(cb); + } + } + else + { + throw new UnsupportedCallbackException(cb); + } + } + } + + private 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 + 1]; + + int index = 0; + for (byte b : digest) + { + index++; + hash[index] = (char) b; + } + + return hash; + } +} diff --git a/java/client/src/main/java/org/apache/qpid/client/security/crammd5hashed/CRAMMD5HashedSaslClientFactory.java b/java/client/src/main/java/org/apache/qpid/client/security/crammd5hashed/CRAMMD5HashedSaslClientFactory.java new file mode 100644 index 0000000000..22bb1ac156 --- /dev/null +++ b/java/client/src/main/java/org/apache/qpid/client/security/crammd5hashed/CRAMMD5HashedSaslClientFactory.java @@ -0,0 +1,72 @@ +/* + * 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.client.security.crammd5hashed; + +import org.apache.qpid.client.security.amqplain.AmqPlainSaslClient; + +import javax.security.sasl.SaslClientFactory; +import javax.security.sasl.SaslClient; +import javax.security.sasl.SaslException; +import javax.security.sasl.Sasl; +import javax.security.auth.callback.CallbackHandler; +import java.util.Map; +import java.security.Security; + +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<String, ?> 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) + { + if (props != null) + { + if (props.containsKey(Sasl.POLICY_NOPLAINTEXT) || + props.containsKey(Sasl.POLICY_NODICTIONARY) || + props.containsKey(Sasl.POLICY_NOACTIVE)) + { + // returned array must be non null according to interface documentation + return new String[0]; + } + } + + return new String[]{MECHANISM}; + } +} |
