aboutsummaryrefslogtreecommitdiff
path: root/src/org/apache/qpid/management/common/sasl
diff options
context:
space:
mode:
Diffstat (limited to 'src/org/apache/qpid/management/common/sasl')
-rw-r--r--src/org/apache/qpid/management/common/sasl/CRAMMD5HashedSaslClientFactory.java59
-rw-r--r--src/org/apache/qpid/management/common/sasl/ClientSaslFactory.java53
-rw-r--r--src/org/apache/qpid/management/common/sasl/Constants.java33
-rw-r--r--src/org/apache/qpid/management/common/sasl/JCAProvider.java55
-rw-r--r--src/org/apache/qpid/management/common/sasl/PlainSaslClient.java210
-rw-r--r--src/org/apache/qpid/management/common/sasl/SaslProvider.java35
-rw-r--r--src/org/apache/qpid/management/common/sasl/UserPasswordCallbackHandler.java77
-rw-r--r--src/org/apache/qpid/management/common/sasl/UsernameHashedPasswordCallbackHandler.java107
8 files changed, 629 insertions, 0 deletions
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<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)
+ {
+ 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<String, Class<? extends SaslClientFactory>> 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<String, Class<? extends SaslClientFactory>> providerMap)
+ {
+ for (Map.Entry<String, Class<? extends SaslClientFactory>> 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;
+ }
+}