diff options
author | Andrew Arnott <andrewarnott@gmail.com> | 2008-09-13 08:50:56 -0700 |
---|---|---|
committer | Andrew <andrewarnott@gmail.com> | 2008-09-13 08:50:56 -0700 |
commit | ae2258f38effe0eca177d3610a9a113288f6365b (patch) | |
tree | f7c4b3d44be7e44daa7eba23d84d16651401d946 /src/DotNetOAuth.Test | |
parent | 5181f7f5d953ede5361ea1ac899818bfad207bf7 (diff) | |
download | DotNetOpenAuth-ae2258f38effe0eca177d3610a9a113288f6365b.zip DotNetOpenAuth-ae2258f38effe0eca177d3610a9a113288f6365b.tar.gz DotNetOpenAuth-ae2258f38effe0eca177d3610a9a113288f6365b.tar.bz2 |
Added tests for signed, expiring and replay protected messages.
Diffstat (limited to 'src/DotNetOAuth.Test')
-rw-r--r-- | src/DotNetOAuth.Test/DotNetOAuth.Test.csproj | 5 | ||||
-rw-r--r-- | src/DotNetOAuth.Test/Messaging/ChannelTests.cs | 111 | ||||
-rw-r--r-- | src/DotNetOAuth.Test/Mocks/TestChannel.cs | 6 | ||||
-rw-r--r-- | src/DotNetOAuth.Test/Mocks/TestExpiringMessage.cs | 32 | ||||
-rw-r--r-- | src/DotNetOAuth.Test/Mocks/TestMessageTypeProvider.cs | 29 | ||||
-rw-r--r-- | src/DotNetOAuth.Test/Mocks/TestReplayProtectedChannel.cs | 35 | ||||
-rw-r--r-- | src/DotNetOAuth.Test/Mocks/TestReplayProtectedMessage.cs | 27 | ||||
-rw-r--r-- | src/DotNetOAuth.Test/Mocks/TestSignedDirectedMessage.cs | 27 | ||||
-rw-r--r-- | src/DotNetOAuth.Test/Mocks/TestSigningChannel.cs | 29 |
9 files changed, 297 insertions, 4 deletions
diff --git a/src/DotNetOAuth.Test/DotNetOAuth.Test.csproj b/src/DotNetOAuth.Test/DotNetOAuth.Test.csproj index 41af758..85957c8 100644 --- a/src/DotNetOAuth.Test/DotNetOAuth.Test.csproj +++ b/src/DotNetOAuth.Test/DotNetOAuth.Test.csproj @@ -63,10 +63,15 @@ <Compile Include="Messaging\DictionaryXmlReaderTests.cs" />
<Compile Include="Messaging\HttpRequestInfoTests.cs" />
<Compile Include="Messaging\ProtocolExceptionTests.cs" />
+ <Compile Include="Mocks\TestReplayProtectedChannel.cs" />
<Compile Include="Mocks\TestBaseMessage.cs" />
<Compile Include="Mocks\TestDerivedMessage.cs" />
+ <Compile Include="Mocks\TestReplayProtectedMessage.cs" />
<Compile Include="Mocks\TestDirectedMessage.cs" />
<Compile Include="Mocks\TestBadChannel.cs" />
+ <Compile Include="Mocks\TestExpiringMessage.cs" />
+ <Compile Include="Mocks\TestSignedDirectedMessage.cs" />
+ <Compile Include="Mocks\TestSigningChannel.cs" />
<Compile Include="Mocks\TestWebRequestHandler.cs" />
<Compile Include="OAuthChannelTests.cs" />
<Compile Include="Messaging\MessageSerializerTests.cs" />
diff --git a/src/DotNetOAuth.Test/Messaging/ChannelTests.cs b/src/DotNetOAuth.Test/Messaging/ChannelTests.cs index dc433cf..4627b87 100644 --- a/src/DotNetOAuth.Test/Messaging/ChannelTests.cs +++ b/src/DotNetOAuth.Test/Messaging/ChannelTests.cs @@ -9,8 +9,8 @@ namespace DotNetOAuth.Test.Messaging { using System.Collections.Generic;
using System.IO;
using System.Net;
- using System.Text;
using System.Web;
+ using System.Xml;
using DotNetOAuth.Messaging;
using DotNetOAuth.Test.Mocks;
using Microsoft.VisualStudio.TestTools.UnitTesting;
@@ -227,6 +227,90 @@ namespace DotNetOAuth.Test.Messaging { badChannel.ReadFromRequest(null);
}
+ [TestMethod, ExpectedException(typeof(NotSupportedException))]
+ public void SendSigningMessagesNotSupported() {
+ TestSignedDirectedMessage message = new TestSignedDirectedMessage(MessageTransport.Direct);
+ message.Recipient = new Uri("http://localtest");
+ this.channel.Send(message);
+ }
+
+ [TestMethod]
+ public void SendSetsTimestamp() {
+ TestExpiringMessage message = new TestExpiringMessage(MessageTransport.Indirect);
+ message.Recipient = new Uri("http://localtest");
+ ((IExpiringProtocolMessage)message).UtcCreationDate = DateTime.Parse("1/1/1990");
+
+ Channel channel = new TestSigningChannel(true, false);
+ channel.Send(message);
+ Assert.IsTrue(DateTime.UtcNow - ((IExpiringProtocolMessage)message).UtcCreationDate < TimeSpan.FromSeconds(3), "The timestamp on the message was not set on send.");
+ }
+
+ [TestMethod, ExpectedException(typeof(NotSupportedException))]
+ public void SendReplayProtectedMessageNotSupported() {
+ TestReplayProtectedMessage message = new TestReplayProtectedMessage(MessageTransport.Indirect);
+ message.Recipient = new Uri("http://localtest");
+
+ Channel channel = new TestSigningChannel(true, false); // use this one to get passed signing NotSupportedException
+ channel.Send(message);
+ }
+
+ [TestMethod]
+ public void SendReplayProtectedMessageSetsNonce() {
+ TestReplayProtectedMessage message = new TestReplayProtectedMessage(MessageTransport.Indirect);
+ message.Recipient = new Uri("http://localtest");
+
+ Channel channel = new TestReplayProtectedChannel();
+ channel.Send(message);
+ Assert.IsNotNull(((IReplayProtectedProtocolMessage)message).Nonce);
+ }
+
+ [TestMethod, ExpectedException(typeof(NotSupportedException))]
+ public void ReceivedSignedMessagesNotSupported() {
+ // Create a channel that doesn't support signed messages, but will recognize one.
+ this.channel = new TestChannel(new TestMessageTypeProvider(true, false, false));
+ this.ParameterizedReceiveTest("GET");
+ }
+
+ [TestMethod, ExpectedException(typeof(ProtocolException))]
+ public void ReceivedInvalidSignature() {
+ this.channel = new TestSigningChannel(false, false);
+ this.ParameterizedReceiveProtectedTest(DateTime.UtcNow, true);
+ }
+
+ [TestMethod]
+ public void VerifyGoodTimestampIsAccepted() {
+ // Create a channel that supports and recognizes signed messages.
+ this.channel = new TestSigningChannel(true, false);
+ this.ParameterizedReceiveProtectedTest(DateTime.UtcNow, false);
+ }
+
+ [TestMethod, ExpectedException(typeof(ProtocolException))]
+ public void VerifyBadTimestampIsRejected() {
+ // Create a channel that supports and recognizes signed messages.
+ this.channel = new TestSigningChannel(true, false);
+ this.ParameterizedReceiveProtectedTest(DateTime.UtcNow - this.channel.MaximumMessageAge - TimeSpan.FromSeconds(1), false);
+ }
+
+ [TestMethod]
+ public void ReceivedReplayProtectedMessageJustOnce() {
+ this.channel = new TestReplayProtectedChannel();
+ this.ParameterizedReceiveProtectedTest(DateTime.UtcNow, false);
+ }
+
+ [TestMethod, ExpectedException(typeof(ProtocolException))]
+ public void ReceivedReplayProtectedMessageTwice() {
+ this.channel = new TestReplayProtectedChannel();
+ this.ParameterizedReceiveProtectedTest(DateTime.UtcNow, false);
+ this.ParameterizedReceiveProtectedTest(DateTime.UtcNow, false);
+ }
+
+ [TestMethod, ExpectedException(typeof(NotSupportedException))]
+ public void ReceivedReplayProtectedMessagesNotSupported() {
+ // Create a channel that doesn't support replay protected messages, but will recognize one.
+ this.channel = new TestSigningChannel(true, true);
+ this.ParameterizedReceiveProtectedTest(DateTime.UtcNow, false);
+ }
+
private static HttpRequestInfo CreateHttpRequestInfo(string method, IDictionary<string, string> fields) {
string query = MessagingUtilities.CreateQueryString(fields);
UriBuilder requestUri = new UriBuilder("http://localhost/path");
@@ -267,5 +351,30 @@ namespace DotNetOAuth.Test.Messaging { Assert.AreEqual("Andrew", testMessage.Name);
Assert.AreEqual("http://hostb/pathB", testMessage.Location.AbsoluteUri);
}
+
+ private void ParameterizedReceiveProtectedTest(DateTime? utcCreatedDate, bool invalidSignature) {
+ var fields = new Dictionary<string, string> {
+ { "age", "15" },
+ { "Name", "Andrew" },
+ { "Location", "http://hostb/pathB" },
+ { "Signature", invalidSignature ? "badsig" : TestSigningChannel.MessageSignature },
+ { "Nonce", "someNonce" },
+ };
+ if (utcCreatedDate.HasValue) {
+ utcCreatedDate = DateTime.Parse(utcCreatedDate.Value.ToUniversalTime().ToString()); // round off the milliseconds so comparisons work later
+ fields.Add("created_on", XmlConvert.ToString(utcCreatedDate.Value, XmlDateTimeSerializationMode.Utc));
+ }
+ IProtocolMessage requestMessage = this.channel.ReadFromRequest(CreateHttpRequestInfo("GET", fields));
+ Assert.IsNotNull(requestMessage);
+ Assert.IsInstanceOfType(requestMessage, typeof(TestSignedDirectedMessage));
+ TestSignedDirectedMessage testMessage = (TestSignedDirectedMessage)requestMessage;
+ Assert.AreEqual(15, testMessage.Age);
+ Assert.AreEqual("Andrew", testMessage.Name);
+ Assert.AreEqual("http://hostb/pathB", testMessage.Location.AbsoluteUri);
+ if (utcCreatedDate.HasValue) {
+ IExpiringProtocolMessage expiringMessage = (IExpiringProtocolMessage)requestMessage;
+ Assert.AreEqual(utcCreatedDate.Value, expiringMessage.UtcCreationDate);
+ }
+ }
}
}
diff --git a/src/DotNetOAuth.Test/Mocks/TestChannel.cs b/src/DotNetOAuth.Test/Mocks/TestChannel.cs index 5663ec2..2431af1 100644 --- a/src/DotNetOAuth.Test/Mocks/TestChannel.cs +++ b/src/DotNetOAuth.Test/Mocks/TestChannel.cs @@ -13,7 +13,11 @@ namespace DotNetOAuth.Test.Mocks { internal class TestChannel : Channel {
internal TestChannel()
- : base(new TestMessageTypeProvider()) {
+ : this(new TestMessageTypeProvider()) {
+ }
+
+ internal TestChannel(IMessageTypeProvider messageTypeProvider)
+ : base(messageTypeProvider) {
}
protected override IProtocolMessage RequestInternal(IDirectedProtocolMessage request) {
diff --git a/src/DotNetOAuth.Test/Mocks/TestExpiringMessage.cs b/src/DotNetOAuth.Test/Mocks/TestExpiringMessage.cs new file mode 100644 index 0000000..cd6f986 --- /dev/null +++ b/src/DotNetOAuth.Test/Mocks/TestExpiringMessage.cs @@ -0,0 +1,32 @@ +//-----------------------------------------------------------------------
+// <copyright file="TestExpiringMessage.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOAuth.Test.Mocks {
+ using System;
+ using System.Diagnostics;
+ using System.Runtime.Serialization;
+ using DotNetOAuth.Messaging;
+
+ [DataContract(Namespace = Protocol.DataContractNamespaceV10)]
+ internal class TestExpiringMessage : TestSignedDirectedMessage, IExpiringProtocolMessage {
+ [DebuggerBrowsable(DebuggerBrowsableState.Never)]
+ private DateTime utcCreationDate;
+
+ internal TestExpiringMessage(MessageTransport transport)
+ : base(transport) {
+ }
+
+ #region IExpiringProtocolMessage Members
+
+ [DataMember(Name = "created_on")]
+ DateTime IExpiringProtocolMessage.UtcCreationDate {
+ get { return this.utcCreationDate; }
+ set { this.utcCreationDate = value.ToUniversalTime(); }
+ }
+
+ #endregion
+ }
+}
diff --git a/src/DotNetOAuth.Test/Mocks/TestMessageTypeProvider.cs b/src/DotNetOAuth.Test/Mocks/TestMessageTypeProvider.cs index 647a09f..85e2b05 100644 --- a/src/DotNetOAuth.Test/Mocks/TestMessageTypeProvider.cs +++ b/src/DotNetOAuth.Test/Mocks/TestMessageTypeProvider.cs @@ -12,14 +12,39 @@ namespace DotNetOAuth.Test.Mocks { using DotNetOAuth.Messaging;
internal class TestMessageTypeProvider : IMessageTypeProvider {
+ private bool signedMessages;
+ private bool expiringMessages;
+ private bool replayMessages;
+
+ internal TestMessageTypeProvider()
+ : this(false, false, false) {
+ }
+
+ internal TestMessageTypeProvider(bool signed, bool expiring, bool replay) {
+ if ((!signed && expiring) || (!expiring && replay)) {
+ throw new ArgumentException("Invalid combination of protection.");
+ }
+ this.signedMessages = signed;
+ this.expiringMessages = expiring;
+ this.replayMessages = replay;
+ }
+
#region IMessageTypeProvider Members
public Type GetRequestMessageType(IDictionary<string, string> fields) {
if (fields.ContainsKey("age")) {
+ if (this.signedMessages) {
+ if (this.expiringMessages) {
+ if (this.replayMessages) {
+ return typeof(TestReplayProtectedMessage);
+ }
+ return typeof(TestExpiringMessage);
+ }
+ return typeof(TestSignedDirectedMessage);
+ }
return typeof(TestMessage);
- } else {
- return null;
}
+ return null;
}
public Type GetResponseMessageType(IProtocolMessage request, IDictionary<string, string> fields) {
diff --git a/src/DotNetOAuth.Test/Mocks/TestReplayProtectedChannel.cs b/src/DotNetOAuth.Test/Mocks/TestReplayProtectedChannel.cs new file mode 100644 index 0000000..d57b72c --- /dev/null +++ b/src/DotNetOAuth.Test/Mocks/TestReplayProtectedChannel.cs @@ -0,0 +1,35 @@ +//-----------------------------------------------------------------------
+// <copyright file="TestReplayProtectedChannel.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOAuth.Test.Mocks {
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Text;
+ using DotNetOAuth.Messaging;
+ using Microsoft.VisualStudio.TestTools.UnitTesting;
+
+ internal class TestReplayProtectedChannel : TestSigningChannel {
+ private bool messageReceived;
+
+ internal TestReplayProtectedChannel()
+ : base(true, true) {
+ }
+
+ protected override bool IsMessageReplayed(DotNetOAuth.Messaging.IReplayProtectedProtocolMessage message) {
+ Assert.AreEqual("someNonce", message.Nonce, "The nonce didn't serialize correctly, or something");
+ // this mock implementation passes the first time and fails subsequent times.
+ bool replay = this.messageReceived;
+ this.messageReceived = true;
+ return replay;
+ }
+
+ protected override void ApplyReplayProtection(IReplayProtectedProtocolMessage message) {
+ message.Nonce = "someNonce";
+ // no-op
+ }
+ }
+}
diff --git a/src/DotNetOAuth.Test/Mocks/TestReplayProtectedMessage.cs b/src/DotNetOAuth.Test/Mocks/TestReplayProtectedMessage.cs new file mode 100644 index 0000000..e9b1984 --- /dev/null +++ b/src/DotNetOAuth.Test/Mocks/TestReplayProtectedMessage.cs @@ -0,0 +1,27 @@ +//-----------------------------------------------------------------------
+// <copyright file="TestReplayProtectedMessage.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOAuth.Test.Mocks {
+ using System.Runtime.Serialization;
+ using DotNetOAuth.Messaging;
+
+ [DataContract(Namespace = Protocol.DataContractNamespaceV10)]
+ internal class TestReplayProtectedMessage : TestExpiringMessage, IReplayProtectedProtocolMessage {
+ internal TestReplayProtectedMessage(MessageTransport transport)
+ : base(transport) {
+ }
+
+ #region IReplayProtectedProtocolMessage Members
+
+ [DataMember(Name = "Nonce")]
+ string IReplayProtectedProtocolMessage.Nonce {
+ get;
+ set;
+ }
+
+ #endregion
+ }
+}
diff --git a/src/DotNetOAuth.Test/Mocks/TestSignedDirectedMessage.cs b/src/DotNetOAuth.Test/Mocks/TestSignedDirectedMessage.cs new file mode 100644 index 0000000..b00d385 --- /dev/null +++ b/src/DotNetOAuth.Test/Mocks/TestSignedDirectedMessage.cs @@ -0,0 +1,27 @@ +//-----------------------------------------------------------------------
+// <copyright file="TestSignedDirectedMessage.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOAuth.Test.Mocks {
+ using System.Runtime.Serialization;
+ using DotNetOAuth.Messaging;
+
+ [DataContract(Namespace = Protocol.DataContractNamespaceV10)]
+ internal class TestSignedDirectedMessage : TestDirectedMessage, ISignedProtocolMessage {
+ internal TestSignedDirectedMessage(MessageTransport transport)
+ : base(transport) {
+ }
+
+ #region ISignedProtocolMessage Members
+
+ [DataMember]
+ public string Signature {
+ get;
+ set;
+ }
+
+ #endregion
+ }
+}
diff --git a/src/DotNetOAuth.Test/Mocks/TestSigningChannel.cs b/src/DotNetOAuth.Test/Mocks/TestSigningChannel.cs new file mode 100644 index 0000000..60037ee --- /dev/null +++ b/src/DotNetOAuth.Test/Mocks/TestSigningChannel.cs @@ -0,0 +1,29 @@ +//-----------------------------------------------------------------------
+// <copyright file="TestSigningChannel.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOAuth.Test.Mocks {
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Text;
+ using DotNetOAuth.Messaging;
+
+ internal class TestSigningChannel : TestChannel {
+ internal const string MessageSignature = "mocksignature";
+
+ internal TestSigningChannel(bool expiring, bool replay)
+ : base(new TestMessageTypeProvider(true, expiring, replay)) {
+ }
+
+ protected override void Sign(ISignedProtocolMessage message) {
+ message.Signature = MessageSignature;
+ }
+
+ protected override bool IsSignatureValid(ISignedProtocolMessage message) {
+ return message.Signature == MessageSignature;
+ }
+ }
+}
|