diff options
9 files changed, 137 insertions, 80 deletions
diff --git a/src/DotNetOAuth/ChannelElements/HmacSha1SigningBindingElement.cs b/src/DotNetOAuth/ChannelElements/HmacSha1SigningBindingElement.cs index 08c1c45..c0bd030 100644 --- a/src/DotNetOAuth/ChannelElements/HmacSha1SigningBindingElement.cs +++ b/src/DotNetOAuth/ChannelElements/HmacSha1SigningBindingElement.cs @@ -6,11 +6,8 @@ namespace DotNetOAuth.ChannelElements {
using System;
- using System.Collections.Generic;
- using System.Linq;
+ using System.Security.Cryptography;
using System.Text;
- using DotNetOAuth.Messaging;
- using DotNetOAuth.Messaging.Bindings;
/// <summary>
/// A binding element that signs outgoing messages and verifies the signature on incoming messages.
@@ -24,21 +21,18 @@ namespace DotNetOAuth.ChannelElements { }
/// <summary>
- /// Applies a signature to the message.
+ /// Calculates a signature for a given message.
/// </summary>
/// <param name="message">The message to sign.</param>
- protected override void Sign(ITamperResistantOAuthMessage message) {
- throw new NotImplementedException();
- }
-
- /// <summary>
- /// Validates the signature on a message.
- /// Does NOT throw an exception on failing signature verification.
- /// </summary>
- /// <param name="message">The message with a signature to verify.</param>
- /// <returns>True if the signature is valid. False otherwise.</returns>
- protected override bool IsSignatureValid(ITamperResistantOAuthMessage message) {
- throw new NotImplementedException();
+ /// <returns>The signature for the message.</returns>
+ /// <remarks>
+ /// This method signs the message per OAuth 1.0 section 9.2.
+ /// </remarks>
+ protected override string GetSignature(ITamperResistantOAuthMessage message) {
+ string key = Uri.EscapeDataString(message.ConsumerSecret) + "&" + Uri.EscapeDataString(message.TokenSecret);
+ HashAlgorithm hasher = new HMACSHA1(Encoding.UTF8.GetBytes(key));
+ byte[] digest = hasher.ComputeHash(Encoding.UTF8.GetBytes(ConstructSignatureBaseString(message)));
+ return Uri.EscapeDataString(Convert.ToBase64String(digest));
}
}
}
diff --git a/src/DotNetOAuth/ChannelElements/ITamperResistantOAuthMessage.cs b/src/DotNetOAuth/ChannelElements/ITamperResistantOAuthMessage.cs index 887efac..cafea5d 100644 --- a/src/DotNetOAuth/ChannelElements/ITamperResistantOAuthMessage.cs +++ b/src/DotNetOAuth/ChannelElements/ITamperResistantOAuthMessage.cs @@ -5,6 +5,7 @@ //-----------------------------------------------------------------------
namespace DotNetOAuth.ChannelElements {
+ using System.Collections.Generic;
using DotNetOAuth.Messaging;
using DotNetOAuth.Messaging.Bindings;
@@ -16,5 +17,29 @@ namespace DotNetOAuth.ChannelElements { /// Gets or sets the method used to sign the message.
/// </summary>
string SignatureMethod { get; set; }
+
+ /// <summary>
+ /// Gets or sets the Token Secret used to sign the message.
+ /// Only applicable to Consumer.
+ /// </summary>
+ string TokenSecret { get; set; }
+
+ /// <summary>
+ /// Gets or sets the Consumer Secret used to sign the message.
+ /// Only applicable to Consumer.
+ /// </summary>
+ string ConsumerSecret { get; set; }
+
+ /// <summary>
+ /// Gets or sets the HTTP method that will be used to transmit the message.
+ /// Only applicable to Consumer.
+ /// </summary>
+ string HttpMethod { get; set; }
+
+ /// <summary>
+ /// Gets or sets the extra, non-OAuth parameters that will be included in the request.
+ /// Only applicable to Consumer.
+ /// </summary>
+ IDictionary<string, string> AdditionalParametersInHttpRequest { get; set; }
}
}
diff --git a/src/DotNetOAuth/ChannelElements/OAuthChannel.cs b/src/DotNetOAuth/ChannelElements/OAuthChannel.cs index 683fdb8..7183fa5 100644 --- a/src/DotNetOAuth/ChannelElements/OAuthChannel.cs +++ b/src/DotNetOAuth/ChannelElements/OAuthChannel.cs @@ -77,14 +77,28 @@ namespace DotNetOAuth.ChannelElements { /// <returns>A dictionary of name-value pairs with their strings encoded.</returns>
internal static IDictionary<string, string> GetEncodedParameters(IProtocolMessage message) {
var encodedDictionary = new Dictionary<string, string>();
- MessageDictionary messageDictionary = new MessageDictionary(message);
- foreach (var pair in messageDictionary) {
+ EncodeParameters(new MessageDictionary(message), encodedDictionary);
+ return encodedDictionary;
+ }
+
+ /// <summary>
+ /// Encodes the names and values in a dictionary per OAuth 1.0 section 5.1.
+ /// </summary>
+ /// <param name="source">The dictionary with names and values to encode.</param>
+ /// <param name="destination">The dictionary to add the encoded pairs to.</param>
+ internal static void EncodeParameters(IDictionary<string, string> source, IDictionary<string, string> destination) {
+ if (source == null) {
+ throw new ArgumentNullException("source");
+ }
+ if (destination == null) {
+ throw new ArgumentNullException("destination");
+ }
+
+ foreach (var pair in source) {
var key = Uri.EscapeDataString(pair.Key);
var value = Uri.EscapeDataString(pair.Value);
- encodedDictionary.Add(key, value);
+ destination.Add(key, value);
}
-
- return encodedDictionary;
}
/// <summary>
diff --git a/src/DotNetOAuth/ChannelElements/PlainTextSigningBindingElement.cs b/src/DotNetOAuth/ChannelElements/PlainTextSigningBindingElement.cs index c106289..cc01678 100644 --- a/src/DotNetOAuth/ChannelElements/PlainTextSigningBindingElement.cs +++ b/src/DotNetOAuth/ChannelElements/PlainTextSigningBindingElement.cs @@ -24,21 +24,19 @@ namespace DotNetOAuth.ChannelElements { }
/// <summary>
- /// Applies a signature to the message.
+ /// Calculates a signature for a given message.
/// </summary>
/// <param name="message">The message to sign.</param>
- protected override void Sign(ITamperResistantOAuthMessage message) {
- throw new NotImplementedException();
- }
-
- /// <summary>
- /// Validates the signature on a message.
- /// Does NOT throw an exception on failing signature verification.
- /// </summary>
- /// <param name="message">The message with a signature to verify.</param>
- /// <returns>True if the signature is valid. False otherwise.</returns>
- protected override bool IsSignatureValid(ITamperResistantOAuthMessage message) {
- throw new NotImplementedException();
+ /// <returns>The signature for the message.</returns>
+ /// <remarks>
+ /// This method signs the message according to OAuth 1.0 section 9.4.1.
+ /// </remarks>
+ protected override string GetSignature(ITamperResistantOAuthMessage message) {
+ StringBuilder builder = new StringBuilder();
+ builder.Append(Uri.EscapeDataString(message.ConsumerSecret));
+ builder.Append("&");
+ builder.Append(Uri.EscapeDataString(message.TokenSecret));
+ return Uri.EscapeDataString(builder.ToString());
}
}
}
diff --git a/src/DotNetOAuth/ChannelElements/RsaSha1SigningBindingElement.cs b/src/DotNetOAuth/ChannelElements/RsaSha1SigningBindingElement.cs index 6bf6fdc..76bcd50 100644 --- a/src/DotNetOAuth/ChannelElements/RsaSha1SigningBindingElement.cs +++ b/src/DotNetOAuth/ChannelElements/RsaSha1SigningBindingElement.cs @@ -24,20 +24,14 @@ namespace DotNetOAuth.ChannelElements { }
/// <summary>
- /// Applies a signature to the message.
+ /// Calculates a signature for a given message.
/// </summary>
/// <param name="message">The message to sign.</param>
- protected override void Sign(ITamperResistantOAuthMessage message) {
- throw new NotImplementedException();
- }
-
- /// <summary>
- /// Validates the signature on a message.
- /// Does NOT throw an exception on failing signature verification.
- /// </summary>
- /// <param name="message">The message with a signature to verify.</param>
- /// <returns>True if the signature is valid. False otherwise.</returns>
- protected override bool IsSignatureValid(ITamperResistantOAuthMessage message) {
+ /// <returns>The signature for the message.</returns>
+ /// <remarks>
+ /// This method signs the message per OAuth 1.0 section 9.3.
+ /// </remarks>
+ protected override string GetSignature(ITamperResistantOAuthMessage message) {
throw new NotImplementedException();
}
}
diff --git a/src/DotNetOAuth/ChannelElements/SigningBindingElementBase.cs b/src/DotNetOAuth/ChannelElements/SigningBindingElementBase.cs index 7b89f84..8a9db7e 100644 --- a/src/DotNetOAuth/ChannelElements/SigningBindingElementBase.cs +++ b/src/DotNetOAuth/ChannelElements/SigningBindingElementBase.cs @@ -7,11 +7,10 @@ namespace DotNetOAuth.ChannelElements {
using System;
using System.Collections.Generic;
- using System.Linq;
+ using System.Globalization;
using System.Text;
using DotNetOAuth.Messaging;
using DotNetOAuth.Messaging.Bindings;
- using DotNetOAuth.Messaging.Reflection;
/// <summary>
/// A binding element that signs outgoing messages and verifies the signature on incoming messages.
@@ -48,7 +47,7 @@ namespace DotNetOAuth.ChannelElements { var signedMessage = message as ITamperResistantOAuthMessage;
if (signedMessage != null) {
signedMessage.SignatureMethod = this.signatureMethod;
- this.Sign(signedMessage);
+ signedMessage.Signature = this.GetSignature(signedMessage);
return true;
}
@@ -69,7 +68,8 @@ namespace DotNetOAuth.ChannelElements { throw new InvalidSignatureException(message);
}
- if (!this.IsSignatureValid(signedMessage)) {
+ string signature = this.GetSignature(signedMessage);
+ if (signedMessage.Signature != signature) {
Logger.Error("Signature verification failed.");
throw new InvalidSignatureException(message);
}
@@ -86,34 +86,32 @@ namespace DotNetOAuth.ChannelElements { /// Constructs the OAuth Signature Base String and returns the result.
/// </summary>
/// <param name="message">The message to derive the signature base string from.</param>
- /// <param name="httpMethod">
- /// The HTTP method to be used in sending the request.
- /// </param>
- /// <param name="additionalParameters">
- /// Parameters outside the OAuth message that are appended to the query string
- /// or included in a POST entity where the content-type is application/x-www-form-urlencoded.
- /// </param>
/// <returns>The signature base string.</returns>
/// <remarks>
/// This method implements OAuth 1.0 section 9.1.
/// </remarks>
- protected static string ConstructSignatureBaseString(ITamperResistantOAuthMessage message, string httpMethod, IDictionary<string, string> additionalParameters) {
- if (String.IsNullOrEmpty(httpMethod)) {
- throw new ArgumentNullException("httpMethod");
+ protected static string ConstructSignatureBaseString(ITamperResistantOAuthMessage message) {
+ if (String.IsNullOrEmpty(message.HttpMethod)) {
+ throw new ArgumentException(
+ string.Format(
+ CultureInfo.CurrentCulture,
+ MessagingStrings.ArgumentPropertyMissing,
+ typeof(ITamperResistantOAuthMessage).Name,
+ "HttpMethod"),
+ "message");
}
List<string> signatureBaseStringElements = new List<string>(3);
- signatureBaseStringElements.Add(httpMethod.ToUpperInvariant());
+ signatureBaseStringElements.Add(message.HttpMethod.ToUpperInvariant());
UriBuilder endpoint = new UriBuilder(message.Recipient);
endpoint.Query = null;
endpoint.Fragment = null;
signatureBaseStringElements.Add(endpoint.Uri.AbsoluteUri);
- // TODO: figure out whether parameters passed by other means in the same HttpWebRequest
- // must also be signed.
var encodedDictionary = OAuthChannel.GetEncodedParameters(message);
+ OAuthChannel.EncodeParameters(message.AdditionalParametersInHttpRequest, encodedDictionary);
encodedDictionary.Remove("oauth_signature");
var sortedKeyValueList = new List<KeyValuePair<string, string>>(encodedDictionary);
sortedKeyValueList.Sort(SignatureBaseStringParameterComparer);
@@ -143,18 +141,11 @@ namespace DotNetOAuth.ChannelElements { }
/// <summary>
- /// Applies a signature to the message.
+ /// Calculates a signature for a given message.
/// </summary>
/// <param name="message">The message to sign.</param>
- protected abstract void Sign(ITamperResistantOAuthMessage message);
-
- /// <summary>
- /// Validates the signature on a message.
- /// Does NOT throw an exception on failing signature verification.
- /// </summary>
- /// <param name="message">The message with a signature to verify.</param>
- /// <returns>True if the signature is valid. False otherwise.</returns>
- protected abstract bool IsSignatureValid(ITamperResistantOAuthMessage message);
+ /// <returns>The signature for the message.</returns>
+ protected abstract string GetSignature(ITamperResistantOAuthMessage message);
/// <summary>
/// Sorts parameters according to OAuth signature base string rules.
diff --git a/src/DotNetOAuth/Messages/SignedMessageBase.cs b/src/DotNetOAuth/Messages/SignedMessageBase.cs index 52f03ab..bc5d48e 100644 --- a/src/DotNetOAuth/Messages/SignedMessageBase.cs +++ b/src/DotNetOAuth/Messages/SignedMessageBase.cs @@ -6,6 +6,7 @@ namespace DotNetOAuth.Messages {
using System;
+ using System.Collections.Generic;
using DotNetOAuth.ChannelElements;
using DotNetOAuth.Messaging;
using DotNetOAuth.Messaging.Bindings;
@@ -45,17 +46,45 @@ namespace DotNetOAuth.Messages { #region ITamperResistantOAuthMessage Members
/// <summary>
- /// Gets or sets the message signature.
- /// </summary>
- [MessagePart("oauth_signature")]
- string ITamperResistantProtocolMessage.Signature { get; set; }
-
- /// <summary>
/// Gets or sets the signature method used to sign the request.
/// </summary>
[MessagePart("oauth_signature_method")]
string ITamperResistantOAuthMessage.SignatureMethod { get; set; }
+ /// <summary>
+ /// Gets or sets the Token Secret used to sign the message.
+ /// Only applicable to Consumer.
+ /// </summary>
+ string ITamperResistantOAuthMessage.TokenSecret { get; set; }
+
+ /// <summary>
+ /// Gets or sets the Consumer Secret used to sign the message.
+ /// Only applicable to Consumer.
+ /// </summary>
+ string ITamperResistantOAuthMessage.ConsumerSecret { get; set; }
+
+ /// <summary>
+ /// Gets or sets the HTTP method that will be used to transmit the message.
+ /// Only applicable to Consumer.
+ /// </summary>
+ string ITamperResistantOAuthMessage.HttpMethod { get; set; }
+
+ /// <summary>
+ /// Gets or sets the extra, non-OAuth parameters that will be included in the request.
+ /// Only applicable to Consumer.
+ /// </summary>
+ IDictionary<string, string> ITamperResistantOAuthMessage.AdditionalParametersInHttpRequest { get; set; }
+
+ #endregion
+
+ #region ITamperResistantProtocolMessage Members
+
+ /// <summary>
+ /// Gets or sets the message signature.
+ /// </summary>
+ [MessagePart("oauth_signature")]
+ string ITamperResistantProtocolMessage.Signature { get; set; }
+
#endregion
#region IExpiringProtocolMessage Members
diff --git a/src/DotNetOAuth/Messaging/MessagingStrings.Designer.cs b/src/DotNetOAuth/Messaging/MessagingStrings.Designer.cs index 3444ea6..cf1ceb0 100644 --- a/src/DotNetOAuth/Messaging/MessagingStrings.Designer.cs +++ b/src/DotNetOAuth/Messaging/MessagingStrings.Designer.cs @@ -61,6 +61,15 @@ namespace DotNetOAuth.Messaging { }
/// <summary>
+ /// Looks up a localized string similar to Argument's {0}.{1} property is required but is empty or null..
+ /// </summary>
+ internal static string ArgumentPropertyMissing {
+ get {
+ return ResourceManager.GetString("ArgumentPropertyMissing", resourceCulture);
+ }
+ }
+
+ /// <summary>
/// Looks up a localized string similar to DataContractSerializer could not be initialized on message type {0}. Is it missing a [DataContract] attribute?.
/// </summary>
internal static string DataContractMissingFromMessageType {
diff --git a/src/DotNetOAuth/Messaging/MessagingStrings.resx b/src/DotNetOAuth/Messaging/MessagingStrings.resx index 4f67059..b36a550 100644 --- a/src/DotNetOAuth/Messaging/MessagingStrings.resx +++ b/src/DotNetOAuth/Messaging/MessagingStrings.resx @@ -117,6 +117,9 @@ <resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
+ <data name="ArgumentPropertyMissing" xml:space="preserve">
+ <value>Argument's {0}.{1} property is required but is empty or null.</value>
+ </data>
<data name="DataContractMissingFromMessageType" xml:space="preserve">
<value>DataContractSerializer could not be initialized on message type {0}. Is it missing a [DataContract] attribute?</value>
</data>
|