summaryrefslogtreecommitdiff
path: root/java
diff options
context:
space:
mode:
Diffstat (limited to 'java')
-rw-r--r--java/broker/distribution/src/main/assembly/broker-bin.xml6
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/security/Passwd.java81
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/security/auth/database/Base64MD5PasswordFilePrincipalDatabase.java (renamed from java/broker/src/main/java/org/apache/qpid/server/security/auth/database/MD5PasswordFilePrincipalDatabase.java)50
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainPasswordVhostFilePrincipalDatabase.java12
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/PrincipalDatabaseAuthenticationManager.java17
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/JCAProvider.java2
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5HashedInitialiser.java50
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5HashedSaslServer.java105
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5HashedServerFactory.java61
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/plain/PlainSaslServerFactory.java2
-rw-r--r--java/client/src/main/java/org/apache/qpid/client/security/CallbackHandlerRegistry.properties1
-rw-r--r--java/client/src/main/java/org/apache/qpid/client/security/DynamicSaslRegistrar.java33
-rw-r--r--java/client/src/main/java/org/apache/qpid/client/security/DynamicSaslRegistrar.properties1
-rw-r--r--java/client/src/main/java/org/apache/qpid/client/security/JCAProvider.java2
-rw-r--r--java/client/src/main/java/org/apache/qpid/client/security/UsernameHashedPasswordCallbackHandler.java103
-rw-r--r--java/client/src/main/java/org/apache/qpid/client/security/crammd5hashed/CRAMMD5HashedSaslClientFactory.java72
16 files changed, 541 insertions, 57 deletions
diff --git a/java/broker/distribution/src/main/assembly/broker-bin.xml b/java/broker/distribution/src/main/assembly/broker-bin.xml
index 4a7343660d..bc2a956c54 100644
--- a/java/broker/distribution/src/main/assembly/broker-bin.xml
+++ b/java/broker/distribution/src/main/assembly/broker-bin.xml
@@ -108,6 +108,12 @@
<fileMode>473</fileMode>
</file>
<file>
+ <source>../bin/passwd</source>
+ <outputDirectory>qpid-${qpid.version}/bin</outputDirectory>
+ <destName>passwd</destName>
+ <fileMode>473</fileMode>
+ </file>
+ <file>
<source>../bin/qpid-server</source>
<outputDirectory>qpid-${qpid.version}/bin</outputDirectory>
<destName>qpid-server</destName>
diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/Passwd.java b/java/broker/src/main/java/org/apache/qpid/server/security/Passwd.java
new file mode 100644
index 0000000000..f9e093dba7
--- /dev/null
+++ b/java/broker/src/main/java/org/apache/qpid/server/security/Passwd.java
@@ -0,0 +1,81 @@
+/*
+ * 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.server.security;
+
+import org.apache.commons.codec.binary.Base64;
+
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.security.DigestException;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.PrintStream;
+
+public class Passwd
+{
+ public static void main(String args[]) throws NoSuchAlgorithmException, DigestException, IOException
+ {
+ if (args.length != 2)
+ {
+ System.out.println("Passwd <username> <password>");
+ System.exit(0);
+ }
+
+ byte[] data = args[1].getBytes("utf-8");
+
+ MessageDigest md = MessageDigest.getInstance("MD5");
+
+ for (byte b : data)
+ {
+ md.update(b);
+ }
+
+ byte[] digest = md.digest();
+
+ Base64 b64 = new Base64();
+
+ byte[] encoded = b64.encode(digest);
+
+ output(args[0], encoded);
+ }
+
+ private static void output(String user, byte[] encoded) throws IOException
+ {
+
+// File passwdFile = new File("qpid.passwd");
+
+ PrintStream ps = new PrintStream(System.out);
+
+ user += ":";
+ ps.write(user.getBytes("utf-8"));
+
+ for (byte b : encoded)
+ {
+ ps.write(b);
+ }
+
+ ps.println();
+
+ ps.flush();
+ ps.close();
+ }
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/MD5PasswordFilePrincipalDatabase.java b/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/Base64MD5PasswordFilePrincipalDatabase.java
index 4548f39eb4..c603a0d5c3 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/MD5PasswordFilePrincipalDatabase.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/Base64MD5PasswordFilePrincipalDatabase.java
@@ -22,8 +22,8 @@ package org.apache.qpid.server.security.auth.database;
import org.apache.log4j.Logger;
import org.apache.qpid.server.security.auth.sasl.AuthenticationProviderInitialiser;
-import org.apache.qpid.server.security.auth.sasl.crammd5.CRAMMD5Initialiser;
-import org.apache.qpid.server.security.auth.sasl.plain.PlainInitialiser;
+import org.apache.qpid.server.security.auth.sasl.crammd5.CRAMMD5HashedInitialiser;
+import org.apache.commons.codec.binary.Base64;
import javax.security.auth.callback.PasswordCallback;
import javax.security.auth.login.AccountNotFoundException;
@@ -44,9 +44,9 @@ import java.security.Principal;
*
* where a carriage return separates each username/password pair. Passwords are assumed to be in plain text.
*/
-public class MD5PasswordFilePrincipalDatabase implements PrincipalDatabase
+public class Base64MD5PasswordFilePrincipalDatabase implements PrincipalDatabase
{
- private static final Logger _logger = Logger.getLogger(MD5PasswordFilePrincipalDatabase.class);
+ private static final Logger _logger = Logger.getLogger(Base64MD5PasswordFilePrincipalDatabase.class);
private File _passwordFile;
@@ -54,7 +54,7 @@ public class MD5PasswordFilePrincipalDatabase implements PrincipalDatabase
private Map<String, AuthenticationProviderInitialiser> _saslServers;
- public MD5PasswordFilePrincipalDatabase()
+ public Base64MD5PasswordFilePrincipalDatabase()
{
_saslServers = new HashMap<String, AuthenticationProviderInitialiser>();
@@ -62,15 +62,10 @@ public class MD5PasswordFilePrincipalDatabase implements PrincipalDatabase
* Create Authenticators for MD5 Password file.
*/
- // Accept MD5 incomming and use plain comparison with the file
- PlainInitialiser cram = new PlainInitialiser();
- cram.initialise(this);
// Accept Plain incomming and hash it for comparison to the file.
- CRAMMD5Initialiser plain = new CRAMMD5Initialiser();
- plain.initialise(this, CRAMMD5Initialiser.HashDirection.INCOMMING);
-
- _saslServers.put(plain.getMechanismName(), cram);
- _saslServers.put(cram.getMechanismName(), plain);
+ CRAMMD5HashedInitialiser cram = new CRAMMD5HashedInitialiser();
+ cram.initialise(this);
+ _saslServers.put(cram.getMechanismName(), cram);
}
public void setPasswordFile(String passwordFile) throws FileNotFoundException
@@ -159,6 +154,7 @@ public class MD5PasswordFilePrincipalDatabase implements PrincipalDatabase
private char[] lookupPassword(String name) throws IOException
{
BufferedReader reader = null;
+ byte[] passwd = null;
try
{
reader = new BufferedReader(new FileReader(_passwordFile));
@@ -174,7 +170,33 @@ public class MD5PasswordFilePrincipalDatabase implements PrincipalDatabase
if (name.equals(result[0]))
{
- return result[1].toCharArray();
+
+
+ char[] raw = result[1].toCharArray();
+
+ byte[] encoded = new byte[result[1].length() + 1];
+
+ int index = 0;
+ for (char c : raw)
+ {
+ index++;
+ encoded[index] = (byte) c;
+ }
+
+ Base64 b64 = new Base64();
+ byte[] decoded = b64.decode(encoded);
+
+
+ char[] hashedPassword = new char[decoded.length + 1];
+
+ index = 0;
+ for (byte c : decoded)
+ {
+ index++;
+ hashedPassword[index] = (char) c;
+ }
+
+ return hashedPassword;
}
}
return null;
diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainPasswordVhostFilePrincipalDatabase.java b/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainPasswordVhostFilePrincipalDatabase.java
index 0c885f8042..af81b70296 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainPasswordVhostFilePrincipalDatabase.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainPasswordVhostFilePrincipalDatabase.java
@@ -20,27 +20,15 @@
*/
package org.apache.qpid.server.security.auth.database;
-import org.apache.qpid.server.security.auth.database.PrincipalDatabase;
-import org.apache.qpid.server.security.auth.sasl.AuthenticationProviderInitialiser;
-import org.apache.qpid.server.security.auth.sasl.crammd5.CRAMMD5Initialiser;
-import org.apache.qpid.server.security.auth.sasl.plain.PlainInitialiser;
import org.apache.qpid.server.security.access.AccessManager;
import org.apache.qpid.server.security.access.AccessResult;
import org.apache.qpid.server.security.access.Accessable;
import org.apache.qpid.server.virtualhost.VirtualHost;
import org.apache.log4j.Logger;
-import javax.security.auth.callback.PasswordCallback;
-import javax.security.auth.login.AccountNotFoundException;
-import java.io.File;
-import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.BufferedReader;
import java.io.FileReader;
-import java.util.regex.Pattern;
-import java.util.Map;
-import java.util.HashMap;
-import java.security.Principal;
/**
* Represents a user database where the account information is stored in a simple flat file.
diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/PrincipalDatabaseAuthenticationManager.java b/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/PrincipalDatabaseAuthenticationManager.java
index 31f881ba78..ce5e0cd748 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/PrincipalDatabaseAuthenticationManager.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/PrincipalDatabaseAuthenticationManager.java
@@ -108,11 +108,15 @@ public class PrincipalDatabaseAuthenticationManager implements AuthenticationMan
if (providerMap.size() > 0)
{
- Security.addProvider(new JCAProvider(providerMap));
+ // Ensure we are used before the defaults
+ if (Security.insertProviderAt(new JCAProvider(providerMap), 1) == -1)
+ {
+ _logger.warn("Unable to set order of providers.");
+ }
}
else
{
- _logger.warn("No SASL providers availble.");
+ _logger.warn("No additional SASL providers registered.");
}
}
@@ -148,21 +152,20 @@ public class PrincipalDatabaseAuthenticationManager implements AuthenticationMan
{
if (database == null || database.getMechanisms().size() == 0)
{
- _logger.warn("");
+ _logger.warn("No Database or no mechanisms to initialise authentication");
return;
}
- for (AuthenticationProviderInitialiser mechanism : database.getMechanisms().values())
+ for (Map.Entry<String, AuthenticationProviderInitialiser> mechanism : database.getMechanisms().entrySet())
{
- initialiseAuthenticationMechanism(mechanism, providerMap);
+ initialiseAuthenticationMechanism(mechanism.getKey(), mechanism.getValue(), providerMap);
}
}
- private void initialiseAuthenticationMechanism(AuthenticationProviderInitialiser initialiser,
+ private void initialiseAuthenticationMechanism(String mechanism, AuthenticationProviderInitialiser initialiser,
Map<String, Class<? extends SaslServerFactory>> providerMap)
throws Exception
{
- String mechanism = initialiser.getMechanismName();
if (_mechanisms == null)
{
_mechanisms = mechanism;
diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/JCAProvider.java b/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/JCAProvider.java
index 8ffcdc4e36..fd4ad86055 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/JCAProvider.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/JCAProvider.java
@@ -33,7 +33,7 @@ public final 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);
}
private void register(Map<String, Class<? extends SaslServerFactory>> providerMap)
diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5HashedInitialiser.java b/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5HashedInitialiser.java
new file mode 100644
index 0000000000..97f9a4e91a
--- /dev/null
+++ b/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5HashedInitialiser.java
@@ -0,0 +1,50 @@
+/*
+ *
+ * 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.server.security.auth.sasl.crammd5;
+
+import org.apache.qpid.server.security.auth.sasl.UsernamePasswordInitialiser;
+import org.apache.qpid.server.security.auth.database.PrincipalDatabase;
+
+import javax.security.sasl.SaslServerFactory;
+import java.util.Map;
+
+public class CRAMMD5HashedInitialiser extends UsernamePasswordInitialiser
+{
+ public String getMechanismName()
+ {
+ return CRAMMD5HashedSaslServer.MECHANISM;
+ }
+
+ public Class<? extends SaslServerFactory> getServerFactoryClassForJCARegistration()
+ {
+ return CRAMMD5HashedServerFactory.class;
+ }
+
+ public void initialise(PrincipalDatabase passwordFile)
+ {
+ super.initialise(passwordFile);
+ }
+
+ public Map<String, ?> getProperties()
+ {
+ return null;
+ }
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5HashedSaslServer.java b/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5HashedSaslServer.java
new file mode 100644
index 0000000000..f6cab084ea
--- /dev/null
+++ b/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5HashedSaslServer.java
@@ -0,0 +1,105 @@
+/*
+ * 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.server.security.auth.sasl.crammd5;
+
+import javax.security.sasl.SaslServer;
+import javax.security.sasl.SaslException;
+import javax.security.sasl.Sasl;
+import javax.security.sasl.SaslServerFactory;
+import javax.security.auth.callback.CallbackHandler;
+import java.util.Enumeration;
+import java.util.Map;
+
+public class CRAMMD5HashedSaslServer implements SaslServer
+{
+ public static final String MECHANISM = "CRAM-MD5-HASHED";
+
+ private SaslServer _realServer;
+
+ public CRAMMD5HashedSaslServer(String mechanism, String protocol, String serverName, Map<String, ?> props,
+ CallbackHandler cbh) throws SaslException
+ {
+ Enumeration factories = Sasl.getSaslServerFactories();
+
+ while (factories.hasMoreElements())
+ {
+ SaslServerFactory factory = (SaslServerFactory) factories.nextElement();
+
+ if (factory instanceof CRAMMD5HashedServerFactory)
+ {
+ continue;
+ }
+
+ String[] mechs = factory.getMechanismNames(props);
+
+ for (String mech : mechs)
+ {
+ if (mech.equals("CRAM-MD5"))
+ {
+ _realServer = factory.createSaslServer("CRAM-MD5", protocol, serverName, props, cbh);
+ return;
+ }
+ }
+ }
+
+ throw new RuntimeException("No default SaslServer found for mechanism:" + "CRAM-MD5");
+ }
+
+ public String getMechanismName()
+ {
+ return MECHANISM;
+ }
+
+ public byte[] evaluateResponse(byte[] response) throws SaslException
+ {
+ return _realServer.evaluateResponse(response);
+ }
+
+ public boolean isComplete()
+ {
+ return _realServer.isComplete();
+ }
+
+ public String getAuthorizationID()
+ {
+ return _realServer.getAuthorizationID();
+ }
+
+ public byte[] unwrap(byte[] incoming, int offset, int len) throws SaslException
+ {
+ return _realServer.unwrap(incoming, offset, len);
+ }
+
+ public byte[] wrap(byte[] outgoing, int offset, int len) throws SaslException
+ {
+ return _realServer.wrap(outgoing, offset, len);
+ }
+
+ public Object getNegotiatedProperty(String propName)
+ {
+ return _realServer.getNegotiatedProperty(propName);
+ }
+
+ public void dispose() throws SaslException
+ {
+ _realServer.dispose();
+ }
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5HashedServerFactory.java b/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5HashedServerFactory.java
new file mode 100644
index 0000000000..5298b5cc63
--- /dev/null
+++ b/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5HashedServerFactory.java
@@ -0,0 +1,61 @@
+/*
+ *
+ * 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.server.security.auth.sasl.crammd5;
+
+import java.util.Map;
+
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.sasl.Sasl;
+import javax.security.sasl.SaslException;
+import javax.security.sasl.SaslServer;
+import javax.security.sasl.SaslServerFactory;
+
+public class CRAMMD5HashedServerFactory implements SaslServerFactory
+{
+ public SaslServer createSaslServer(String mechanism, String protocol, String serverName, Map<String, ?> props,
+ CallbackHandler cbh) throws SaslException
+ {
+ if (mechanism.equals(CRAMMD5HashedSaslServer.MECHANISM))
+ {
+ return new CRAMMD5HashedSaslServer(mechanism, protocol, serverName, props, cbh);
+ }
+ else
+ {
+ 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[]{CRAMMD5HashedSaslServer.MECHANISM};
+ }
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/plain/PlainSaslServerFactory.java b/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/plain/PlainSaslServerFactory.java
index ff3e87e3a0..f0dd9eeb6d 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/plain/PlainSaslServerFactory.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/plain/PlainSaslServerFactory.java
@@ -29,7 +29,7 @@ import javax.security.sasl.SaslServer;
import javax.security.sasl.SaslServerFactory;
public class PlainSaslServerFactory implements SaslServerFactory
-{
+{
public SaslServer createSaslServer(String mechanism, String protocol, String serverName, Map props,
CallbackHandler cbh) throws SaslException
{
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};
+ }
+}