//----------------------------------------------------------------------- // // Copyright (c) Andrew Arnott. All rights reserved. // //----------------------------------------------------------------------- namespace DotNetOpenAuth.Test.Messaging { using System; using System.Collections.Generic; using System.IO; using System.Net; using System.Web; using DotNetOpenAuth.Messaging; using DotNetOpenAuth.Messaging.Bindings; using DotNetOpenAuth.Test.Mocks; using NUnit.Framework; [TestFixture] public class ChannelTests : MessagingTestBase { [TestCase, ExpectedException(typeof(ArgumentNullException))] public void CtorNull() { // This bad channel is deliberately constructed to pass null to // its protected base class' constructor. new TestBadChannel(true); } [TestCase] public void ReadFromRequestQueryString() { this.ParameterizedReceiveTest("GET"); } [TestCase] public void ReadFromRequestForm() { this.ParameterizedReceiveTest("POST"); } /// /// Verifies compliance to OpenID 2.0 section 5.1.1 by verifying the channel /// will reject messages that come with an unexpected HTTP verb. /// [TestCase, ExpectedException(typeof(ProtocolException))] public void ReadFromRequestDisallowedHttpMethod() { var fields = GetStandardTestFields(FieldFill.CompleteBeforeBindings); fields["GetOnly"] = "true"; this.Channel.ReadFromRequest(CreateHttpRequestInfo("POST", fields)); } [TestCase, ExpectedException(typeof(ArgumentNullException))] public void SendNull() { this.Channel.PrepareResponse(null); } [TestCase, ExpectedException(typeof(ArgumentException))] public void SendIndirectedUndirectedMessage() { IProtocolMessage message = new TestDirectedMessage(MessageTransport.Indirect); this.Channel.PrepareResponse(message); } [TestCase, ExpectedException(typeof(ArgumentException))] public void SendDirectedNoRecipientMessage() { IProtocolMessage message = new TestDirectedMessage(MessageTransport.Indirect); this.Channel.PrepareResponse(message); } [TestCase, ExpectedException(typeof(ArgumentException))] public void SendInvalidMessageTransport() { IProtocolMessage message = new TestDirectedMessage((MessageTransport)100); this.Channel.PrepareResponse(message); } [TestCase] public void SendIndirectMessage301Get() { TestDirectedMessage message = new TestDirectedMessage(MessageTransport.Indirect); GetStandardTestMessage(FieldFill.CompleteBeforeBindings, message); message.Recipient = new Uri("http://provider/path"); var expected = GetStandardTestFields(FieldFill.CompleteBeforeBindings); OutgoingWebResponse response = this.Channel.PrepareResponse(message); Assert.AreEqual(HttpStatusCode.Redirect, response.Status); StringAssert.StartsWith("http://provider/path", response.Headers[HttpResponseHeader.Location]); foreach (var pair in expected) { string key = MessagingUtilities.EscapeUriDataStringRfc3986(pair.Key); string value = MessagingUtilities.EscapeUriDataStringRfc3986(pair.Value); string substring = string.Format("{0}={1}", key, value); StringAssert.Contains(substring, response.Headers[HttpResponseHeader.Location]); } } [TestCase, ExpectedException(typeof(ArgumentNullException))] public void SendIndirectMessage301GetNullMessage() { TestBadChannel badChannel = new TestBadChannel(false); badChannel.Create301RedirectResponse(null, new Dictionary()); } [TestCase, ExpectedException(typeof(ArgumentException))] public void SendIndirectMessage301GetEmptyRecipient() { TestBadChannel badChannel = new TestBadChannel(false); var message = new TestDirectedMessage(MessageTransport.Indirect); badChannel.Create301RedirectResponse(message, new Dictionary()); } [TestCase, ExpectedException(typeof(ArgumentNullException))] public void SendIndirectMessage301GetNullFields() { TestBadChannel badChannel = new TestBadChannel(false); var message = new TestDirectedMessage(MessageTransport.Indirect); message.Recipient = new Uri("http://someserver"); badChannel.Create301RedirectResponse(message, null); } [TestCase] public void SendIndirectMessageFormPost() { // We craft a very large message to force fallback to form POST. // We'll also stick some HTML reserved characters in the string value // to test proper character escaping. var message = new TestDirectedMessage(MessageTransport.Indirect) { Age = 15, Name = "c", body); StringAssert.Contains("", body); StringAssert.Contains("", body); StringAssert.Contains(".submit()", body, "There should be some javascript to automate form submission."); } [TestCase, ExpectedException(typeof(ArgumentNullException))] public void SendIndirectMessageFormPostNullMessage() { TestBadChannel badChannel = new TestBadChannel(false); badChannel.CreateFormPostResponse(null, new Dictionary()); } [TestCase, ExpectedException(typeof(ArgumentException))] public void SendIndirectMessageFormPostEmptyRecipient() { TestBadChannel badChannel = new TestBadChannel(false); var message = new TestDirectedMessage(MessageTransport.Indirect); badChannel.CreateFormPostResponse(message, new Dictionary()); } [TestCase, ExpectedException(typeof(ArgumentNullException))] public void SendIndirectMessageFormPostNullFields() { TestBadChannel badChannel = new TestBadChannel(false); var message = new TestDirectedMessage(MessageTransport.Indirect); message.Recipient = new Uri("http://someserver"); badChannel.CreateFormPostResponse(message, null); } /// /// Tests that a direct message is sent when the appropriate message type is provided. /// /// /// Since this is a mock channel that doesn't actually formulate a direct message response, /// we just check that the right method was called. /// [TestCase, ExpectedException(typeof(NotImplementedException))] public void SendDirectMessageResponse() { IProtocolMessage message = new TestDirectedMessage { Age = 15, Name = "Andrew", Location = new Uri("http://host/path"), }; this.Channel.PrepareResponse(message); } [TestCase, ExpectedException(typeof(ArgumentNullException))] public void SendIndirectMessageNull() { TestBadChannel badChannel = new TestBadChannel(false); badChannel.PrepareIndirectResponse(null); } [TestCase, ExpectedException(typeof(ArgumentNullException))] public void ReceiveNull() { TestBadChannel badChannel = new TestBadChannel(false); badChannel.Receive(null, null); } [TestCase] public void ReceiveUnrecognizedMessage() { TestBadChannel badChannel = new TestBadChannel(false); Assert.IsNull(badChannel.Receive(new Dictionary(), null)); } [TestCase] public void ReadFromRequestWithContext() { var fields = GetStandardTestFields(FieldFill.AllRequired); TestMessage expectedMessage = GetStandardTestMessage(FieldFill.AllRequired); HttpRequest request = new HttpRequest("somefile", "http://someurl", MessagingUtilities.CreateQueryString(fields)); HttpContext.Current = new HttpContext(request, new HttpResponse(new StringWriter())); IProtocolMessage message = this.Channel.ReadFromRequest(); Assert.IsNotNull(message); Assert.IsInstanceOfType(typeof(TestMessage), message); Assert.AreEqual(expectedMessage.Age, ((TestMessage)message).Age); } [TestCase, ExpectedException(typeof(InvalidOperationException))] public void ReadFromRequestNoContext() { HttpContext.Current = null; TestBadChannel badChannel = new TestBadChannel(false); badChannel.ReadFromRequest(); } [TestCase, ExpectedException(typeof(ArgumentNullException))] public void ReadFromRequestNull() { TestBadChannel badChannel = new TestBadChannel(false); badChannel.ReadFromRequest(null); } [TestCase] public void SendReplayProtectedMessageSetsNonce() { TestReplayProtectedMessage message = new TestReplayProtectedMessage(MessageTransport.Indirect); message.Recipient = new Uri("http://localtest"); this.Channel = CreateChannel(MessageProtections.ReplayProtection); this.Channel.PrepareResponse(message); Assert.IsNotNull(((IReplayProtectedProtocolMessage)message).Nonce); } [TestCase, ExpectedException(typeof(InvalidSignatureException))] public void ReceivedInvalidSignature() { this.Channel = CreateChannel(MessageProtections.TamperProtection); this.ParameterizedReceiveProtectedTest(DateTime.UtcNow, true); } [TestCase] public void ReceivedReplayProtectedMessageJustOnce() { this.Channel = CreateChannel(MessageProtections.ReplayProtection); this.ParameterizedReceiveProtectedTest(DateTime.UtcNow, false); } [TestCase, ExpectedException(typeof(ReplayedMessageException))] public void ReceivedReplayProtectedMessageTwice() { this.Channel = CreateChannel(MessageProtections.ReplayProtection); this.ParameterizedReceiveProtectedTest(DateTime.UtcNow, false); this.ParameterizedReceiveProtectedTest(DateTime.UtcNow, false); } [TestCase, ExpectedException(typeof(ProtocolException))] public void MessageExpirationWithoutTamperResistance() { new TestChannel( new TestMessageFactory(), new StandardExpirationBindingElement()); } [TestCase, ExpectedException(typeof(ProtocolException))] public void TooManyBindingElementsProvidingSameProtection() { Channel channel = new TestChannel( new TestMessageFactory(), new MockSigningBindingElement(), new MockSigningBindingElement()); Channel_Accessor accessor = Channel_Accessor.AttachShadow(channel); accessor.ProcessOutgoingMessage(new TestSignedDirectedMessage()); } [TestCase] public void BindingElementsOrdering() { IChannelBindingElement transformA = new MockTransformationBindingElement("a"); IChannelBindingElement transformB = new MockTransformationBindingElement("b"); IChannelBindingElement sign = new MockSigningBindingElement(); IChannelBindingElement replay = new MockReplayProtectionBindingElement(); IChannelBindingElement expire = new StandardExpirationBindingElement(); Channel channel = new TestChannel( new TestMessageFactory(), sign, replay, expire, transformB, transformA); Assert.AreEqual(5, channel.BindingElements.Count); Assert.AreSame(transformB, channel.BindingElements[0]); Assert.AreSame(transformA, channel.BindingElements[1]); Assert.AreSame(replay, channel.BindingElements[2]); Assert.AreSame(expire, channel.BindingElements[3]); Assert.AreSame(sign, channel.BindingElements[4]); } [TestCase, ExpectedException(typeof(UnprotectedMessageException))] public void InsufficientlyProtectedMessageSent() { var message = new TestSignedDirectedMessage(MessageTransport.Direct); message.Recipient = new Uri("http://localtest"); this.Channel.PrepareResponse(message); } [TestCase, ExpectedException(typeof(UnprotectedMessageException))] public void InsufficientlyProtectedMessageReceived() { this.Channel = CreateChannel(MessageProtections.None, MessageProtections.TamperProtection); this.ParameterizedReceiveProtectedTest(DateTime.Now, false); } [TestCase, ExpectedException(typeof(ProtocolException))] public void IncomingMessageMissingRequiredParameters() { var fields = GetStandardTestFields(FieldFill.IdentifiableButNotAllRequired); this.Channel.ReadFromRequest(CreateHttpRequestInfo("GET", fields)); } } }