blob: 5a18ebaefd515e858d099ec1e39c4ddbc1be430b [file] [log] [blame]
/*
*
* 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