summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/DotNetOpenAuth.Test/OAuth/ChannelElements/HmacSha1SigningBindingElementTests.cs2
-rw-r--r--src/DotNetOpenAuth.Test/OAuth/ChannelElements/SigningBindingElementBaseTests.cs36
-rw-r--r--src/DotNetOpenAuth.Test/OpenId/Extensions/AttributeExchange/FetchResponseTests.cs2
-rw-r--r--src/DotNetOpenAuth.Test/OpenId/IdentifierTests.cs2
-rw-r--r--src/DotNetOpenAuth/OAuth/ChannelElements/SigningBindingElementBase.cs22
-rw-r--r--src/DotNetOpenAuth/OAuth/ServiceProvider.cs31
-rw-r--r--src/DotNetOpenAuth/OpenId/HmacShaAssociation.cs11
-rw-r--r--src/DotNetOpenAuth/OpenId/Messages/AssociateRequest.cs2
8 files changed, 92 insertions, 16 deletions
diff --git a/src/DotNetOpenAuth.Test/OAuth/ChannelElements/HmacSha1SigningBindingElementTests.cs b/src/DotNetOpenAuth.Test/OAuth/ChannelElements/HmacSha1SigningBindingElementTests.cs
index 2596bc5..fcdb5e8 100644
--- a/src/DotNetOpenAuth.Test/OAuth/ChannelElements/HmacSha1SigningBindingElementTests.cs
+++ b/src/DotNetOpenAuth.Test/OAuth/ChannelElements/HmacSha1SigningBindingElementTests.cs
@@ -14,7 +14,7 @@ namespace DotNetOpenAuth.Test.ChannelElements {
public class HmacSha1SigningBindingElementTests : MessagingTestBase {
[TestMethod]
public void SignatureTest() {
- UnauthorizedTokenRequest message = SigningBindingElementBaseTests.CreateTestRequestTokenMessage(this.MessageDescriptions);
+ UnauthorizedTokenRequest message = SigningBindingElementBaseTests.CreateTestRequestTokenMessage(this.MessageDescriptions, null);
HmacSha1SigningBindingElement_Accessor hmac = new HmacSha1SigningBindingElement_Accessor();
hmac.Channel = new TestChannel(this.MessageDescriptions);
diff --git a/src/DotNetOpenAuth.Test/OAuth/ChannelElements/SigningBindingElementBaseTests.cs b/src/DotNetOpenAuth.Test/OAuth/ChannelElements/SigningBindingElementBaseTests.cs
index e890b6f..cff46af 100644
--- a/src/DotNetOpenAuth.Test/OAuth/ChannelElements/SigningBindingElementBaseTests.cs
+++ b/src/DotNetOpenAuth.Test/OAuth/ChannelElements/SigningBindingElementBaseTests.cs
@@ -15,15 +15,45 @@ namespace DotNetOpenAuth.Test.ChannelElements {
public class SigningBindingElementBaseTests : MessagingTestBase {
[TestMethod]
public void BaseSignatureStringTest() {
- UnauthorizedTokenRequest message = CreateTestRequestTokenMessage(this.MessageDescriptions);
+ // Tests a message sent by HTTP GET, with no query string included in the endpoint.
+ UnauthorizedTokenRequest message = CreateTestRequestTokenMessage(
+ this.MessageDescriptions,
+ new MessageReceivingEndpoint("https://www.google.com/accounts/OAuthGetRequestToken", HttpDeliveryMethods.AuthorizationHeaderRequest | HttpDeliveryMethods.GetRequest));
+ Assert.AreEqual(
+ "GET&https%3A%2F%2Fwww.google.com%2Faccounts%2FOAuthGetRequestToken&oauth_consumer_key%3Dnerdbank.org%26oauth_nonce%3Dfe4045a3f0efdd1e019fa8f8ae3f5c38%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D1222665749%26oauth_version%3D1.0%26scope%3Dhttp%253A%252F%252Fwww.google.com%252Fm8%252Ffeeds%252F",
+ SigningBindingElementBase_Accessor.ConstructSignatureBaseString(message, MessageDictionary_Accessor.AttachShadow(this.MessageDescriptions.GetAccessor(message))));
+
+ // Test HTTP GET with an attached query string. We're elevating the scope parameter to the query string
+ // and removing it from the extradata dictionary. This should NOT affect the base signature string.
+ message = CreateTestRequestTokenMessage(
+ this.MessageDescriptions,
+ new MessageReceivingEndpoint("https://www.google.com/accounts/OAuthGetRequestToken?scope=http://www.google.com/m8/feeds/", HttpDeliveryMethods.AuthorizationHeaderRequest | HttpDeliveryMethods.GetRequest));
+ message.ExtraData.Remove("scope"); // remove it from ExtraData since we put it in the URL
+ Assert.AreEqual(
+ "GET&https%3A%2F%2Fwww.google.com%2Faccounts%2FOAuthGetRequestToken&oauth_consumer_key%3Dnerdbank.org%26oauth_nonce%3Dfe4045a3f0efdd1e019fa8f8ae3f5c38%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D1222665749%26oauth_version%3D1.0%26scope%3Dhttp%253A%252F%252Fwww.google.com%252Fm8%252Ffeeds%252F",
+ SigningBindingElementBase_Accessor.ConstructSignatureBaseString(message, MessageDictionary_Accessor.AttachShadow(this.MessageDescriptions.GetAccessor(message))));
+
+ // Test HTTP POST, with query string as well
+ message = CreateTestRequestTokenMessage(
+ this.MessageDescriptions,
+ new MessageReceivingEndpoint("https://www.google.com/accounts/OAuthGetRequestToken?scope=http://www.google.com/m8/feeds/", HttpDeliveryMethods.AuthorizationHeaderRequest | HttpDeliveryMethods.PostRequest));
+ message.ExtraData.Remove("scope"); // remove it from ExtraData since we put it in the URL
+ Assert.AreEqual(
+ "GET&https%3A%2F%2Fwww.google.com%2Faccounts%2FOAuthGetRequestToken&oauth_consumer_key%3Dnerdbank.org%26oauth_nonce%3Dfe4045a3f0efdd1e019fa8f8ae3f5c38%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D1222665749%26oauth_version%3D1.0%26scope%3Dhttp%253A%252F%252Fwww.google.com%252Fm8%252Ffeeds%252F",
+ SigningBindingElementBase_Accessor.ConstructSignatureBaseString(message, MessageDictionary_Accessor.AttachShadow(this.MessageDescriptions.GetAccessor(message))));
+ // Test HTTP POST, with query string, but not using the Authorization header
+ message = CreateTestRequestTokenMessage(
+ this.MessageDescriptions,
+ new MessageReceivingEndpoint("https://www.google.com/accounts/OAuthGetRequestToken?scope=http://www.google.com/m8/feeds/", HttpDeliveryMethods.PostRequest));
+ message.ExtraData.Remove("scope"); // remove it from ExtraData since we put it in the URL
Assert.AreEqual(
"GET&https%3A%2F%2Fwww.google.com%2Faccounts%2FOAuthGetRequestToken&oauth_consumer_key%3Dnerdbank.org%26oauth_nonce%3Dfe4045a3f0efdd1e019fa8f8ae3f5c38%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D1222665749%26oauth_version%3D1.0%26scope%3Dhttp%253A%252F%252Fwww.google.com%252Fm8%252Ffeeds%252F",
SigningBindingElementBase_Accessor.ConstructSignatureBaseString(message, MessageDictionary_Accessor.AttachShadow(this.MessageDescriptions.GetAccessor(message))));
}
- internal static UnauthorizedTokenRequest CreateTestRequestTokenMessage(MessageDescriptionCollection messageDescriptions) {
- MessageReceivingEndpoint endpoint = new MessageReceivingEndpoint("https://www.google.com/accounts/OAuthGetRequestToken", HttpDeliveryMethods.AuthorizationHeaderRequest | HttpDeliveryMethods.GetRequest);
+ internal static UnauthorizedTokenRequest CreateTestRequestTokenMessage(MessageDescriptionCollection messageDescriptions, MessageReceivingEndpoint endpoint) {
+ endpoint = endpoint ?? new MessageReceivingEndpoint("https://www.google.com/accounts/OAuthGetRequestToken", HttpDeliveryMethods.AuthorizationHeaderRequest | HttpDeliveryMethods.GetRequest);
UnauthorizedTokenRequest message = new UnauthorizedTokenRequest(endpoint);
message.ConsumerKey = "nerdbank.org";
((ITamperResistantOAuthMessage)message).ConsumerSecret = "nerdbanksecret";
diff --git a/src/DotNetOpenAuth.Test/OpenId/Extensions/AttributeExchange/FetchResponseTests.cs b/src/DotNetOpenAuth.Test/OpenId/Extensions/AttributeExchange/FetchResponseTests.cs
index d467186..9d209a9 100644
--- a/src/DotNetOpenAuth.Test/OpenId/Extensions/AttributeExchange/FetchResponseTests.cs
+++ b/src/DotNetOpenAuth.Test/OpenId/Extensions/AttributeExchange/FetchResponseTests.cs
@@ -4,7 +4,7 @@
// </copyright>
//-----------------------------------------------------------------------
-namespace DotNetOpenId.Test.OpenId.Extensions {
+namespace DotNetOpenAuth.Test.OpenId.Extensions {
using System;
using System.IO;
using DotNetOpenAuth.OpenId.Extensions.AttributeExchange;
diff --git a/src/DotNetOpenAuth.Test/OpenId/IdentifierTests.cs b/src/DotNetOpenAuth.Test/OpenId/IdentifierTests.cs
index 53df6c8..3e599e9 100644
--- a/src/DotNetOpenAuth.Test/OpenId/IdentifierTests.cs
+++ b/src/DotNetOpenAuth.Test/OpenId/IdentifierTests.cs
@@ -22,7 +22,7 @@ namespace DotNetOpenAuth.Test.OpenId {
public void TryParseNoThrow() {
Identifier id;
Assert.IsFalse(Identifier.TryParse(null, out id));
- Assert.IsFalse(Identifier.TryParse("", out id));
+ Assert.IsFalse(Identifier.TryParse(string.Empty, out id));
}
[TestMethod]
diff --git a/src/DotNetOpenAuth/OAuth/ChannelElements/SigningBindingElementBase.cs b/src/DotNetOpenAuth/OAuth/ChannelElements/SigningBindingElementBase.cs
index d5ba346..d1fc10b 100644
--- a/src/DotNetOpenAuth/OAuth/ChannelElements/SigningBindingElementBase.cs
+++ b/src/DotNetOpenAuth/OAuth/ChannelElements/SigningBindingElementBase.cs
@@ -7,9 +7,11 @@
namespace DotNetOpenAuth.OAuth.ChannelElements {
using System;
using System.Collections.Generic;
+ using System.Collections.Specialized;
using System.Diagnostics.Contracts;
using System.Globalization;
using System.Text;
+ using System.Web;
using DotNetOpenAuth.Messaging;
using DotNetOpenAuth.Messaging.Bindings;
using DotNetOpenAuth.Messaging.Reflection;
@@ -164,13 +166,29 @@ namespace DotNetOpenAuth.OAuth.ChannelElements {
signatureBaseStringElements.Add(message.HttpMethod.ToUpperInvariant());
+ var encodedDictionary = OAuthChannel.GetUriEscapedParameters(messageDictionary);
+ encodedDictionary.Remove("oauth_signature");
+ if (message.Recipient.Query != null) {
+ // It seeems to me a deviation from the OAuth 1.0 spec to be willing to scrape the query
+ // for parameters on anything but GET requests, but Google does it so to interop we must
+ // as well. Besides, it seems more secure to sign everything if it's there.
+ NameValueCollection nvc = HttpUtility.ParseQueryString(message.Recipient.Query);
+ foreach (string key in nvc) {
+ encodedDictionary.Add(Uri.EscapeDataString(key), Uri.EscapeDataString(nvc[key]));
+ }
+ } else if (message.HttpMethod == "POST") {
+ // If the HttpWebRequest that we're sending out has a content-type header
+ // of application/x-www-form-urlencoded, we should be parsing out those parameters
+ // and adding them to this dictionary as well.
+ // But at this point we don't have access to the HttpWebRequest (design flaw?)
+ // TODO: figure this out.
+ }
+
UriBuilder endpoint = new UriBuilder(message.Recipient);
endpoint.Query = null;
endpoint.Fragment = null;
signatureBaseStringElements.Add(endpoint.Uri.AbsoluteUri);
- var encodedDictionary = OAuthChannel.GetUriEscapedParameters(messageDictionary);
- encodedDictionary.Remove("oauth_signature");
var sortedKeyValueList = new List<KeyValuePair<string, string>>(encodedDictionary);
sortedKeyValueList.Sort(SignatureBaseStringParameterComparer);
StringBuilder paramBuilder = new StringBuilder();
diff --git a/src/DotNetOpenAuth/OAuth/ServiceProvider.cs b/src/DotNetOpenAuth/OAuth/ServiceProvider.cs
index a8a702b..122e7ee 100644
--- a/src/DotNetOpenAuth/OAuth/ServiceProvider.cs
+++ b/src/DotNetOpenAuth/OAuth/ServiceProvider.cs
@@ -271,23 +271,44 @@ namespace DotNetOpenAuth.OAuth {
/// <param name="request">The Consumer's original authorization request.</param>
/// <returns>
/// The message to send to the Consumer using <see cref="Channel"/> if one is necessary.
- /// Null if the Consumer did not request a callback.
+ /// Null if the Consumer did not request a callback as part of the authorization request.
/// </returns>
[SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic", Justification = "Consistent user experience with instance.")]
public UserAuthorizationResponse PrepareAuthorizationResponse(UserAuthorizationRequest request) {
+ Contract.Requires(request != null);
ErrorUtilities.VerifyArgumentNotNull(request, "request");
if (request.Callback != null) {
- var authorization = new UserAuthorizationResponse(request.Callback) {
- RequestToken = request.RequestToken,
- };
- return authorization;
+ return this.PrepareAuthorizationResponse(request, request.Callback);
} else {
return null;
}
}
/// <summary>
+ /// Prepares the message to send back to the consumer following proper authorization of
+ /// a token by an interactive user at the Service Provider's web site.
+ /// </summary>
+ /// <param name="request">The Consumer's original authorization request.</param>
+ /// <param name="callback">The callback URI the consumer has previously registered
+ /// with this service provider.</param>
+ /// <returns>
+ /// The message to send to the Consumer using <see cref="Channel"/>.
+ /// </returns>
+ [SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic", Justification = "Consistent user experience with instance.")]
+ public UserAuthorizationResponse PrepareAuthorizationResponse(UserAuthorizationRequest request, Uri callback) {
+ Contract.Requires(request != null);
+ Contract.Requires(callback != null);
+ ErrorUtilities.VerifyArgumentNotNull(request, "request");
+ ErrorUtilities.VerifyArgumentNotNull(callback, "callback");
+
+ var authorization = new UserAuthorizationResponse(request.Callback) {
+ RequestToken = request.RequestToken,
+ };
+ return authorization;
+ }
+
+ /// <summary>
/// Gets the incoming request to exchange an authorized token for an access token.
/// </summary>
/// <returns>The incoming request, or null if no OAuth message was attached.</returns>
diff --git a/src/DotNetOpenAuth/OpenId/HmacShaAssociation.cs b/src/DotNetOpenAuth/OpenId/HmacShaAssociation.cs
index d35dcd1..16d8f74 100644
--- a/src/DotNetOpenAuth/OpenId/HmacShaAssociation.cs
+++ b/src/DotNetOpenAuth/OpenId/HmacShaAssociation.cs
@@ -8,6 +8,7 @@ namespace DotNetOpenAuth.OpenId {
using System;
using System.Collections.Generic;
using System.Diagnostics;
+ using System.Globalization;
using System.Linq;
using System.Security.Cryptography;
using DotNetOpenAuth.Messaging;
@@ -148,13 +149,19 @@ namespace DotNetOpenAuth.OpenId {
ErrorUtilities.VerifyNonZeroLength(associationType, "associationType");
ErrorUtilities.VerifyArgumentNotNull(securitySettings, "securitySettings");
+ int secretLength = GetSecretLength(protocol, associationType);
+
// Generate the handle. It must be unique, and preferably unpredictable,
// so we use a time element and a random data element to generate it.
string uniq = MessagingUtilities.GetCryptoRandomDataAsBase64(4);
- string handle = "{" + associationType + "}{" + DateTime.UtcNow.Ticks + "}{" + uniq + "}";
+ string handle = string.Format(
+ CultureInfo.InvariantCulture,
+ "{{{0}}}{{{1}}}{{{2}}}",
+ DateTime.UtcNow.Ticks,
+ uniq,
+ secretLength);
// Generate the secret that will be used for signing
- int secretLength = GetSecretLength(protocol, associationType);
byte[] secret = MessagingUtilities.GetCryptoRandomData(secretLength);
TimeSpan lifetime;
diff --git a/src/DotNetOpenAuth/OpenId/Messages/AssociateRequest.cs b/src/DotNetOpenAuth/OpenId/Messages/AssociateRequest.cs
index f9f638a..6a5c0a8 100644
--- a/src/DotNetOpenAuth/OpenId/Messages/AssociateRequest.cs
+++ b/src/DotNetOpenAuth/OpenId/Messages/AssociateRequest.cs
@@ -40,7 +40,7 @@ namespace DotNetOpenAuth.OpenId.Messages {
/// </summary>
/// <value>Value: A valid association session type from Section 8.4 (Association Session Types). </value>
/// <remarks>Note: Unless using transport layer encryption, "no-encryption" MUST NOT be used. </remarks>
- [MessagePart("openid.session_type", IsRequired = true, AllowEmpty = true)]
+ [MessagePart("openid.session_type", IsRequired = false, AllowEmpty = true)]
[MessagePart("openid.session_type", IsRequired = true, AllowEmpty = false, MinVersion = "2.0")]
internal string SessionType { get; set; }