summaryrefslogtreecommitdiff
path: root/java/common
diff options
context:
space:
mode:
Diffstat (limited to 'java/common')
-rw-r--r--java/common/src/main/java/org/apache/qpidity/Channel.java11
-rw-r--r--java/common/src/main/java/org/apache/qpidity/Connection.java11
-rw-r--r--java/common/src/main/java/org/apache/qpidity/ConnectionDelegate.java246
-rw-r--r--java/common/src/main/java/org/apache/qpidity/Frame.java3
-rw-r--r--java/common/src/main/java/org/apache/qpidity/MinaHandler.java7
-rw-r--r--java/common/src/main/java/org/apache/qpidity/ProtocolHeader.java4
-rw-r--r--java/common/src/main/java/org/apache/qpidity/QpidConfig.java90
-rw-r--r--java/common/src/main/java/org/apache/qpidity/QpidException.java20
-rw-r--r--java/common/src/main/java/org/apache/qpidity/SecurityHelper.java71
-rw-r--r--java/common/src/main/java/org/apache/qpidity/Session.java4
-rw-r--r--java/common/src/main/java/org/apache/qpidity/ToyBroker.java21
-rw-r--r--java/common/src/main/java/org/apache/qpidity/api/Message.java4
-rw-r--r--java/common/src/main/java/org/apache/qpidity/filter/PropertyExpression.java2
-rw-r--r--java/common/src/main/java/org/apache/qpidity/security/AMQPCallbackHandler.java (renamed from java/common/src/main/java/org/apache/qpidity/CommonSessionDelegate.java)29
-rw-r--r--java/common/src/main/java/org/apache/qpidity/security/CallbackHandlerRegistry.java92
-rw-r--r--java/common/src/main/java/org/apache/qpidity/security/DynamicSaslRegistrar.java70
-rw-r--r--java/common/src/main/java/org/apache/qpidity/security/JCAProvider.java44
-rw-r--r--java/common/src/main/java/org/apache/qpidity/security/UsernamePasswordCallbackHandler.java60
-rw-r--r--java/common/src/main/java/org/apache/qpidity/security/amqplain/AmqPlainSaslClient.java105
-rw-r--r--java/common/src/main/java/org/apache/qpidity/security/amqplain/AmqPlainSaslClientFactory.java62
20 files changed, 902 insertions, 54 deletions
diff --git a/java/common/src/main/java/org/apache/qpidity/Channel.java b/java/common/src/main/java/org/apache/qpidity/Channel.java
index f20c65e467..483b5e7f21 100644
--- a/java/common/src/main/java/org/apache/qpidity/Channel.java
+++ b/java/common/src/main/java/org/apache/qpidity/Channel.java
@@ -35,30 +35,31 @@ import static org.apache.qpidity.Functions.*;
* @author Rafael H. Schloming
*/
-class Channel extends Invoker implements Handler<Frame>
+public class Channel extends Invoker implements Handler<Frame>
{
final private Connection connection;
final private int channel;
final private TrackSwitch<Channel> tracks;
final private Delegate<Channel> delegate;
-
+ final private SessionDelegate sessionDelegate;
// session may be null
private Session session;
private Method method = null;
private List<ByteBuffer> data = null;
private int dataSize;
-
+
public Channel(Connection connection, int channel, SessionDelegate delegate)
{
this.connection = connection;
this.channel = channel;
this.delegate = new ChannelDelegate();
-
+ this.sessionDelegate = delegate;
+
tracks = new TrackSwitch<Channel>();
tracks.map(L1, new MethodHandler<Channel>
- (getMajor(), getMinor(), this.delegate));
+ (getMajor(), getMinor(), connection.getConnectionDelegate()));
tracks.map(L2, new MethodHandler<Channel>
(getMajor(), getMinor(), this.delegate));
tracks.map(L3, new SessionResolver<Frame>
diff --git a/java/common/src/main/java/org/apache/qpidity/Connection.java b/java/common/src/main/java/org/apache/qpidity/Connection.java
index 9171208a28..c387a38b17 100644
--- a/java/common/src/main/java/org/apache/qpidity/Connection.java
+++ b/java/common/src/main/java/org/apache/qpidity/Connection.java
@@ -36,7 +36,8 @@ import java.nio.ByteBuffer;
* short instead of Short
*/
-class Connection implements ProtocolActions
+// RA making this public until we sort out the package issues
+public class Connection implements ProtocolActions
{
final private Handler<ByteBuffer> input;
@@ -58,6 +59,11 @@ class Connection implements ProtocolActions
this.delegate = delegate;
}
+ public ConnectionDelegate getConnectionDelegate()
+ {
+ return delegate;
+ }
+
public Connection(Handler<ByteBuffer> output,
ConnectionDelegate delegate)
{
@@ -103,6 +109,9 @@ class Connection implements ProtocolActions
output.handle(header.toByteBuffer());
// XXX: how do we close the connection?
}
+
+ // not sure if this is the right place
+ getChannel(0).connectionStart(header.getMajor(), header.getMinor(), null, "PLAIN", "utf8");
}
public Channel getChannel(int number)
diff --git a/java/common/src/main/java/org/apache/qpidity/ConnectionDelegate.java b/java/common/src/main/java/org/apache/qpidity/ConnectionDelegate.java
index 9df264561c..537a7ef586 100644
--- a/java/common/src/main/java/org/apache/qpidity/ConnectionDelegate.java
+++ b/java/common/src/main/java/org/apache/qpidity/ConnectionDelegate.java
@@ -20,6 +20,17 @@
*/
package org.apache.qpidity;
+import java.io.UnsupportedEncodingException;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.locks.Condition;
+import java.util.concurrent.locks.Lock;
+
+import javax.security.sasl.Sasl;
+import javax.security.sasl.SaslClient;
+import javax.security.sasl.SaslException;
+import javax.security.sasl.SaslServer;
+
/**
* ConnectionDelegate
@@ -27,9 +38,240 @@ package org.apache.qpidity;
* @author Rafael H. Schloming
*/
-public interface ConnectionDelegate
+/**
+ * Currently only implemented client specific methods
+ * the server specific methods are dummy impls for testing
+ *
+ * the connectionClose is kind of different for both sides
+ */
+public abstract class ConnectionDelegate extends Delegate<Channel>
{
+ private String _username;
+ private String _password;
+ private String _mechanism;
+ private String _virtualHost;
+ private SaslClient saslClient;
+ private SaslServer saslServer;
+ private String _locale = "utf8";
+ private int maxFrame = 64*1024;
+ private Condition _negotiationComplete;
+ private Lock _negotiationCompleteLock;
+
+ public abstract SessionDelegate getSessionDelegate();
+
+ public void setCondition(Lock negotiationCompleteLock,Condition negotiationComplete)
+ {
+ _negotiationComplete = negotiationComplete;
+ _negotiationCompleteLock = negotiationCompleteLock;
+ }
+
+ // ----------------------------------------------
+ // Client side
+ //-----------------------------------------------
+ @Override public void connectionStart(Channel context, ConnectionStart struct)
+ {
+ System.out.println("The broker has sent connection-start");
+
+ String mechanism = null;
+ String response = null;
+ try
+ {
+ mechanism = SecurityHelper.chooseMechanism(struct.getMechanisms());
+ saslClient = Sasl.createSaslClient(new String[]{ mechanism },null, "AMQP", "localhost", null,
+ SecurityHelper.createCallbackHandler(mechanism,_username,_password ));
+ response = new String(saslClient.evaluateChallenge(new byte[0]),_locale);
+ }
+ catch (UnsupportedEncodingException e)
+ {
+ // need error handling
+ }
+ catch (SaslException e)
+ {
+ // need error handling
+ }
+ catch (QpidException e)
+ {
+ // need error handling
+ }
+
+ Map<String,?> props = new HashMap<String,String>();
+ context.connectionStartOk(props, mechanism, response, _locale);
+ }
+
+ @Override public void connectionSecure(Channel context, ConnectionSecure struct)
+ {
+ System.out.println("The broker has sent connection-secure with chanllenge " + struct.getChallenge());
+
+ try
+ {
+ String response = new String(saslClient.evaluateChallenge(struct.getChallenge().getBytes()),_locale);
+ context.connectionSecureOk(response);
+ }
+ catch (UnsupportedEncodingException e)
+ {
+ // need error handling
+ }
+ catch (SaslException e)
+ {
+ // need error handling
+ }
+ }
+
+ @Override public void connectionTune(Channel context, ConnectionTune struct)
+ {
+ System.out.println("The broker has sent connection-tune " + struct.toString());
+
+ // should update the channel max given by the broker.
+ context.connectionTuneOk(struct.getChannelMax(), struct.getFrameMax(), struct.getHeartbeat());
+ context.connectionOpen(_virtualHost, null, Option.INSIST);
+ }
+
+
+ @Override public void connectionOpenOk(Channel context, ConnectionOpenOk struct)
+ {
+ String knownHosts = struct.getKnownHosts();
+ System.out.println("The broker has opened the connection for use");
+ System.out.println("The broker supplied the following hosts for failover " + knownHosts);
+ _negotiationCompleteLock.lock();
+ try
+ {
+ _negotiationComplete.signalAll();
+ }
+ finally
+ {
+ _negotiationCompleteLock.unlock();
+ }
+ }
+
+ public void connectionRedirect(Channel context, ConnectionRedirect struct)
+ {
+ // not going to bother at the moment
+ }
+
+ // ----------------------------------------------
+ // Server side
+ //-----------------------------------------------
+ @Override public void connectionStartOk(Channel context, ConnectionStartOk struct)
+ {
+ //set the client side locale on the server side
+ _locale = struct.getLocale();
+ _mechanism = struct.getMechanism();
+
+ System.out.println("The client has sent connection-start-ok");
+
+ //try
+ //{
+ //saslServer = Sasl.createSaslServer(_mechanism, "AMQP", "ABC",null,SecurityHelper.createCallbackHandler(_mechanism,_username,_password));
+ //byte[] challenge = saslServer.evaluateResponse(struct.getResponse().getBytes());
+ byte[] challenge = null;
+ if ( challenge == null)
+ {
+ System.out.println("Authentication sucessfull");
+ context.connectionTune(Integer.MAX_VALUE,maxFrame, 0);
+ }
+ else
+ {
+ System.out.println("Authentication failed");
+ try
+ {
+ context.connectionSecure(new String(challenge,_locale));
+ }
+ catch(Exception e)
+ {
+
+ }
+ }
+
+
+ /*}
+ catch (SaslException e)
+ {
+ // need error handling
+ }
+ catch (QpidException e)
+ {
+ // need error handling
+ }*/
+ }
+
+ @Override public void connectionTuneOk(Channel context, ConnectionTuneOk struct)
+ {
+ System.out.println("The client has excepted the tune params");
+ }
+
+ @Override public void connectionSecureOk(Channel context, ConnectionSecureOk struct)
+ {
+ System.out.println("The client has sent connection-secure-ok");
+ try
+ {
+ saslServer = Sasl.createSaslServer(_mechanism, "AMQP", "ABC",new HashMap(),SecurityHelper.createCallbackHandler(_mechanism,_username,_password));
+ byte[] challenge = saslServer.evaluateResponse(struct.getResponse().getBytes());
+ if ( challenge == null)
+ {
+ System.out.println("Authentication sucessfull");
+ context.connectionTune(Integer.MAX_VALUE,maxFrame, 0);
+ }
+ else
+ {
+ System.out.println("Authentication failed");
+ try
+ {
+ context.connectionSecure(new String(challenge,_locale));
+ }
+ catch(Exception e)
+ {
+
+ }
+ }
+
+
+ }
+ catch (SaslException e)
+ {
+ // need error handling
+ }
+ catch (QpidException e)
+ {
+ // need error handling
+ }
+ }
+
+
+ @Override public void connectionOpen(Channel context, ConnectionOpen struct)
+ {
+ String hosts = "amqp:1223243232325";
+ System.out.println("The client has sent connection-open-ok");
+ context.connectionOpenOk(hosts);
+ }
+
+
+ public String getPassword()
+ {
+ return _password;
+ }
+
+ public void setPassword(String password)
+ {
+ _password = password;
+ }
+
+ public String getUsername()
+ {
+ return _username;
+ }
+
+ public void setUsername(String username)
+ {
+ _username = username;
+ }
- SessionDelegate getSessionDelegate();
+ public String getVirtualHost()
+ {
+ return _virtualHost;
+ }
+ public void setVirtualHost(String host)
+ {
+ _virtualHost = host;
+ }
}
diff --git a/java/common/src/main/java/org/apache/qpidity/Frame.java b/java/common/src/main/java/org/apache/qpidity/Frame.java
index d5076e0ef0..89e7579cb3 100644
--- a/java/common/src/main/java/org/apache/qpidity/Frame.java
+++ b/java/common/src/main/java/org/apache/qpidity/Frame.java
@@ -35,7 +35,8 @@ import static org.apache.qpidity.Functions.*;
* @author Rafael H. Schloming
*/
-class Frame implements Iterable<ByteBuffer>
+// RA: changed it to public until we sort the package issues
+public class Frame implements Iterable<ByteBuffer>
{
public static final int HEADER_SIZE = 12;
diff --git a/java/common/src/main/java/org/apache/qpidity/MinaHandler.java b/java/common/src/main/java/org/apache/qpidity/MinaHandler.java
index a40753ed91..f255b56d0b 100644
--- a/java/common/src/main/java/org/apache/qpidity/MinaHandler.java
+++ b/java/common/src/main/java/org/apache/qpidity/MinaHandler.java
@@ -42,8 +42,8 @@ import org.apache.mina.transport.socket.nio.SocketConnector;
*
* @author Rafael H. Schloming
*/
-
-class MinaHandler implements IoHandler
+//RA making this public until we sort out the package issues
+public class MinaHandler implements IoHandler
{
private final ConnectionDelegate delegate;
@@ -124,7 +124,8 @@ class MinaHandler implements IoHandler
{
IoAcceptor acceptor = new SocketAcceptor();
acceptor.bind(new InetSocketAddress(host, port),
- new MinaHandler(delegate, InputHandler.State.PROTO_HDR));
+ new MinaHandler(delegate, InputHandler.State.PROTO_HDR));
+
}
public static final Connection connect(String host, int port,
diff --git a/java/common/src/main/java/org/apache/qpidity/ProtocolHeader.java b/java/common/src/main/java/org/apache/qpidity/ProtocolHeader.java
index 56c73d1f00..140d5ecbe3 100644
--- a/java/common/src/main/java/org/apache/qpidity/ProtocolHeader.java
+++ b/java/common/src/main/java/org/apache/qpidity/ProtocolHeader.java
@@ -29,7 +29,9 @@ import java.nio.ByteBuffer;
* @author Rafael H. Schloming
*/
-class ProtocolHeader
+//RA making this public until we sort out the package issues
+
+public class ProtocolHeader
{
private static final byte[] AMQP = {'A', 'M', 'Q', 'P' };
diff --git a/java/common/src/main/java/org/apache/qpidity/QpidConfig.java b/java/common/src/main/java/org/apache/qpidity/QpidConfig.java
new file mode 100644
index 0000000000..b5aad12f10
--- /dev/null
+++ b/java/common/src/main/java/org/apache/qpidity/QpidConfig.java
@@ -0,0 +1,90 @@
+package org.apache.qpidity;
+
+/**
+ * API to configure the Security parameters of the client.
+ * The user can choose to pick the config from any source
+ * and set it using this class.
+ *
+ */
+public class QpidConfig
+{
+ private static QpidConfig _instance = new QpidConfig();
+
+ private SecurityMechanism[] securityMechanisms =
+ new SecurityMechanism[]{new SecurityMechanism("PLAIN","org.apache.qpidity.security.UsernamePasswordCallbackHandler"),
+ new SecurityMechanism("CRAM_MD5","org.apache.qpidity.security.UsernamePasswordCallbackHandler")};
+
+ private SaslClientFactory[] saslClientFactories =
+ new SaslClientFactory[]{new SaslClientFactory("AMQPLAIN","org.apache.qpidity.security.amqplain.AmqPlainSaslClientFactory")};
+
+ private QpidConfig(){}
+
+ public static QpidConfig get()
+ {
+ return _instance;
+ }
+
+ public void setSecurityMechanisms(SecurityMechanism... securityMechanisms)
+ {
+ this.securityMechanisms = securityMechanisms;
+ }
+
+ public SecurityMechanism[] getSecurityMechanisms()
+ {
+ return securityMechanisms;
+ }
+
+ public void setSaslClientFactories(SaslClientFactory... saslClientFactories)
+ {
+ this.saslClientFactories = saslClientFactories;
+ }
+
+ public SaslClientFactory[] getSaslClientFactories()
+ {
+ return saslClientFactories;
+ }
+
+ public class SecurityMechanism
+ {
+ String type;
+ String handler;
+
+ SecurityMechanism(String type,String handler)
+ {
+ this.type = type;
+ this.handler = handler;
+ }
+
+ public String getHandler()
+ {
+ return handler;
+ }
+
+ public String getType()
+ {
+ return type;
+ }
+ }
+
+ public class SaslClientFactory
+ {
+ String type;
+ String factoryClass;
+
+ SaslClientFactory(String type,String factoryClass)
+ {
+ this.type = type;
+ this.factoryClass = factoryClass;
+ }
+
+ public String getFactoryClass()
+ {
+ return factoryClass;
+ }
+
+ public String getType()
+ {
+ return type;
+ }
+ }
+}
diff --git a/java/common/src/main/java/org/apache/qpidity/QpidException.java b/java/common/src/main/java/org/apache/qpidity/QpidException.java
index 4ab99b677f..5b3671cebd 100644
--- a/java/common/src/main/java/org/apache/qpidity/QpidException.java
+++ b/java/common/src/main/java/org/apache/qpidity/QpidException.java
@@ -25,12 +25,9 @@ package org.apache.qpidity;
public class QpidException extends Exception
{
/**
- * This exception error code.
- * <p> This error code is used for internationalisation purpose.
- * <p> This error code is set from the AMQP ones.
- * <TODO> So we may want to use the AMQP error code directly.
+ * AMQP error code
*/
- private String _errorCode;
+ private int _errorCode;
/**
* Constructor for a Qpid Exception.
@@ -38,20 +35,27 @@ public class QpidException extends Exception
* they are unknown.
* @param message A description of the reason of this exception .
* @param errorCode A string specifyin the error code of this exception.
- * @param cause The linked Execption.
+ * @param cause The linked Execption. *
+ *
*/
- public QpidException(String message, String errorCode, Throwable cause)
+ public QpidException(String message, int errorCode, Throwable cause)
{
super(message, cause);
_errorCode = errorCode;
}
+
+ //hack to get rid of a compile error from a generated class
+ public QpidException(String message, String errorCode, Throwable cause)
+ {
+
+ }
/**
* Get this execption error code.
*
* @return This exception error code.
*/
- public String getErrorCode()
+ public int getErrorCode()
{
return _errorCode;
}
diff --git a/java/common/src/main/java/org/apache/qpidity/SecurityHelper.java b/java/common/src/main/java/org/apache/qpidity/SecurityHelper.java
new file mode 100644
index 0000000000..474e2f7e8f
--- /dev/null
+++ b/java/common/src/main/java/org/apache/qpidity/SecurityHelper.java
@@ -0,0 +1,71 @@
+/*
+ *
+ * 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.qpidity;
+
+import java.io.UnsupportedEncodingException;
+import java.util.HashSet;
+import java.util.StringTokenizer;
+
+import org.apache.qpidity.security.AMQPCallbackHandler;
+import org.apache.qpidity.security.CallbackHandlerRegistry;
+
+public class SecurityHelper
+{
+ public static String chooseMechanism(String mechanisms) throws UnsupportedEncodingException
+ {
+ StringTokenizer tokenizer = new StringTokenizer(mechanisms, " ");
+ HashSet mechanismSet = new HashSet();
+ while (tokenizer.hasMoreTokens())
+ {
+ mechanismSet.add(tokenizer.nextToken());
+ }
+
+ String preferredMechanisms = CallbackHandlerRegistry.getInstance().getMechanisms();
+ StringTokenizer prefTokenizer = new StringTokenizer(preferredMechanisms, " ");
+ while (prefTokenizer.hasMoreTokens())
+ {
+ String mech = prefTokenizer.nextToken();
+ if (mechanismSet.contains(mech))
+ {
+ return mech;
+ }
+ }
+ return null;
+ }
+
+ public static AMQPCallbackHandler createCallbackHandler(String mechanism, String username,String password)
+ throws QpidException
+ {
+ Class mechanismClass = CallbackHandlerRegistry.getInstance().getCallbackHandlerClass(mechanism);
+ try
+ {
+ Object instance = mechanismClass.newInstance();
+ AMQPCallbackHandler cbh = (AMQPCallbackHandler) instance;
+ cbh.initialise(username,password);
+ return cbh;
+ }
+ catch (Exception e)
+ {
+ throw new QpidException("Unable to create callback handler: " + e,0, e.getCause());
+ }
+ }
+
+}
diff --git a/java/common/src/main/java/org/apache/qpidity/Session.java b/java/common/src/main/java/org/apache/qpidity/Session.java
index 3b33fde2df..d3a24ffd8a 100644
--- a/java/common/src/main/java/org/apache/qpidity/Session.java
+++ b/java/common/src/main/java/org/apache/qpidity/Session.java
@@ -42,11 +42,12 @@ public class Session extends Invoker
// completed incoming commands
private final RangeSet processed = new RangeSet();
private Range syncPoint = null;
-
+
// outgoing command count
private long commandsOut = 0;
private Map<Long,Method> commands = new HashMap<Long,Method>();
private long mark = 0;
+
public Map<Long,Method> getOutstandingCommands()
{
@@ -231,7 +232,6 @@ public class Session extends Invoker
}
future.set(result);
}
-
protected <T> Future<T> invoke(Method m, Class<T> klass)
{
long command = commandsOut;
diff --git a/java/common/src/main/java/org/apache/qpidity/ToyBroker.java b/java/common/src/main/java/org/apache/qpidity/ToyBroker.java
index 651241f63c..683008fe8a 100644
--- a/java/common/src/main/java/org/apache/qpidity/ToyBroker.java
+++ b/java/common/src/main/java/org/apache/qpidity/ToyBroker.java
@@ -190,13 +190,20 @@ class ToyBroker extends SessionDelegate
{
final Map<String,Queue<Message>> queues =
new HashMap<String,Queue<Message>>();
- MinaHandler.accept("0.0.0.0", 5672, new ConnectionDelegate()
- {
- public SessionDelegate getSessionDelegate()
- {
- return new ToyBroker(queues);
- }
- });
+
+ ConnectionDelegate delegate = new ConnectionDelegate()
+ {
+ public SessionDelegate getSessionDelegate()
+ {
+ return new ToyBroker(queues);
+ }
+ };
+
+ //hack
+ delegate.setUsername("guest");
+ delegate.setPassword("guest");
+
+ MinaHandler.accept("0.0.0.0", 5672, delegate);
}
}
diff --git a/java/common/src/main/java/org/apache/qpidity/api/Message.java b/java/common/src/main/java/org/apache/qpidity/api/Message.java
index 2305027556..ccad3577f0 100644
--- a/java/common/src/main/java/org/apache/qpidity/api/Message.java
+++ b/java/common/src/main/java/org/apache/qpidity/api/Message.java
@@ -1,5 +1,7 @@
package org.apache.qpidity.api;
+import java.nio.ByteBuffer;
+
import org.apache.qpidity.MessageProperties;
import org.apache.qpidity.DeliveryProperties;
@@ -43,6 +45,8 @@ public interface Message
*/
public void appendData(byte[] src);
+ public void appendData(ByteBuffer src);
+
/**
* This will abstract the underlying message data.
* The Message implementation may not hold all message
diff --git a/java/common/src/main/java/org/apache/qpidity/filter/PropertyExpression.java b/java/common/src/main/java/org/apache/qpidity/filter/PropertyExpression.java
index 7db5cd5e11..ac3888d5bb 100644
--- a/java/common/src/main/java/org/apache/qpidity/filter/PropertyExpression.java
+++ b/java/common/src/main/java/org/apache/qpidity/filter/PropertyExpression.java
@@ -56,7 +56,7 @@ public class PropertyExpression implements Expression
}
catch (Exception e)
{
- throw new QpidException("cannot evaluate property ", "message selector", e);
+ throw new QpidException("cannot evaluate property ", 0, e);
}
}
return result;
diff --git a/java/common/src/main/java/org/apache/qpidity/CommonSessionDelegate.java b/java/common/src/main/java/org/apache/qpidity/security/AMQPCallbackHandler.java
index cd9d31b1c2..2e7afa1b87 100644
--- a/java/common/src/main/java/org/apache/qpidity/CommonSessionDelegate.java
+++ b/java/common/src/main/java/org/apache/qpidity/security/AMQPCallbackHandler.java
@@ -7,9 +7,9 @@
* 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
@@ -18,28 +18,11 @@
* under the License.
*
*/
-package org.apache.qpidity;
+package org.apache.qpidity.security;
-/**
- * CommonSessionDelegate
- */
+import javax.security.auth.callback.CallbackHandler;
-public class CommonSessionDelegate extends Delegate<Session>
+public interface AMQPCallbackHandler extends CallbackHandler
{
-
- @Override public void sessionAttached(Session session, SessionAttached struct) {}
-
- @Override public void sessionFlow(Session session, SessionFlow struct) {}
-
- @Override public void sessionFlowOk(Session session, SessionFlowOk struct) {}
-
- @Override public void sessionClose(Session session, SessionClose struct) {}
-
- @Override public void sessionClosed(Session session, SessionClosed struct) {}
-
- @Override public void sessionResume(Session session, SessionResume struct) {}
-
- @Override public void sessionSuspend(Session session, SessionSuspend struct) {}
-
- @Override public void sessionDetached(Session session, SessionDetached struct) {}
+ void initialise(String username,String password);
}
diff --git a/java/common/src/main/java/org/apache/qpidity/security/CallbackHandlerRegistry.java b/java/common/src/main/java/org/apache/qpidity/security/CallbackHandlerRegistry.java
new file mode 100644
index 0000000000..624b015c69
--- /dev/null
+++ b/java/common/src/main/java/org/apache/qpidity/security/CallbackHandlerRegistry.java
@@ -0,0 +1,92 @@
+/*
+ *
+ * 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.qpidity.security;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.qpidity.QpidConfig;
+
+public class CallbackHandlerRegistry
+{
+
+ private static CallbackHandlerRegistry _instance = new CallbackHandlerRegistry();
+
+ private Map<String,Class> _mechanismToHandlerClassMap = new HashMap<String,Class>();
+
+ private StringBuilder _mechanisms;
+
+ public static CallbackHandlerRegistry getInstance()
+ {
+ return _instance;
+ }
+
+ public Class getCallbackHandlerClass(String mechanism)
+ {
+ return _mechanismToHandlerClassMap.get(mechanism);
+ }
+
+ public String getMechanisms()
+ {
+ return _mechanisms.toString();
+ }
+
+ private CallbackHandlerRegistry()
+ {
+ // first we register any Sasl client factories
+ DynamicSaslRegistrar.registerSaslProviders();
+ registerMechanisms();
+ }
+
+ private void registerMechanisms()
+ {
+ for (QpidConfig.SecurityMechanism securityMechanism: QpidConfig.get().getSecurityMechanisms() )
+ {
+ Class clazz = null;
+ try
+ {
+ clazz = Class.forName(securityMechanism.getHandler());
+ if (!AMQPCallbackHandler.class.isAssignableFrom(clazz))
+ {
+ System.out.println("SASL provider " + clazz + " does not implement " + AMQPCallbackHandler.class +
+ ". Skipping");
+ continue;
+ }
+ _mechanismToHandlerClassMap.put(securityMechanism.getType(), clazz);
+ if (_mechanisms == null)
+ {
+
+ _mechanisms = new StringBuilder();
+ _mechanisms.append(securityMechanism.getType());
+ }
+ else
+ {
+ _mechanisms.append(" " + securityMechanism.getType());
+ }
+ }
+ catch (ClassNotFoundException ex)
+ {
+ System.out.println("Unable to load class " + securityMechanism.getHandler() + ". Skipping that SASL provider");
+ continue;
+ }
+ }
+ }
+}
diff --git a/java/common/src/main/java/org/apache/qpidity/security/DynamicSaslRegistrar.java b/java/common/src/main/java/org/apache/qpidity/security/DynamicSaslRegistrar.java
new file mode 100644
index 0000000000..52dacc6985
--- /dev/null
+++ b/java/common/src/main/java/org/apache/qpidity/security/DynamicSaslRegistrar.java
@@ -0,0 +1,70 @@
+/*
+ *
+ * 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.qpidity.security;
+
+import java.security.Security;
+import java.util.Map;
+import java.util.TreeMap;
+
+import javax.security.sasl.SaslClientFactory;
+
+import org.apache.qpidity.QpidConfig;
+
+public class DynamicSaslRegistrar
+{
+ public static void registerSaslProviders()
+ {
+ Map<String, Class> factories = registerSaslClientFactories();
+ if (factories.size() > 0)
+ {
+ Security.addProvider(new JCAProvider(factories));
+ System.out.println("Dynamic SASL provider added as a security provider");
+ }
+ }
+
+ private static Map<String, Class> registerSaslClientFactories()
+ {
+ TreeMap<String, Class> factoriesToRegister =
+ new TreeMap<String, Class>();
+
+ for (QpidConfig.SaslClientFactory factory: QpidConfig.get().getSaslClientFactories())
+ {
+ String className = factory.getFactoryClass();
+ try
+ {
+ Class clazz = Class.forName(className);
+ if (!(SaslClientFactory.class.isAssignableFrom(clazz)))
+ {
+ System.out.println("Class " + clazz + " does not implement " + SaslClientFactory.class + " - skipping");
+ continue;
+ }
+ factoriesToRegister.put(factory.getType(), clazz);
+ }
+ catch (Exception ex)
+ {
+ System.out.println("Error instantiating SaslClientFactory calss " + className + " - skipping");
+ }
+ }
+ return factoriesToRegister;
+ }
+
+
+}
diff --git a/java/common/src/main/java/org/apache/qpidity/security/JCAProvider.java b/java/common/src/main/java/org/apache/qpidity/security/JCAProvider.java
new file mode 100644
index 0000000000..c775171a5f
--- /dev/null
+++ b/java/common/src/main/java/org/apache/qpidity/security/JCAProvider.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.qpidity.security;
+
+import java.security.Provider;
+import java.security.Security;
+import java.util.Map;
+
+public class JCAProvider extends Provider
+{
+ public JCAProvider(Map<String, Class> providerMap)
+ {
+ super("AMQSASLProvider", 1.0, "A JCA provider that registers all " +
+ "AMQ SASL providers that want to be registered");
+ register(providerMap);
+ Security.addProvider(this);
+ }
+
+ private void register(Map<String, Class> providerMap)
+ {
+ for (Map.Entry<String, Class> me :providerMap.entrySet())
+ {
+ put("SaslClientFactory." + me.getKey(), me.getValue().getName());
+ }
+ }
+} \ No newline at end of file
diff --git a/java/common/src/main/java/org/apache/qpidity/security/UsernamePasswordCallbackHandler.java b/java/common/src/main/java/org/apache/qpidity/security/UsernamePasswordCallbackHandler.java
new file mode 100644
index 0000000000..0fd647e015
--- /dev/null
+++ b/java/common/src/main/java/org/apache/qpidity/security/UsernamePasswordCallbackHandler.java
@@ -0,0 +1,60 @@
+/*
+ *
+ * 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.qpidity.security;
+
+import java.io.IOException;
+
+import javax.security.auth.callback.Callback;
+import javax.security.auth.callback.NameCallback;
+import javax.security.auth.callback.PasswordCallback;
+import javax.security.auth.callback.UnsupportedCallbackException;
+
+public class UsernamePasswordCallbackHandler implements AMQPCallbackHandler
+{
+ private String _username;
+ private String _password;
+
+ public void initialise(String username,String password)
+ {
+ _username = username;
+ _password = password;
+ }
+
+ 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(_username);
+ }
+ else if (cb instanceof PasswordCallback)
+ {
+ ((PasswordCallback)cb).setPassword((_password).toCharArray());
+ }
+ else
+ {
+ throw new UnsupportedCallbackException(cb);
+ }
+ }
+ }
+}
diff --git a/java/common/src/main/java/org/apache/qpidity/security/amqplain/AmqPlainSaslClient.java b/java/common/src/main/java/org/apache/qpidity/security/amqplain/AmqPlainSaslClient.java
new file mode 100644
index 0000000000..6e4a0218d2
--- /dev/null
+++ b/java/common/src/main/java/org/apache/qpidity/security/amqplain/AmqPlainSaslClient.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.qpidity.security.amqplain;
+
+import org.apache.qpid.framing.FieldTable;
+import org.apache.qpid.framing.FieldTableFactory;
+
+import javax.security.sasl.SaslClient;
+import javax.security.sasl.SaslException;
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.auth.callback.NameCallback;
+import javax.security.auth.callback.PasswordCallback;
+import javax.security.auth.callback.Callback;
+
+/**
+ * Implements the "AMQPlain" authentication protocol that uses FieldTables to send username and pwd.
+ *
+ */
+public class AmqPlainSaslClient implements SaslClient
+{
+ /**
+ * The name of this mechanism
+ */
+ public static final String MECHANISM = "AMQPLAIN";
+
+ private CallbackHandler _cbh;
+
+ public AmqPlainSaslClient(CallbackHandler cbh)
+ {
+ _cbh = cbh;
+ }
+
+ public String getMechanismName()
+ {
+ return "AMQPLAIN";
+ }
+
+ public boolean hasInitialResponse()
+ {
+ return true;
+ }
+
+ public byte[] evaluateChallenge(byte[] challenge) throws SaslException
+ {
+ // we do not care about the prompt or the default name
+ NameCallback nameCallback = new NameCallback("prompt", "defaultName");
+ PasswordCallback pwdCallback = new PasswordCallback("prompt", false);
+ Callback[] callbacks = new Callback[]{nameCallback, pwdCallback};
+ try
+ {
+ _cbh.handle(callbacks);
+ }
+ catch (Exception e)
+ {
+ throw new SaslException("Error handling SASL callbacks: " + e, e);
+ }
+ FieldTable table = FieldTableFactory.newFieldTable();
+ table.setString("LOGIN", nameCallback.getName());
+ table.setString("PASSWORD", new String(pwdCallback.getPassword()));
+ return table.getDataAsBytes();
+ }
+
+ public boolean isComplete()
+ {
+ return true;
+ }
+
+ public byte[] unwrap(byte[] incoming, int offset, int len) throws SaslException
+ {
+ throw new SaslException("Not supported");
+ }
+
+ public byte[] wrap(byte[] outgoing, int offset, int len) throws SaslException
+ {
+ throw new SaslException("Not supported");
+ }
+
+ public Object getNegotiatedProperty(String propName)
+ {
+ return null;
+ }
+
+ public void dispose() throws SaslException
+ {
+ _cbh = null;
+ }
+}
diff --git a/java/common/src/main/java/org/apache/qpidity/security/amqplain/AmqPlainSaslClientFactory.java b/java/common/src/main/java/org/apache/qpidity/security/amqplain/AmqPlainSaslClientFactory.java
new file mode 100644
index 0000000000..abc881f433
--- /dev/null
+++ b/java/common/src/main/java/org/apache/qpidity/security/amqplain/AmqPlainSaslClientFactory.java
@@ -0,0 +1,62 @@
+/*
+ *
+ * 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.qpidity.security.amqplain;
+
+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;
+
+public class AmqPlainSaslClientFactory implements SaslClientFactory
+{
+ 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(AmqPlainSaslClient.MECHANISM))
+ {
+ if (cbh == null)
+ {
+ throw new SaslException("CallbackHandler must not be null");
+ }
+ return new AmqPlainSaslClient(cbh);
+ }
+ }
+ return null;
+ }
+
+ public String[] getMechanismNames(Map props)
+ {
+ 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];
+ }
+ else
+ {
+ return new String[]{AmqPlainSaslClient.MECHANISM};
+ }
+ }
+}