summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/DotNetOAuth.Test/DotNetOAuth.Test.csproj6
-rw-r--r--src/DotNetOAuth.Test/Messaging/ChannelTests.cs46
-rw-r--r--src/DotNetOAuth.Test/Messaging/MessageSerializerTests.cs (renamed from src/DotNetOAuth.Test/Messaging/MessageSerializerTest.cs)19
-rw-r--r--src/DotNetOAuth.Test/Mocks/TestChannel.cs35
-rw-r--r--src/DotNetOAuth.Test/Mocks/TestMessageTypeProvider.cs32
-rw-r--r--src/DotNetOAuth.Test/OAuthChannelTests.cs18
-rw-r--r--src/DotNetOAuth/DotNetOAuth.csproj2
-rw-r--r--src/DotNetOAuth/Messaging/Channel.cs61
-rw-r--r--src/DotNetOAuth/Messaging/IMessageTypeProvider.cs17
-rw-r--r--src/DotNetOAuth/Messaging/IndirectMessageEncoder.cs21
-rw-r--r--src/DotNetOAuth/OAuthChannel.cs40
-rw-r--r--src/DotNetOAuth/OAuthMessageTypeProvider.cs27
12 files changed, 290 insertions, 34 deletions
diff --git a/src/DotNetOAuth.Test/DotNetOAuth.Test.csproj b/src/DotNetOAuth.Test/DotNetOAuth.Test.csproj
index 86edb3c..fd01adb 100644
--- a/src/DotNetOAuth.Test/DotNetOAuth.Test.csproj
+++ b/src/DotNetOAuth.Test/DotNetOAuth.Test.csproj
@@ -58,8 +58,12 @@
</Reference>
</ItemGroup>
<ItemGroup>
- <Compile Include="Messaging\MessageSerializerTest.cs" />
+ <Compile Include="Messaging\ChannelTests.cs" />
+ <Compile Include="OAuthChannelTests.cs" />
+ <Compile Include="Messaging\MessageSerializerTests.cs" />
+ <Compile Include="Mocks\TestChannel.cs" />
<Compile Include="Mocks\TestMessage.cs" />
+ <Compile Include="Mocks\TestMessageTypeProvider.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="ServiceProviderTest.cs" />
<Compile Include="TestBase.cs" />
diff --git a/src/DotNetOAuth.Test/Messaging/ChannelTests.cs b/src/DotNetOAuth.Test/Messaging/ChannelTests.cs
new file mode 100644
index 0000000..5d027fc
--- /dev/null
+++ b/src/DotNetOAuth.Test/Messaging/ChannelTests.cs
@@ -0,0 +1,46 @@
+//-----------------------------------------------------------------------
+// <copyright file="ChannelTests.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOAuth.Test.Messaging {
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Text;
+ using Microsoft.VisualStudio.TestTools.UnitTesting;
+ using DotNetOAuth.Messaging;
+ using DotNetOAuth.Test.Mocks;
+ using System.Web;
+
+ [TestClass]
+ public class ChannelTests : TestBase {
+ Channel channel;
+
+ [TestInitialize]
+ public override void SetUp() {
+ base.SetUp();
+
+ channel = new TestChannel();
+ }
+
+ [TestMethod]
+ public void DequeueIndirectOrResponseMessageReturnsNull() {
+ Assert.IsNull(this.channel.DequeueIndirectOrResponseMessage());
+ }
+
+ [TestMethod]
+ public void ReceiveFromQueryString() {
+ string queryString = "age=15&Name=Andrew&Location=http%3A%2F%2Fhostb%2FpathB";
+ var httpRequest = new HttpRequest("filename", "http://localhost/path?" + queryString, queryString);
+ IProtocolMessage requestMessage = this.channel.Receive(httpRequest);
+ Assert.IsNotNull(requestMessage);
+ Assert.IsInstanceOfType(requestMessage, typeof(TestMessage));
+ TestMessage testMessage = (TestMessage)requestMessage;
+ Assert.AreEqual(15, testMessage.Age);
+ Assert.AreEqual("Andrew", testMessage.Name);
+ Assert.AreEqual("http://hostb/pathB", testMessage.Location.AbsoluteUri);
+ }
+ }
+}
diff --git a/src/DotNetOAuth.Test/Messaging/MessageSerializerTest.cs b/src/DotNetOAuth.Test/Messaging/MessageSerializerTests.cs
index b59e48f..7224e84 100644
--- a/src/DotNetOAuth.Test/Messaging/MessageSerializerTest.cs
+++ b/src/DotNetOAuth.Test/Messaging/MessageSerializerTests.cs
@@ -1,5 +1,5 @@
//-----------------------------------------------------------------------
-// <copyright file="MessageSerializerTest.cs" company="Andrew Arnott">
+// <copyright file="MessageSerializerTests.cs" company="Andrew Arnott">
// Copyright (c) Andrew Arnott. All rights reserved.
// </copyright>
//-----------------------------------------------------------------------
@@ -14,7 +14,7 @@ namespace DotNetOAuth.Test.Messaging {
/// Tests for the <see cref="MessageSerializer"/> class.
/// </summary>
[TestClass()]
- public class MessageSerializerTest : TestBase {
+ public class MessageSerializerTests : TestBase {
[TestMethod, ExpectedException(typeof(ArgumentNullException))]
public void SerializeNull() {
var serializer = MessageSerializer.Get(typeof(Mocks.TestMessage));
@@ -33,6 +33,21 @@ namespace DotNetOAuth.Test.Messaging {
serializer.Serialize(new Dictionary<string, string>(), null);
}
+ [TestMethod, ExpectedException(typeof(ArgumentException))]
+ public void GetInvalidMessageType() {
+ MessageSerializer.Get(typeof(string));
+ }
+
+ [TestMethod, ExpectedException(typeof(ArgumentNullException))]
+ public void GetNullType() {
+ MessageSerializer.Get(null);
+ }
+
+ [TestMethod]
+ public void GetReturnsSameSerializerTwice() {
+ Assert.AreSame(MessageSerializer.Get(typeof(Mocks.TestMessage)), MessageSerializer.Get(typeof(Mocks.TestMessage)));
+ }
+
[TestMethod, ExpectedException(typeof(ProtocolException))]
public void SerializeInvalidMessage() {
var serializer = MessageSerializer.Get(typeof(Mocks.TestMessage));
diff --git a/src/DotNetOAuth.Test/Mocks/TestChannel.cs b/src/DotNetOAuth.Test/Mocks/TestChannel.cs
new file mode 100644
index 0000000..c280243
--- /dev/null
+++ b/src/DotNetOAuth.Test/Mocks/TestChannel.cs
@@ -0,0 +1,35 @@
+//-----------------------------------------------------------------------
+// <copyright file="TestChannel.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 TestChannel : Channel {
+ internal TestChannel()
+ : base(new TestMessageTypeProvider()) {
+ }
+
+ protected override IProtocolMessage Request(IDirectedProtocolMessage request) {
+ throw new NotImplementedException();
+ }
+
+ protected override void SendDirectMessageResponse(IProtocolMessage response) {
+ throw new NotImplementedException();
+ }
+
+ protected override void ReportErrorToUser(ProtocolException exception) {
+ throw new NotImplementedException();
+ }
+
+ protected override void ReportErrorAsDirectResponse(ProtocolException exception) {
+ throw new NotImplementedException();
+ }
+ }
+}
diff --git a/src/DotNetOAuth.Test/Mocks/TestMessageTypeProvider.cs b/src/DotNetOAuth.Test/Mocks/TestMessageTypeProvider.cs
new file mode 100644
index 0000000..3caf81c
--- /dev/null
+++ b/src/DotNetOAuth.Test/Mocks/TestMessageTypeProvider.cs
@@ -0,0 +1,32 @@
+//-----------------------------------------------------------------------
+// <copyright file="TestMessageTypeProvider.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 TestMessageTypeProvider : IMessageTypeProvider {
+
+ #region IMessageTypeProvider Members
+
+ public Type GetRequestMessageType(IDictionary<string, string> fields) {
+ if (fields.ContainsKey("age")) {
+ return typeof(TestMessage);
+ } else {
+ return null;
+ }
+ }
+
+ public Type GetResponseMessageType(IProtocolMessage request, IDictionary<string, string> fields) {
+ return GetRequestMessageType(fields);
+ }
+
+ #endregion
+ }
+}
diff --git a/src/DotNetOAuth.Test/OAuthChannelTests.cs b/src/DotNetOAuth.Test/OAuthChannelTests.cs
new file mode 100644
index 0000000..2d55f8c
--- /dev/null
+++ b/src/DotNetOAuth.Test/OAuthChannelTests.cs
@@ -0,0 +1,18 @@
+//-----------------------------------------------------------------------
+// <copyright file="OAuthChannelTests.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOAuth.Test {
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Text;
+ using Microsoft.VisualStudio.TestTools.UnitTesting;
+ using DotNetOAuth.Messaging;
+
+ [TestClass]
+ public class OAuthChannelTests : TestBase {
+ }
+}
diff --git a/src/DotNetOAuth/DotNetOAuth.csproj b/src/DotNetOAuth/DotNetOAuth.csproj
index b6624ca..13bc1ed 100644
--- a/src/DotNetOAuth/DotNetOAuth.csproj
+++ b/src/DotNetOAuth/DotNetOAuth.csproj
@@ -80,7 +80,6 @@
<Compile Include="Messaging\MessagingUtilities.cs" />
<Compile Include="OAuthChannel.cs" />
<Compile Include="Messaging\Response.cs" />
- <Compile Include="Messaging\IndirectMessageEncoder.cs" />
<Compile Include="Messaging\IProtocolMessage.cs" />
<Compile Include="Logger.cs" />
<Compile Include="Loggers\ILog.cs" />
@@ -89,6 +88,7 @@
<Compile Include="Loggers\TraceLogger.cs" />
<Compile Include="Messaging\MessageScheme.cs" />
<Compile Include="Messaging\MessageTransport.cs" />
+ <Compile Include="OAuthMessageTypeProvider.cs" />
<Compile Include="ProtocolException.cs" />
<Compile Include="Messaging\MessageSerializer.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
diff --git a/src/DotNetOAuth/Messaging/Channel.cs b/src/DotNetOAuth/Messaging/Channel.cs
index 6951046..8646cf4 100644
--- a/src/DotNetOAuth/Messaging/Channel.cs
+++ b/src/DotNetOAuth/Messaging/Channel.cs
@@ -7,7 +7,6 @@
namespace DotNetOAuth.Messaging {
using System;
using System.Collections.Generic;
- using System.Diagnostics;
using System.IO;
using System.Net;
using System.Text;
@@ -130,6 +129,66 @@ namespace DotNetOAuth.Messaging {
}
/// <summary>
+ /// Gets the protocol message embedded in the given HTTP request, if present.
+ /// </summary>
+ /// <returns>The deserialized message, if one is found. Null otherwise.</returns>
+ /// <remarks>
+ /// Requires an HttpContext.Current context.
+ /// </remarks>
+ internal IProtocolMessage Receive() {
+ return this.Receive(HttpContext.Current.Request);
+ }
+
+ /// <summary>
+ /// Gets the protocol message embedded in the given HTTP request, if present.
+ /// </summary>
+ /// <param name="request">The request to search for an embedded message.</param>
+ /// <returns>The deserialized message, if one is found. Null otherwise.</returns>
+ internal virtual IProtocolMessage Receive(HttpRequest request) {
+ if (request == null) {
+ throw new ArgumentNullException("request");
+ }
+
+ // Extract the message data and attempt to determine what kind of message it is.
+ Type messageType = null;
+ var fields = this.ExtractDataFromRequest(request);
+ if (fields != null) {
+ messageType = this.MessageTypeProvider.GetRequestMessageType(fields);
+ }
+
+ // If there was no data, or we couldn't recognize it as a message, abort.
+ if (messageType == null) {
+ return null;
+ }
+
+ // We have a message! Assemble it.
+ var serializer = MessageSerializer.Get(messageType);
+ IProtocolMessage message = serializer.Deserialize(fields);
+
+ return message;
+ }
+
+ /// <summary>
+ /// Searches an incoming HTTP request for data that could be used to assemble
+ /// a protocol request message.
+ /// </summary>
+ /// <param name="request">The HTTP request to search.</param>
+ /// <returns>A dictionary of data in the request. Should never be null, but may be empty.</returns>
+ protected virtual Dictionary<string, string> ExtractDataFromRequest(HttpRequest request) {
+ if (request == null) {
+ throw new ArgumentNullException("request");
+ }
+
+ // Search Form data first, and if nothing is there search the QueryString
+ var fields = request.Form.ToDictionary();
+ if (fields.Count == 0) {
+ fields = request.QueryString.ToDictionary();
+ }
+
+ return fields;
+ }
+
+ /// <summary>
/// Takes a message and temporarily stores it for sending as the hosting site's
/// HTTP response to the current request.
/// </summary>
diff --git a/src/DotNetOAuth/Messaging/IMessageTypeProvider.cs b/src/DotNetOAuth/Messaging/IMessageTypeProvider.cs
index b000a20..17affcb 100644
--- a/src/DotNetOAuth/Messaging/IMessageTypeProvider.cs
+++ b/src/DotNetOAuth/Messaging/IMessageTypeProvider.cs
@@ -15,22 +15,27 @@ namespace DotNetOAuth.Messaging {
internal interface IMessageTypeProvider {
/// <summary>
/// Analyzes an incoming request message payload to discover what kind of
- /// message is embedded in it.
+ /// message is embedded in it and returns the type, or null if no match is found.
/// </summary>
/// <param name="fields">The name/value pairs that make up the message payload.</param>
- /// <returns>The <see cref="IProtocolMessage"/>-derived concrete class that
- /// this message can deserialize to.</returns>
+ /// <returns>
+ /// The <see cref="IProtocolMessage"/>-derived concrete class that this message can
+ /// deserialize to. Null if the request isn't recognized as a valid protocol message.
+ /// </returns>
Type GetRequestMessageType(IDictionary<string, string> fields);
/// <summary>
- /// Analyzes a response message payload to discover what kind of message is embedded in it.
+ /// Analyzes an incoming request message payload to discover what kind of
+ /// message is embedded in it and returns the type, or null if no match is found.
/// </summary>
/// <param name="request">
/// The message that was sent as a request that resulted in the response.
/// </param>
/// <param name="fields">The name/value pairs that make up the message payload.</param>
- /// <returns>The <see cref="IProtocolMessage"/>-derived concrete class that
- /// this message can deserialize to.</returns>
+ /// <returns>
+ /// The <see cref="IProtocolMessage"/>-derived concrete class that this message can
+ /// deserialize to. Null if the request isn't recognized as a valid protocol message.
+ /// </returns>
Type GetResponseMessageType(IProtocolMessage request, IDictionary<string, string> fields);
}
}
diff --git a/src/DotNetOAuth/Messaging/IndirectMessageEncoder.cs b/src/DotNetOAuth/Messaging/IndirectMessageEncoder.cs
deleted file mode 100644
index 3cfc64e..0000000
--- a/src/DotNetOAuth/Messaging/IndirectMessageEncoder.cs
+++ /dev/null
@@ -1,21 +0,0 @@
-//-----------------------------------------------------------------------
-// <copyright file="IndirectMessageEncoder.cs" company="Andrew Arnott">
-// Copyright (c) Andrew Arnott. All rights reserved.
-// </copyright>
-//-----------------------------------------------------------------------
-
-namespace DotNetOAuth.Messaging {
- /// <summary>
- /// A message encoder that prepares messages for transmittal.
- /// </summary>
- internal class IndirectMessageEncoder {
- /// <summary>
- /// Prepares a message for sending
- /// </summary>
- /// <param name="message">The indirect message to send.</param>
- /// <returns>The encoded message to send to the user agent.</returns>
- internal Response Encode(IProtocolMessage message) {
- throw new System.NotImplementedException();
- }
- }
-}
diff --git a/src/DotNetOAuth/OAuthChannel.cs b/src/DotNetOAuth/OAuthChannel.cs
index 9a066ff..52611f6 100644
--- a/src/DotNetOAuth/OAuthChannel.cs
+++ b/src/DotNetOAuth/OAuthChannel.cs
@@ -24,8 +24,8 @@ namespace DotNetOAuth {
/// A class prepared to analyze incoming messages and indicate what concrete
/// message types can deserialize from it.
/// </param>
- internal OAuthChannel(IMessageTypeProvider messageTypeProvider)
- : base(messageTypeProvider) {
+ internal OAuthChannel()
+ : base(new OAuthMessageTypeProvider()) {
}
/// <summary>
@@ -98,6 +98,42 @@ namespace DotNetOAuth {
}
/// <summary>
+ /// Searches an incoming HTTP request for data that could be used to assemble
+ /// a protocol request message.
+ /// </summary>
+ /// <param name="request">The HTTP request to search.</param>
+ /// <returns>A dictionary of data in the request. Should never be null, but may be empty.</returns>
+ protected override Dictionary<string, string> ExtractDataFromRequest(HttpRequest request) {
+ // First search the Authorization header. Use it exclusively if it's present.
+ if (request.Headers["Authorization"] != null) {
+ string[] authorizationSections = request.Headers["Authorization"].Split(';'); // TODO: is this the right delimiter?
+ string oauthPrefix = Protocol.Default.AuthorizationHeaderScheme + " ";
+
+ // The Authorization header may have multiple uses, and OAuth may be just one of them.
+ // Go through each one looking for an OAuth one.
+ foreach (string auth in authorizationSections) {
+ string trimmedAuth = auth.Trim();
+ if (trimmedAuth.StartsWith(oauthPrefix, StringComparison.Ordinal)) {
+ // We found an Authorization: OAuth header.
+ // Parse it according to the rules in section 5.4.1 of the V1.0 spec.
+ var fields = new Dictionary<string, string>();
+ foreach (string stringPair in trimmedAuth.Substring(oauthPrefix.Length).Split(',')) {
+ string[] keyValueStringPair = stringPair.Trim().Split('=');
+ string key = Uri.UnescapeDataString(keyValueStringPair[0]);
+ string value = Uri.UnescapeDataString(keyValueStringPair[1].Trim('"'));
+ fields.Add(key, value);
+ }
+
+ return fields;
+ }
+ }
+ }
+
+ // We didn't find an OAuth authorization header. Revert to other payload methods.
+ return base.ExtractDataFromRequest(request);
+ }
+
+ /// <summary>
/// Reports an error to the user via the user agent.
/// </summary>
/// <param name="exception">The error information.</param>
diff --git a/src/DotNetOAuth/OAuthMessageTypeProvider.cs b/src/DotNetOAuth/OAuthMessageTypeProvider.cs
new file mode 100644
index 0000000..63e1e6f
--- /dev/null
+++ b/src/DotNetOAuth/OAuthMessageTypeProvider.cs
@@ -0,0 +1,27 @@
+//-----------------------------------------------------------------------
+// <copyright file="OAuthMessageTypeProvider.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOAuth {
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Text;
+ using DotNetOAuth.Messaging;
+
+ internal class OAuthMessageTypeProvider : IMessageTypeProvider {
+ #region IMessageTypeProvider Members
+
+ public Type GetRequestMessageType(IDictionary<string, string> fields) {
+ throw new NotImplementedException();
+ }
+
+ public Type GetResponseMessageType(IProtocolMessage request, IDictionary<string, string> fields) {
+ throw new NotImplementedException();
+ }
+
+ #endregion
+ }
+}