| /* | |
| * | |
| * 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.Text; | |
| using NUnit.Framework; | |
| using Apache.Qpid.Sasl; | |
| using Apache.Qpid.Sasl.Mechanisms; | |
| namespace Apache.Qpid.Sasl.Tests.Mechanisms | |
| { | |
| [TestFixture] | |
| public class DigestSaslClientTests : ISaslCallbackHandler | |
| { | |
| private const string USERNAME = "chris"; | |
| private const string PASSWORD = "secret"; | |
| private const string AUTHID = null; | |
| private const string PROTOCOL = "IMAP"; | |
| private const string SERVERNAME = "elwood.innosoft.com"; | |
| #region Digest Challenge Parsing Tests | |
| // | |
| // Digest Challenge Parsing Tests | |
| // | |
| [Test] | |
| public void CanParseSimpleString() | |
| { | |
| string challenge = "realm=\"elwood.innosoft.com\", algorithm=md5-sess"; | |
| StringDictionary values = DigestChallenge.ParseParameters(challenge); | |
| Assert.AreEqual(2, values.Count); | |
| Assert.AreEqual("elwood.innosoft.com", values["realm"]); | |
| Assert.AreEqual("md5-sess", values["algorithm"]); | |
| } | |
| [Test] | |
| public void CanParseEscapedQuotes() | |
| { | |
| string challenge = "realm=\"elwood\\\".innosoft.com\", algorithm=md5-sess"; | |
| StringDictionary values = DigestChallenge.ParseParameters(challenge); | |
| Assert.AreEqual(2, values.Count); | |
| Assert.AreEqual("elwood\\\".innosoft.com", values["realm"]); | |
| Assert.AreEqual("md5-sess", values["algorithm"]); | |
| } | |
| [Test] | |
| public void CanParseEmbeddedDelimiter() | |
| { | |
| string challenge = "realm=\"elwood,innosoft.com\", algorithm=md5-sess"; | |
| StringDictionary values = DigestChallenge.ParseParameters(challenge); | |
| Assert.AreEqual(2, values.Count); | |
| Assert.AreEqual("elwood,innosoft.com", values["realm"]); | |
| Assert.AreEqual("md5-sess", values["algorithm"]); | |
| } | |
| [Test] | |
| public void CanParse1() | |
| { | |
| string challenge = "realm=\"elwood.innosoft.com\",nonce=\"OA6MG9tEQGm2hh\",qop=\"auth\",algorithm=md5-sess,charset=utf-8"; | |
| DigestChallenge parsed = DigestChallenge.Parse(challenge); | |
| Assert.AreEqual("elwood.innosoft.com", parsed.Realm); | |
| Assert.AreEqual("OA6MG9tEQGm2hh", parsed.Nonce); | |
| Assert.Contains("auth", parsed.QopOptions); | |
| Assert.AreEqual("md5-sess", parsed.Algorithm); | |
| Assert.AreEqual("utf-8", parsed.Charset); | |
| } | |
| #endregion // Digest Challenge Parsing Tests | |
| #region Digest Response Tests | |
| // | |
| // Digest Response Tests | |
| // | |
| [Test] | |
| public void CanWriteResponse() | |
| { | |
| DigestResponse resp = new DigestResponse(); | |
| resp.Username = "user"; | |
| resp.Realm = "nowhere.com"; | |
| resp.Nonce = "OA9BSXrbuRhWay"; | |
| resp.Cnonce = "OA9BSuZWMSpW8m"; | |
| resp.NonceCount = 16; | |
| resp.DigestUri = "acap/elwood.innosoft.com"; | |
| resp.Response = "6084c6db3fede7352c551284490fd0fc"; | |
| resp.Qop = "auth"; | |
| resp.MaxBuffer = 65536; | |
| resp.Cipher = "3des"; | |
| resp.Authzid = "user2"; | |
| resp.AuthParam = "ap"; | |
| resp.Charset = "utf-8"; | |
| string expected = "username=\"user\",realm=\"nowhere.com\",nonce=\"OA9BSXrbuRhWay\",cnonce=\"OA9BSuZWMSpW8m\",nc=00000010,qop=auth,digest-uri=\"acap/elwood.innosoft.com\",response=\"6084c6db3fede7352c551284490fd0fc\",maxbuf=65536,charset=utf-8,cipher=3des,authzid=\"user2\",auth-param=\"ap\""; | |
| Assert.AreEqual(expected, resp.ToString()); | |
| } | |
| [Test] | |
| public void CanWriteEscapedSecuence() | |
| { | |
| DigestResponse resp = new DigestResponse(); | |
| resp.Username = "us\"er"; | |
| string expected = "username=\"us\\\"er\",nc=00000000,maxbuf=0"; | |
| Assert.AreEqual(expected, resp.ToString()); | |
| } | |
| #endregion // Digest Response Tests | |
| #region Authentication Tests | |
| // | |
| // Authentication Tests | |
| // | |
| [Test] | |
| public void ReturnsRightMechanismName() | |
| { | |
| ISaslClient client = CreateClient(); | |
| Assert.AreEqual("DIGEST-MD5", client.MechanismName); | |
| } | |
| [Test] | |
| public void HasInitialResponseReturnsFalse() | |
| { | |
| ISaslClient client = CreateClient(); | |
| Assert.IsFalse(client.HasInitialResponse); | |
| } | |
| [Test] | |
| public void CanAuthenticate() | |
| { | |
| string challenge = "realm=\"elwood.innosoft.com\",nonce=\"OA6MG9tEQGm2hh\",qop=\"auth\",algorithm=md5-sess,charset=utf-8"; | |
| DigestSaslClient client = CreateClient(); | |
| client.Cnonce = "OA6MHXh6VqTrRk"; | |
| byte[] bresp = client.EvaluateChallenge(Encoding.UTF8.GetBytes(challenge)); | |
| string response = Encoding.UTF8.GetString(bresp); | |
| string expectedResp = "username=\"chris\",realm=\"elwood.innosoft.com\",nonce=\"OA6MG9tEQGm2hh\",cnonce=\"" + | |
| client.Cnonce + "\",nc=00000001,qop=auth,digest-uri=\"imap/elwood.innosoft.com\",response=\"d388dad90d4bbd760a152321f2143af7\",maxbuf=65536,charset=utf-8"; | |
| Assert.AreEqual(expectedResp, response); | |
| Assert.IsFalse(client.IsComplete); | |
| string challenge2 = "rspauth=ea40f60335c427b5527b84dbabcdfffd"; | |
| bresp = client.EvaluateChallenge(Encoding.UTF8.GetBytes(challenge2)); | |
| // client responds with zero-length array | |
| Assert.AreEqual(0, bresp.Length); | |
| Assert.IsTrue(client.IsComplete); | |
| } | |
| [Test] | |
| [ExpectedException(typeof(ArgumentNullException))] | |
| public void ThrowsExceptionWhenChallengeIsMissing() | |
| { | |
| DigestSaslClient client = CreateClient(); | |
| client.EvaluateChallenge(null); | |
| } | |
| [Test] | |
| [ExpectedException(typeof(SaslException))] | |
| public void ThrowsExceptionWhenNonceMissing() | |
| { | |
| string challenge = "realm=\"elwood.innosoft.com\""; | |
| DigestSaslClient client = CreateClient(); | |
| client.EvaluateChallenge(Encoding.UTF8.GetBytes(challenge)); | |
| } | |
| [Test] | |
| [ExpectedException(typeof(SaslException))] | |
| public void ThrowsExceptionWhenAlgorithmMissing() | |
| { | |
| string challenge = "realm=\"elwood.innosoft.com\",nonce=\"asdasadsad\""; | |
| DigestSaslClient client = CreateClient(); | |
| client.EvaluateChallenge(Encoding.UTF8.GetBytes(challenge)); | |
| } | |
| [Test] | |
| [ExpectedException(typeof(SaslException))] | |
| public void ThrowsExceptionWhenSecondChallengeInvalid() | |
| { | |
| string challenge = "realm=\"elwood.innosoft.com\",nonce=\"OA6MG9tEQGm2hh\",qop=\"auth\",algorithm=md5-sess,charset=utf-8"; | |
| DigestSaslClient client = CreateClient(); | |
| byte[] bresp = client.EvaluateChallenge(Encoding.UTF8.GetBytes(challenge)); | |
| Encoding.UTF8.GetString(bresp); | |
| // repeat challenge 1, which is incorrect | |
| client.EvaluateChallenge(Encoding.UTF8.GetBytes(challenge)); | |
| } | |
| private DigestSaslClient CreateClient() | |
| { | |
| return new DigestSaslClient( | |
| AUTHID, SERVERNAME, PROTOCOL, | |
| new Hashtable(), this | |
| ); | |
| } | |
| void ISaslCallbackHandler.Handle(ISaslCallback[] callbacks) | |
| { | |
| foreach ( ISaslCallback cb in callbacks ) | |
| { | |
| if ( cb is NameCallback ) | |
| { | |
| ((NameCallback)cb).Text = USERNAME; | |
| } else if ( cb is PasswordCallback ) | |
| { | |
| ((PasswordCallback)cb).Text = PASSWORD; | |
| } else if ( cb is RealmCallback ) | |
| { | |
| ((RealmCallback)cb).Text = SERVERNAME; | |
| } | |
| } | |
| } | |
| #endregion // Authentication Tests | |
| } // class DigestSaslClientTests | |
| } // namespace Apache.Qpid.Sasl.Tests.Mechanisms |