diff options
Diffstat (limited to 'src/DotNetOAuth/ChannelElements')
6 files changed, 144 insertions, 71 deletions
diff --git a/src/DotNetOAuth/ChannelElements/HmacSha1SigningBindingElement.cs b/src/DotNetOAuth/ChannelElements/HmacSha1SigningBindingElement.cs index d44c64f..f6c7b03 100644 --- a/src/DotNetOAuth/ChannelElements/HmacSha1SigningBindingElement.cs +++ b/src/DotNetOAuth/ChannelElements/HmacSha1SigningBindingElement.cs @@ -15,22 +15,9 @@ namespace DotNetOAuth.ChannelElements { internal class HmacSha1SigningBindingElement : SigningBindingElementBase {
/// <summary>
/// Initializes a new instance of the <see cref="HmacSha1SigningBindingElement"/> class
- /// for use by Consumers.
/// </summary>
internal HmacSha1SigningBindingElement()
- : this(null) {
- }
-
- /// <summary>
- /// Initializes a new instance of the <see cref="HmacSha1SigningBindingElement"/> class.
- /// </summary>
- /// <param name="signatureVerificationCallback">
- /// The delegate that will initialize the non-serialized properties necessary on a signed
- /// message so that its signature can be correctly calculated for verification.
- /// May be null for Consumers (who never have to verify signatures).
- /// </param>
- internal HmacSha1SigningBindingElement(Action<ITamperResistantOAuthMessage> signatureVerificationCallback)
- : base("HMAC-SHA1", signatureVerificationCallback) {
+ : base("HMAC-SHA1") {
}
/// <summary>
diff --git a/src/DotNetOAuth/ChannelElements/OAuthChannel.cs b/src/DotNetOAuth/ChannelElements/OAuthChannel.cs index 3840d14..197acc4 100644 --- a/src/DotNetOAuth/ChannelElements/OAuthChannel.cs +++ b/src/DotNetOAuth/ChannelElements/OAuthChannel.cs @@ -32,7 +32,7 @@ namespace DotNetOAuth.ChannelElements { /// <param name="signingBindingElement">The binding element to use for signing.</param>
/// <param name="store">The web application store to use for nonces.</param>
/// <param name="tokenManager">The token manager instance to use.</param>
- internal OAuthChannel(SigningBindingElementBase signingBindingElement, INonceStore store, ITokenManager tokenManager)
+ internal OAuthChannel(ITamperProtectionChannelBindingElement signingBindingElement, INonceStore store, ITokenManager tokenManager)
: this(signingBindingElement, store, new OAuthMessageTypeProvider(tokenManager), new StandardWebRequestHandler()) {
}
@@ -52,7 +52,7 @@ namespace DotNetOAuth.ChannelElements { /// <remarks>
/// This overload for testing purposes only.
/// </remarks>
- internal OAuthChannel(SigningBindingElementBase signingBindingElement, INonceStore store, IMessageTypeProvider messageTypeProvider, IWebRequestHandler webRequestHandler)
+ internal OAuthChannel(ITamperProtectionChannelBindingElement signingBindingElement, INonceStore store, IMessageTypeProvider messageTypeProvider, IWebRequestHandler webRequestHandler)
: base(messageTypeProvider, signingBindingElement, new StandardExpirationBindingElement(), new StandardReplayProtectionBindingElement(store)) {
if (webRequestHandler == null) {
throw new ArgumentNullException("webRequestHandler");
diff --git a/src/DotNetOAuth/ChannelElements/PlainTextSigningBindingElement.cs b/src/DotNetOAuth/ChannelElements/PlainTextSigningBindingElement.cs index 83c3e8b..7181580 100644 --- a/src/DotNetOAuth/ChannelElements/PlainTextSigningBindingElement.cs +++ b/src/DotNetOAuth/ChannelElements/PlainTextSigningBindingElement.cs @@ -17,23 +17,10 @@ namespace DotNetOAuth.ChannelElements { /// </summary>
internal class PlainTextSigningBindingElement : SigningBindingElementBase {
/// <summary>
- /// Initializes a new instance of the <see cref="PlainTextSigningBindingElement"/> class
- /// for use by Consumers.
- /// </summary>
- internal PlainTextSigningBindingElement()
- : this(null) {
- }
-
- /// <summary>
/// Initializes a new instance of the <see cref="PlainTextSigningBindingElement"/> class.
/// </summary>
- /// <param name="signatureVerificationCallback">
- /// The delegate that will initialize the non-serialized properties necessary on a signed
- /// message so that its signature can be correctly calculated for verification.
- /// May be null for Consumers (who never have to verify signatures).
- /// </param>
- internal PlainTextSigningBindingElement(Action<ITamperResistantOAuthMessage> signatureVerificationCallback)
- : base("PLAINTEXT", signatureVerificationCallback) {
+ internal PlainTextSigningBindingElement()
+ : base("PLAINTEXT") {
}
/// <summary>
diff --git a/src/DotNetOAuth/ChannelElements/RsaSha1SigningBindingElement.cs b/src/DotNetOAuth/ChannelElements/RsaSha1SigningBindingElement.cs index b8ba841..edd5109 100644 --- a/src/DotNetOAuth/ChannelElements/RsaSha1SigningBindingElement.cs +++ b/src/DotNetOAuth/ChannelElements/RsaSha1SigningBindingElement.cs @@ -14,23 +14,10 @@ namespace DotNetOAuth.ChannelElements { /// </summary>
internal class RsaSha1SigningBindingElement : SigningBindingElementBase {
/// <summary>
- /// Initializes a new instance of the <see cref="RsaSha1SigningBindingElement"/> class
- /// for use by Consumers.
- /// </summary>
- internal RsaSha1SigningBindingElement()
- : this(null) {
- }
-
- /// <summary>
/// Initializes a new instance of the <see cref="RsaSha1SigningBindingElement"/> class.
/// </summary>
- /// <param name="signatureVerificationCallback">
- /// The delegate that will initialize the non-serialized properties necessary on a signed
- /// message so that its signature can be correctly calculated for verification.
- /// May be null for Consumers (who never have to verify signatures).
- /// </param>
- internal RsaSha1SigningBindingElement(Action<ITamperResistantOAuthMessage> signatureVerificationCallback)
- : base("RSA-SHA1", signatureVerificationCallback) {
+ internal RsaSha1SigningBindingElement()
+ : base("RSA-SHA1") {
}
/// <summary>
diff --git a/src/DotNetOAuth/ChannelElements/SigningBindingElementBase.cs b/src/DotNetOAuth/ChannelElements/SigningBindingElementBase.cs index ebcc8b2..6c18703 100644 --- a/src/DotNetOAuth/ChannelElements/SigningBindingElementBase.cs +++ b/src/DotNetOAuth/ChannelElements/SigningBindingElementBase.cs @@ -15,13 +15,7 @@ namespace DotNetOAuth.ChannelElements { /// <summary>
/// A binding element that signs outgoing messages and verifies the signature on incoming messages.
/// </summary>
- internal abstract class SigningBindingElementBase : IChannelBindingElement {
- /// <summary>
- /// 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>
- private readonly Action<ITamperResistantOAuthMessage> incomingMessageSignatureVerificationCallback;
-
+ internal abstract class SigningBindingElementBase : ITamperProtectionChannelBindingElement {
/// <summary>
/// The signature method this binding element uses.
/// </summary>
@@ -31,20 +25,20 @@ namespace DotNetOAuth.ChannelElements { /// Initializes a new instance of the <see cref="SigningBindingElementBase"/> class.
/// </summary>
/// <param name="signatureMethod">The OAuth signature method that the binding element uses.</param>
- /// <param name="signatureVerificationCallback">
- /// The delegate that will initialize the non-serialized properties necessary on a signed
- /// message so that its signature can be correctly calculated for verification.
- /// May be null for Consumers (who never have to verify signatures).
- /// </param>
- internal SigningBindingElementBase(string signatureMethod, Action<ITamperResistantOAuthMessage> signatureVerificationCallback) {
- if (String.IsNullOrEmpty(signatureMethod)) {
- throw new ArgumentNullException("signatureMethod");
- }
-
+ internal SigningBindingElementBase(string signatureMethod) {
this.signatureMethod = signatureMethod;
- this.incomingMessageSignatureVerificationCallback = signatureVerificationCallback;
}
+ #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> SignatureVerificationCallback { get; set; }
+
+ #endregion
+
#region IChannelBindingElement Members
/// <summary>
@@ -78,16 +72,16 @@ namespace DotNetOAuth.ChannelElements { /// <exception cref="InvalidSignatureException">Thrown if the signature is invalid.</exception>
public bool PrepareMessageForReceiving(IProtocolMessage message) {
var signedMessage = message as ITamperResistantOAuthMessage;
- if (signedMessage != null) {
+ if (signedMessage != null && this.IsMessageApplicable(signedMessage)) {
if (!string.Equals(signedMessage.SignatureMethod, this.signatureMethod, StringComparison.Ordinal)) {
- Logger.ErrorFormat("Expected signature method '{0}' but received message with a signature method of '{1}'.", this.signatureMethod, signedMessage.SignatureMethod);
- throw new InvalidSignatureException(message);
+ Logger.WarnFormat("Expected signature method '{0}' but received message with a signature method of '{1}'.", this.signatureMethod, signedMessage.SignatureMethod);
+ return false;
}
- if (this.incomingMessageSignatureVerificationCallback != null) {
- this.incomingMessageSignatureVerificationCallback(signedMessage);
+ if (this.SignatureVerificationCallback != null) {
+ this.SignatureVerificationCallback(signedMessage);
} else {
- throw new InvalidOperationException(MessagingStrings.SignatureVerificationCallbackMissing);
+ Logger.Warn("Signature verification required, but callback delegate was not provided to provide additional data for signing.");
}
string signature = this.GetSignature(signedMessage);
@@ -175,7 +169,7 @@ namespace DotNetOAuth.ChannelElements { /// <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 true;
+ return string.IsNullOrEmpty(message.SignatureMethod) || message.SignatureMethod == this.signatureMethod;
}
/// <summary>
diff --git a/src/DotNetOAuth/ChannelElements/SigningBindingElementChain.cs b/src/DotNetOAuth/ChannelElements/SigningBindingElementChain.cs new file mode 100644 index 0000000..e3dbc3d --- /dev/null +++ b/src/DotNetOAuth/ChannelElements/SigningBindingElementChain.cs @@ -0,0 +1,118 @@ +//-----------------------------------------------------------------------
+// <copyright file="SigningBindingElementChain.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOAuth.ChannelElements {
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Text;
+ using DotNetOAuth.Messaging;
+
+ /// <summary>
+ /// A tamper protection applying binding element that can use any of several given
+ /// binding elements to apply the protection.
+ /// </summary>
+ internal class SigningBindingElementChain : ITamperProtectionChannelBindingElement {
+ /// <summary>
+ /// The various signing binding elements that may be applicable to a message in preferred use order.
+ /// </summary>
+ private ITamperProtectionChannelBindingElement[] signers;
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="SigningBindingElementChain"/> class.
+ /// </summary>
+ /// <param name="signers">
+ /// The signing binding elements that may be used for some outgoing message,
+ /// in preferred use order.
+ /// </param>
+ internal SigningBindingElementChain(ITamperProtectionChannelBindingElement[] signers) {
+ if (signers == null) {
+ throw new ArgumentNullException("signers");
+ }
+ if (signers.Length == 0) {
+ throw new ArgumentException(MessagingStrings.SequenceContainsNoElements, "signers");
+ }
+ if (signers.Contains(null)) {
+ throw new ArgumentException(MessagingStrings.SequenceContainsNullElement, "signers");
+ }
+ MessageProtection protection = signers[0].Protection;
+ if (signers.Any(element => element.Protection != protection)) {
+ throw new ArgumentException(Strings.SigningElementsMustShareSameProtection, "signers");
+ }
+
+ this.signers = signers;
+ }
+
+ #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.
+ /// May be null for Consumers (who never have to verify signatures).
+ /// </summary>
+ public Action<ITamperResistantOAuthMessage> SignatureVerificationCallback {
+ get {
+ return this.signers[0].SignatureVerificationCallback;
+ }
+
+ set {
+ foreach (ITamperProtectionChannelBindingElement signer in this.signers) {
+ signer.SignatureVerificationCallback = value;
+ }
+ }
+ }
+
+ #endregion
+
+ #region IChannelBindingElement Members
+
+ /// <summary>
+ /// Gets the protection offered (if any) by this binding element.
+ /// </summary>
+ public MessageProtection Protection {
+ get { return this.signers[0].Protection; }
+ }
+
+ /// <summary>
+ /// Prepares a message for sending based on the rules of this channel binding element.
+ /// </summary>
+ /// <param name="message">The message to prepare for sending.</param>
+ /// <returns>
+ /// True if the <paramref name="message"/> applied to this binding element
+ /// and the operation was successful. False otherwise.
+ /// </returns>
+ public bool PrepareMessageForSending(IProtocolMessage message) {
+ foreach (IChannelBindingElement signer in this.signers) {
+ if (signer.PrepareMessageForSending(message)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /// <summary>
+ /// Performs any transformation on an incoming message that may be necessary and/or
+ /// validates an incoming message based on the rules of this channel binding element.
+ /// </summary>
+ /// <param name="message">The incoming message to process.</param>
+ /// <returns>
+ /// True if the <paramref name="message"/> applied to this binding element
+ /// and the operation was successful. False if the operation did not apply to this message.
+ /// </returns>
+ public bool PrepareMessageForReceiving(IProtocolMessage message) {
+ foreach (IChannelBindingElement signer in this.signers) {
+ if (signer.PrepareMessageForReceiving(message)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ #endregion
+ }
+}
|