summaryrefslogtreecommitdiff
path: root/dotnet/Qpid.Client/Client
diff options
context:
space:
mode:
authorRobert Greig <rgreig@apache.org>2007-01-29 10:46:27 +0000
committerRobert Greig <rgreig@apache.org>2007-01-29 10:46:27 +0000
commit2bcc371558ce0659f53b86046cdf3d5de3b20910 (patch)
treed0c987cfa076eb90edb80620661d69a6e7354d3a /dotnet/Qpid.Client/Client
parentfe736211136b60bec61c1a22d3765be9142c6b39 (diff)
downloadqpid-python-2bcc371558ce0659f53b86046cdf3d5de3b20910.tar.gz
(Patch supplied by Tomas Restrepo) QPID-291-2.diff applied. Adds SASL capability to the .Net client.
git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk/qpid@501001 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'dotnet/Qpid.Client/Client')
-rw-r--r--dotnet/Qpid.Client/Client/AMQAuthenticationException.cs39
-rw-r--r--dotnet/Qpid.Client/Client/AMQConnection.cs2
-rw-r--r--dotnet/Qpid.Client/Client/Configuration/AuthenticationConfigurationSectionHandler.cs64
-rw-r--r--dotnet/Qpid.Client/Client/Handler/ChannelCloseMethodHandler.cs5
-rw-r--r--dotnet/Qpid.Client/Client/Handler/ConnectionCloseMethodHandler.cs25
-rw-r--r--dotnet/Qpid.Client/Client/Handler/ConnectionSecureMethodHandler.cs27
-rw-r--r--dotnet/Qpid.Client/Client/Handler/ConnectionStartMethodHandler.cs81
-rw-r--r--dotnet/Qpid.Client/Client/Protocol/AMQProtocolSession.cs8
-rw-r--r--dotnet/Qpid.Client/Client/Security/CallbackHandlerRegistry.cs114
-rw-r--r--dotnet/Qpid.Client/Client/Security/IAMQCallbackHandler.cs34
-rw-r--r--dotnet/Qpid.Client/Client/Security/UsernamePasswordCallbackHandler.cs56
11 files changed, 423 insertions, 32 deletions
diff --git a/dotnet/Qpid.Client/Client/AMQAuthenticationException.cs b/dotnet/Qpid.Client/Client/AMQAuthenticationException.cs
new file mode 100644
index 0000000000..68cacad1ef
--- /dev/null
+++ b/dotnet/Qpid.Client/Client/AMQAuthenticationException.cs
@@ -0,0 +1,39 @@
+/*
+ *
+ * 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.
+ *
+ */
+using System;
+using System.Runtime.Serialization;
+
+namespace Qpid.Client
+{
+ [Serializable]
+ public class AMQAuthenticationException : AMQException
+ {
+ public AMQAuthenticationException(int error, String message)
+ : base(error, message)
+ {
+ }
+
+ protected AMQAuthenticationException(SerializationInfo info, StreamingContext ctxt)
+ : base(info, ctxt)
+ {
+ }
+ }
+}
diff --git a/dotnet/Qpid.Client/Client/AMQConnection.cs b/dotnet/Qpid.Client/Client/AMQConnection.cs
index 1da46f19fd..3192b0018d 100644
--- a/dotnet/Qpid.Client/Client/AMQConnection.cs
+++ b/dotnet/Qpid.Client/Client/AMQConnection.cs
@@ -730,7 +730,7 @@ namespace Qpid.Client
catch (AMQException e)
{
_lastAMQException = e;
- throw e;
+ throw; // rethrow
}
}
diff --git a/dotnet/Qpid.Client/Client/Configuration/AuthenticationConfigurationSectionHandler.cs b/dotnet/Qpid.Client/Client/Configuration/AuthenticationConfigurationSectionHandler.cs
new file mode 100644
index 0000000000..54ee2c6660
--- /dev/null
+++ b/dotnet/Qpid.Client/Client/Configuration/AuthenticationConfigurationSectionHandler.cs
@@ -0,0 +1,64 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+using System;
+using System.Collections;
+using System.Collections.Specialized;
+using System.Configuration;
+using System.Text;
+
+using Qpid.Client.Security;
+using Qpid.Sasl.Mechanisms;
+
+namespace Qpid.Client.Configuration
+{
+ public class AuthenticationConfigurationSectionHandler
+ : IConfigurationSectionHandler
+ {
+
+ public object Create(object parent, object configContext, System.Xml.XmlNode section)
+ {
+ NameValueSectionHandler handler = new NameValueSectionHandler();
+ IDictionary schemes = new Hashtable();
+
+ NameValueCollection options = (NameValueCollection)
+ handler.Create(parent, configContext, section);
+
+ if ( options != null )
+ {
+ foreach ( string key in options.Keys )
+ {
+ Type type = Type.GetType(options[key]);
+ if ( type == null )
+ throw new ConfigurationException(string.Format("Type '{0}' not found", key));
+ if ( !typeof(IAMQCallbackHandler).IsAssignableFrom(type) )
+ throw new ConfigurationException(string.Format("Type '{0}' does not implement IAMQCallbackHandler", key));
+
+ schemes[key] = type;
+ }
+ }
+
+ return schemes;
+ }
+
+ } // class AuthenticationConfigurationSectionHandler
+
+} // namespace Qpid.Client.Configuration
diff --git a/dotnet/Qpid.Client/Client/Handler/ChannelCloseMethodHandler.cs b/dotnet/Qpid.Client/Client/Handler/ChannelCloseMethodHandler.cs
index 1031f804a6..0ce8a393c9 100644
--- a/dotnet/Qpid.Client/Client/Handler/ChannelCloseMethodHandler.cs
+++ b/dotnet/Qpid.Client/Client/Handler/ChannelCloseMethodHandler.cs
@@ -21,6 +21,7 @@
using log4net;
using Qpid.Client.Protocol;
using Qpid.Client.State;
+using Qpid.Protocol;
using Qpid.Framing;
namespace Qpid.Client.Handler
@@ -43,9 +44,8 @@ namespace Qpid.Client.Handler
AMQFrame frame = ChannelCloseOkBody.CreateAMQFrame(evt.ChannelId);
evt.ProtocolSession.WriteFrame(frame);
- //if (errorCode != AMQConstant.REPLY_SUCCESS.getCode())
// HACK
- if (errorCode != 200)
+ if ( errorCode != AMQConstant.REPLY_SUCCESS.Code )
{
_logger.Debug("Channel close received with errorCode " + errorCode + ", throwing exception");
evt.ProtocolSession.AMQConnection.ExceptionReceived(new AMQChannelClosedException(errorCode, "Error: " + reason));
@@ -55,3 +55,4 @@ namespace Qpid.Client.Handler
}
}
+
diff --git a/dotnet/Qpid.Client/Client/Handler/ConnectionCloseMethodHandler.cs b/dotnet/Qpid.Client/Client/Handler/ConnectionCloseMethodHandler.cs
index c3acc0b098..dea5316d25 100644
--- a/dotnet/Qpid.Client/Client/Handler/ConnectionCloseMethodHandler.cs
+++ b/dotnet/Qpid.Client/Client/Handler/ConnectionCloseMethodHandler.cs
@@ -19,10 +19,12 @@
*
*/
using System;
+using System.Threading;
using log4net;
using Qpid.Client.Protocol;
using Qpid.Client.State;
using Qpid.Framing;
+using Qpid.Protocol;
namespace Qpid.Client.Handler
{
@@ -38,16 +40,29 @@ namespace Qpid.Client.Handler
int errorCode = method.ReplyCode;
String reason = method.ReplyText;
+ // send CloseOK
evt.ProtocolSession.WriteFrame(ConnectionCloseOkBody.CreateAMQFrame(evt.ChannelId));
- stateManager.ChangeState(AMQState.CONNECTION_CLOSED);
- if (errorCode != 200)
+
+ if ( errorCode != AMQConstant.REPLY_SUCCESS.Code )
{
- _logger.Debug("Connection close received with error code " + errorCode);
- throw new AMQConnectionClosedException(errorCode, "Error: " + reason);
- }
+ if ( errorCode == AMQConstant.NOT_ALLOWED.Code )
+ {
+ _logger.Info("Authentication Error: " + Thread.CurrentThread.Name);
+ evt.ProtocolSession.CloseProtocolSession();
+
+ //todo this is a bit of a fudge (could be conssidered such as each new connection needs a new state manager or at least a fresh state.
+ stateManager.ChangeState(AMQState.CONNECTION_NOT_STARTED);
+ throw new AMQAuthenticationException(errorCode, reason);
+ } else
+ {
+ _logger.Info("Connection close received with error code " + errorCode);
+ throw new AMQConnectionClosedException(errorCode, "Error: " + reason);
+ }
+ }
// this actually closes the connection in the case where it is not an error.
evt.ProtocolSession.CloseProtocolSession();
+ stateManager.ChangeState(AMQState.CONNECTION_CLOSED);
}
}
}
diff --git a/dotnet/Qpid.Client/Client/Handler/ConnectionSecureMethodHandler.cs b/dotnet/Qpid.Client/Client/Handler/ConnectionSecureMethodHandler.cs
index 7c0fbd8f40..fe123e6745 100644
--- a/dotnet/Qpid.Client/Client/Handler/ConnectionSecureMethodHandler.cs
+++ b/dotnet/Qpid.Client/Client/Handler/ConnectionSecureMethodHandler.cs
@@ -21,6 +21,7 @@
using Qpid.Client.Protocol;
using Qpid.Client.State;
using Qpid.Framing;
+using Qpid.Sasl;
namespace Qpid.Client.Handler
{
@@ -28,9 +29,31 @@ namespace Qpid.Client.Handler
{
public void MethodReceived(AMQStateManager stateManager, AMQMethodEvent evt)
{
- AMQFrame response = ConnectionSecureOkBody.CreateAMQFrame(evt.ChannelId, null);
- evt.ProtocolSession.WriteFrame(response);
+ ISaslClient saslClient = evt.ProtocolSession.SaslClient;
+ if ( saslClient == null )
+ {
+ throw new AMQException("No SASL client set up - cannot proceed with authentication");
+ }
+
+
+ ConnectionSecureBody body = (ConnectionSecureBody)evt.Method;
+
+ try
+ {
+ // Evaluate server challenge
+ byte[] response = saslClient.EvaluateChallenge(body.Challenge);
+ // AMQP version change: Hardwire the version to 0-8 (major=8, minor=0)
+ // TODO: Connect this to the session version obtained from ProtocolInitiation for this session.
+ // Be aware of possible changes to parameter order as versions change.
+ AMQFrame responseFrame = ConnectionSecureOkBody.CreateAMQFrame(
+ evt.ChannelId, response);
+ evt.ProtocolSession.WriteFrame(responseFrame);
+ } catch ( SaslException e )
+ {
+ throw new AMQException("Error processing SASL challenge: " + e, e);
+ }
}
}
}
+
diff --git a/dotnet/Qpid.Client/Client/Handler/ConnectionStartMethodHandler.cs b/dotnet/Qpid.Client/Client/Handler/ConnectionStartMethodHandler.cs
index e88ff3ddbd..1815bea152 100644
--- a/dotnet/Qpid.Client/Client/Handler/ConnectionStartMethodHandler.cs
+++ b/dotnet/Qpid.Client/Client/Handler/ConnectionStartMethodHandler.cs
@@ -19,11 +19,15 @@
*
*/
using System;
+using System.Collections;
using System.Text;
using log4net;
using Qpid.Client.Protocol;
+using Qpid.Client.Security;
using Qpid.Client.State;
using Qpid.Framing;
+using Qpid.Sasl;
+
namespace Qpid.Client.Handler
{
@@ -35,36 +39,22 @@ namespace Qpid.Client.Handler
{
ConnectionStartBody body = (ConnectionStartBody) evt.Method;
AMQProtocolSession ps = evt.ProtocolSession;
- string username = ps.Username;
- string password = ps.Password;
try
{
- if (body.Mechanisms == null)
+ if ( body.Mechanisms == null )
{
throw new AMQException("mechanism not specified in ConnectionStart method frame");
}
- string allMechanisms = Encoding.ASCII.GetString(body.Mechanisms);
- string[] mechanisms = allMechanisms.Split(' ');
- string selectedMechanism = null;
- foreach (string mechanism in mechanisms)
- {
- if (mechanism.Equals("PLAIN"))
- {
- selectedMechanism = mechanism;
- break;
- }
- }
-
- if (selectedMechanism == null)
+ string mechanisms = Encoding.UTF8.GetString(body.Mechanisms);
+ string selectedMechanism = ChooseMechanism(mechanisms);
+ if ( selectedMechanism == null )
{
throw new AMQException("No supported security mechanism found, passed: " + mechanisms);
}
+
+ byte[] saslResponse = DoAuthentication(selectedMechanism, ps);
- // we always write out a null authzid which we don't currently use
- byte[] plainData = new byte[1 + ps.Username.Length + 1 + ps.Password.Length];
- Encoding.UTF8.GetBytes(username, 0, username.Length, plainData, 1);
- Encoding.UTF8.GetBytes(password, 0, password.Length, plainData, username.Length + 2);
if (body.Locales == null)
{
throw new AMQException("Locales is not defined in Connection Start method");
@@ -86,8 +76,9 @@ namespace Qpid.Client.Handler
clientProperties["product"] = "Qpid.NET";
clientProperties["version"] = "1.0";
clientProperties["platform"] = GetFullSystemInfo();
- AMQFrame frame = ConnectionStartOkBody.CreateAMQFrame(evt.ChannelId, clientProperties, selectedMechanism,
- plainData, selectedLocale);
+ AMQFrame frame = ConnectionStartOkBody.CreateAMQFrame(
+ evt.ChannelId, clientProperties, selectedMechanism,
+ saslResponse, selectedLocale);
ps.WriteFrame(frame);
}
catch (Exception e)
@@ -109,5 +100,51 @@ namespace Qpid.Client.Handler
// TODO: add in details here
return ".NET 1.1 Client";
}
+
+ private string ChooseMechanism(string mechanisms)
+ {
+ foreach ( string mech in mechanisms.Split(' ') )
+ {
+ if ( CallbackHandlerRegistry.Instance.IsSupportedMechanism(mech) )
+ {
+ return mech;
+ }
+ }
+ return null;
+ }
+
+ private byte[] DoAuthentication(string selectedMechanism, AMQProtocolSession ps)
+ {
+ ISaslClient saslClient = Sasl.Sasl.CreateClient(
+ new string[] { selectedMechanism }, null, "AMQP", "localhost",
+ new Hashtable(), CreateCallbackHandler(selectedMechanism, ps)
+ );
+ if ( saslClient == null )
+ {
+ throw new AMQException("Client SASL configuration error: no SaslClient could be created for mechanism " +
+ selectedMechanism);
+ }
+ ps.SaslClient = saslClient;
+ try
+ {
+ return saslClient.HasInitialResponse ?
+ saslClient.EvaluateChallenge(new byte[0]) : null;
+ } catch ( Exception ex )
+ {
+ ps.SaslClient = null;
+ throw new AMQException("Unable to create SASL client", ex);
+ }
+ }
+
+ private IAMQCallbackHandler CreateCallbackHandler(string mechanism, AMQProtocolSession session)
+ {
+ Type type = CallbackHandlerRegistry.Instance.GetCallbackHandler(mechanism);
+ IAMQCallbackHandler handler =
+ (IAMQCallbackHandler)Activator.CreateInstance(type);
+ if ( handler == null )
+ throw new AMQException("Unable to create callback handler: " + mechanism);
+ handler.Initialize(session);
+ return handler;
+ }
}
}
diff --git a/dotnet/Qpid.Client/Client/Protocol/AMQProtocolSession.cs b/dotnet/Qpid.Client/Client/Protocol/AMQProtocolSession.cs
index 15696f38c5..42169f31b3 100644
--- a/dotnet/Qpid.Client/Client/Protocol/AMQProtocolSession.cs
+++ b/dotnet/Qpid.Client/Client/Protocol/AMQProtocolSession.cs
@@ -24,6 +24,7 @@ using log4net;
using Qpid.Client.Message;
using Qpid.Client.Transport;
using Qpid.Framing;
+using Qpid.Sasl;
namespace Qpid.Client.Protocol
{
@@ -104,6 +105,13 @@ namespace Qpid.Client.Protocol
con.MaximumFrameSize = value.FrameMax;
}
}
+
+ private ISaslClient _saslClient;
+ public ISaslClient SaslClient
+ {
+ get { return _saslClient; }
+ set { _saslClient = value; }
+ }
/// <summary>
/// Callback invoked from the BasicDeliverMethodHandler when a message has been received.
diff --git a/dotnet/Qpid.Client/Client/Security/CallbackHandlerRegistry.cs b/dotnet/Qpid.Client/Client/Security/CallbackHandlerRegistry.cs
new file mode 100644
index 0000000000..78f13c9f42
--- /dev/null
+++ b/dotnet/Qpid.Client/Client/Security/CallbackHandlerRegistry.cs
@@ -0,0 +1,114 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+using System;
+using System.Collections;
+using System.Configuration;
+using System.Text;
+using Qpid.Sasl;
+using Qpid.Sasl.Mechanisms;
+
+using Qpid.Client.Configuration;
+
+namespace Qpid.Client.Security
+{
+
+ /// <summary>
+ /// Helper class to map SASL mechanisms to our
+ /// internal ISaslCallbackHandler implementations.
+ /// </summary>
+ /// <remarks>
+ /// The set of configured callback handlers and their order
+ /// controls the selection of the SASL mechanism used for authentication.
+ /// <para>
+ /// You can either replace the default handler for CRAM-MD5 and PLAIN
+ /// authentication (the two default options) using the application
+ /// configuration file. Configuration is done by especifying the SASL
+ /// mechanism name (e.g PLAIN) and the type implementing the callback handler
+ /// used to provide any data required by the mechanism like username and password.
+ /// </para>
+ /// <para>
+ /// Callback handler types should implement the IAMQCallbackHandler interface.
+ /// </para>
+ /// <para>
+ /// New callbacks or authentication mechanisms can be configured like this:
+ /// </para>
+ /// <example><![CDATA[
+ /// <configuration>
+ /// <configSections>
+ /// <sectionGroup name="qpid.client">
+ /// <section name="authentication" type="Qpid.Client.Configuration.AuthenticationConfigurationSectionHandler, Qpid.Client"/>
+ /// </sectionGroup>
+ /// </configSections>
+ /// <qpid.client>
+ /// <authentication>
+ /// <add key="TEST" value="Qpid.Client.Tests.Security.TestCallbackHandler, Qpid.Client.Tests"/>
+ /// </authentication>
+ /// </qpid.client>
+ /// </configuration>
+ /// ]]></example>
+ /// </remarks>
+ public sealed class CallbackHandlerRegistry
+ {
+ private static CallbackHandlerRegistry _instance =
+ new CallbackHandlerRegistry();
+ private IDictionary _mechanism2HandlerMap;
+ private string[] _mechanisms;
+
+ public static CallbackHandlerRegistry Instance
+ {
+ get { return _instance; }
+ }
+
+ public string[] Mechanisms
+ {
+ get { return _mechanisms; }
+ }
+
+ private CallbackHandlerRegistry()
+ {
+ _mechanism2HandlerMap = (IDictionary)
+ ConfigurationSettings.GetConfig("qpid.client/authentication");
+
+ // configure default options if not available
+ if ( _mechanism2HandlerMap == null )
+ _mechanism2HandlerMap = new Hashtable();
+
+ if ( !_mechanism2HandlerMap.Contains(CramMD5SaslClient.Mechanism) )
+ _mechanism2HandlerMap.Add(CramMD5SaslClient.Mechanism, typeof(UsernamePasswordCallbackHandler));
+ if ( !_mechanism2HandlerMap.Contains(PlainSaslClient.Mechanism) )
+ _mechanism2HandlerMap.Add(PlainSaslClient.Mechanism, typeof(UsernamePasswordCallbackHandler));
+
+ _mechanisms = new string[_mechanism2HandlerMap.Keys.Count];
+ _mechanism2HandlerMap.Keys.CopyTo(_mechanisms, 0);
+ }
+
+ public bool IsSupportedMechanism(string mechanism)
+ {
+ return _mechanism2HandlerMap.Contains(mechanism);
+ }
+
+ public Type GetCallbackHandler(string mechanism)
+ {
+ return (Type)_mechanism2HandlerMap[mechanism];
+ }
+ }
+}
diff --git a/dotnet/Qpid.Client/Client/Security/IAMQCallbackHandler.cs b/dotnet/Qpid.Client/Client/Security/IAMQCallbackHandler.cs
new file mode 100644
index 0000000000..6802b90cee
--- /dev/null
+++ b/dotnet/Qpid.Client/Client/Security/IAMQCallbackHandler.cs
@@ -0,0 +1,34 @@
+/*
+ *
+ * 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.
+ *
+ */
+using System;
+using System.Text;
+using Qpid.Client.Protocol;
+using Qpid.Sasl;
+
+namespace Qpid.Client.Security
+{
+ public interface IAMQCallbackHandler : ISaslCallbackHandler
+ {
+ void Initialize(AMQProtocolSession session);
+ }
+
+}
+
diff --git a/dotnet/Qpid.Client/Client/Security/UsernamePasswordCallbackHandler.cs b/dotnet/Qpid.Client/Client/Security/UsernamePasswordCallbackHandler.cs
new file mode 100644
index 0000000000..a14139496c
--- /dev/null
+++ b/dotnet/Qpid.Client/Client/Security/UsernamePasswordCallbackHandler.cs
@@ -0,0 +1,56 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+using System;
+using System.Collections;
+using System.Text;
+using Qpid.Client.Protocol;
+using Qpid.Sasl;
+
+namespace Qpid.Client.Security
+{
+ internal class UsernamePasswordCallbackHandler : IAMQCallbackHandler
+ {
+ private AMQProtocolSession _session;
+
+ public void Initialize(AMQProtocolSession session)
+ {
+ if ( session == null )
+ throw new ArgumentNullException("session");
+
+ _session = session;
+ }
+
+ public void Handle(ISaslCallback[] callbacks)
+ {
+ foreach ( ISaslCallback cb in callbacks )
+ {
+ if ( cb is NameCallback )
+ {
+ ((NameCallback)cb).Text = _session.Username;
+ } else if ( cb is PasswordCallback )
+ {
+ ((PasswordCallback)cb).Text = _session.Password;
+ }
+ }
+ }
+ }
+}