From d4cebdd93030e253d40c8c08162704016cec8a3c Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Mon, 30 Nov 2009 14:35:43 +0000 Subject: QPID-2222: Added new CramMD5HexSaslClient.cs and registered it in the Sasl Factory and the client CallbackHandler Merge code changes from M2.x branch r663999,r664020 git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@885435 13f79535-47bb-0310-9956-ffa450edef68 --- .../Client/Security/CallbackHandlerRegistry.cs | 2 + qpid/dotnet/Qpid.Sasl/Callbacks.cs | 33 ++++++++ qpid/dotnet/Qpid.Sasl/DefaultClientFactory.cs | 4 + .../Qpid.Sasl/Mechanisms/CramMD5HexSaslClient.cs | 93 ++++++++++++++++++++++ 4 files changed, 132 insertions(+) create mode 100644 qpid/dotnet/Qpid.Sasl/Mechanisms/CramMD5HexSaslClient.cs diff --git a/qpid/dotnet/Qpid.Client/Client/Security/CallbackHandlerRegistry.cs b/qpid/dotnet/Qpid.Client/Client/Security/CallbackHandlerRegistry.cs index 85be927ff4..22f1c9d89b 100644 --- a/qpid/dotnet/Qpid.Client/Client/Security/CallbackHandlerRegistry.cs +++ b/qpid/dotnet/Qpid.Client/Client/Security/CallbackHandlerRegistry.cs @@ -96,6 +96,8 @@ namespace Apache.Qpid.Client.Security _mechanism2HandlerMap.Add(ExternalSaslClient.Mechanism, typeof(UsernamePasswordCallbackHandler)); if ( !_mechanism2HandlerMap.Contains(CramMD5SaslClient.Mechanism) ) _mechanism2HandlerMap.Add(CramMD5SaslClient.Mechanism, typeof(UsernamePasswordCallbackHandler)); + if ( !_mechanism2HandlerMap.Contains(CramMD5HexSaslClient.Mechanism) ) + _mechanism2HandlerMap.Add(CramMD5HexSaslClient.Mechanism, typeof(UsernamePasswordCallbackHandler)); if ( !_mechanism2HandlerMap.Contains(PlainSaslClient.Mechanism) ) _mechanism2HandlerMap.Add(PlainSaslClient.Mechanism, typeof(UsernamePasswordCallbackHandler)); diff --git a/qpid/dotnet/Qpid.Sasl/Callbacks.cs b/qpid/dotnet/Qpid.Sasl/Callbacks.cs index 90e36beeb8..a5913eb61e 100644 --- a/qpid/dotnet/Qpid.Sasl/Callbacks.cs +++ b/qpid/dotnet/Qpid.Sasl/Callbacks.cs @@ -21,6 +21,8 @@ using System; using System.Text; +using System.Globalization; +using System.Security.Cryptography; namespace Apache.Qpid.Sasl { @@ -87,6 +89,37 @@ namespace Apache.Qpid.Sasl : 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 diff --git a/qpid/dotnet/Qpid.Sasl/DefaultClientFactory.cs b/qpid/dotnet/Qpid.Sasl/DefaultClientFactory.cs index d552aa80c0..a38e5d50c7 100644 --- a/qpid/dotnet/Qpid.Sasl/DefaultClientFactory.cs +++ b/qpid/dotnet/Qpid.Sasl/DefaultClientFactory.cs @@ -31,6 +31,7 @@ namespace Apache.Qpid.Sasl private static readonly string[] SUPPORTED = new string[] { DigestSaslClient.Mechanism, CramMD5SaslClient.Mechanism, + CramMD5HexSaslClient.Mechanism, PlainSaslClient.Mechanism, AnonymousSaslClient.Mechanism, ExternalSaslClient.Mechanism, @@ -50,6 +51,7 @@ namespace Apache.Qpid.Sasl props.Contains(SaslProperties.PolicyPassCredentials) ) { vetoed.Add(CramMD5SaslClient.Mechanism); + vetoed.Add(CramMD5HexSaslClient.Mechanism); vetoed.Add(PlainSaslClient.Mechanism); vetoed.Add(AnonymousSaslClient.Mechanism); vetoed.Add(ExternalSaslClient.Mechanism); @@ -81,6 +83,8 @@ namespace Apache.Qpid.Sasl 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) ) diff --git a/qpid/dotnet/Qpid.Sasl/Mechanisms/CramMD5HexSaslClient.cs b/qpid/dotnet/Qpid.Sasl/Mechanisms/CramMD5HexSaslClient.cs new file mode 100644 index 0000000000..b58d0f2b1c --- /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 +{ + /// + /// Implements the CRAM-MD5 authentication mechanism as outlined + /// in RFC 2195 + /// + 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 -- cgit v1.2.1