summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorAndrew Arnott <andrewarnott@gmail.com>2008-11-07 21:57:01 -0800
committerAndrew <andrewarnott@gmail.com>2008-11-07 21:57:01 -0800
commitf2d618e5cf4010d4a3bf6ea357c72c88bfdf693c (patch)
tree186248daa4cfa3641cc9dbf64310a81ac5a2adb0 /src
parent4f5bcdfe5ef25816225a7bd73ab69c2c02bea1cf (diff)
downloadDotNetOpenAuth-f2d618e5cf4010d4a3bf6ea357c72c88bfdf693c.zip
DotNetOpenAuth-f2d618e5cf4010d4a3bf6ea357c72c88bfdf693c.tar.gz
DotNetOpenAuth-f2d618e5cf4010d4a3bf6ea357c72c88bfdf693c.tar.bz2
Added OpenIdChannel and Key-Value Form encoding.
Also several primitive tests for the association messages.
Diffstat (limited to 'src')
-rw-r--r--src/DotNetOpenAuth.Test/DotNetOpenAuth.Test.csproj4
-rw-r--r--src/DotNetOpenAuth.Test/OpenId/Messages/AssociateDiffieHellmanRequestTests.cs32
-rw-r--r--src/DotNetOpenAuth.Test/OpenId/Messages/AssociateRequestTests.cs15
-rw-r--r--src/DotNetOpenAuth.Test/OpenId/Messages/AssociateUnencryptedResponseTests.cs48
-rw-r--r--src/DotNetOpenAuth.Test/OpenId/Messages/AssociateUnsuccessfulResponseTests.cs37
-rw-r--r--src/DotNetOpenAuth.Test/OpenId/OpenIdChannelTests.cs28
-rw-r--r--src/DotNetOpenAuth.sln2
-rw-r--r--src/DotNetOpenAuth/DotNetOpenAuth.csproj2
-rw-r--r--src/DotNetOpenAuth/OpenId/ChannelElements/KeyValueFormEncoding.cs197
-rw-r--r--src/DotNetOpenAuth/OpenId/ChannelElements/OpenIdChannel.cs99
-rw-r--r--src/DotNetOpenAuth/OpenId/ChannelElements/OpenIdMessageTypeProvider.cs49
-rw-r--r--src/DotNetOpenAuth/OpenId/Messages/AssociateUnsuccessfulResponse.cs6
-rw-r--r--src/DotNetOpenAuth/OpenId/OpenIdStrings.Designer.cs27
-rw-r--r--src/DotNetOpenAuth/OpenId/OpenIdStrings.resx9
14 files changed, 554 insertions, 1 deletions
diff --git a/src/DotNetOpenAuth.Test/DotNetOpenAuth.Test.csproj b/src/DotNetOpenAuth.Test/DotNetOpenAuth.Test.csproj
index b89a22d..ca1e93c 100644
--- a/src/DotNetOpenAuth.Test/DotNetOpenAuth.Test.csproj
+++ b/src/DotNetOpenAuth.Test/DotNetOpenAuth.Test.csproj
@@ -92,7 +92,11 @@
<Compile Include="OAuth\ConsumerDescription.cs" />
<Compile Include="OAuth\ProtocolTests.cs" />
<Compile Include="OAuth\ServiceProviderDescriptionTests.cs" />
+ <Compile Include="OpenId\Messages\AssociateDiffieHellmanRequestTests.cs" />
<Compile Include="OpenId\Messages\AssociateRequestTests.cs" />
+ <Compile Include="OpenId\Messages\AssociateUnsuccessfulResponseTests.cs" />
+ <Compile Include="OpenId\Messages\AssociateUnencryptedResponseTests.cs" />
+ <Compile Include="OpenId\OpenIdChannelTests.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Messaging\ResponseTests.cs" />
<Compile Include="Scenarios\AppendixScenarios.cs" />
diff --git a/src/DotNetOpenAuth.Test/OpenId/Messages/AssociateDiffieHellmanRequestTests.cs b/src/DotNetOpenAuth.Test/OpenId/Messages/AssociateDiffieHellmanRequestTests.cs
new file mode 100644
index 0000000..81014f2
--- /dev/null
+++ b/src/DotNetOpenAuth.Test/OpenId/Messages/AssociateDiffieHellmanRequestTests.cs
@@ -0,0 +1,32 @@
+//-----------------------------------------------------------------------
+// <copyright file="AssociateDiffieHellmanRequestTests.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOpenAuth.Test.OpenId.Messages {
+ using System;
+ using DotNetOpenAuth.OpenId.Messages;
+ using Microsoft.VisualStudio.TestTools.UnitTesting;
+
+ [TestClass]
+ public class AssociateDiffieHellmanRequestTests {
+ private static readonly Uri Recipient = new Uri("http://host");
+ private AssociateDiffieHellmanRequest request;
+
+ [TestInitialize]
+ public void Setup() {
+ this.request = new AssociateDiffieHellmanRequest(Recipient);
+ }
+
+ [TestMethod]
+ public void Ctor() {
+ Assert.AreEqual(Recipient, this.request.Recipient);
+ }
+
+ [TestMethod]
+ public void Mode() {
+ Assert.AreEqual("associate", this.request.Mode);
+ }
+ }
+}
diff --git a/src/DotNetOpenAuth.Test/OpenId/Messages/AssociateRequestTests.cs b/src/DotNetOpenAuth.Test/OpenId/Messages/AssociateRequestTests.cs
index ff611a1..acc885b 100644
--- a/src/DotNetOpenAuth.Test/OpenId/Messages/AssociateRequestTests.cs
+++ b/src/DotNetOpenAuth.Test/OpenId/Messages/AssociateRequestTests.cs
@@ -29,6 +29,11 @@ namespace DotNetOpenAuth.Test.OpenId.Messages {
}
[TestMethod]
+ public void Mode() {
+ Assert.AreEqual("associate", this.request.Mode);
+ }
+
+ [TestMethod]
public void MessagePartsTest() {
this.request.AssociationType = "HMAC-SHA1";
this.request.SessionType = "no-encryption";
@@ -59,5 +64,15 @@ namespace DotNetOpenAuth.Test.OpenId.Messages {
this.request.SessionType = "no-encryption";
this.request.EnsureValidMessage(); // no-encryption only allowed for secure channels.
}
+
+ [TestMethod]
+ public void RequiredProtection() {
+ Assert.AreEqual(MessageProtections.None, this.request.RequiredProtection);
+ }
+
+ [TestMethod]
+ public void Transport() {
+ Assert.AreEqual(MessageTransport.Direct, this.request.Transport);
+ }
}
}
diff --git a/src/DotNetOpenAuth.Test/OpenId/Messages/AssociateUnencryptedResponseTests.cs b/src/DotNetOpenAuth.Test/OpenId/Messages/AssociateUnencryptedResponseTests.cs
new file mode 100644
index 0000000..7455cce
--- /dev/null
+++ b/src/DotNetOpenAuth.Test/OpenId/Messages/AssociateUnencryptedResponseTests.cs
@@ -0,0 +1,48 @@
+//-----------------------------------------------------------------------
+// <copyright file="AssociateUnencryptedResponseTests.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOpenAuth.Test.OpenId.Messages {
+ using DotNetOpenAuth.Messaging;
+ using DotNetOpenAuth.OpenId;
+ using DotNetOpenAuth.OpenId.Messages;
+ using Microsoft.VisualStudio.TestTools.UnitTesting;
+
+ [TestClass]
+ public class AssociateUnencryptedResponseTests {
+ private AssociateUnencryptedResponse response;
+
+ [TestInitialize]
+ public void Setup() {
+ this.response = new AssociateUnencryptedResponse();
+ }
+
+ [TestMethod]
+ public void ParameterNames() {
+ this.response.AssociationHandle = "HANDLE";
+ this.response.AssociationType = "HMAC-SHA1";
+ this.response.SessionType = "DH-SHA1";
+ this.response.ExpiresIn = 50;
+
+ MessageSerializer serializer = MessageSerializer.Get(this.response.GetType());
+ var fields = serializer.Serialize(this.response);
+ Assert.AreEqual(Protocol.OpenId2Namespace, fields["ns"]);
+ Assert.AreEqual("HANDLE", fields["assoc_handle"]);
+ Assert.AreEqual("HMAC-SHA1", fields["assoc_type"]);
+ Assert.AreEqual("DH-SHA1", fields["session_type"]);
+ Assert.AreEqual("50", fields["expires_in"]);
+ }
+
+ [TestMethod]
+ public void RequiredProtection() {
+ Assert.AreEqual(MessageProtections.None, this.response.RequiredProtection);
+ }
+
+ [TestMethod]
+ public void Transport() {
+ Assert.AreEqual(MessageTransport.Direct, this.response.Transport);
+ }
+ }
+} \ No newline at end of file
diff --git a/src/DotNetOpenAuth.Test/OpenId/Messages/AssociateUnsuccessfulResponseTests.cs b/src/DotNetOpenAuth.Test/OpenId/Messages/AssociateUnsuccessfulResponseTests.cs
new file mode 100644
index 0000000..588ea76
--- /dev/null
+++ b/src/DotNetOpenAuth.Test/OpenId/Messages/AssociateUnsuccessfulResponseTests.cs
@@ -0,0 +1,37 @@
+//-----------------------------------------------------------------------
+// <copyright file="AssociateUnsuccessfulResponseTests.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOpenAuth.Test.OpenId.Messages {
+ using DotNetOpenAuth.Messaging;
+ using DotNetOpenAuth.OpenId;
+ using DotNetOpenAuth.OpenId.Messages;
+ using Microsoft.VisualStudio.TestTools.UnitTesting;
+
+ [TestClass]
+ public class AssociateUnsuccessfulResponseTests {
+ private AssociateUnsuccessfulResponse response;
+
+ [TestInitialize]
+ public void Setup() {
+ this.response = new AssociateUnsuccessfulResponse();
+ }
+
+ [TestMethod]
+ public void ParameterNames() {
+ this.response.ErrorMessage = "Some Error";
+ this.response.AssociationType = "HMAC-SHA1";
+ this.response.SessionType = "DH-SHA1";
+
+ MessageSerializer serializer = MessageSerializer.Get(this.response.GetType());
+ var fields = serializer.Serialize(this.response);
+ Assert.AreEqual(Protocol.OpenId2Namespace, fields["ns"]);
+ Assert.AreEqual("unsupported-type", fields["error_code"]);
+ Assert.AreEqual("Some Error", fields["error"]);
+ Assert.AreEqual("HMAC-SHA1", fields["assoc_type"]);
+ Assert.AreEqual("DH-SHA1", fields["session_type"]);
+ }
+ }
+} \ No newline at end of file
diff --git a/src/DotNetOpenAuth.Test/OpenId/OpenIdChannelTests.cs b/src/DotNetOpenAuth.Test/OpenId/OpenIdChannelTests.cs
new file mode 100644
index 0000000..0843601
--- /dev/null
+++ b/src/DotNetOpenAuth.Test/OpenId/OpenIdChannelTests.cs
@@ -0,0 +1,28 @@
+//-----------------------------------------------------------------------
+// <copyright file="OpenIdChannelTests.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOpenAuth.Test.OpenId {
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Text;
+ using DotNetOpenAuth.OpenId.ChannelElements;
+ using Microsoft.VisualStudio.TestTools.UnitTesting;
+
+ [TestClass]
+ public class OpenIdChannelTests : TestBase {
+ private OpenIdChannel channel;
+
+ [TestInitialize]
+ public void Setup() {
+ this.channel = new OpenIdChannel();
+ }
+
+ [TestMethod]
+ public void Ctor() {
+ }
+ }
+}
diff --git a/src/DotNetOpenAuth.sln b/src/DotNetOpenAuth.sln
index 9c82423..e636d1b 100644
--- a/src/DotNetOpenAuth.sln
+++ b/src/DotNetOpenAuth.sln
@@ -34,7 +34,7 @@ Project("{E24C65DC-7377-472B-9ABA-BC803B73C61A}") = "Consumer", "..\samples\Cons
Release.AspNetCompiler.ForceOverwrite = "true"
Release.AspNetCompiler.FixedNames = "false"
Release.AspNetCompiler.Debug = "False"
- VWDPort = "16323"
+ VWDPort = "33321"
DefaultWebSiteLanguage = "Visual C#"
EndProjectSection
ProjectSection(ProjectDependencies) = postProject
diff --git a/src/DotNetOpenAuth/DotNetOpenAuth.csproj b/src/DotNetOpenAuth/DotNetOpenAuth.csproj
index 911b302..98a38c8 100644
--- a/src/DotNetOpenAuth/DotNetOpenAuth.csproj
+++ b/src/DotNetOpenAuth/DotNetOpenAuth.csproj
@@ -144,7 +144,9 @@
<Compile Include="Messaging\MessageTransport.cs" />
<Compile Include="OAuth\ChannelElements\OAuthServiceProviderMessageTypeProvider.cs" />
<Compile Include="Messaging\ProtocolException.cs" />
+ <Compile Include="OpenId\ChannelElements\KeyValueFormEncoding.cs" />
<Compile Include="OpenId\ChannelElements\OpenIdChannel.cs" />
+ <Compile Include="OpenId\ChannelElements\OpenIdMessageTypeProvider.cs" />
<Compile Include="OpenId\Messages\AssociateDiffieHellmanRequest.cs" />
<Compile Include="OpenId\Messages\AssociateDiffieHellmanResponse.cs" />
<Compile Include="OpenId\Messages\AssociateRequest.cs" />
diff --git a/src/DotNetOpenAuth/OpenId/ChannelElements/KeyValueFormEncoding.cs b/src/DotNetOpenAuth/OpenId/ChannelElements/KeyValueFormEncoding.cs
new file mode 100644
index 0000000..c9210d8
--- /dev/null
+++ b/src/DotNetOpenAuth/OpenId/ChannelElements/KeyValueFormEncoding.cs
@@ -0,0 +1,197 @@
+//-----------------------------------------------------------------------
+// <copyright file="KeyValueFormEncoding.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOpenAuth.OpenId.ChannelElements {
+ using System;
+ using System.Collections.Generic;
+ using System.Diagnostics.CodeAnalysis;
+ using System.Globalization;
+ using System.IO;
+ using System.Text;
+
+ /// <summary>
+ /// Indicates the level of strictness to require when decoding a
+ /// Key-Value Form encoded dictionary.
+ /// </summary>
+ public enum KeyValueFormConformanceLevel {
+ /// <summary>
+ /// Be as forgiving as possible to errors made while encoding.
+ /// </summary>
+ Loose,
+
+ /// <summary>
+ /// Allow for certain errors in encoding attributable to ambiguities
+ /// in the OpenID 1.1 spec's description of the encoding.
+ /// </summary>
+ OpenId11,
+
+ /// <summary>
+ /// The strictest mode. The decoder requires the encoded dictionary
+ /// to be in strict compliance with OpenID 2.0's description of
+ /// the encoding.
+ /// </summary>
+ OpenId20,
+ }
+
+ /// <summary>
+ /// Performs conversion to and from the Key-Value Form Encoding defined by
+ /// OpenID Authentication 2.0 section 4.1.1.
+ /// http://openid.net/specs/openid-authentication-2_0.html#anchor4
+ /// </summary>
+ /// <remarks>
+ /// This class is thread safe and immutable.
+ /// </remarks>
+ internal class KeyValueFormEncoding {
+ /// <summary>
+ /// Characters that must not appear in parameter names.
+ /// </summary>
+ private static readonly char[] IllegalKeyCharacters = { '\n', ':' };
+
+ /// <summary>
+ /// Characters that must not appaer in parameter values.
+ /// </summary>
+ private static readonly char[] IllegalValueCharacters = { '\n' };
+
+ /// <summary>
+ /// The newline character sequence to use.
+ /// </summary>
+ private const string NewLineCharacters = "\n";
+
+ /// <summary>
+ /// The character encoding to use.
+ /// </summary>
+ private static readonly Encoding textEncoding = new UTF8Encoding(false);
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="KeyValueFormEncoding"/> class.
+ /// </summary>
+ public KeyValueFormEncoding() {
+ this.ConformanceLevel = KeyValueFormConformanceLevel.Loose;
+ }
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="KeyValueFormEncoding"/> class.
+ /// </summary>
+ /// <param name="conformanceLevel">How strictly an incoming Key-Value Form message will be held to the spec.</param>
+ public KeyValueFormEncoding(KeyValueFormConformanceLevel conformanceLevel) {
+ this.ConformanceLevel = conformanceLevel;
+ }
+
+ /// <summary>
+ /// Gets a value controlling how strictly an incoming Key-Value Form message will be held to the spec.
+ /// </summary>
+ public KeyValueFormConformanceLevel ConformanceLevel { get; private set; }
+
+ /// <summary>
+ /// Encodes key/value pairs to Key-Value Form.
+ /// Do not use for dictionaries of signed fields! Instead use the overload
+ /// that accepts a list of in-order keys.
+ /// </summary>
+ /// <param name="dictionary">The dictionary with key/value pairs to encode in Key-Value Form.</param>
+ /// <returns>The UTF8 byte array.</returns>
+ /// <remarks>
+ /// Because dictionaries do not guarantee ordering,
+ /// encoding a dictionary without an explicitly given key order
+ /// is useless in OpenID scenarios where a signature must match.
+ /// </remarks>
+ public byte[] GetBytes(IDictionary<string, string> dictionary) {
+ string[] keys = new string[dictionary.Count];
+ dictionary.Keys.CopyTo(keys, 0);
+ return this.GetBytes(dictionary, keys);
+ }
+
+ /// <summary>
+ /// Encodes key/value pairs to Key-Value Form.
+ /// </summary>
+ /// <param name="dictionary">
+ /// The dictionary of key/value pairs to convert to a byte stream.
+ /// </param>
+ /// <param name="keyOrder">
+ /// The order in which to encode the key/value pairs.
+ /// Useful in scenarios where a byte[] must be exactly reproduced.
+ /// </param>
+ /// <returns>The UTF8 byte array.</returns>
+ public byte[] GetBytes(IDictionary<string, string> dictionary, IList<string> keyOrder) {
+ if (dictionary == null) {
+ throw new ArgumentNullException("dictionary");
+ }
+ if (keyOrder == null) {
+ throw new ArgumentNullException("keyOrder");
+ }
+ if (dictionary.Count != keyOrder.Count) {
+ throw new ArgumentException(OpenIdStrings.KeysListAndDictionaryDoNotMatch);
+ }
+
+ MemoryStream ms = new MemoryStream();
+ using (StreamWriter sw = new StreamWriter(ms, textEncoding)) {
+ sw.NewLine = NewLineCharacters;
+ foreach (string keyInOrder in keyOrder) {
+ string key = keyInOrder.Trim();
+ string value = dictionary[key].Trim();
+ if (key.IndexOfAny(IllegalKeyCharacters) >= 0) {
+ throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, OpenIdStrings.InvalidCharacterInKeyValueFormInput, key));
+ }
+ if (value.IndexOfAny(IllegalValueCharacters) >= 0) {
+ throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, OpenIdStrings.InvalidCharacterInKeyValueFormInput, value));
+ }
+
+ sw.Write(key);
+ sw.Write(':');
+ sw.Write(value);
+ sw.WriteLine();
+ }
+ }
+ return ms.ToArray();
+ }
+
+ /// <summary>
+ /// Decodes bytes in Key-Value Form to key/value pairs.
+ /// </summary>
+ /// <param name="data">The stream of Key-Value Form encoded bytes.</param>
+ /// <returns>The deserialized dictionary.</returns>
+ public IDictionary<string, string> GetDictionary(Stream data) {
+ using (StreamReader reader = new StreamReader(data, textEncoding)) {
+ var dict = new Dictionary<string, string>();
+ int line_num = 0;
+ string line;
+ while ((line = reader.ReadLine()) != null) {
+ line_num++;
+ if (this.ConformanceLevel == KeyValueFormConformanceLevel.Loose) {
+ line = line.Trim();
+ if (line.Length == 0) {
+ continue;
+ }
+ }
+ string[] parts = line.Split(new[] { ':' }, 2);
+ if (parts.Length != 2) {
+ throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, OpenIdStrings.InvalidKeyValueFormCharacterMissing, ':', line_num, line));
+ }
+ if (this.ConformanceLevel > KeyValueFormConformanceLevel.Loose) {
+ if (char.IsWhiteSpace(parts[0], parts[0].Length - 1) ||
+ char.IsWhiteSpace(parts[1], 0)) {
+ throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, OpenIdStrings.InvalidCharacterInKeyValueFormInput, ' ', line_num, line));
+ }
+ }
+ if (this.ConformanceLevel < KeyValueFormConformanceLevel.OpenId20) {
+ parts[0] = parts[0].Trim();
+ parts[1] = parts[1].Trim();
+ }
+
+ // calling Add method will throw if a key is encountered twice,
+ // which we should do.
+ dict.Add(parts[0], parts[1]);
+ }
+ if (this.ConformanceLevel > KeyValueFormConformanceLevel.Loose) {
+ reader.BaseStream.Seek(-1, SeekOrigin.End);
+ if (reader.BaseStream.ReadByte() != '\n') {
+ throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, OpenIdStrings.InvalidKeyValueFormCharacterMissing, "\\n", line_num, line));
+ }
+ }
+ return dict;
+ }
+ }
+ }
+}
diff --git a/src/DotNetOpenAuth/OpenId/ChannelElements/OpenIdChannel.cs b/src/DotNetOpenAuth/OpenId/ChannelElements/OpenIdChannel.cs
new file mode 100644
index 0000000..e13e09c
--- /dev/null
+++ b/src/DotNetOpenAuth/OpenId/ChannelElements/OpenIdChannel.cs
@@ -0,0 +1,99 @@
+//-----------------------------------------------------------------------
+// <copyright file="OpenIdChannel.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOpenAuth.OpenId.ChannelElements {
+ using System;
+ using System.Collections.Generic;
+ using System.IO;
+ using System.Linq;
+ using System.Net;
+ using System.Text;
+ using DotNetOpenAuth.Messaging;
+
+ /// <summary>
+ /// A channel that knows how to send and receive OpenID messages.
+ /// </summary>
+ internal class OpenIdChannel : Channel {
+ /// <summary>
+ /// The HTTP Content-Type to use in Key-Value Form responses.
+ /// </summary>
+ private const string KeyValueFormContentType = "application/x-openid-kvf";
+
+ /// <summary>
+ /// The encoder that understands how to read and write Key-Value Form.
+ /// </summary>
+ private KeyValueFormEncoding keyValueForm = new KeyValueFormEncoding();
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="OpenIdChannel"/> class.
+ /// </summary>
+ internal OpenIdChannel()
+ : this(new OpenIdMessageTypeProvider()) {
+ }
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="OpenIdChannel"/> class.
+ /// </summary>
+ /// <param name="messageTypeProvider">An object that knows how to distinguish the various OpenID message types for deserialization purposes.</param>
+ private OpenIdChannel(IMessageTypeProvider messageTypeProvider) :
+ base(messageTypeProvider) {
+ }
+
+ /// <summary>
+ /// Prepares an HTTP request that carries a given message.
+ /// </summary>
+ /// <param name="request">The message to send.</param>
+ /// <returns>
+ /// The <see cref="HttpWebRequest"/> prepared to send the request.
+ /// </returns>
+ protected override HttpWebRequest CreateHttpRequest(IDirectedProtocolMessage request) {
+ return this.InitializeRequestAsPost(request);
+ }
+
+ /// <summary>
+ /// Gets the protocol message that may be in the given HTTP response.
+ /// </summary>
+ /// <param name="response">The response that is anticipated to contain an protocol message.</param>
+ /// <returns>
+ /// The deserialized message parts, if found. Null otherwise.
+ /// </returns>
+ protected override IDictionary<string, string> ReadFromResponseInternal(Response response) {
+ if (response == null) {
+ throw new ArgumentNullException("response");
+ }
+
+ return this.keyValueForm.GetDictionary(response.ResponseStream);
+ }
+
+ /// <summary>
+ /// Queues a message for sending in the response stream where the fields
+ /// are sent in the response stream in querystring style.
+ /// </summary>
+ /// <param name="response">The message to send as a response.</param>
+ /// <returns>
+ /// The pending user agent redirect based message to be sent as an HttpResponse.
+ /// </returns>
+ /// <remarks>
+ /// This method implements spec V1.0 section 5.3.
+ /// </remarks>
+ protected override Response SendDirectMessageResponse(IProtocolMessage response) {
+ if (response == null) {
+ throw new ArgumentNullException("response");
+ }
+
+ var serializer = MessageSerializer.Get(response.GetType());
+ var fields = serializer.Serialize(response);
+ byte[] keyValueEncoding = this.keyValueForm.GetBytes(fields);
+
+ Response preparedResponse = new Response();
+ preparedResponse.Headers.Add(HttpResponseHeader.ContentType, "application/x-openid-kvf");
+ preparedResponse.OriginalMessage = response;
+ preparedResponse.ResponseStream = new MemoryStream(keyValueEncoding);
+
+ return preparedResponse;
+ }
+ }
+}
diff --git a/src/DotNetOpenAuth/OpenId/ChannelElements/OpenIdMessageTypeProvider.cs b/src/DotNetOpenAuth/OpenId/ChannelElements/OpenIdMessageTypeProvider.cs
new file mode 100644
index 0000000..d811d61
--- /dev/null
+++ b/src/DotNetOpenAuth/OpenId/ChannelElements/OpenIdMessageTypeProvider.cs
@@ -0,0 +1,49 @@
+//-----------------------------------------------------------------------
+// <copyright file="OpenIdMessageTypeProvider.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOpenAuth.OpenId.ChannelElements {
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Text;
+ using DotNetOpenAuth.Messaging;
+
+ /// <summary>
+ /// Distinguishes the various OpenID message types for deserialization purposes.
+ /// </summary>
+ internal class OpenIdMessageTypeProvider : IMessageTypeProvider {
+ #region IMessageTypeProvider Members
+
+ /// <summary>
+ /// 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="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. Null if the request isn't recognized as a valid protocol message.
+ /// </returns>
+ public Type GetRequestMessageType(IDictionary<string, string> fields) {
+ throw new NotImplementedException();
+ }
+
+ /// <summary>
+ /// 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. Null if the request isn't recognized as a valid protocol message.
+ /// </returns>
+ public Type GetResponseMessageType(IProtocolMessage request, IDictionary<string, string> fields) {
+ throw new NotImplementedException();
+ }
+
+ #endregion
+ }
+}
diff --git a/src/DotNetOpenAuth/OpenId/Messages/AssociateUnsuccessfulResponse.cs b/src/DotNetOpenAuth/OpenId/Messages/AssociateUnsuccessfulResponse.cs
index 4d8bfec..17c017b 100644
--- a/src/DotNetOpenAuth/OpenId/Messages/AssociateUnsuccessfulResponse.cs
+++ b/src/DotNetOpenAuth/OpenId/Messages/AssociateUnsuccessfulResponse.cs
@@ -28,6 +28,12 @@ namespace DotNetOpenAuth.OpenId.Messages {
#pragma warning restore 0414
/// <summary>
+ /// Initializes a new instance of the <see cref="AssociateUnsuccessfulResponse"/> class.
+ /// </summary>
+ internal AssociateUnsuccessfulResponse() {
+ }
+
+ /// <summary>
/// Gets or sets a human-readable message indicating why the association request failed.
/// </summary>
[MessagePart("error", IsRequired = true, AllowEmpty = true)]
diff --git a/src/DotNetOpenAuth/OpenId/OpenIdStrings.Designer.cs b/src/DotNetOpenAuth/OpenId/OpenIdStrings.Designer.cs
index 2e434b6..e6ff018 100644
--- a/src/DotNetOpenAuth/OpenId/OpenIdStrings.Designer.cs
+++ b/src/DotNetOpenAuth/OpenId/OpenIdStrings.Designer.cs
@@ -61,6 +61,33 @@ namespace DotNetOpenAuth.OpenId {
}
/// <summary>
+ /// Looks up a localized string similar to Cannot encode &apos;{0}&apos; because it contains an illegal character for Key-Value Form encoding. (line {1}: &apos;{2}&apos;).
+ /// </summary>
+ internal static string InvalidCharacterInKeyValueFormInput {
+ get {
+ return ResourceManager.GetString("InvalidCharacterInKeyValueFormInput", resourceCulture);
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to Cannot decode Key-Value Form because a line was found without a &apos;{0}&apos; character. (line {1}: &apos;{2}&apos;).
+ /// </summary>
+ internal static string InvalidKeyValueFormCharacterMissing {
+ get {
+ return ResourceManager.GetString("InvalidKeyValueFormCharacterMissing", resourceCulture);
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to The list of keys do not match the provided dictionary..
+ /// </summary>
+ internal static string KeysListAndDictionaryDoNotMatch {
+ get {
+ return ResourceManager.GetString("KeysListAndDictionaryDoNotMatch", resourceCulture);
+ }
+ }
+
+ /// <summary>
/// Looks up a localized string similar to Unless using transport layer encryption, &quot;no-encryption&quot; MUST NOT be used..
/// </summary>
internal static string NoEncryptionSessionRequiresHttps {
diff --git a/src/DotNetOpenAuth/OpenId/OpenIdStrings.resx b/src/DotNetOpenAuth/OpenId/OpenIdStrings.resx
index fa7c82b..00d6d1b 100644
--- a/src/DotNetOpenAuth/OpenId/OpenIdStrings.resx
+++ b/src/DotNetOpenAuth/OpenId/OpenIdStrings.resx
@@ -117,6 +117,15 @@
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
+ <data name="InvalidCharacterInKeyValueFormInput" xml:space="preserve">
+ <value>Cannot encode '{0}' because it contains an illegal character for Key-Value Form encoding. (line {1}: '{2}')</value>
+ </data>
+ <data name="InvalidKeyValueFormCharacterMissing" xml:space="preserve">
+ <value>Cannot decode Key-Value Form because a line was found without a '{0}' character. (line {1}: '{2}')</value>
+ </data>
+ <data name="KeysListAndDictionaryDoNotMatch" xml:space="preserve">
+ <value>The list of keys do not match the provided dictionary.</value>
+ </data>
<data name="NoEncryptionSessionRequiresHttps" xml:space="preserve">
<value>Unless using transport layer encryption, "no-encryption" MUST NOT be used.</value>
</data>