summaryrefslogtreecommitdiff
path: root/qpid/dotnet/Qpid.Sasl
diff options
context:
space:
mode:
authorRajith Muditha Attapattu <rajith@apache.org>2011-05-27 15:44:23 +0000
committerRajith Muditha Attapattu <rajith@apache.org>2011-05-27 15:44:23 +0000
commit66765100f4257159622cefe57bed50125a5ad017 (patch)
treea88ee23bb194eb91f0ebb2d9b23ff423e3ea8e37 /qpid/dotnet/Qpid.Sasl
parent1aeaa7b16e5ce54f10c901d75c4d40f9f88b9db6 (diff)
parent88b98b2f4152ef59a671fad55a0d08338b6b78ca (diff)
downloadqpid-python-rajith_jms_client.tar.gz
Creating a branch for experimenting with some ideas for JMS client.rajith_jms_client
git-svn-id: https://svn.apache.org/repos/asf/qpid/branches/rajith_jms_client@1128369 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'qpid/dotnet/Qpid.Sasl')
-rw-r--r--qpid/dotnet/Qpid.Sasl/Callbacks.cs139
-rw-r--r--qpid/dotnet/Qpid.Sasl/Configuration/SaslConfiguration.cs90
-rw-r--r--qpid/dotnet/Qpid.Sasl/Configuration/SaslConfigurationSectionHandler.cs84
-rw-r--r--qpid/dotnet/Qpid.Sasl/DefaultClientFactory.cs99
-rw-r--r--qpid/dotnet/Qpid.Sasl/ISaslCallbackHandler.cs35
-rw-r--r--qpid/dotnet/Qpid.Sasl/ISaslClient.cs42
-rw-r--r--qpid/dotnet/Qpid.Sasl/ISaslClientFactory.cs40
-rw-r--r--qpid/dotnet/Qpid.Sasl/MD5HMAC.cs115
-rw-r--r--qpid/dotnet/Qpid.Sasl/Mechanisms/AnonymousSaslClient.cs69
-rw-r--r--qpid/dotnet/Qpid.Sasl/Mechanisms/CramMD5HexSaslClient.cs93
-rw-r--r--qpid/dotnet/Qpid.Sasl/Mechanisms/CramMD5SaslClient.cs91
-rw-r--r--qpid/dotnet/Qpid.Sasl/Mechanisms/DigestSaslClient.cs576
-rw-r--r--qpid/dotnet/Qpid.Sasl/Mechanisms/ExternalSaslClient.cs69
-rw-r--r--qpid/dotnet/Qpid.Sasl/Mechanisms/PlainSaslClient.cs81
-rw-r--r--qpid/dotnet/Qpid.Sasl/Properties/AssemblyInfo.cs57
-rw-r--r--qpid/dotnet/Qpid.Sasl/Qpid.Sasl.csproj73
-rw-r--r--qpid/dotnet/Qpid.Sasl/Sasl.cs115
-rw-r--r--qpid/dotnet/Qpid.Sasl/SaslClient.cs145
-rw-r--r--qpid/dotnet/Qpid.Sasl/SaslException.cs56
-rw-r--r--qpid/dotnet/Qpid.Sasl/SaslProperties.cs42
-rw-r--r--qpid/dotnet/Qpid.Sasl/default.build45
21 files changed, 2156 insertions, 0 deletions
diff --git a/qpid/dotnet/Qpid.Sasl/Callbacks.cs b/qpid/dotnet/Qpid.Sasl/Callbacks.cs
new file mode 100644
index 0000000000..f4fcc1c54b
--- /dev/null
+++ b/qpid/dotnet/Qpid.Sasl/Callbacks.cs
@@ -0,0 +1,139 @@
+/*
+ *
+ * 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 System.Globalization;
+using System.Security.Cryptography;
+
+namespace Apache.Qpid.Sasl
+{
+ /// <summary>
+ /// Marker interface for Sasl Callbacks
+ /// </summary>
+ public interface ISaslCallback
+ {
+ } // interface ISaslCallback
+
+ public abstract class TextSaslCallback : ISaslCallback
+ {
+ private string _prompt;
+ private string _text;
+ private string _defaultText;
+
+ public string Prompt
+ {
+ get { return _prompt; }
+ set { _prompt = value; }
+ }
+
+ public string Text
+ {
+ get {
+ if ( _text == null || _text.Length == 0 )
+ return DefaultText;
+ else
+ return _text;
+ }
+ set { _text = value; }
+ }
+
+ public string DefaultText
+ {
+ get { return _defaultText; }
+ set { _defaultText = value; }
+ }
+
+ protected TextSaslCallback(string prompt, string text, string defaultText)
+ {
+ _prompt = prompt;
+ _text = text;
+ _defaultText = defaultText;
+ }
+
+ } // class TextSaslCallback
+
+ public class NameCallback : TextSaslCallback
+ {
+ public NameCallback()
+ : this(Environment.UserName)
+ {
+ }
+ public NameCallback(string defaultText)
+ : base("username:", "", defaultText)
+ {
+ }
+ } // class NameCallback
+
+ public class PasswordCallback : TextSaslCallback
+ {
+ public PasswordCallback()
+ : base("password:", "", "")
+ {
+ }
+
+ public byte[] HashedText
+ {
+ get
+ {
+ string _text = this.Text;
+ System.Security.Cryptography.MD5CryptoServiceProvider x = new System.Security.Cryptography.MD5CryptoServiceProvider();
+ byte[] bs = x.ComputeHash(Encoding.UTF8.GetBytes(_text));
+ return bs;
+ }
+
+ }
+ } // class PasswordCallback
+
+ public class HashedPasswordCallback : TextSaslCallback
+ {
+ public HashedPasswordCallback()
+ : base("password:", "", "")
+ {
+ }
+
+ public byte[] HashedText
+ {
+ get {
+ string _text = this.Text;
+ System.Security.Cryptography.MD5CryptoServiceProvider x = new System.Security.Cryptography.MD5CryptoServiceProvider();
+ _text = _text.PadRight(16, '\0');
+ byte[] bs = x.ComputeHash(Encoding.UTF8.GetBytes(_text));
+ return bs;
+ }
+ }
+ } // class PasswordCallback
+
+ public class RealmCallback : TextSaslCallback
+ {
+ public RealmCallback()
+ : this("localhost")
+ {
+ }
+ public RealmCallback(string defaultText)
+ : base("realm:", "", defaultText)
+ {
+ }
+ } // class RealmCallback
+
+} // namespace Apache.Qpid.Sasl
+
+
diff --git a/qpid/dotnet/Qpid.Sasl/Configuration/SaslConfiguration.cs b/qpid/dotnet/Qpid.Sasl/Configuration/SaslConfiguration.cs
new file mode 100644
index 0000000000..7a71ec28da
--- /dev/null
+++ b/qpid/dotnet/Qpid.Sasl/Configuration/SaslConfiguration.cs
@@ -0,0 +1,90 @@
+/*
+ *
+ * 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 System.Xml;
+
+namespace Apache.Qpid.Sasl.Configuration
+{
+ /// <summary>
+ /// Represents an Sasl configuration section
+ /// in the config file
+ /// </summary>
+ internal class SaslConfiguration
+ {
+ private IList _clientFactories;
+
+ /// <summary>
+ /// Set of configured client factores
+ /// </summary>
+ public IList ClientFactories
+ {
+ get { return _clientFactories; }
+ }
+
+ internal SaslConfiguration(IList clientFactoryTypes)
+ {
+ _clientFactories = new ArrayList();
+ foreach ( Type type in clientFactoryTypes )
+ {
+ _clientFactories.Add(Activator.CreateInstance(type));
+ }
+ }
+
+ /// <summary>
+ /// Get the configuration for the library
+ /// </summary>
+ /// <returns>The configuration from app.config or a default configuration</returns>
+ internal static SaslConfiguration GetConfiguration()
+ {
+ // 'obsolete' warning, but needed for .NET 1.1 compatibility
+ SaslConfiguration config = (SaslConfiguration)
+ ConfigurationSettings.GetConfig("qpid.sasl");
+ if ( config == null )
+ {
+ // create default configuration
+ IList clientFactories = GetDefaultClientFactories();
+ config = new SaslConfiguration(clientFactories);
+ }
+ return config;
+ }
+
+ /// <summary>
+ /// Create a list filled with the default client
+ /// factories supported by the library
+ /// </summary>
+ /// <returns>The list of client factory types</returns>
+ internal static IList GetDefaultClientFactories()
+ {
+ IList clientFactories = new ArrayList();
+ clientFactories.Add(typeof(DefaultClientFactory));
+ return clientFactories;
+ }
+
+
+ } // class SaslConfiguration
+
+} // namespace Apache.Qpid.Sasl.Configuration
+
+
diff --git a/qpid/dotnet/Qpid.Sasl/Configuration/SaslConfigurationSectionHandler.cs b/qpid/dotnet/Qpid.Sasl/Configuration/SaslConfigurationSectionHandler.cs
new file mode 100644
index 0000000000..ea8669f8c4
--- /dev/null
+++ b/qpid/dotnet/Qpid.Sasl/Configuration/SaslConfigurationSectionHandler.cs
@@ -0,0 +1,84 @@
+/*
+ *
+ * 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 System.Xml;
+
+namespace Apache.Qpid.Sasl.Configuration
+{
+ /// <summary>
+ /// Defines the configuration section to configure extra
+ /// Sasl client factories
+ /// </summary>
+ public class SaslConfigurationSectionHandler
+ : IConfigurationSectionHandler
+ {
+ public object Create(object parent, object configContext, XmlNode section)
+ {
+ IList clientFactories = SaslConfiguration.GetDefaultClientFactories();
+
+ foreach ( XmlNode node in section.ChildNodes )
+ {
+ if ( node.LocalName == "clientFactories" )
+ {
+ ProcessFactories(node, clientFactories);
+ }
+ }
+
+ SaslConfiguration config = new SaslConfiguration(clientFactories);
+ return config;
+ }
+
+
+ private void ProcessFactories(XmlNode node, IList factories)
+ {
+ foreach ( XmlNode child in node.ChildNodes )
+ {
+ Type type;
+ switch ( child.LocalName )
+ {
+ case "add":
+ type = Type.GetType(child.Attributes["type"].Value);
+ if ( !factories.Contains(type) )
+ factories.Add(type);
+ break;
+ case "remove":
+ type = Type.GetType(child.Attributes["type"].Value);
+ if ( factories.Contains(type) )
+ factories.Remove(type);
+ break;
+ case "clear":
+ factories.Clear();
+ break;
+ default:
+ // gives obsolete warning but needed for .NET 1.1 support
+ throw new ConfigurationException(string.Format("Unknown element '{0}' in section '{0}'", child.LocalName, node.LocalName));
+ }
+ }
+ }
+ } // class SaslConfigurationSectionHandler
+
+} // namespace Apache.Qpid.Sasl.Configuration
+
+
diff --git a/qpid/dotnet/Qpid.Sasl/DefaultClientFactory.cs b/qpid/dotnet/Qpid.Sasl/DefaultClientFactory.cs
new file mode 100644
index 0000000000..744d7cae40
--- /dev/null
+++ b/qpid/dotnet/Qpid.Sasl/DefaultClientFactory.cs
@@ -0,0 +1,99 @@
+/*
+ *
+ * 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 Apache.Qpid.Sasl.Mechanisms;
+
+namespace Apache.Qpid.Sasl
+{
+ public class DefaultClientFactory : ISaslClientFactory
+ {
+ private static readonly string[] SUPPORTED = new string[] {
+ DigestSaslClient.Mechanism,
+ CramMD5SaslClient.Mechanism,
+ CramMD5HexSaslClient.Mechanism,
+ PlainSaslClient.Mechanism,
+ AnonymousSaslClient.Mechanism,
+ ExternalSaslClient.Mechanism,
+ };
+
+ public string[] GetSupportedMechanisms(IDictionary props)
+ {
+ if ( props == null )
+ throw new ArgumentNullException("props");
+
+ ArrayList vetoed = new ArrayList();
+
+ if ( props.Contains(SaslProperties.PolicyNoPlainText) ||
+ props.Contains(SaslProperties.PolicyNoDictionary) ||
+ props.Contains(SaslProperties.PolicyNoActive) ||
+ props.Contains(SaslProperties.PolicyForwardSecrecy) ||
+ props.Contains(SaslProperties.PolicyPassCredentials) )
+ {
+ vetoed.Add(CramMD5SaslClient.Mechanism);
+ vetoed.Add(CramMD5HexSaslClient.Mechanism);
+ vetoed.Add(PlainSaslClient.Mechanism);
+ vetoed.Add(AnonymousSaslClient.Mechanism);
+ vetoed.Add(ExternalSaslClient.Mechanism);
+ }
+ if ( props.Contains(SaslProperties.PolicyNoAnonymous) )
+ {
+ vetoed.Add(AnonymousSaslClient.Mechanism);
+ }
+
+ ArrayList available = new ArrayList();
+ foreach ( string mech in SUPPORTED )
+ {
+ if ( !vetoed.Contains(mech) )
+ available.Add(mech);
+ }
+ return (string[])available.ToArray(typeof(string));
+ }
+
+ public ISaslClient CreateClient(
+ string[] mechanisms, string authorizationId,
+ string protocol, string serverName,
+ IDictionary props, ISaslCallbackHandler handler
+ )
+ {
+ IList mechs = mechanisms;
+ if ( mechs.Contains(ExternalSaslClient.Mechanism) )
+ return new ExternalSaslClient(authorizationId, props, handler);
+ if ( mechs.Contains(DigestSaslClient.Mechanism) )
+ return new DigestSaslClient(authorizationId, serverName, protocol, props, handler);
+ if ( mechs.Contains(CramMD5SaslClient.Mechanism) )
+ return new CramMD5SaslClient(authorizationId, props, handler);
+ if ( mechs.Contains(CramMD5HexSaslClient.Mechanism) )
+ return new CramMD5HexSaslClient(authorizationId, props, handler);
+ if ( mechs.Contains(PlainSaslClient.Mechanism) )
+ return new PlainSaslClient(authorizationId, props, handler);
+ if ( mechs.Contains(AnonymousSaslClient.Mechanism) )
+ return new AnonymousSaslClient(authorizationId, props, handler);
+ // unknown mechanism
+ return null;
+ }
+ } // class DefaultClientFactory
+
+} // namespace Apache.Qpid.Sasl
+
+
diff --git a/qpid/dotnet/Qpid.Sasl/ISaslCallbackHandler.cs b/qpid/dotnet/Qpid.Sasl/ISaslCallbackHandler.cs
new file mode 100644
index 0000000000..c2638f245e
--- /dev/null
+++ b/qpid/dotnet/Qpid.Sasl/ISaslCallbackHandler.cs
@@ -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.
+ *
+ */
+
+using System;
+using System.Text;
+
+namespace Apache.Qpid.Sasl
+{
+ public interface ISaslCallbackHandler
+ {
+ void Handle(ISaslCallback[] callbacks);
+
+ } // interface ISaslCallbackHandler
+
+} // namespace Apache.Qpid.Sasl
+
+
diff --git a/qpid/dotnet/Qpid.Sasl/ISaslClient.cs b/qpid/dotnet/Qpid.Sasl/ISaslClient.cs
new file mode 100644
index 0000000000..668ca05d26
--- /dev/null
+++ b/qpid/dotnet/Qpid.Sasl/ISaslClient.cs
@@ -0,0 +1,42 @@
+/*
+ *
+ * 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;
+
+namespace Apache.Qpid.Sasl
+{
+ public interface ISaslClient
+ {
+ string MechanismName { get; }
+ bool HasInitialResponse { get; }
+ bool IsComplete { get; }
+
+ byte[] EvaluateChallenge(byte[] challenge);
+ object GetNegotiatedProperty(string propName);
+ byte[] Unwrap(byte[] buffer, int offset, int length);
+ byte[] Wrap(byte[] buffer, int offset, int lenght);
+
+ } // interface ISaslClient
+
+} // namespace Apache.Qpid.Sasl
+
+
diff --git a/qpid/dotnet/Qpid.Sasl/ISaslClientFactory.cs b/qpid/dotnet/Qpid.Sasl/ISaslClientFactory.cs
new file mode 100644
index 0000000000..f052e07ad9
--- /dev/null
+++ b/qpid/dotnet/Qpid.Sasl/ISaslClientFactory.cs
@@ -0,0 +1,40 @@
+/*
+ *
+ * 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;
+
+namespace Apache.Qpid.Sasl
+{
+ public interface ISaslClientFactory
+ {
+ string[] GetSupportedMechanisms(IDictionary props);
+ ISaslClient CreateClient(
+ string[] mechanisms, string authorizationId,
+ string protocol, string serverName,
+ IDictionary props, ISaslCallbackHandler handler
+ );
+ } // interface ISaslClientFactory
+
+} // namespace Apache.Qpid.Sasl
+
+
diff --git a/qpid/dotnet/Qpid.Sasl/MD5HMAC.cs b/qpid/dotnet/Qpid.Sasl/MD5HMAC.cs
new file mode 100644
index 0000000000..7e310c5364
--- /dev/null
+++ b/qpid/dotnet/Qpid.Sasl/MD5HMAC.cs
@@ -0,0 +1,115 @@
+/*
+ *
+ * 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.Security.Cryptography;
+
+namespace Apache.Qpid.Sasl
+{
+ /// <summary>
+ /// Rough HMAC MD5 implementation as presented in
+ /// RFC 2104. Used because the HMACMD5 class in the
+ /// .NET framework is not available in v1.1.
+ /// </summary>
+ public sealed class MD5HMAC : IDisposable
+ {
+ private const int BLOCK_LEN = 64;
+ private MD5 _hash;
+ private byte[] _key;
+ private byte[] _ipad;
+ private byte[] _opad;
+
+ public MD5HMAC(byte[] key)
+ {
+ if ( key == null || key.Length == 0 )
+ throw new ArgumentNullException("key");
+
+ _hash = new MD5CryptoServiceProvider();
+
+ byte[] theKey = key;
+ if ( theKey.Length > BLOCK_LEN )
+ {
+ theKey = _hash.ComputeHash(theKey);
+ }
+ // pad key with 0's up to BLOCK_LEN
+ _key = new byte[BLOCK_LEN];
+ Array.Copy(theKey, _key, theKey.Length);
+
+ CreatePads();
+ }
+
+ public byte[] ComputeHash(byte[] input)
+ {
+ // H(K XOR opad, H(K XOR ipad, text))
+ return H(_opad, H(_ipad, input));
+ }
+
+ public void Dispose()
+ {
+ if ( _hash != null )
+ {
+ ((IDisposable)_hash).Dispose();
+ _hash = null;
+ }
+ }
+
+ #region Private Methods
+ //
+ // Private Methods
+ //
+
+ private void CreatePads()
+ {
+ _ipad = new byte[BLOCK_LEN];
+ _opad = new byte[BLOCK_LEN];
+ for ( int i = 0; i < BLOCK_LEN; i++ )
+ {
+ _ipad[i] = 0x36;
+ _opad[i] = 0x5c;
+ }
+
+ XOR(_ipad, _key);
+ XOR(_opad, _key);
+ }
+
+ private static void XOR(byte[] dest, byte[] other)
+ {
+ // assume both are same size
+ for ( int i = 0; i < dest.Length; i++ )
+ {
+ dest[i] ^= other[i];
+ }
+ }
+
+ private byte[] H(byte[] v1, byte[] v2)
+ {
+ byte[] total = new byte[v1.Length + v2.Length];
+ Array.Copy(v1, total, v1.Length);
+ Array.Copy(v2, 0, total, v1.Length, v2.Length);
+
+ return _hash.ComputeHash(total);
+ }
+
+ #endregion // Private Methods
+
+ } // class MD5HMAC
+
+} // namespace Apache.Qpid.Sasl
diff --git a/qpid/dotnet/Qpid.Sasl/Mechanisms/AnonymousSaslClient.cs b/qpid/dotnet/Qpid.Sasl/Mechanisms/AnonymousSaslClient.cs
new file mode 100644
index 0000000000..e550d10d97
--- /dev/null
+++ b/qpid/dotnet/Qpid.Sasl/Mechanisms/AnonymousSaslClient.cs
@@ -0,0 +1,69 @@
+/*
+ *
+ * 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;
+
+namespace Apache.Qpid.Sasl.Mechanisms
+{
+ /// <summary>
+ /// Implements the ANONYMOUS authentication mechanism
+ /// as outlined in RFC 2245
+ /// </summary>
+ public class AnonymousSaslClient : SaslClient
+ {
+ public const string Mechanism = "ANONYMOUS";
+
+ public AnonymousSaslClient(
+ string authid, IDictionary properties,
+ ISaslCallbackHandler handler)
+ : base(authid, null, null, properties, handler)
+ {
+ }
+
+ #region ISaslClient Implementation
+ //
+ // ISaslClient Implementation
+ //
+
+ public override string MechanismName
+ {
+ get { return Mechanism; }
+ }
+
+ public override bool HasInitialResponse
+ {
+ get { return true; }
+ }
+
+ public override byte[] EvaluateChallenge(byte[] challenge)
+ {
+ // ignore challenge
+ SetComplete();
+ return Encoding.UTF8.GetBytes(AuthorizationId);
+ }
+
+ #endregion // ISaslClient Implementation
+
+ } // class AnonymousSaslClient
+
+} // namespace Apache.Qpid.Sasl.Mechanisms
diff --git a/qpid/dotnet/Qpid.Sasl/Mechanisms/CramMD5HexSaslClient.cs b/qpid/dotnet/Qpid.Sasl/Mechanisms/CramMD5HexSaslClient.cs
new file mode 100644
index 0000000000..3cce0e3a2d
--- /dev/null
+++ b/qpid/dotnet/Qpid.Sasl/Mechanisms/CramMD5HexSaslClient.cs
@@ -0,0 +1,93 @@
+/*
+ *
+ * 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.Security.Cryptography;
+using System.Text;
+
+namespace Apache.Qpid.Sasl.Mechanisms
+{
+ /// <summary>
+ /// Implements the CRAM-MD5 authentication mechanism as outlined
+ /// in RFC 2195
+ /// </summary>
+ public class CramMD5HexSaslClient : SaslClient
+ {
+ public const string Mechanism = "CRAM-MD5-HEX";
+ private const int MinPwdLen = 16;
+
+ public CramMD5HexSaslClient(
+ string authorizationId,
+ IDictionary properties,
+ ISaslCallbackHandler handler)
+ : base(authorizationId, null, null, properties, handler)
+ {
+ }
+
+ #region ISaslClient Implementation
+ //
+ // ISaslClient Implementation
+ //
+
+ public override string MechanismName
+ {
+ get { return Mechanism; }
+ }
+
+ public override bool HasInitialResponse
+ {
+ get { return false; }
+ }
+
+
+ public override byte[] EvaluateChallenge(byte[] challenge)
+ {
+ if ( challenge == null || challenge.Length == 0 )
+ throw new ArgumentNullException("challenge");
+
+
+ NameCallback nameCB = new NameCallback(AuthorizationId);
+ PasswordCallback pwdCB = new PasswordCallback();
+ ISaslCallback[] callbacks = { nameCB, pwdCB };
+ Handler.Handle(callbacks);
+
+ string username = nameCB.Text;
+
+ //Encode the Hashed Password as Hex
+ byte[] passwd = Encoding.UTF8.GetBytes(ToHex(pwdCB.HashedText));
+
+ string s = System.Text.UTF8Encoding.UTF8.GetString(challenge);
+
+ using ( HMAC hmac = new HMACMD5(passwd) )
+ {
+ byte[] value = hmac.ComputeHash(challenge);
+ string encoded = ToHex(value);
+ SetComplete();
+ return Encoding.UTF8.GetBytes(username + " " + encoded);
+ }
+ }
+
+ #endregion // ISaslClient Implementation
+
+ } // class CramMD5HashedSaslClient
+
+} // namespace Apache.Qpid.Sasl.Mechanisms
diff --git a/qpid/dotnet/Qpid.Sasl/Mechanisms/CramMD5SaslClient.cs b/qpid/dotnet/Qpid.Sasl/Mechanisms/CramMD5SaslClient.cs
new file mode 100644
index 0000000000..56b0f6ecd4
--- /dev/null
+++ b/qpid/dotnet/Qpid.Sasl/Mechanisms/CramMD5SaslClient.cs
@@ -0,0 +1,91 @@
+/*
+ *
+ * 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.Security.Cryptography;
+using System.Text;
+
+namespace Apache.Qpid.Sasl.Mechanisms
+{
+ /// <summary>
+ /// Implements the CRAM-MD5 authentication mechanism as outlined
+ /// in RFC 2195
+ /// </summary>
+ public class CramMD5SaslClient : SaslClient
+ {
+ public const string Mechanism = "CRAM-MD5";
+ private const int MinPwdLen = 16;
+
+ public CramMD5SaslClient(
+ string authorizationId,
+ IDictionary properties,
+ ISaslCallbackHandler handler)
+ : base(authorizationId, null, null, properties, handler)
+ {
+ }
+
+ #region ISaslClient Implementation
+ //
+ // ISaslClient Implementation
+ //
+
+ public override string MechanismName
+ {
+ get { return Mechanism; }
+ }
+
+ public override bool HasInitialResponse
+ {
+ get { return false; }
+ }
+
+ public override byte[] EvaluateChallenge(byte[] challenge)
+ {
+ if ( challenge == null || challenge.Length == 0 )
+ throw new ArgumentNullException("challenge");
+
+ NameCallback nameCB = new NameCallback(AuthorizationId);
+ PasswordCallback pwdCB = new PasswordCallback();
+ ISaslCallback[] callbacks = { nameCB, pwdCB };
+ Handler.Handle(callbacks);
+
+ string username = nameCB.Text;
+ string passwd = pwdCB.Text.PadRight(MinPwdLen, '\0');
+
+ byte[] secret = Encoding.UTF8.GetBytes(passwd);
+
+ //using ( HMAC hmac = new HMACMD5(secret) )
+ using ( MD5HMAC hmac = new MD5HMAC(secret) )
+ {
+ byte[] value = hmac.ComputeHash(challenge);
+ string encoded = ToHex(value);
+ SetComplete();
+ return Encoding.UTF8.GetBytes(username + " " + encoded);
+ }
+
+ }
+
+ #endregion // ISaslClient Implementation
+
+ } // class CramMD5SaslClient
+
+} // namespace Apache.Qpid.Sasl.Mechanisms
diff --git a/qpid/dotnet/Qpid.Sasl/Mechanisms/DigestSaslClient.cs b/qpid/dotnet/Qpid.Sasl/Mechanisms/DigestSaslClient.cs
new file mode 100644
index 0000000000..79843587c7
--- /dev/null
+++ b/qpid/dotnet/Qpid.Sasl/Mechanisms/DigestSaslClient.cs
@@ -0,0 +1,576 @@
+/*
+ *
+ * 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.Globalization;
+using System.Security.Cryptography;
+using System.Text;
+
+namespace Apache.Qpid.Sasl.Mechanisms
+{
+
+ /// <summary>
+ /// Implements the DIGEST MD5 authentication mechanism
+ /// as outlined in RFC 2831
+ /// </summary>
+ public class DigestSaslClient : SaslClient
+ {
+ public const string Mechanism = "DIGEST-MD5";
+ private static readonly MD5 _md5 = new MD5CryptoServiceProvider();
+ private int _state;
+ private string _cnonce;
+ private Encoding _encoding = Encoding.UTF8;
+
+ public string Cnonce
+ {
+ get { return _cnonce; }
+ set { _cnonce = value; }
+ }
+
+ public DigestSaslClient(
+ string authid, string serverName, string protocol,
+ IDictionary properties, ISaslCallbackHandler handler)
+ : base(authid, serverName, protocol, properties, handler)
+ {
+ _cnonce = Guid.NewGuid().ToString("N");
+ }
+
+ #region ISaslClient Implementation
+ //
+ // ISaslClient Implementation
+ //
+
+ public override string MechanismName
+ {
+ get { return Mechanism; }
+ }
+
+ public override bool HasInitialResponse
+ {
+ get { return false; }
+ }
+
+ public override byte[] EvaluateChallenge(byte[] challenge)
+ {
+ if ( challenge == null || challenge.Length <= 0 )
+ throw new ArgumentNullException("challenge");
+
+ switch ( _state++ )
+ {
+ case 0: return OnInitialChallenge(challenge);
+ case 1: return OnFinalResponse(challenge);
+ }
+ throw new SaslException("Invalid State for authentication");
+ }
+
+ #endregion // ISaslClient Implementation
+
+
+ #region Private Methods
+ //
+ // Private Methods
+ //
+
+ /// <summary>
+ /// Process the first challenge from the server
+ /// and calculate a response
+ /// </summary>
+ /// <param name="challenge">The server issued challenge</param>
+ /// <returns>Client response</returns>
+ private byte[] OnInitialChallenge(byte[] challenge)
+ {
+ DigestChallenge dch =
+ DigestChallenge.Parse(_encoding.GetString(challenge));
+ // validate input challenge
+ if ( dch.Nonce == null || dch.Nonce.Length == 0 )
+ throw new SaslException("Nonce value missing in server challenge");
+ if ( dch.Algorithm != "md5-sess" )
+ throw new SaslException("Invalid or missing algorithm value in server challenge");
+
+
+ NameCallback nameCB = new NameCallback(AuthorizationId);
+ PasswordCallback pwdCB = new PasswordCallback();
+ RealmCallback realmCB = new RealmCallback(dch.Realm);
+ ISaslCallback[] callbacks = { nameCB, pwdCB, realmCB };
+ Handler.Handle(callbacks);
+
+ DigestResponse response = new DigestResponse();
+ response.Username = nameCB.Text;
+ response.Realm = realmCB.Text;
+ response.Nonce = dch.Nonce;
+ response.Cnonce = Cnonce;
+ response.NonceCount = 1;
+ response.Qop = DigestQop.Auth; // only auth supported for now
+ response.DigestUri = Protocol.ToLower() + "/" + ServerName;
+ response.MaxBuffer = dch.MaxBuffer;
+ response.Charset = dch.Charset;
+ response.Cipher = null; // not supported for now
+ response.Authzid = AuthorizationId;
+ response.AuthParam = dch.AuthParam;
+
+ response.Response = CalculateResponse(
+ nameCB.Text, realmCB.Text, pwdCB.Text,
+ dch.Nonce, response.NonceCount, response.Qop, response.DigestUri
+ );
+
+ return _encoding.GetBytes(response.ToString());
+ }
+
+ /// <summary>
+ /// Process the second server challenge
+ /// </summary>
+ /// <param name="challenge">Server issued challenge</param>
+ /// <returns>The client response</returns>
+ private byte[] OnFinalResponse(byte[] challenge)
+ {
+ DigestChallenge dch =
+ DigestChallenge.Parse(_encoding.GetString(challenge));
+
+ if ( dch.Rspauth == null || dch.Rspauth.Length == 0 )
+ throw new SaslException("Expected 'rspauth' in server challenge not found");
+
+ SetComplete();
+ return new byte[0];
+ }
+
+
+
+ /// <summary>
+ /// Calculate the response field of the client response
+ /// </summary>
+ /// <param name="username">The user name</param>
+ /// <param name="realm">The realm</param>
+ /// <param name="passwd">The user's password</param>
+ /// <param name="nonce">Server nonce value</param>
+ /// <param name="nc">Client nonce count (always 1)</param>
+ /// <param name="qop">Quality of Protection</param>
+ /// <param name="digestUri">Digest-URI</param>
+ /// <returns>The value for the response field</returns>
+ private string CalculateResponse(
+ string username, string realm, string passwd,
+ string nonce, int nc, string qop, string digestUri
+ )
+ {
+ string a1 = CalcHexA1(username, realm, passwd, nonce);
+ string a2 = CalcHexA2(digestUri, qop);
+
+ string ncs = nc.ToString("x8", CultureInfo.InvariantCulture);
+ StringBuilder prekd = new StringBuilder();
+ prekd.Append(a1).Append(':').Append(nonce).Append(':')
+ .Append(ncs).Append(':').Append(Cnonce)
+ .Append(':').Append(qop).Append(':').Append(a2);
+
+ return ToHex(CalcH(_encoding.GetBytes(prekd.ToString())));
+ }
+
+ private string CalcHexA1(
+ string username, string realm,
+ string passwd, string nonce
+ )
+ {
+ bool hasAuthId = AuthorizationId != null && AuthorizationId.Length > 0;
+
+ string premd = username + ":" + realm + ":" + passwd;
+ byte[] temp1 = CalcH(_encoding.GetBytes(premd));
+
+
+ int a1len = 16 + 1 + nonce.Length + 1 + Cnonce.Length;
+ if ( hasAuthId )
+ a1len += 1 + AuthorizationId.Length;
+
+ byte[] buffer = new byte[a1len];
+ Array.Copy(temp1, buffer, temp1.Length);
+
+ string p2 = ":" + nonce + ":" + Cnonce;
+ if ( hasAuthId )
+ p2 += ":" + AuthorizationId;
+
+ byte[] temp2 = _encoding.GetBytes(p2);
+ Array.Copy(temp2, 0, buffer, 16, temp2.Length);
+
+ return ToHex(CalcH(buffer));
+ }
+
+ private string CalcHexA2(string digestUri, string qop)
+ {
+ string a2 = "AUTHENTICATE:" + digestUri;
+ if ( qop != DigestQop.Auth )
+ a2 += ":00000000000000000000000000000000";
+ return ToHex(CalcH(_encoding.GetBytes(a2)));
+ }
+
+ private static byte[] CalcH(byte[] value)
+ {
+ return _md5.ComputeHash(value);
+ }
+
+ #endregion // Private Methods
+
+
+ } // class DigestSaslClient
+
+
+ /// <summary>
+ /// Available QOP options in the DIGEST scheme
+ /// </summary>
+ public sealed class DigestQop
+ {
+ public const string Auth = "auth";
+ public const string AuthInt = "auth-int";
+ public const string AuthConf = "auth-conf";
+ } // class DigestQop
+
+
+ /// <summary>
+ /// Represents and parses a digest server challenge
+ /// </summary>
+ public class DigestChallenge
+ {
+ private string _realm = "localhost";
+ private string _nonce;
+ private string[] _qopOptions = { DigestQop.Auth };
+ private bool _stale;
+ private int _maxBuffer = 65536;
+ private string _charset = "ISO 8859-1";
+ private string _algorithm;
+ private string[] _cipherOptions;
+ private string _authParam;
+ private string _rspauth;
+
+ #region Properties
+ //
+ // Properties
+ //
+
+ public string Realm
+ {
+ get { return _realm; }
+ }
+
+ public string Nonce
+ {
+ get { return _nonce; }
+ }
+
+ public string[] QopOptions
+ {
+ get { return _qopOptions; }
+ }
+
+ public bool Stale
+ {
+ get { return _stale; }
+ }
+
+ public int MaxBuffer
+ {
+ get { return _maxBuffer; }
+ set { _maxBuffer = value; }
+ }
+
+ public string Charset
+ {
+ get { return _charset; }
+ }
+
+ public string Algorithm
+ {
+ get { return _algorithm; }
+ }
+
+ public string[] CipherOptions
+ {
+ get { return _cipherOptions; }
+ }
+
+ public string AuthParam
+ {
+ get { return _authParam; }
+ }
+
+ public string Rspauth
+ {
+ get { return _rspauth; }
+ }
+
+ #endregion // Properties
+
+ public static DigestChallenge Parse(string challenge)
+ {
+ DigestChallenge parsed = new DigestChallenge();
+ StringDictionary parts = ParseParameters(challenge);
+ foreach ( string optname in parts.Keys )
+ {
+ switch ( optname )
+ {
+ case "realm":
+ parsed._realm = parts[optname];
+ break;
+ case "nonce":
+ parsed._nonce = parts[optname];
+ break;
+ case "qop-options":
+ parsed._qopOptions = GetOptions(parts[optname]);
+ break;
+ case "cipher-opts":
+ parsed._cipherOptions = GetOptions(parts[optname]);
+ break;
+ case "stale":
+ parsed._stale = Convert.ToBoolean(parts[optname], CultureInfo.InvariantCulture);
+ break;
+ case "maxbuf":
+ parsed._maxBuffer = Convert.ToInt32(parts[optname], CultureInfo.InvariantCulture);
+ break;
+ case "charset":
+ parsed._charset = parts[optname];
+ break;
+ case "algorithm":
+ parsed._algorithm = parts[optname];
+ break;
+ case "auth-param":
+ parsed._authParam = parts[optname];
+ break;
+ case "rspauth":
+ parsed._rspauth = parts[optname];
+ break;
+ }
+ }
+
+ return parsed;
+ }
+
+
+ public static StringDictionary ParseParameters(string source)
+ {
+ if ( source == null )
+ throw new ArgumentNullException("source");
+
+ StringDictionary ret = new StringDictionary();
+
+ string remaining = source.Trim();
+ while ( remaining.Length > 0 )
+ {
+ int equals = remaining.IndexOf('=');
+ if ( equals < 0 )
+ break;
+
+ string optname = remaining.Substring(0, equals).Trim();
+ remaining = remaining.Substring(equals + 1);
+
+ string value = ParseQuoted(ref remaining);
+ ret[optname] = value.Trim();
+ }
+ return ret;
+ }
+
+ private static string ParseQuoted(ref string str)
+ {
+ string ns = str.TrimStart();
+
+ int start = 0;
+ bool quoted = ns[0] == '\"';
+ if ( quoted ) start++;
+ bool inquotes = quoted;
+ bool escaped = false;
+
+ int pos = start;
+ for ( ; pos < ns.Length; pos++ )
+ {
+ if ( !inquotes && ns[pos] == ',' )
+ break;
+
+ // at end of quotes?
+ if ( quoted && !escaped && ns[pos] == '\"' )
+ inquotes = false;
+ // is this char an escape for the next one?
+ escaped = inquotes && ns[pos] == '\\';
+ }
+ // pos has end of string
+ string value = ns.Substring(start, pos-start).Trim();
+ if ( quoted )
+ {
+ // remove trailing quote
+ value = value.Substring(0, value.Length - 1);
+ }
+ str = ns.Substring(pos < ns.Length-1 ? pos+1 : pos);
+ return value;
+ }
+
+ private static string[] GetOptions(string value)
+ {
+ return value.Split(' ');
+ }
+
+ } // class DigestChallenge
+
+
+ /// <summary>
+ /// Represents and knows how to write a
+ /// digest client response
+ /// </summary>
+ public class DigestResponse
+ {
+ private string _username;
+ private string _realm;
+ private string _nonce;
+ private string _cnonce;
+ private int _nonceCount;
+ private string _qop;
+ private string _digestUri;
+ private string _response;
+ private int _maxBuffer;
+ private string _charset;
+ private string _cipher;
+ private string _authzid;
+ private string _authParam;
+
+ #region Properties
+ //
+ // Properties
+ //
+
+ public string Username
+ {
+ get { return _username; }
+ set { _username = value; }
+ }
+
+ public string Realm
+ {
+ get { return _realm; }
+ set { _realm = value; }
+ }
+
+ public string Nonce
+ {
+ get { return _nonce; }
+ set { _nonce = value; }
+ }
+
+ public string Cnonce
+ {
+ get { return _cnonce; }
+ set { _cnonce = value; }
+ }
+
+ public int NonceCount
+ {
+ get { return _nonceCount; }
+ set { _nonceCount = value; }
+ }
+
+ public string Qop
+ {
+ get { return _qop; }
+ set { _qop = value; }
+ }
+
+ public string DigestUri
+ {
+ get { return _digestUri; }
+ set { _digestUri = value; }
+ }
+
+ public string Response
+ {
+ get { return _response; }
+ set { _response = value; }
+ }
+
+ public int MaxBuffer
+ {
+ get { return _maxBuffer; }
+ set { _maxBuffer = value; }
+ }
+
+ public string Charset
+ {
+ get { return _charset; }
+ set { _charset = value; }
+ }
+
+ public string Cipher
+ {
+ get { return _cipher; }
+ set { _cipher = value; }
+ }
+
+ public string Authzid
+ {
+ get { return _authzid; }
+ set { _authzid = value; }
+ }
+
+ public string AuthParam
+ {
+ get { return _authParam; }
+ set { _authParam = value; }
+ }
+
+ #endregion // Properties
+
+
+ public override string ToString()
+ {
+ StringBuilder buffer = new StringBuilder();
+ Pair(buffer, "username", Username, true);
+ Pair(buffer, "realm", Realm, true);
+ Pair(buffer, "nonce", Nonce, true);
+ Pair(buffer, "cnonce", Cnonce, true);
+ string nc = NonceCount.ToString("x8", CultureInfo.InvariantCulture);
+ Pair(buffer, "nc", nc, false);
+ Pair(buffer, "qop", Qop, false);
+ Pair(buffer, "digest-uri", DigestUri, true);
+ Pair(buffer, "response", Response, true);
+ string maxBuffer = MaxBuffer.ToString(CultureInfo.InvariantCulture);
+ Pair(buffer, "maxbuf", maxBuffer, false);
+ Pair(buffer, "charset", Charset, false);
+ Pair(buffer, "cipher", Cipher, false);
+ Pair(buffer, "authzid", Authzid, true);
+ Pair(buffer, "auth-param", AuthParam, true);
+
+ return buffer.ToString().TrimEnd(',');
+ }
+
+ private static void Pair(StringBuilder buffer, string name, string value, bool quoted)
+ {
+ if ( value != null && value.Length > 0 )
+ {
+ buffer.Append(name);
+ buffer.Append('=');
+ if ( quoted )
+ {
+ buffer.Append('\"');
+ buffer.Append(value.Replace("\"", "\\\""));
+ buffer.Append('\"');
+ } else
+ {
+ buffer.Append(value);
+ }
+ buffer.Append(',');
+ }
+ }
+
+ } // class DigestResponse
+
+} // namespace Apache.Qpid.Sasl.Mechanisms
diff --git a/qpid/dotnet/Qpid.Sasl/Mechanisms/ExternalSaslClient.cs b/qpid/dotnet/Qpid.Sasl/Mechanisms/ExternalSaslClient.cs
new file mode 100644
index 0000000000..fec0d2d3c2
--- /dev/null
+++ b/qpid/dotnet/Qpid.Sasl/Mechanisms/ExternalSaslClient.cs
@@ -0,0 +1,69 @@
+/*
+ *
+ * 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;
+
+namespace Apache.Qpid.Sasl.Mechanisms
+{
+ /// <summary>
+ /// Implements the EXTERNAL authentication mechanism
+ /// as outlined in RFC 2222
+ /// </summary>
+ public class ExternalSaslClient : SaslClient
+ {
+ public const string Mechanism = "EXTERNAL";
+
+ public ExternalSaslClient(
+ string authid, IDictionary properties,
+ ISaslCallbackHandler handler)
+ : base(authid, null, null, properties, handler)
+ {
+ }
+
+ #region ISaslClient Implementation
+ //
+ // ISaslClient Implementation
+ //
+
+ public override string MechanismName
+ {
+ get { return Mechanism; }
+ }
+
+ public override bool HasInitialResponse
+ {
+ get { return true; }
+ }
+
+ public override byte[] EvaluateChallenge(byte[] challenge)
+ {
+ // ignore challenge
+ SetComplete();
+ return Encoding.UTF8.GetBytes(AuthorizationId);
+ }
+
+ #endregion // ISaslClient Implementation
+
+ } // class ExternalSaslClient
+
+} // namespace Apache.Qpid.Sasl.Mechanisms
diff --git a/qpid/dotnet/Qpid.Sasl/Mechanisms/PlainSaslClient.cs b/qpid/dotnet/Qpid.Sasl/Mechanisms/PlainSaslClient.cs
new file mode 100644
index 0000000000..534be171b7
--- /dev/null
+++ b/qpid/dotnet/Qpid.Sasl/Mechanisms/PlainSaslClient.cs
@@ -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.
+ *
+ */
+
+using System;
+using System.Collections;
+using System.Text;
+
+namespace Apache.Qpid.Sasl.Mechanisms
+{
+
+ /// <summary>
+ /// Implements the PLAIN authentication mechanism
+ /// as outlined in RFC 4616
+ /// </summary>
+ public class PlainSaslClient : SaslClient
+ {
+ public const string Mechanism = "PLAIN";
+
+ public PlainSaslClient(
+ string authid, IDictionary properties,
+ ISaslCallbackHandler handler)
+ : base(authid, null, null, properties, handler)
+ {
+ }
+
+ #region ISaslClient Implementation
+ //
+ // ISaslClient Implementation
+ //
+
+ public override string MechanismName
+ {
+ get { return Mechanism; }
+ }
+
+ public override bool HasInitialResponse
+ {
+ get { return true; }
+ }
+
+ public override byte[] EvaluateChallenge(byte[] challenge)
+ {
+ // ignore challenge
+
+ NameCallback nameCB = new NameCallback();
+ PasswordCallback pwdCB = new PasswordCallback();
+ ISaslCallback[] callbacks = { nameCB, pwdCB };
+ Handler.Handle(callbacks);
+
+ string username = nameCB.Text;
+ string authid = AuthorizationId;
+ string passwd = pwdCB.Text;
+
+ string response =
+ string.Format("{0}\0{1}\0{2}", authid, username, passwd);
+ SetComplete();
+ return Encoding.UTF8.GetBytes(response);
+ }
+
+ #endregion // ISaslClient Implementation
+
+ } // class PlainSaslClient
+} // namespace Apache.Qpid.Sasl.Mechanisms
diff --git a/qpid/dotnet/Qpid.Sasl/Properties/AssemblyInfo.cs b/qpid/dotnet/Qpid.Sasl/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000000..5245b97d1f
--- /dev/null
+++ b/qpid/dotnet/Qpid.Sasl/Properties/AssemblyInfo.cs
@@ -0,0 +1,57 @@
+/*
+ *
+ * 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.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("Apache.Qpid.Sasl")]
+[assembly: AssemblyDescription("Built from svn revision number: ")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("Apache Software Foundation")]
+[assembly: AssemblyProduct("Apache.Qpid.Sasl")]
+[assembly: AssemblyCopyright("Apache Software Foundation")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("27ea23e4-6f84-4a54-8f1f-5725e6d767cc")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Revision and Build Numbers
+// by using the '*' as shown below:
+[assembly: AssemblyVersion("0.5.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
+[assembly: CLSCompliant(true)]
diff --git a/qpid/dotnet/Qpid.Sasl/Qpid.Sasl.csproj b/qpid/dotnet/Qpid.Sasl/Qpid.Sasl.csproj
new file mode 100644
index 0000000000..8c1d568aa3
--- /dev/null
+++ b/qpid/dotnet/Qpid.Sasl/Qpid.Sasl.csproj
@@ -0,0 +1,73 @@
+<!--
+
+ 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.
+
+-->
+
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="3.5">
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProductVersion>8.0.50727</ProductVersion>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{1465B0EE-6452-42A6-AB73-B2F9EABEEE75}</ProjectGuid>
+ <OutputType>Library</OutputType>
+ <AppDesignerFolder>Properties</AppDesignerFolder>
+ <RootNamespace>Apache.Qpid.Sasl</RootNamespace>
+ <AssemblyName>Apache.Qpid.Sasl</AssemblyName>
+ <FileUpgradeFlags>
+ </FileUpgradeFlags>
+ <OldToolsVersion>2.0</OldToolsVersion>
+ <UpgradeBackupLocation>
+ </UpgradeBackupLocation>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>..\bin\net-2.0\debug\</OutputPath>
+ <DefineConstants>DEBUG;TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ <UseVSHostingProcess>true</UseVSHostingProcess>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>bin\Release\</OutputPath>
+ <DefineConstants>TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="System" />
+ <Reference Include="System.Data" />
+ <Reference Include="System.Xml" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="**\*.cs" />
+ </ItemGroup>
+ <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
+ <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
+ Other similar extension points exist, see Microsoft.Common.targets.
+ <Target Name="BeforeBuild">
+ </Target>
+ <Target Name="AfterBuild">
+ </Target>
+ -->
+</Project>
diff --git a/qpid/dotnet/Qpid.Sasl/Sasl.cs b/qpid/dotnet/Qpid.Sasl/Sasl.cs
new file mode 100644
index 0000000000..2f7bacb939
--- /dev/null
+++ b/qpid/dotnet/Qpid.Sasl/Sasl.cs
@@ -0,0 +1,115 @@
+/*
+ *
+ * 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 Apache.Qpid.Sasl.Configuration;
+
+namespace Apache.Qpid.Sasl
+{
+ /// <summary>
+ /// Static class used to access the SASL functionality.
+ /// The core SASL mechanism is described in RFC 2222.
+ /// </summary>
+ /// <remarks>
+ /// Only client side mechanisms are implemented.
+ /// <para>
+ /// New client side factories can be added programatically using the
+ /// RegisterClientFactory method, or through the application
+ /// configuration file, like this:
+ /// </para>
+ /// <example><![CDATA[
+ /// <configuration>
+ /// <configSections>
+ /// <section name="qpid.sasl" type="Apache.Qpid.Sasl.Configuration.SaslConfigurationSectionHandler, Apache.Qpid.Sasl"/>
+ /// </configSections>
+ ///
+ /// <qpid.sasl>
+ /// <clientFactories>
+ /// <add type="Apache.Qpid.Sasl.Tests.TestClientFactory, Apache.Qpid.Sasl.Tests"/>
+ /// </clientFactories>
+ /// </qpid.sasl>
+ /// </configuration>
+ /// ]]></example>
+ /// </remarks>
+ public sealed class Sasl
+ {
+ private static IList _clientFactories;
+
+
+ static Sasl()
+ {
+ SaslConfiguration config = SaslConfiguration.GetConfiguration();
+ _clientFactories = config.ClientFactories;
+ }
+ private Sasl()
+ {
+ }
+
+ public static ISaslClient CreateClient(
+ string[] mechanisms, string authorizationId,
+ string protocol, string serverName,
+ IDictionary props, ISaslCallbackHandler handler
+ )
+ {
+ ISaslClientFactory factory = FindFactory(mechanisms, props);
+ if ( factory == null )
+ return null;
+
+ return factory.CreateClient (
+ mechanisms, authorizationId,
+ protocol, serverName, props, handler
+ );
+ }
+
+ public static void RegisterClientFactory(ISaslClientFactory factory)
+ {
+ lock ( _clientFactories )
+ {
+ _clientFactories.Add(factory);
+ }
+ }
+
+ private static ISaslClientFactory FindFactory(string[] mechanisms, IDictionary props)
+ {
+ lock ( _clientFactories )
+ {
+ foreach ( ISaslClientFactory factory in _clientFactories )
+ {
+ string[] mechs = factory.GetSupportedMechanisms(props);
+ foreach ( string m1 in mechs )
+ {
+ foreach (string m2 in mechanisms )
+ {
+ if ( m1 == m2 )
+ return factory;
+ }
+ }
+ }
+ return null;
+ }
+ }
+ } // class Sasl
+
+} // namespace Apache.Qpid.Sasl.Mechanisms
diff --git a/qpid/dotnet/Qpid.Sasl/SaslClient.cs b/qpid/dotnet/Qpid.Sasl/SaslClient.cs
new file mode 100644
index 0000000000..a22013181b
--- /dev/null
+++ b/qpid/dotnet/Qpid.Sasl/SaslClient.cs
@@ -0,0 +1,145 @@
+/*
+ *
+ * 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.Globalization;
+using System.Text;
+
+namespace Apache.Qpid.Sasl
+{
+ public abstract class SaslClient : ISaslClient
+ {
+ private bool _isComplete;
+ private IDictionary _properties;
+ private string _authorizationId;
+ private string _serverName;
+ private string _protocol;
+ private ISaslCallbackHandler _handler;
+
+ protected string AuthorizationId
+ {
+ get { return _authorizationId; }
+ }
+ protected string ServerName
+ {
+ get { return _serverName; }
+ }
+
+ protected string Protocol
+ {
+ get { return _protocol; }
+ }
+
+ protected ISaslCallbackHandler Handler
+ {
+ get { return _handler; }
+ }
+
+ protected IDictionary Properties
+ {
+ get { return _properties; }
+ }
+
+ protected SaslClient(
+ string authid, string serverName,
+ string protocol, IDictionary properties,
+ ISaslCallbackHandler handler)
+ {
+ if ( properties == null )
+ throw new ArgumentNullException("properties");
+ if ( handler == null )
+ throw new ArgumentNullException("handler");
+
+ _authorizationId = authid==null ? "" : authid;
+ _serverName = serverName;
+ _protocol = protocol;
+ _properties = properties;
+ _handler = handler;
+
+ if ( _serverName == null || _serverName.Length == 0 )
+ {
+ _serverName = System.Net.Dns.GetHostName();
+ }
+ }
+
+
+
+
+ #region ISaslClient Implementation
+ //
+ // ISaslClient Implementation
+ //
+
+ public abstract string MechanismName { get; }
+
+ public abstract bool HasInitialResponse { get; }
+
+ public bool IsComplete
+ {
+ get { return _isComplete; }
+ }
+
+ public abstract byte[] EvaluateChallenge(byte[] challenge);
+
+ public virtual object GetNegotiatedProperty(string propName)
+ {
+ return null;
+ }
+
+ public virtual byte[] Unwrap(byte[] buffer, int offset, int length)
+ {
+ throw new NotImplementedException();
+ }
+
+ public virtual byte[] Wrap(byte[] buffer, int offset, int lenght)
+ {
+ throw new NotImplementedException();
+ }
+
+ #endregion // ISaslClient Implementation
+
+
+ #region Helper Methods
+ //
+ // Helper Methods
+ //
+
+ protected void SetComplete()
+ {
+ _isComplete = true;
+ }
+
+ protected static string ToHex(byte[] buffer)
+ {
+ StringBuilder builder = new StringBuilder();
+ foreach ( byte b in buffer )
+ {
+ builder.Append(b.ToString("x2", CultureInfo.InvariantCulture));
+ }
+ return builder.ToString();
+ }
+
+ #endregion // Helper Methods
+
+ } // class SaslClient
+
+} // namespace Apache.Qpid.Sasl.Mechanisms
diff --git a/qpid/dotnet/Qpid.Sasl/SaslException.cs b/qpid/dotnet/Qpid.Sasl/SaslException.cs
new file mode 100644
index 0000000000..d770ee63fd
--- /dev/null
+++ b/qpid/dotnet/Qpid.Sasl/SaslException.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.Runtime.Serialization;
+using System.Text;
+
+namespace Apache.Qpid.Sasl
+{
+ /// <summary>
+ /// Reports an exception during the processing of an SASL
+ /// Operation. Only used for authentication-relared errors
+ /// </summary>
+ [Serializable]
+ public class SaslException : Exception
+ {
+ public SaslException()
+ {
+ }
+
+ public SaslException(string message)
+ : base(message)
+ {
+ }
+ public SaslException(string message, Exception innerException)
+ : base(message, innerException)
+ {
+ }
+
+ protected SaslException(SerializationInfo info, StreamingContext ctxt)
+ : base(info, ctxt)
+ {
+ }
+
+ } // class SaslException
+
+} // namespace Apache.Qpid.Sasl.Mechanisms
diff --git a/qpid/dotnet/Qpid.Sasl/SaslProperties.cs b/qpid/dotnet/Qpid.Sasl/SaslProperties.cs
new file mode 100644
index 0000000000..f9ad1c68cd
--- /dev/null
+++ b/qpid/dotnet/Qpid.Sasl/SaslProperties.cs
@@ -0,0 +1,42 @@
+/*
+ *
+ * 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;
+
+namespace Apache.Qpid.Sasl
+{
+ public sealed class SaslProperties
+ {
+ public const string PolicyNoPlainText = "NOPLAINTEXT";
+ public const string PolicyNoActive = "NOACTIVE";
+ public const string PolicyNoDictionary = "NODICTIONARY";
+ public const string PolicyNoAnonymous = "NOANONYMOUS";
+ public const string PolicyForwardSecrecy = "FORWARD_SECRECY";
+ public const string PolicyPassCredentials = "PASS_CREDENTIALS";
+
+ public const string Qop = "QOP";
+ public const string Strength = "STRENGTH";
+
+ } // class SaslProperties
+
+} // namespace Apache.Qpid.Sasl.Mechanisms
diff --git a/qpid/dotnet/Qpid.Sasl/default.build b/qpid/dotnet/Qpid.Sasl/default.build
new file mode 100644
index 0000000000..57049ee2ee
--- /dev/null
+++ b/qpid/dotnet/Qpid.Sasl/default.build
@@ -0,0 +1,45 @@
+<?xml version="1.0"?>
+<!--
+
+ 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.
+
+-->
+
+<project name="Apache.Qpid.Sasl" default="build">
+ <!--
+ Properties that come from master build file
+ - build.dir: root directory for build
+ - build.debug: true if building debug release
+ - build.defines: variables to define during build
+ -->
+
+ <target name="build">
+ <csc target="library"
+ define="${build.defines}"
+ debug="${build.debug}"
+ output="${build.dir}/${project::get-name()}.dll">
+
+ <sources>
+ <include name="**/*.cs" />
+ </sources>
+ <references>
+ </references>
+ </csc>
+ </target>
+</project>
+