summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/DotNetOpenAuth.Core/Messaging/ErrorUtilities.cs20
-rw-r--r--src/DotNetOpenAuth.Core/Messaging/MessagingStrings.Designer.cs11
-rw-r--r--src/DotNetOpenAuth.Core/Messaging/MessagingStrings.resx5
-rw-r--r--src/DotNetOpenAuth.OpenId/OpenId/ChannelElements/SigningBindingElement.cs4
-rw-r--r--src/DotNetOpenAuth.Test/Mocks/TestChannel.cs15
-rw-r--r--src/DotNetOpenAuth.Test/OpenId/ChannelElements/SigningBindingElementTests.cs35
6 files changed, 86 insertions, 4 deletions
diff --git a/src/DotNetOpenAuth.Core/Messaging/ErrorUtilities.cs b/src/DotNetOpenAuth.Core/Messaging/ErrorUtilities.cs
index c6a652b..129a03d 100644
--- a/src/DotNetOpenAuth.Core/Messaging/ErrorUtilities.cs
+++ b/src/DotNetOpenAuth.Core/Messaging/ErrorUtilities.cs
@@ -6,6 +6,7 @@
namespace DotNetOpenAuth.Messaging {
using System;
+ using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.Contracts;
using System.Globalization;
@@ -361,5 +362,24 @@ namespace DotNetOpenAuth.Messaging {
Contract.Ensures(HttpContext.Current.Request != null);
ErrorUtilities.VerifyOperation(HttpContext.Current != null && HttpContext.Current.Request != null, MessagingStrings.HttpContextRequired);
}
+
+ /// <summary>
+ /// Obtains a value from the dictionary if possible, or throws a <see cref="ProtocolException"/> if it's missing.
+ /// </summary>
+ /// <typeparam name="TKey">The type of key in the dictionary.</typeparam>
+ /// <typeparam name="TValue">The type of value in the dictionary.</typeparam>
+ /// <param name="dictionary">The dictionary.</param>
+ /// <param name="key">The key to use to look up the value.</param>
+ /// <param name="message">The message to claim is invalid if the key cannot be found.</param>
+ /// <returns>The value for the given key.</returns>
+ [Pure]
+ internal static TValue GetValueOrThrow<TKey, TValue>(this IDictionary<TKey, TValue> dictionary, TKey key, IMessage message) {
+ Requires.NotNull(dictionary, "dictionary");
+ Requires.NotNull(message, "message");
+
+ TValue value;
+ VerifyProtocol(dictionary.TryGetValue(key, out value), MessagingStrings.ExpectedParameterWasMissing, key, message.GetType().Name);
+ return value;
+ }
}
}
diff --git a/src/DotNetOpenAuth.Core/Messaging/MessagingStrings.Designer.cs b/src/DotNetOpenAuth.Core/Messaging/MessagingStrings.Designer.cs
index 11bd751..3ad2bdd 100644
--- a/src/DotNetOpenAuth.Core/Messaging/MessagingStrings.Designer.cs
+++ b/src/DotNetOpenAuth.Core/Messaging/MessagingStrings.Designer.cs
@@ -1,7 +1,7 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
-// Runtime Version:4.0.30319.1
+// Runtime Version:4.0.30319.239
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
@@ -187,6 +187,15 @@ namespace DotNetOpenAuth.Messaging {
}
/// <summary>
+ /// Looks up a localized string similar to The message part {0} was expected in the {1} message but was not found..
+ /// </summary>
+ internal static string ExpectedParameterWasMissing {
+ get {
+ return ResourceManager.GetString("ExpectedParameterWasMissing", resourceCulture);
+ }
+ }
+
+ /// <summary>
/// Looks up a localized string similar to The message expired at {0} and it is now {1}..
/// </summary>
internal static string ExpiredMessage {
diff --git a/src/DotNetOpenAuth.Core/Messaging/MessagingStrings.resx b/src/DotNetOpenAuth.Core/Messaging/MessagingStrings.resx
index bd10b76..5f3f79a 100644
--- a/src/DotNetOpenAuth.Core/Messaging/MessagingStrings.resx
+++ b/src/DotNetOpenAuth.Core/Messaging/MessagingStrings.resx
@@ -321,4 +321,7 @@
<data name="ExtraParameterAddFailure" xml:space="preserve">
<value>Failed to add extra parameter '{0}' with value '{1}'.</value>
</data>
-</root>
+ <data name="ExpectedParameterWasMissing" xml:space="preserve">
+ <value>The message part {0} was expected in the {1} message but was not found.</value>
+ </data>
+</root> \ No newline at end of file
diff --git a/src/DotNetOpenAuth.OpenId/OpenId/ChannelElements/SigningBindingElement.cs b/src/DotNetOpenAuth.OpenId/OpenId/ChannelElements/SigningBindingElement.cs
index 95a748e..d14ca8a 100644
--- a/src/DotNetOpenAuth.OpenId/OpenId/ChannelElements/SigningBindingElement.cs
+++ b/src/DotNetOpenAuth.OpenId/OpenId/ChannelElements/SigningBindingElement.cs
@@ -128,8 +128,8 @@ namespace DotNetOpenAuth.OpenId.ChannelElements {
// of check_authentication with its original id_res so the signature matches.
MessageDictionary dictionary = this.Channel.MessageDescriptions.GetAccessor(signedMessage);
var parametersToSign = from name in signedMessage.SignedParameterOrder.Split(',')
- let prefixedName = Protocol.V20.openid.Prefix + name
- select new KeyValuePair<string, string>(name, dictionary[prefixedName]);
+ let prefixedName = Protocol.V20.openid.Prefix + name
+ select new KeyValuePair<string, string>(name, dictionary.GetValueOrThrow(prefixedName, signedMessage));
byte[] dataToSign = KeyValueFormEncoding.GetBytes(parametersToSign);
string signature = Convert.ToBase64String(association.Sign(dataToSign));
diff --git a/src/DotNetOpenAuth.Test/Mocks/TestChannel.cs b/src/DotNetOpenAuth.Test/Mocks/TestChannel.cs
index 95fb90a..92fd9c6 100644
--- a/src/DotNetOpenAuth.Test/Mocks/TestChannel.cs
+++ b/src/DotNetOpenAuth.Test/Mocks/TestChannel.cs
@@ -25,6 +25,21 @@ namespace DotNetOpenAuth.Test.Mocks {
: base(messageTypeProvider, bindingElements) {
}
+ /// <summary>
+ /// Deserializes a dictionary of values into a message.
+ /// </summary>
+ /// <param name="fields">The dictionary of values that were read from an HTTP request or response.</param>
+ /// <param name="recipient">Information about where the message was directed. Null for direct response messages.</param>
+ /// <returns>
+ /// The deserialized message, or null if no message could be recognized in the provided data.
+ /// </returns>
+ /// <remarks>
+ /// This internal method exposes Receive directly to unit tests for easier deserialization of custom (possibly malformed) messages.
+ /// </remarks>
+ internal new IProtocolMessage Receive(Dictionary<string, string> fields, MessageReceivingEndpoint recipient) {
+ return base.Receive(fields, recipient);
+ }
+
protected override IDictionary<string, string> ReadFromResponseCore(IncomingWebResponse response) {
throw new NotImplementedException("ReadFromResponseInternal");
}
diff --git a/src/DotNetOpenAuth.Test/OpenId/ChannelElements/SigningBindingElementTests.cs b/src/DotNetOpenAuth.Test/OpenId/ChannelElements/SigningBindingElementTests.cs
index 955ea2d..22714a9 100644
--- a/src/DotNetOpenAuth.Test/OpenId/ChannelElements/SigningBindingElementTests.cs
+++ b/src/DotNetOpenAuth.Test/OpenId/ChannelElements/SigningBindingElementTests.cs
@@ -6,13 +6,16 @@
namespace DotNetOpenAuth.Test.OpenId.ChannelElements {
using System;
+ using System.Collections.Generic;
using System.Linq;
+ using DotNetOpenAuth.Messaging;
using DotNetOpenAuth.Messaging.Bindings;
using DotNetOpenAuth.OpenId;
using DotNetOpenAuth.OpenId.ChannelElements;
using DotNetOpenAuth.OpenId.Messages;
using DotNetOpenAuth.OpenId.Provider;
using DotNetOpenAuth.Test.Mocks;
+ using Moq;
using NUnit.Framework;
[TestFixture]
@@ -68,5 +71,37 @@ namespace DotNetOpenAuth.Test.OpenId.ChannelElements {
Assert.IsTrue(signedParameters.Contains("somesigned"));
Assert.IsFalse(signedParameters.Contains("someunsigned"));
}
+
+ /// <summary>
+ /// Regression test for bug #45 (https://github.com/AArnott/dotnetopenid/issues/45)
+ /// </summary>
+ [TestCase, ExpectedException(typeof(ProtocolException))]
+ public void MissingSignedParameter() {
+ var cryptoStore = new MemoryCryptoKeyStore();
+ byte[] associationSecret = Convert.FromBase64String("rsSwv1zPWfjPRQU80hciu8FPDC+GONAMJQ/AvSo1a2M=");
+ string handle = "{634477555066085461}{TTYcIg==}{32}";
+ cryptoStore.StoreKey(ProviderAssociationKeyStorage.PrivateAssociationBucket, handle, new CryptoKey(associationSecret, DateTime.UtcNow.AddDays(1)));
+
+ var signer = new ProviderSigningBindingElement(new ProviderAssociationKeyStorage(cryptoStore), new ProviderSecuritySettings());
+ var testChannel = new TestChannel(new OpenIdProviderMessageFactory());
+ signer.Channel = testChannel;
+
+ var buggyRPMessage = new Dictionary<string, string>() {
+ { "openid.assoc_handle", "{634477555066085461}{TTYcIg==}{32}" },
+ { "openid.claimed_id", "https://openid.stackexchange.com/user/f5e91123-e5b4-43c5-871f-5f276c75d31a" },
+ { "openid.identity", "https://openid.stackexchange.com/user/f5e91123-e5b4-43c5-871f-5f276c75d31a" },
+ { "openid.mode", "check_authentication" },
+ { "openid.op_endpoint", "https://openid.stackexchange.com/openid/provider" },
+ { "openid.response_nonce", "2011-08-01T00:32:10Zvdyt3efw" },
+ { "openid.return_to", "http://openid-consumer.appspot.com/finish?session_id=1543025&janrain_nonce=2011-08-01T00%3A32%3A09ZIPGz7D" },
+ { "openid.sig", "b0Rll6Kt1KKBWWBEg/qBvW3sQYtmhOUmpI0/UREBVZ0=" },
+ { "openid.signed", "claimed_id,identity,assoc_handle,op_endpoint,return_to,response_nonce,ns.sreg,sreg.email,sreg.fullname" },
+ { "openid.sreg.email", "kevin.montrose@stackoverflow.com" },
+ { "openid.sreg.fullname", "Kevin K Montrose" },
+ };
+ var message = (CheckAuthenticationRequest)testChannel.Receive(buggyRPMessage, new MessageReceivingEndpoint(OPUri, HttpDeliveryMethods.PostRequest));
+ var originalResponse = new IndirectSignedResponse(message, signer.Channel);
+ signer.ProcessIncomingMessage(originalResponse);
+ }
}
}