diff options
author | Andrew Arnott <andrewarnott@gmail.com> | 2011-07-01 16:49:44 -0700 |
---|---|---|
committer | Andrew Arnott <andrewarnott@gmail.com> | 2011-07-01 16:49:44 -0700 |
commit | b6f7a18b949acb4346754ae47fb07424076a3cd0 (patch) | |
tree | 4c23cb2b8174f3288cb0b787cff4c6ac432c6bef /src/DotNetOpenAuth/OAuth/ChannelElements/SigningBindingElementBase.cs | |
parent | f16525005555b86151b7a1c741aa29550635108a (diff) | |
download | DotNetOpenAuth-b6f7a18b949acb4346754ae47fb07424076a3cd0.zip DotNetOpenAuth-b6f7a18b949acb4346754ae47fb07424076a3cd0.tar.gz DotNetOpenAuth-b6f7a18b949acb4346754ae47fb07424076a3cd0.tar.bz2 |
First pass at dividing DotNetOpenAuth features into separate assemblies.
Nothing compiles at this point.
Diffstat (limited to 'src/DotNetOpenAuth/OAuth/ChannelElements/SigningBindingElementBase.cs')
-rw-r--r-- | src/DotNetOpenAuth/OAuth/ChannelElements/SigningBindingElementBase.cs | 329 |
1 files changed, 0 insertions, 329 deletions
diff --git a/src/DotNetOpenAuth/OAuth/ChannelElements/SigningBindingElementBase.cs b/src/DotNetOpenAuth/OAuth/ChannelElements/SigningBindingElementBase.cs deleted file mode 100644 index 31b5149..0000000 --- a/src/DotNetOpenAuth/OAuth/ChannelElements/SigningBindingElementBase.cs +++ /dev/null @@ -1,329 +0,0 @@ -//----------------------------------------------------------------------- -// <copyright file="SigningBindingElementBase.cs" company="Andrew Arnott"> -// Copyright (c) Andrew Arnott. All rights reserved. -// </copyright> -//----------------------------------------------------------------------- - -namespace DotNetOpenAuth.OAuth.ChannelElements { - using System; - using System.Collections.Generic; - using System.Collections.Specialized; - using System.Diagnostics.CodeAnalysis; - using System.Diagnostics.Contracts; - using System.Globalization; - using System.Linq; - using System.Text; - using System.Web; - using DotNetOpenAuth.Messaging; - using DotNetOpenAuth.Messaging.Bindings; - using DotNetOpenAuth.Messaging.Reflection; - - /// <summary> - /// A binding element that signs outgoing messages and verifies the signature on incoming messages. - /// </summary> - [ContractClass(typeof(SigningBindingElementBaseContract))] - public abstract class SigningBindingElementBase : ITamperProtectionChannelBindingElement { - /// <summary> - /// The signature method this binding element uses. - /// </summary> - private string signatureMethod; - - /// <summary> - /// Initializes a new instance of the <see cref="SigningBindingElementBase"/> class. - /// </summary> - /// <param name="signatureMethod">The OAuth signature method that the binding element uses.</param> - internal SigningBindingElementBase(string signatureMethod) { - this.signatureMethod = signatureMethod; - } - - #region IChannelBindingElement Properties - - /// <summary> - /// Gets the message protection provided by this binding element. - /// </summary> - public MessageProtections Protection { - get { return MessageProtections.TamperProtection; } - } - - /// <summary> - /// Gets or sets the channel that this binding element belongs to. - /// </summary> - public Channel Channel { get; set; } - - #endregion - - #region ITamperProtectionChannelBindingElement members - - /// <summary> - /// Gets or sets the delegate that will initialize the non-serialized properties necessary on a signed - /// message so that its signature can be correctly calculated for verification. - /// </summary> - public Action<ITamperResistantOAuthMessage> SignatureCallback { get; set; } - - /// <summary> - /// Creates a new object that is a copy of the current instance. - /// </summary> - /// <returns> - /// A new object that is a copy of this instance. - /// </returns> - ITamperProtectionChannelBindingElement ITamperProtectionChannelBindingElement.Clone() { - ITamperProtectionChannelBindingElement clone = this.Clone(); - clone.SignatureCallback = this.SignatureCallback; - return clone; - } - - #endregion - - #region IChannelBindingElement Methods - - /// <summary> - /// Signs the outgoing message. - /// </summary> - /// <param name="message">The message to sign.</param> - /// <returns> - /// The protections (if any) that this binding element applied to the message. - /// Null if this binding element did not even apply to this binding element. - /// </returns> - public MessageProtections? ProcessOutgoingMessage(IProtocolMessage message) { - var signedMessage = message as ITamperResistantOAuthMessage; - if (signedMessage != null && this.IsMessageApplicable(signedMessage)) { - if (this.SignatureCallback != null) { - this.SignatureCallback(signedMessage); - } else { - Logger.Bindings.Warn("Signing required, but callback delegate was not provided to provide additional data for signing."); - } - - signedMessage.SignatureMethod = this.signatureMethod; - Logger.Bindings.DebugFormat("Signing {0} message using {1}.", message.GetType().Name, this.signatureMethod); - signedMessage.Signature = this.GetSignature(signedMessage); - return MessageProtections.TamperProtection; - } - - return null; - } - - /// <summary> - /// Verifies the signature on an incoming message. - /// </summary> - /// <param name="message">The message whose signature should be verified.</param> - /// <returns> - /// The protections (if any) that this binding element applied to the message. - /// Null if this binding element did not even apply to this binding element. - /// </returns> - /// <exception cref="InvalidSignatureException">Thrown if the signature is invalid.</exception> - public MessageProtections? ProcessIncomingMessage(IProtocolMessage message) { - var signedMessage = message as ITamperResistantOAuthMessage; - if (signedMessage != null && this.IsMessageApplicable(signedMessage)) { - Logger.Bindings.DebugFormat("Verifying incoming {0} message signature of: {1}", message.GetType().Name, signedMessage.Signature); - - if (!string.Equals(signedMessage.SignatureMethod, this.signatureMethod, StringComparison.Ordinal)) { - Logger.Bindings.WarnFormat("Expected signature method '{0}' but received message with a signature method of '{1}'.", this.signatureMethod, signedMessage.SignatureMethod); - return MessageProtections.None; - } - - if (this.SignatureCallback != null) { - this.SignatureCallback(signedMessage); - } else { - Logger.Bindings.Warn("Signature verification required, but callback delegate was not provided to provide additional data for signature verification."); - } - - if (!this.IsSignatureValid(signedMessage)) { - Logger.Bindings.Error("Signature verification failed."); - throw new InvalidSignatureException(message); - } - - return MessageProtections.TamperProtection; - } - - return null; - } - - #endregion - - /// <summary> - /// Constructs the OAuth Signature Base String and returns the result. - /// </summary> - /// <param name="message">The message.</param> - /// <param name="messageDictionary">The message to derive the signature base string from.</param> - /// <returns>The signature base string.</returns> - /// <remarks> - /// This method implements OAuth 1.0 section 9.1. - /// </remarks> - [SuppressMessage("Microsoft.Maintainability", "CA1506:AvoidExcessiveClassCoupling", Justification = "Unavoidable")] - internal static string ConstructSignatureBaseString(ITamperResistantOAuthMessage message, MessageDictionary messageDictionary) { - Contract.Requires<ArgumentNullException>(message != null); - Contract.Requires<ArgumentException>(!string.IsNullOrEmpty(message.HttpMethod)); - Contract.Requires<ArgumentNullException>(messageDictionary != null); - Contract.Requires<ArgumentException>(messageDictionary.Message == message); - - List<string> signatureBaseStringElements = new List<string>(3); - - signatureBaseStringElements.Add(message.HttpMethod.ToUpperInvariant()); - - // For multipart POST messages, only include the message parts that are NOT - // in the POST entity (those parts that may appear in an OAuth authorization header). - var encodedDictionary = new Dictionary<string, string>(); - IEnumerable<KeyValuePair<string, string>> partsToInclude = Enumerable.Empty<KeyValuePair<string, string>>(); - var binaryMessage = message as IMessageWithBinaryData; - if (binaryMessage != null && binaryMessage.SendAsMultipart) { - HttpDeliveryMethods authHeaderInUseFlags = HttpDeliveryMethods.PostRequest | HttpDeliveryMethods.AuthorizationHeaderRequest; - ErrorUtilities.VerifyProtocol((binaryMessage.HttpMethods & authHeaderInUseFlags) == authHeaderInUseFlags, OAuthStrings.MultipartPostMustBeUsedWithAuthHeader); - - // Include the declared keys in the signature as those will be signable. - // Cache in local variable to avoid recalculating DeclaredKeys in the delegate. - ICollection<string> declaredKeys = messageDictionary.DeclaredKeys; - partsToInclude = messageDictionary.Where(pair => declaredKeys.Contains(pair.Key)); - } else { - partsToInclude = messageDictionary; - } - - // If this message was deserialized, include only those explicitly included message parts (excludes defaulted values) - // in the signature. - var originalPayloadMessage = (IMessageOriginalPayload)message; - if (originalPayloadMessage.OriginalPayload != null) { - partsToInclude = partsToInclude.Where(pair => originalPayloadMessage.OriginalPayload.ContainsKey(pair.Key)); - } - - foreach (var pair in OAuthChannel.GetUriEscapedParameters(partsToInclude)) { - encodedDictionary[pair.Key] = pair.Value; - } - - // An incoming message will already have included the query and form parameters - // in the message dictionary, but an outgoing message COULD have SOME parameters - // in the query that are not in the message dictionary because they were included - // in the receiving endpoint (the original URL). - // In an outgoing message, the POST entity can only contain parameters if they were - // in the message dictionary, so no need to pull out any parameters from there. - if (message.Recipient.Query != null) { - NameValueCollection nvc = HttpUtility.ParseQueryString(message.Recipient.Query); - foreach (string key in nvc) { - string escapedKey = MessagingUtilities.EscapeUriDataStringRfc3986(key); - string escapedValue = MessagingUtilities.EscapeUriDataStringRfc3986(nvc[key]); - string existingValue; - if (!encodedDictionary.TryGetValue(escapedKey, out existingValue)) { - encodedDictionary.Add(escapedKey, escapedValue); - } else { - ErrorUtilities.VerifyInternal(escapedValue == existingValue, "Somehow we have conflicting values for the '{0}' parameter.", escapedKey); - } - } - } - encodedDictionary.Remove("oauth_signature"); - - UriBuilder endpoint = new UriBuilder(message.Recipient); - endpoint.Query = null; - endpoint.Fragment = null; - signatureBaseStringElements.Add(endpoint.Uri.AbsoluteUri); - - var sortedKeyValueList = new List<KeyValuePair<string, string>>(encodedDictionary); - sortedKeyValueList.Sort(SignatureBaseStringParameterComparer); - StringBuilder paramBuilder = new StringBuilder(); - foreach (var pair in sortedKeyValueList) { - if (paramBuilder.Length > 0) { - paramBuilder.Append("&"); - } - - paramBuilder.Append(pair.Key); - paramBuilder.Append('='); - paramBuilder.Append(pair.Value); - } - - signatureBaseStringElements.Add(paramBuilder.ToString()); - - StringBuilder signatureBaseString = new StringBuilder(); - foreach (string element in signatureBaseStringElements) { - if (signatureBaseString.Length > 0) { - signatureBaseString.Append("&"); - } - - signatureBaseString.Append(MessagingUtilities.EscapeUriDataStringRfc3986(element)); - } - - Logger.Bindings.DebugFormat("Constructed signature base string: {0}", signatureBaseString); - return signatureBaseString.ToString(); - } - - /// <summary> - /// Calculates a signature for a given message. - /// </summary> - /// <param name="message">The message to sign.</param> - /// <returns>The signature for the message.</returns> - /// <remarks> - /// This method signs the message per OAuth 1.0 section 9.2. - /// </remarks> - internal string GetSignatureTestHook(ITamperResistantOAuthMessage message) { - return this.GetSignature(message); - } - - /// <summary> - /// Gets the "ConsumerSecret&TokenSecret" string, allowing either property to be empty or null. - /// </summary> - /// <param name="message">The message to extract the secrets from.</param> - /// <returns>The concatenated string.</returns> - protected static string GetConsumerAndTokenSecretString(ITamperResistantOAuthMessage message) { - StringBuilder builder = new StringBuilder(); - if (!string.IsNullOrEmpty(message.ConsumerSecret)) { - builder.Append(MessagingUtilities.EscapeUriDataStringRfc3986(message.ConsumerSecret)); - } - builder.Append("&"); - if (!string.IsNullOrEmpty(message.TokenSecret)) { - builder.Append(MessagingUtilities.EscapeUriDataStringRfc3986(message.TokenSecret)); - } - return builder.ToString(); - } - - /// <summary> - /// Determines whether the signature on some message is valid. - /// </summary> - /// <param name="message">The message to check the signature on.</param> - /// <returns> - /// <c>true</c> if the signature on the message is valid; otherwise, <c>false</c>. - /// </returns> - protected virtual bool IsSignatureValid(ITamperResistantOAuthMessage message) { - Contract.Requires<ArgumentNullException>(message != null); - - string signature = this.GetSignature(message); - return MessagingUtilities.EqualsConstantTime(message.Signature, signature); - } - - /// <summary> - /// Clones this instance. - /// </summary> - /// <returns>A new instance of the binding element.</returns> - /// <remarks> - /// Implementations of this method need not clone the SignatureVerificationCallback member, as the - /// <see cref="SigningBindingElementBase"/> class does this. - /// </remarks> - protected abstract ITamperProtectionChannelBindingElement Clone(); - - /// <summary> - /// Calculates a signature for a given message. - /// </summary> - /// <param name="message">The message to sign.</param> - /// <returns>The signature for the message.</returns> - protected abstract string GetSignature(ITamperResistantOAuthMessage message); - - /// <summary> - /// Checks whether this binding element applies to this message. - /// </summary> - /// <param name="message">The message that needs to be signed.</param> - /// <returns>True if this binding element can be used to sign the message. False otherwise.</returns> - protected virtual bool IsMessageApplicable(ITamperResistantOAuthMessage message) { - return string.IsNullOrEmpty(message.SignatureMethod) || message.SignatureMethod == this.signatureMethod; - } - - /// <summary> - /// Sorts parameters according to OAuth signature base string rules. - /// </summary> - /// <param name="left">The first parameter to compare.</param> - /// <param name="right">The second parameter to compare.</param> - /// <returns>Negative, zero or positive.</returns> - private static int SignatureBaseStringParameterComparer(KeyValuePair<string, string> left, KeyValuePair<string, string> right) { - int result = string.CompareOrdinal(left.Key, right.Key); - if (result != 0) { - return result; - } - - return string.CompareOrdinal(left.Value, right.Value); - } - } -} |