summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/DotNetOAuth.Test/ChannelElements/PlainTextSigningBindingElementTest.cs40
-rw-r--r--src/DotNetOAuth.Test/Scenarios/AppendixScenarios.cs2
-rw-r--r--src/DotNetOAuth.Test/Scenarios/CoordinatingOAuthChannel.cs2
-rw-r--r--src/DotNetOAuth.Test/Scenarios/Coordinator.cs4
-rw-r--r--src/DotNetOAuth/ChannelElements/HmacSha1SigningBindingElement.cs15
-rw-r--r--src/DotNetOAuth/ChannelElements/OAuthChannel.cs4
-rw-r--r--src/DotNetOAuth/ChannelElements/PlainTextSigningBindingElement.cs17
-rw-r--r--src/DotNetOAuth/ChannelElements/RsaSha1SigningBindingElement.cs17
-rw-r--r--src/DotNetOAuth/ChannelElements/SigningBindingElementBase.cs44
-rw-r--r--src/DotNetOAuth/ChannelElements/SigningBindingElementChain.cs118
-rw-r--r--src/DotNetOAuth/Consumer.cs5
-rw-r--r--src/DotNetOAuth/DotNetOAuth.csproj2
-rw-r--r--src/DotNetOAuth/Messaging/ITamperProtectionChannelBindingElement.cs23
-rw-r--r--src/DotNetOAuth/Messaging/MessagingStrings.Designer.cs18
-rw-r--r--src/DotNetOAuth/Messaging/MessagingStrings.resx6
-rw-r--r--src/DotNetOAuth/ServiceProvider.cs6
-rw-r--r--src/DotNetOAuth/Strings.Designer.cs9
-rw-r--r--src/DotNetOAuth/Strings.resx3
18 files changed, 244 insertions, 91 deletions
diff --git a/src/DotNetOAuth.Test/ChannelElements/PlainTextSigningBindingElementTest.cs b/src/DotNetOAuth.Test/ChannelElements/PlainTextSigningBindingElementTest.cs
index 13fce38..de2c45f 100644
--- a/src/DotNetOAuth.Test/ChannelElements/PlainTextSigningBindingElementTest.cs
+++ b/src/DotNetOAuth.Test/ChannelElements/PlainTextSigningBindingElementTest.cs
@@ -14,7 +14,7 @@ namespace DotNetOAuth.Test.ChannelElements
[TestClass]
public class PlainTextSigningBindingElementTest {
[TestMethod]
- public void GetSignatureTest() {
+ public void HttpsSignatureGeneration() {
SigningBindingElementBase target = new PlainTextSigningBindingElement();
ServiceProviderEndpoint endpoint = new ServiceProviderEndpoint("https://localtest", HttpDeliveryMethod.GetRequest);
ITamperResistantOAuthMessage message = new RequestTokenMessage(endpoint);
@@ -26,7 +26,31 @@ namespace DotNetOAuth.Test.ChannelElements
}
[TestMethod]
- public void GetNonEncryptedSignature() {
+ public void HttpsSignatureVerification() {
+ ServiceProviderEndpoint endpoint = new ServiceProviderEndpoint("https://localtest", HttpDeliveryMethod.GetRequest);
+ ITamperProtectionChannelBindingElement target = new PlainTextSigningBindingElement();
+ ITamperResistantOAuthMessage message = new RequestTokenMessage(endpoint);
+ message.ConsumerSecret = "cs";
+ message.TokenSecret = "ts";
+ message.SignatureMethod = "PLAINTEXT";
+ message.Signature = "cs%26ts";
+ Assert.IsTrue(target.PrepareMessageForReceiving(message));
+ }
+
+ [TestMethod]
+ public void HttpsSignatureVerificationNotApplicable() {
+ SigningBindingElementBase target = new PlainTextSigningBindingElement();
+ ServiceProviderEndpoint endpoint = new ServiceProviderEndpoint("https://localtest", HttpDeliveryMethod.GetRequest);
+ ITamperResistantOAuthMessage message = new RequestTokenMessage(endpoint);
+ message.ConsumerSecret = "cs";
+ message.TokenSecret = "ts";
+ message.SignatureMethod = "ANOTHERALGORITHM";
+ message.Signature = "somethingelse";
+ Assert.IsFalse(target.PrepareMessageForReceiving(message), "PLAINTEXT binding element should opt-out where it doesn't understand.");
+ }
+
+ [TestMethod]
+ public void HttpSignatureGeneration() {
SigningBindingElementBase target = new PlainTextSigningBindingElement();
ServiceProviderEndpoint endpoint = new ServiceProviderEndpoint("http://localtest", HttpDeliveryMethod.GetRequest);
ITamperResistantOAuthMessage message = new RequestTokenMessage(endpoint);
@@ -38,5 +62,17 @@ namespace DotNetOAuth.Test.ChannelElements
Assert.IsNull(message.SignatureMethod);
Assert.IsNull(message.Signature);
}
+
+ [TestMethod]
+ public void HttpSignatureVerification() {
+ SigningBindingElementBase target = new PlainTextSigningBindingElement();
+ ServiceProviderEndpoint endpoint = new ServiceProviderEndpoint("http://localtest", HttpDeliveryMethod.GetRequest);
+ ITamperResistantOAuthMessage message = new RequestTokenMessage(endpoint);
+ message.ConsumerSecret = "cs";
+ message.TokenSecret = "ts";
+ message.SignatureMethod = "PLAINTEXT";
+ message.Signature = "cs%26ts";
+ Assert.IsFalse(target.PrepareMessageForReceiving(message), "PLAINTEXT signature binding element should refuse to participate in non-encrypted messages.");
+ }
}
}
diff --git a/src/DotNetOAuth.Test/Scenarios/AppendixScenarios.cs b/src/DotNetOAuth.Test/Scenarios/AppendixScenarios.cs
index 61f7968..3181841 100644
--- a/src/DotNetOAuth.Test/Scenarios/AppendixScenarios.cs
+++ b/src/DotNetOAuth.Test/Scenarios/AppendixScenarios.cs
@@ -62,7 +62,7 @@ namespace DotNetOAuth.Test {
},
});
});
- coordinator.SigningElement = (SigningBindingElementBase)sp.Channel.BindingElements.Single(el => el is SigningBindingElementBase);
+ coordinator.SigningElement = (ITamperProtectionChannelBindingElement)sp.Channel.BindingElements.Single(el => el is ITamperProtectionChannelBindingElement);
coordinator.Run();
}
}
diff --git a/src/DotNetOAuth.Test/Scenarios/CoordinatingOAuthChannel.cs b/src/DotNetOAuth.Test/Scenarios/CoordinatingOAuthChannel.cs
index 300c252..8846aad 100644
--- a/src/DotNetOAuth.Test/Scenarios/CoordinatingOAuthChannel.cs
+++ b/src/DotNetOAuth.Test/Scenarios/CoordinatingOAuthChannel.cs
@@ -29,7 +29,7 @@ namespace DotNetOAuth.Test.Scenarios {
/// <param name="signingBindingElement">
/// The signing element for the Consumer to use. Null for the Service Provider.
/// </param>
- internal CoordinatingOAuthChannel(SigningBindingElementBase signingBindingElement)
+ internal CoordinatingOAuthChannel(ITamperProtectionChannelBindingElement signingBindingElement)
: base(
signingBindingElement,
new NonceMemoryStore(StandardExpirationBindingElement.DefaultMaximumMessageAge),
diff --git a/src/DotNetOAuth.Test/Scenarios/Coordinator.cs b/src/DotNetOAuth.Test/Scenarios/Coordinator.cs
index 77449c6..ef0795e 100644
--- a/src/DotNetOAuth.Test/Scenarios/Coordinator.cs
+++ b/src/DotNetOAuth.Test/Scenarios/Coordinator.cs
@@ -7,7 +7,7 @@
namespace DotNetOAuth.Test.Scenarios {
using System;
using System.Threading;
- using DotNetOAuth.ChannelElements;
+ using DotNetOAuth.Messaging;
using Microsoft.VisualStudio.TestTools.UnitTesting;
/// <summary>
@@ -40,7 +40,7 @@ namespace DotNetOAuth.Test.Scenarios {
/// <remarks>
/// The Service Provider never signs a message, so no property is necessary for that.
/// </remarks>
- internal SigningBindingElementBase SigningElement { get; set; }
+ internal ITamperProtectionChannelBindingElement SigningElement { get; set; }
/// <summary>
/// Starts the simulation.
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
+ }
+}
diff --git a/src/DotNetOAuth/Consumer.cs b/src/DotNetOAuth/Consumer.cs
index 08320c3..e45e7f4 100644
--- a/src/DotNetOAuth/Consumer.cs
+++ b/src/DotNetOAuth/Consumer.cs
@@ -30,7 +30,10 @@ namespace DotNetOAuth {
}
this.WebRequestHandler = new StandardWebRequestHandler();
- SigningBindingElementBase signingElement = new PlainTextSigningBindingElement();
+ ITamperProtectionChannelBindingElement signingElement = new SigningBindingElementChain(new ITamperProtectionChannelBindingElement[] {
+ new PlainTextSigningBindingElement(),
+ new HmacSha1SigningBindingElement(),
+ });
INonceStore store = new NonceMemoryStore(StandardExpirationBindingElement.DefaultMaximumMessageAge);
this.Channel = new OAuthChannel(signingElement, store, new OAuthMessageTypeProvider(tokenManager), this.WebRequestHandler);
this.ServiceProvider = endpoints;
diff --git a/src/DotNetOAuth/DotNetOAuth.csproj b/src/DotNetOAuth/DotNetOAuth.csproj
index dcefa1d..db751b4 100644
--- a/src/DotNetOAuth/DotNetOAuth.csproj
+++ b/src/DotNetOAuth/DotNetOAuth.csproj
@@ -61,8 +61,10 @@
<Compile Include="ChannelElements\ITokenManager.cs" />
<Compile Include="ChannelElements\PlainTextSigningBindingElement.cs" />
<Compile Include="ChannelElements\HmacSha1SigningBindingElement.cs" />
+ <Compile Include="ChannelElements\SigningBindingElementChain.cs" />
<Compile Include="ChannelElements\StandardTokenGenerator.cs" />
<Compile Include="ChannelElements\TokenType.cs" />
+ <Compile Include="Messaging\ITamperProtectionChannelBindingElement.cs" />
<Compile Include="ServiceProviderEndpoints.cs" />
<Compile Include="Messages\ITokenContainingMessage.cs" />
<Compile Include="Messages\SignedMessageBase.cs" />
diff --git a/src/DotNetOAuth/Messaging/ITamperProtectionChannelBindingElement.cs b/src/DotNetOAuth/Messaging/ITamperProtectionChannelBindingElement.cs
new file mode 100644
index 0000000..40203e9
--- /dev/null
+++ b/src/DotNetOAuth/Messaging/ITamperProtectionChannelBindingElement.cs
@@ -0,0 +1,23 @@
+//-----------------------------------------------------------------------
+// <copyright file="ITamperProtectionChannelBindingElement.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOAuth.Messaging {
+ using System;
+ using DotNetOAuth.ChannelElements;
+
+ /// <summary>
+ /// An interface that must be implemented by message transforms/validators in order
+ /// to be included in the channel stack.
+ /// </summary>
+ internal interface ITamperProtectionChannelBindingElement : IChannelBindingElement {
+ /// <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>
+ Action<ITamperResistantOAuthMessage> SignatureVerificationCallback { get; set; }
+ }
+}
diff --git a/src/DotNetOAuth/Messaging/MessagingStrings.Designer.cs b/src/DotNetOAuth/Messaging/MessagingStrings.Designer.cs
index 9bac8f7..b3d9d2e 100644
--- a/src/DotNetOAuth/Messaging/MessagingStrings.Designer.cs
+++ b/src/DotNetOAuth/Messaging/MessagingStrings.Designer.cs
@@ -241,29 +241,29 @@ namespace DotNetOAuth.Messaging {
}
/// <summary>
- /// Looks up a localized string similar to The list contains a null element..
+ /// Looks up a localized string similar to The list is empty..
/// </summary>
- internal static string SequenceContainsNullElement {
+ internal static string SequenceContainsNoElements {
get {
- return ResourceManager.GetString("SequenceContainsNullElement", resourceCulture);
+ return ResourceManager.GetString("SequenceContainsNoElements", resourceCulture);
}
}
/// <summary>
- /// Looks up a localized string similar to Message signature was incorrect..
+ /// Looks up a localized string similar to The list contains a null element..
/// </summary>
- internal static string SignatureInvalid {
+ internal static string SequenceContainsNullElement {
get {
- return ResourceManager.GetString("SignatureInvalid", resourceCulture);
+ return ResourceManager.GetString("SequenceContainsNullElement", resourceCulture);
}
}
/// <summary>
- /// Looks up a localized string similar to Signature verification required, but required callback delegate was not provided..
+ /// Looks up a localized string similar to Message signature was incorrect..
/// </summary>
- internal static string SignatureVerificationCallbackMissing {
+ internal static string SignatureInvalid {
get {
- return ResourceManager.GetString("SignatureVerificationCallbackMissing", resourceCulture);
+ return ResourceManager.GetString("SignatureInvalid", resourceCulture);
}
}
diff --git a/src/DotNetOAuth/Messaging/MessagingStrings.resx b/src/DotNetOAuth/Messaging/MessagingStrings.resx
index 91688fb..1753bb7 100644
--- a/src/DotNetOAuth/Messaging/MessagingStrings.resx
+++ b/src/DotNetOAuth/Messaging/MessagingStrings.resx
@@ -177,15 +177,15 @@
<data name="RequiredProtectionMissing" xml:space="preserve">
<value>The binding element offering the {0} protection requires other protection that is not provided.</value>
</data>
+ <data name="SequenceContainsNoElements" xml:space="preserve">
+ <value>The list is empty.</value>
+ </data>
<data name="SequenceContainsNullElement" xml:space="preserve">
<value>The list contains a null element.</value>
</data>
<data name="SignatureInvalid" xml:space="preserve">
<value>Message signature was incorrect.</value>
</data>
- <data name="SignatureVerificationCallbackMissing" xml:space="preserve">
- <value>Signature verification required, but required callback delegate was not provided.</value>
- </data>
<data name="SigningNotSupported" xml:space="preserve">
<value>This channel does not support signing messages. To support signing messages, a derived Channel type must override the Sign and IsSignatureValid methods.</value>
</data>
diff --git a/src/DotNetOAuth/ServiceProvider.cs b/src/DotNetOAuth/ServiceProvider.cs
index db2d24b..9201628 100644
--- a/src/DotNetOAuth/ServiceProvider.cs
+++ b/src/DotNetOAuth/ServiceProvider.cs
@@ -38,7 +38,11 @@ namespace DotNetOAuth {
throw new ArgumentNullException("tokenManager");
}
- SigningBindingElementBase signingElement = new PlainTextSigningBindingElement(this.TokenSignatureVerificationCallback);
+ ITamperProtectionChannelBindingElement signingElement = new SigningBindingElementChain(new ITamperProtectionChannelBindingElement[] {
+ new PlainTextSigningBindingElement(),
+ new HmacSha1SigningBindingElement(),
+ });
+ signingElement.SignatureVerificationCallback = this.TokenSignatureVerificationCallback;
INonceStore store = new NonceMemoryStore(StandardExpirationBindingElement.DefaultMaximumMessageAge);
this.Endpoints = endpoints;
this.Channel = new OAuthChannel(signingElement, store, tokenManager);
diff --git a/src/DotNetOAuth/Strings.Designer.cs b/src/DotNetOAuth/Strings.Designer.cs
index 07d73d4..357a3ca 100644
--- a/src/DotNetOAuth/Strings.Designer.cs
+++ b/src/DotNetOAuth/Strings.Designer.cs
@@ -104,5 +104,14 @@ namespace DotNetOAuth {
return ResourceManager.GetString("RequestUrlMustNotHaveOAuthParameters", resourceCulture);
}
}
+
+ /// <summary>
+ /// Looks up a localized string similar to All signing elements must offer the same message protection..
+ /// </summary>
+ internal static string SigningElementsMustShareSameProtection {
+ get {
+ return ResourceManager.GetString("SigningElementsMustShareSameProtection", resourceCulture);
+ }
+ }
}
}
diff --git a/src/DotNetOAuth/Strings.resx b/src/DotNetOAuth/Strings.resx
index 98cb7fc..9ed8ab6 100644
--- a/src/DotNetOAuth/Strings.resx
+++ b/src/DotNetOAuth/Strings.resx
@@ -132,4 +132,7 @@
<data name="RequestUrlMustNotHaveOAuthParameters" xml:space="preserve">
<value>The request URL query MUST NOT contain any OAuth Protocol Parameters.</value>
</data>
+ <data name="SigningElementsMustShareSameProtection" xml:space="preserve">
+ <value>All signing elements must offer the same message protection.</value>
+ </data>
</root> \ No newline at end of file