summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/DotNetOpenAuth.Test/Mocks/CoordinatingChannel.cs5
-rw-r--r--src/DotNetOpenAuth.Test/Mocks/MockReplayProtectionBindingElement.cs2
-rw-r--r--src/DotNetOpenAuth.Test/OpenId/AuthenticationTests.cs6
-rw-r--r--src/DotNetOpenAuth/Messaging/Channel.cs58
-rw-r--r--src/DotNetOpenAuth/OAuth/ChannelElements/SigningBindingElementBase.cs10
-rw-r--r--src/DotNetOpenAuth/OpenId/ChannelElements/OpenIdChannel.cs24
-rw-r--r--src/DotNetOpenAuth/OpenId/ChannelElements/SigningBindingElement.cs6
-rw-r--r--src/DotNetOpenAuth/OpenId/Messages/CheckAuthenticationRequest.cs36
-rw-r--r--src/DotNetOpenAuth/OpenId/Messages/IndirectResponseBase.cs6
-rw-r--r--src/DotNetOpenAuth/OpenId/Messages/IndirectSignedResponse.cs20
-rw-r--r--src/DotNetOpenAuth/OpenId/Messages/RequestBase.cs11
11 files changed, 134 insertions, 50 deletions
diff --git a/src/DotNetOpenAuth.Test/Mocks/CoordinatingChannel.cs b/src/DotNetOpenAuth.Test/Mocks/CoordinatingChannel.cs
index 0bb2195..7a96718 100644
--- a/src/DotNetOpenAuth.Test/Mocks/CoordinatingChannel.cs
+++ b/src/DotNetOpenAuth.Test/Mocks/CoordinatingChannel.cs
@@ -72,6 +72,11 @@ namespace DotNetOpenAuth.Test.Mocks {
return accessor.ReadFromResponseInternal(response);
}
+ protected override void VerifyMessageAfterReceiving(IProtocolMessage message) {
+ Channel_Accessor accessor = Channel_Accessor.AttachShadow(this.wrappedChannel);
+ accessor.VerifyMessageAfterReceiving(message);
+ }
+
/// <summary>
/// Spoof HTTP request information for signing/verification purposes.
/// </summary>
diff --git a/src/DotNetOpenAuth.Test/Mocks/MockReplayProtectionBindingElement.cs b/src/DotNetOpenAuth.Test/Mocks/MockReplayProtectionBindingElement.cs
index d550514..11d7e67 100644
--- a/src/DotNetOpenAuth.Test/Mocks/MockReplayProtectionBindingElement.cs
+++ b/src/DotNetOpenAuth.Test/Mocks/MockReplayProtectionBindingElement.cs
@@ -17,7 +17,7 @@ namespace DotNetOpenAuth.Test.Mocks {
MessageProtections IChannelBindingElement.Protection {
get { return MessageProtections.ReplayProtection; }
}
-
+
/// <summary>
/// Gets or sets the channel that this binding element belongs to.
/// </summary>
diff --git a/src/DotNetOpenAuth.Test/OpenId/AuthenticationTests.cs b/src/DotNetOpenAuth.Test/OpenId/AuthenticationTests.cs
index fa769ec..887bd69 100644
--- a/src/DotNetOpenAuth.Test/OpenId/AuthenticationTests.cs
+++ b/src/DotNetOpenAuth.Test/OpenId/AuthenticationTests.cs
@@ -102,9 +102,9 @@ namespace DotNetOpenAuth.Test.OpenId {
Assert.IsNotNull(request);
var response = new PositiveAssertionResponse(request);
op.Channel.Send(response);
- var checkauth = op.Channel.ReadFromRequest<CheckAuthenticationRequest>();
- var checkauthResponse = new CheckAuthenticationResponse(checkauth);
- checkauthResponse.IsValid = true; // TODO: how do we establish that the signature is good?
+ var checkauthRequest = op.Channel.ReadFromRequest<CheckAuthenticationRequest>();
+ var checkauthResponse = new CheckAuthenticationResponse(checkauthRequest);
+ checkauthResponse.IsValid = checkauthRequest.IsValid;
op.Channel.Send(checkauthResponse);
});
coordinator.Run();
diff --git a/src/DotNetOpenAuth/Messaging/Channel.cs b/src/DotNetOpenAuth/Messaging/Channel.cs
index 4cfa0f4..46b932d 100644
--- a/src/DotNetOpenAuth/Messaging/Channel.cs
+++ b/src/DotNetOpenAuth/Messaging/Channel.cs
@@ -641,6 +641,35 @@ namespace DotNetOpenAuth.Messaging {
}
/// <summary>
+ /// Verifies the integrity and applicability of an incoming message.
+ /// </summary>
+ /// <param name="message">The message just received.</param>
+ /// <exception cref="ProtocolException">
+ /// Thrown when the message is somehow invalid.
+ /// This can be due to tampering, replay attack or expiration, among other things.
+ /// </exception>
+ protected virtual void VerifyMessageAfterReceiving(IProtocolMessage message) {
+ Debug.Assert(message != null, "message == null");
+
+ MessageProtections appliedProtection = MessageProtections.None;
+ foreach (IChannelBindingElement bindingElement in this.bindingElements.Reverse<IChannelBindingElement>()) {
+ if (bindingElement.PrepareMessageForReceiving(message)) {
+ appliedProtection |= bindingElement.Protection;
+ }
+ }
+
+ // Ensure that the message's protection requirements have been satisfied.
+ if ((message.RequiredProtection & appliedProtection) != message.RequiredProtection) {
+ throw new UnprotectedMessageException(message, appliedProtection);
+ }
+
+ // We do NOT verify that all required message parts are present here... the
+ // message deserializer did for us. It would be too late to do it here since
+ // they might look initialized by the time we have an IProtocolMessage instance.
+ message.EnsureValidMessage();
+ }
+
+ /// <summary>
/// Verifies that all required message parts are initialized to values
/// prior to sending the message to a remote party.
/// </summary>
@@ -749,34 +778,5 @@ namespace DotNetOpenAuth.Messaging {
// Now put the protection ones in the right order.
return -((int)protection1).CompareTo((int)protection2); // descending flag ordinal order
}
-
- /// <summary>
- /// Verifies the integrity and applicability of an incoming message.
- /// </summary>
- /// <param name="message">The message just received.</param>
- /// <exception cref="ProtocolException">
- /// Thrown when the message is somehow invalid.
- /// This can be due to tampering, replay attack or expiration, among other things.
- /// </exception>
- private void VerifyMessageAfterReceiving(IProtocolMessage message) {
- Debug.Assert(message != null, "message == null");
-
- MessageProtections appliedProtection = MessageProtections.None;
- foreach (IChannelBindingElement bindingElement in this.bindingElements.Reverse<IChannelBindingElement>()) {
- if (bindingElement.PrepareMessageForReceiving(message)) {
- appliedProtection |= bindingElement.Protection;
- }
- }
-
- // Ensure that the message's protection requirements have been satisfied.
- if ((message.RequiredProtection & appliedProtection) != message.RequiredProtection) {
- throw new UnprotectedMessageException(message, appliedProtection);
- }
-
- // We do NOT verify that all required message parts are present here... the
- // message deserializer did for us. It would be too late to do it here since
- // they might look initialized by the time we have an IProtocolMessage instance.
- message.EnsureValidMessage();
- }
}
}
diff --git a/src/DotNetOpenAuth/OAuth/ChannelElements/SigningBindingElementBase.cs b/src/DotNetOpenAuth/OAuth/ChannelElements/SigningBindingElementBase.cs
index 36c823d..7337760 100644
--- a/src/DotNetOpenAuth/OAuth/ChannelElements/SigningBindingElementBase.cs
+++ b/src/DotNetOpenAuth/OAuth/ChannelElements/SigningBindingElementBase.cs
@@ -38,6 +38,11 @@ namespace DotNetOpenAuth.OAuth.ChannelElements {
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
@@ -65,11 +70,6 @@ namespace DotNetOpenAuth.OAuth.ChannelElements {
#region IChannelBindingElement Methods
/// <summary>
- /// Gets or sets the channel that this binding element belongs to.
- /// </summary>
- public Channel Channel { get; set; }
-
- /// <summary>
/// Signs the outgoing message.
/// </summary>
/// <param name="message">The message to sign.</param>
diff --git a/src/DotNetOpenAuth/OpenId/ChannelElements/OpenIdChannel.cs b/src/DotNetOpenAuth/OpenId/ChannelElements/OpenIdChannel.cs
index 77d7c1f..f669a2b 100644
--- a/src/DotNetOpenAuth/OpenId/ChannelElements/OpenIdChannel.cs
+++ b/src/DotNetOpenAuth/OpenId/ChannelElements/OpenIdChannel.cs
@@ -13,6 +13,7 @@ namespace DotNetOpenAuth.OpenId.ChannelElements {
using System.Text;
using DotNetOpenAuth.Messaging;
using DotNetOpenAuth.Messaging.Bindings;
+ using DotNetOpenAuth.OpenId.Messages;
/// <summary>
/// A channel that knows how to send and receive OpenID messages.
@@ -77,6 +78,29 @@ namespace DotNetOpenAuth.OpenId.ChannelElements {
}
/// <summary>
+ /// Verifies the integrity and applicability of an incoming message.
+ /// </summary>
+ /// <param name="message">The message just received.</param>
+ /// <exception cref="ProtocolException">
+ /// Thrown when the message is somehow invalid, except for check_authentication messages.
+ /// This can be due to tampering, replay attack or expiration, among other things.
+ /// </exception>
+ protected override void VerifyMessageAfterReceiving(IProtocolMessage message) {
+ var checkAuthRequest = message as CheckAuthenticationRequest;
+ if (checkAuthRequest != null) {
+ IndirectSignedResponse originalResponse = new IndirectSignedResponse(checkAuthRequest);
+ try {
+ base.VerifyMessageAfterReceiving(originalResponse);
+ checkAuthRequest.IsValid = true;
+ } catch (ProtocolException) {
+ checkAuthRequest.IsValid = false;
+ }
+ } else {
+ base.VerifyMessageAfterReceiving(message);
+ }
+ }
+
+ /// <summary>
/// Prepares an HTTP request that carries a given message.
/// </summary>
/// <param name="request">The message to send.</param>
diff --git a/src/DotNetOpenAuth/OpenId/ChannelElements/SigningBindingElement.cs b/src/DotNetOpenAuth/OpenId/ChannelElements/SigningBindingElement.cs
index bf4b428..64b3b60 100644
--- a/src/DotNetOpenAuth/OpenId/ChannelElements/SigningBindingElement.cs
+++ b/src/DotNetOpenAuth/OpenId/ChannelElements/SigningBindingElement.cs
@@ -115,6 +115,7 @@ namespace DotNetOpenAuth.OpenId.ChannelElements {
}
} else {
ErrorUtilities.VerifyInternal(this.Channel != null, "Cannot verify private association signature because we don't have a channel.");
+
// We did not recognize the association the provider used to sign the message.
// Ask the provider to check the signature then.
var checkSignatureRequest = new CheckAuthenticationRequest((IndirectSignedResponse)signedMessage);
@@ -193,9 +194,8 @@ namespace DotNetOpenAuth.OpenId.ChannelElements {
Protocol protocol = Protocol.Lookup(signedMessage.ProtocolVersion);
MessageDictionary dictionary = new MessageDictionary(signedMessage);
var parametersToSign = from name in signedMessage.SignedParameterOrder.Split(',')
- let prefixedName = Protocol.V20.openid.Prefix + name
- let alteredValue = name == protocol.openidnp.mode && dictionary[prefixedName] == protocol.Args.Mode.check_authentication ? protocol.Args.Mode.id_res : dictionary[prefixedName]
- select new KeyValuePair<string, string>(prefixedName, alteredValue);
+ let prefixedName = Protocol.V20.openid.Prefix + name
+ select new KeyValuePair<string, string>(prefixedName, dictionary[prefixedName]);
byte[] dataToSign = KeyValueFormEncoding.GetBytes(parametersToSign);
return Convert.ToBase64String(association.Sign(dataToSign));
diff --git a/src/DotNetOpenAuth/OpenId/Messages/CheckAuthenticationRequest.cs b/src/DotNetOpenAuth/OpenId/Messages/CheckAuthenticationRequest.cs
index f8773a0..71da4c8 100644
--- a/src/DotNetOpenAuth/OpenId/Messages/CheckAuthenticationRequest.cs
+++ b/src/DotNetOpenAuth/OpenId/Messages/CheckAuthenticationRequest.cs
@@ -10,6 +10,7 @@ namespace DotNetOpenAuth.OpenId.Messages {
using System.Linq;
using System.Text;
using DotNetOpenAuth.Messaging;
+ using DotNetOpenAuth.Messaging.Reflection;
using DotNetOpenAuth.OpenId.ChannelElements;
/// <summary>
@@ -32,12 +33,43 @@ namespace DotNetOpenAuth.OpenId.Messages {
}
/// <summary>
- /// Initializes a new instance of the <see cref="CheckAuthenticationRequest"/> class.
+ /// Initializes a new instance of the <see cref="CheckAuthenticationRequest"/> class
+ /// based on the contents of some signed message whose signature must be verified.
/// </summary>
/// <param name="message">The message whose signature should be verified.</param>
internal CheckAuthenticationRequest(IndirectSignedResponse message)
: base(message.ProtocolVersion, message.ProviderEndpoint, GetProtocolConstant(message.ProtocolVersion, p => p.Args.Mode.check_authentication), MessageTransport.Direct) {
- // TODO: code here to copy data from message into this one.
+ // Copy all message parts from the id_res message into this one,
+ // except for the openid.mode parameter.
+ MessageDictionary checkPayload = new MessageDictionary(message);
+ MessageDictionary thisPayload = new MessageDictionary(this);
+ foreach (var pair in checkPayload) {
+ if (!string.Equals(pair.Key, this.Protocol.openid.mode)) {
+ thisPayload[pair.Key] = pair.Value;
+ }
+ }
}
+
+ /// <summary>
+ /// Gets or sets a value indicating whether the signature being verified by this request
+ /// is in fact valid.
+ /// </summary>
+ /// <value><c>true</c> if the signature is valid; otherwise, <c>false</c>.</value>
+ /// <remarks>
+ /// This property is automatically set as the message is received by the channel's
+ /// signing binding element.
+ /// </remarks>
+ internal bool IsValid { get; set; }
+
+ /// <summary>
+ /// Gets or sets the ReturnTo that existed in the original signed message.
+ /// </summary>
+ /// <remarks>
+ /// This exists strictly for convenience in recreating the <see cref="IndirectSignedResponse"/>
+ /// message.
+ /// </remarks>
+ [MessagePart("openid.return_to", IsRequired = true, AllowEmpty = false)]
+ [MessagePart("openid.return_to", IsRequired = false, AllowEmpty = false, MinVersion = "2.0")]
+ internal Uri ReturnTo { get; set; }
}
}
diff --git a/src/DotNetOpenAuth/OpenId/Messages/IndirectResponseBase.cs b/src/DotNetOpenAuth/OpenId/Messages/IndirectResponseBase.cs
index 140fc63..2aaff15 100644
--- a/src/DotNetOpenAuth/OpenId/Messages/IndirectResponseBase.cs
+++ b/src/DotNetOpenAuth/OpenId/Messages/IndirectResponseBase.cs
@@ -20,7 +20,7 @@ namespace DotNetOpenAuth.OpenId.Messages {
/// </summary>
/// <param name="request">The request that caused this response message to be constructed.</param>
/// <param name="mode">The value of the openid.mode parameter.</param>
- protected IndirectResponseBase(CheckIdRequest request, string mode)
+ protected IndirectResponseBase(SignedResponseRequest request, string mode)
: base(GetVersion(request), GetReturnTo(request), mode, MessageTransport.Indirect) {
ErrorUtilities.VerifyArgumentNotNull(request, "request");
@@ -43,7 +43,7 @@ namespace DotNetOpenAuth.OpenId.Messages {
/// <summary>
/// Gets the originating request message, if applicable.
/// </summary>
- protected CheckIdRequest OriginatingRequest { get; private set; }
+ protected SignedResponseRequest OriginatingRequest { get; private set; }
/// <summary>
/// Gets the <see cref="IProtocolMessage.ProtocolVersion"/> property of a message.
@@ -68,7 +68,7 @@ namespace DotNetOpenAuth.OpenId.Messages {
/// This method can be used by a constructor to throw an <see cref="ArgumentNullException"/>
/// instead of a <see cref="NullReferenceException"/>.
/// </remarks>
- private static Uri GetReturnTo(CheckIdRequest message) {
+ private static Uri GetReturnTo(SignedResponseRequest message) {
ErrorUtilities.VerifyArgumentNotNull(message, "message");
ErrorUtilities.VerifyProtocol(message.ReturnTo != null, OpenIdStrings.ReturnToRequiredForResponse);
return message.ReturnTo;
diff --git a/src/DotNetOpenAuth/OpenId/Messages/IndirectSignedResponse.cs b/src/DotNetOpenAuth/OpenId/Messages/IndirectSignedResponse.cs
index 8883acb..2c5c150 100644
--- a/src/DotNetOpenAuth/OpenId/Messages/IndirectSignedResponse.cs
+++ b/src/DotNetOpenAuth/OpenId/Messages/IndirectSignedResponse.cs
@@ -39,7 +39,7 @@ namespace DotNetOpenAuth.OpenId.Messages {
/// <param name="request">
/// The authentication request that caused this assertion to be generated.
/// </param>
- internal IndirectSignedResponse(CheckIdRequest request)
+ internal IndirectSignedResponse(SignedResponseRequest request)
: base(request, Protocol.Lookup(GetVersion(request)).Args.Mode.id_res) {
ErrorUtilities.VerifyArgumentNotNull(request, "request");
@@ -50,6 +50,24 @@ namespace DotNetOpenAuth.OpenId.Messages {
/// <summary>
/// Initializes a new instance of the <see cref="IndirectSignedResponse"/> class
+ /// in order to perform signature verification at the Provider.
+ /// </summary>
+ /// <param name="previouslySignedMessage">The previously signed message.</param>
+ internal IndirectSignedResponse(CheckAuthenticationRequest previouslySignedMessage)
+ : base(GetVersion(previouslySignedMessage), previouslySignedMessage.ReturnTo, Protocol.Lookup(GetVersion(previouslySignedMessage)).Args.Mode.id_res) {
+ // Copy all message parts from the check_authentication message into this one,
+ // except for the openid.mode parameter.
+ MessageDictionary checkPayload = new MessageDictionary(previouslySignedMessage);
+ MessageDictionary thisPayload = new MessageDictionary(this);
+ foreach (var pair in checkPayload) {
+ if (!string.Equals(pair.Key, this.Protocol.openid.mode)) {
+ thisPayload[pair.Key] = pair.Value;
+ }
+ }
+ }
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="IndirectSignedResponse"/> class
/// for unsolicited assertions.
/// </summary>
/// <param name="version">The OpenID version to use.</param>
diff --git a/src/DotNetOpenAuth/OpenId/Messages/RequestBase.cs b/src/DotNetOpenAuth/OpenId/Messages/RequestBase.cs
index 98821ac..6786a44 100644
--- a/src/DotNetOpenAuth/OpenId/Messages/RequestBase.cs
+++ b/src/DotNetOpenAuth/OpenId/Messages/RequestBase.cs
@@ -30,11 +30,16 @@ namespace DotNetOpenAuth.OpenId.Messages {
#pragma warning restore 0414
/// <summary>
- /// Backing store for the <see cref="Incoming"/> properties.
+ /// Backing store for the <see cref="Incoming"/> property.
/// </summary>
private bool incoming;
/// <summary>
+ /// Backing store for the <see cref="ExtraData"/> property.
+ /// </summary>
+ private Dictionary<string, string> extraData = new Dictionary<string, string>();
+
+ /// <summary>
/// Initializes a new instance of the <see cref="RequestBase"/> class.
/// </summary>
/// <param name="version">The OpenID version this message must comply with.</param>
@@ -114,11 +119,11 @@ namespace DotNetOpenAuth.OpenId.Messages {
public MessageTransport Transport { get; private set; }
/// <summary>
- /// Gets the extra, non-OAuth parameters included in the message.
+ /// Gets the extra parameters included in the message.
/// </summary>
/// <value>An empty dictionary.</value>
public IDictionary<string, string> ExtraData {
- get { return EmptyDictionary<string, string>.Instance; }
+ get { return this.extraData; }
}
/// <summary>