From d677015f9f92b8c38ac5ee71ff30b9c33d14b89c Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Mon, 30 Mar 2009 18:56:55 -0700 Subject: Added capability for RPs to receive unsigned extension responses if they so choose. --- .../Mocks/MockOpenIdExtension.cs | 9 ++ .../ExtensionsBindingElementTests.cs | 8 +- .../PositiveAuthenticationResponseTests.cs | 4 +- .../RelyingPartySecuritySettingsTests.cs | 8 -- src/DotNetOpenAuth.vsmdi | 141 +++++++++++---------- .../ChannelElements/ExtensionsBindingElement.cs | 93 +++++++++----- .../OpenId/Extensions/ExtensionBase.cs | 9 ++ .../OpenId/Messages/IOpenIdMessageExtension.cs | 9 ++ .../OpenId/Messages/IndirectSignedResponse.cs | 14 ++ .../RelyingParty/AuthenticationResponseSnapshot.cs | 75 +++++++++++ .../RelyingParty/FailedAuthenticationResponse.cs | 75 +++++++++++ .../OpenId/RelyingParty/IAuthenticationResponse.cs | 72 +++++++++++ .../RelyingParty/NegativeAuthenticationResponse.cs | 75 +++++++++++ .../RelyingParty/PositiveAuthenticationResponse.cs | 78 +++++++++++- .../RelyingParty/RelyingPartySecuritySettings.cs | 14 -- 15 files changed, 554 insertions(+), 130 deletions(-) diff --git a/src/DotNetOpenAuth.Test/Mocks/MockOpenIdExtension.cs b/src/DotNetOpenAuth.Test/Mocks/MockOpenIdExtension.cs index d04e504..80b34a7 100644 --- a/src/DotNetOpenAuth.Test/Mocks/MockOpenIdExtension.cs +++ b/src/DotNetOpenAuth.Test/Mocks/MockOpenIdExtension.cs @@ -48,6 +48,15 @@ namespace DotNetOpenAuth.Test.Mocks { get { return Enumerable.Empty(); } } + /// + /// Gets or sets a value indicating whether this extension was + /// signed by the OpenID Provider. + /// + /// + /// true if this instance is signed by the provider; otherwise, false. + /// + public bool IsSignedByProvider { get; set; } + #endregion #region IMessage Properties diff --git a/src/DotNetOpenAuth.Test/OpenId/ChannelElements/ExtensionsBindingElementTests.cs b/src/DotNetOpenAuth.Test/OpenId/ChannelElements/ExtensionsBindingElementTests.cs index 67f7a54..24c62e1 100644 --- a/src/DotNetOpenAuth.Test/OpenId/ChannelElements/ExtensionsBindingElementTests.cs +++ b/src/DotNetOpenAuth.Test/OpenId/ChannelElements/ExtensionsBindingElementTests.cs @@ -113,15 +113,17 @@ namespace DotNetOpenAuth.Test.OpenId.ChannelElements { /// Verifies that unsigned extension responses (where any or all fields are unsigned) are ignored. /// [TestMethod] - public void UnsignedExtensionsAreIgnored() { + public void ExtensionsAreIdentifiedAsSignedOrUnsigned() { Protocol protocol = Protocol.Default; OpenIdCoordinator coordinator = new OpenIdCoordinator( rp => { RegisterMockExtension(rp.Channel); var response = rp.Channel.ReadFromRequest(); - Assert.AreEqual(1, response.Extensions.Count, "Signed extension should have been received."); + Assert.AreEqual(1, response.SignedExtensions.Count(), "Signed extension should have been received."); + Assert.AreEqual(0, response.UnsignedExtensions.Count(), "No unsigned extension should be present."); response = rp.Channel.ReadFromRequest(); - Assert.AreEqual(0, response.Extensions.Count, "Unsigned extension should have been ignored."); + Assert.AreEqual(0, response.SignedExtensions.Count(), "No signed extension should have been received."); + Assert.AreEqual(1, response.UnsignedExtensions.Count(), "Unsigned extension should have been received."); }, op => { RegisterMockExtension(op.Channel); diff --git a/src/DotNetOpenAuth.Test/OpenId/RelyingParty/PositiveAuthenticationResponseTests.cs b/src/DotNetOpenAuth.Test/OpenId/RelyingParty/PositiveAuthenticationResponseTests.cs index 7a18c8e..7701090 100644 --- a/src/DotNetOpenAuth.Test/OpenId/RelyingParty/PositiveAuthenticationResponseTests.cs +++ b/src/DotNetOpenAuth.Test/OpenId/RelyingParty/PositiveAuthenticationResponseTests.cs @@ -39,8 +39,8 @@ namespace DotNetOpenAuth.Test.OpenId.RelyingParty { Assert.IsNull(authResponse.Exception); Assert.AreEqual(assertion.ClaimedIdentifier, authResponse.ClaimedIdentifier); Assert.AreEqual(authResponseAccessor.endpoint.FriendlyIdentifierForDisplay, authResponse.FriendlyIdentifierForDisplay); - Assert.AreSame(extension, authResponse.GetExtension(typeof(ClaimsResponse))); - Assert.AreSame(extension, authResponse.GetExtension()); + Assert.AreSame(extension, authResponse.GetUntrustedExtension(typeof(ClaimsResponse))); + Assert.AreSame(extension, authResponse.GetUntrustedExtension()); Assert.IsNull(authResponse.GetCallbackArgument("a")); Assert.AreEqual(0, authResponse.GetCallbackArguments().Count); } diff --git a/src/DotNetOpenAuth.Test/OpenId/RelyingParty/RelyingPartySecuritySettingsTests.cs b/src/DotNetOpenAuth.Test/OpenId/RelyingParty/RelyingPartySecuritySettingsTests.cs index 8c5dc6a..cb5fbb5 100644 --- a/src/DotNetOpenAuth.Test/OpenId/RelyingParty/RelyingPartySecuritySettingsTests.cs +++ b/src/DotNetOpenAuth.Test/OpenId/RelyingParty/RelyingPartySecuritySettingsTests.cs @@ -53,13 +53,5 @@ namespace DotNetOpenAuth.Test.OpenId.RelyingParty { this.settings.RequireSsl = !this.settings.RequireSsl; Assert.IsTrue(requireSslChanged); } - - /// - /// Verifies default value for AllowUnsignedIncomingExtensions. - /// - [TestMethod] - public void AllowUnsignedIncomingExtensionsDefault() { - Assert.IsFalse(this.settings.AllowUnsignedIncomingExtensions); - } } } diff --git a/src/DotNetOpenAuth.vsmdi b/src/DotNetOpenAuth.vsmdi index a992475..4b2716b 100644 --- a/src/DotNetOpenAuth.vsmdi +++ b/src/DotNetOpenAuth.vsmdi @@ -14,13 +14,15 @@ - + + + @@ -33,14 +35,12 @@ - - @@ -61,16 +61,14 @@ - - - + @@ -85,17 +83,18 @@ + + - + - - + @@ -107,68 +106,68 @@ - - + - - + - + + - - - + + - + - + + + + - + + - - @@ -180,25 +179,25 @@ - + - - + + + - - + + - - + + - @@ -210,17 +209,16 @@ - - + - + @@ -233,15 +231,16 @@ - + - + + @@ -265,13 +264,15 @@ + + - + @@ -286,16 +287,15 @@ - + - - - + + @@ -309,7 +309,7 @@ - + @@ -323,25 +323,25 @@ + - - - + + - - + + @@ -351,6 +351,7 @@ + @@ -359,10 +360,11 @@ + - + @@ -375,70 +377,71 @@ - + - - + - + - - + + - + - + - + - + - + + - + + - + - - + + - + - + - + - - + + - - + + diff --git a/src/DotNetOpenAuth/OpenId/ChannelElements/ExtensionsBindingElement.cs b/src/DotNetOpenAuth/OpenId/ChannelElements/ExtensionsBindingElement.cs index d9fb90d..700e404 100644 --- a/src/DotNetOpenAuth/OpenId/ChannelElements/ExtensionsBindingElement.cs +++ b/src/DotNetOpenAuth/OpenId/ChannelElements/ExtensionsBindingElement.cs @@ -159,30 +159,18 @@ namespace DotNetOpenAuth.OpenId.ChannelElements { public MessageProtections? ProcessIncomingMessage(IProtocolMessage message) { var extendableMessage = message as IProtocolMessageWithExtensions; if (extendableMessage != null) { - // We have a helper class that will do all the heavy-lifting of organizing - // all the extensions, their aliases, and their parameters. - var extensionManager = ExtensionArgumentsManager.CreateIncomingExtensions(this.GetExtensionsDictionary(message)); - foreach (string typeUri in extensionManager.GetExtensionTypeUris()) { - var extensionData = extensionManager.GetExtensionArguments(typeUri); - - // Initialize this particular extension. - IOpenIdMessageExtension extension = this.ExtensionFactory.Create(typeUri, extensionData, extendableMessage); - if (extension != null) { - MessageDictionary extensionDictionary = this.Channel.MessageDescriptions.GetAccessor(extension); - foreach (var pair in extensionData) { - extensionDictionary[pair.Key] = pair.Value; - } - - // Give extensions that require custom serialization a chance to do their work. - var customSerializingExtension = extension as IMessageWithEvents; - if (customSerializingExtension != null) { - customSerializingExtension.OnReceiving(); - } + // First add the extensions that are signed by the Provider. + foreach (IOpenIdMessageExtension signedExtension in this.GetExtensions(extendableMessage, true, null)) { + signedExtension.IsSignedByProvider = true; + extendableMessage.Extensions.Add(signedExtension); + } - extendableMessage.Extensions.Add(extension); - } else { - Logger.OpenId.WarnFormat("Extension with type URI '{0}' ignored because it is not a recognized extension.", typeUri); - } + // Now search again, considering ALL extensions whether they are signed or not, + // skipping the signed ones and adding the new ones as unsigned extensions. + Func isNotSigned = typeUri => !extendableMessage.Extensions.Cast().Any(ext => ext.TypeUri == typeUri); + foreach (IOpenIdMessageExtension unsignedExtension in this.GetExtensions(extendableMessage, false, isNotSigned)) { + unsignedExtension.IsSignedByProvider = false; + extendableMessage.Extensions.Add(unsignedExtension); } return MessageProtections.None; @@ -194,23 +182,62 @@ namespace DotNetOpenAuth.OpenId.ChannelElements { #endregion /// + /// Gets the extensions on a message. + /// + /// The carrier of the extensions. + /// If set to true only signed extensions will be available. + /// A optional filter that takes an extension type URI and + /// returns a value indicating whether that extension should be deserialized and + /// returned in the sequence. May be null. + /// A sequence of extensions in the message. + private IEnumerable GetExtensions(IProtocolMessageWithExtensions message, bool ignoreUnsigned, Func extensionFilter) { + // We have a helper class that will do all the heavy-lifting of organizing + // all the extensions, their aliases, and their parameters. + var extensionManager = ExtensionArgumentsManager.CreateIncomingExtensions(this.GetExtensionsDictionary(message, ignoreUnsigned)); + foreach (string typeUri in extensionManager.GetExtensionTypeUris()) { + // Our caller may have already obtained a signed version of this extension, + // so skip it if they don't want this one. + if (extensionFilter != null && !extensionFilter(typeUri)) { + continue; + } + + var extensionData = extensionManager.GetExtensionArguments(typeUri); + + // Initialize this particular extension. + IOpenIdMessageExtension extension = this.ExtensionFactory.Create(typeUri, extensionData, message); + if (extension != null) { + MessageDictionary extensionDictionary = this.Channel.MessageDescriptions.GetAccessor(extension); + foreach (var pair in extensionData) { + extensionDictionary[pair.Key] = pair.Value; + } + + // Give extensions that require custom serialization a chance to do their work. + var customSerializingExtension = extension as IMessageWithEvents; + if (customSerializingExtension != null) { + customSerializingExtension.OnReceiving(); + } + + yield return extension; + } else { + Logger.OpenId.WarnFormat("Extension with type URI '{0}' ignored because it is not a recognized extension.", typeUri); + } + } + } + + /// /// Gets the dictionary of message parts that should be deserialized into extensions. /// /// The message. - /// A dictionary of message parts, including only signed parts when appropriate. - private IDictionary GetExtensionsDictionary(IProtocolMessage message) { + /// If set to true only signed extensions will be available. + /// + /// A dictionary of message parts, including only signed parts when appropriate. + /// + private IDictionary GetExtensionsDictionary(IProtocolMessage message, bool ignoreUnsigned) { Contract.Requires(this.Channel != null); ErrorUtilities.VerifyOperation(this.Channel != null, "Channel property has not been set."); - // An IndirectSignedResponse message (the only one we care to filter parts for) - // can be received both by RPs and OPs (during check_auth). - // Whichever party is reading the extensions, apply their security policy regarding - // signing. (Although OPs have no reason to deserialize extensions during check_auth) - // so that scenario might be optimized away eventually. - bool extensionsShouldBeSigned = this.rpSecuritySettings != null ? !this.rpSecuritySettings.AllowUnsignedIncomingExtensions : this.opSecuritySettings.SignOutgoingExtensions; - IndirectSignedResponse signedResponse = message as IndirectSignedResponse; - if (signedResponse != null && extensionsShouldBeSigned) { + if (signedResponse != null && ignoreUnsigned) { return signedResponse.GetSignedMessageParts(this.Channel); } else { return this.Channel.MessageDescriptions.GetAccessor(message); diff --git a/src/DotNetOpenAuth/OpenId/Extensions/ExtensionBase.cs b/src/DotNetOpenAuth/OpenId/Extensions/ExtensionBase.cs index 3ca979d..347f4f9 100644 --- a/src/DotNetOpenAuth/OpenId/Extensions/ExtensionBase.cs +++ b/src/DotNetOpenAuth/OpenId/Extensions/ExtensionBase.cs @@ -72,6 +72,15 @@ namespace DotNetOpenAuth.OpenId.Extensions { get { return this.AdditionalSupportedTypeUris; } } + /// + /// Gets or sets a value indicating whether this extension was + /// signed by the OpenID Provider. + /// + /// + /// true if this instance is signed by the provider; otherwise, false. + /// + public bool IsSignedByProvider { get; set; } + #endregion #region IMessage Properties diff --git a/src/DotNetOpenAuth/OpenId/Messages/IOpenIdMessageExtension.cs b/src/DotNetOpenAuth/OpenId/Messages/IOpenIdMessageExtension.cs index 38df7f1..d396de7 100644 --- a/src/DotNetOpenAuth/OpenId/Messages/IOpenIdMessageExtension.cs +++ b/src/DotNetOpenAuth/OpenId/Messages/IOpenIdMessageExtension.cs @@ -36,5 +36,14 @@ namespace DotNetOpenAuth.OpenId.Messages { /// The for an example. /// IEnumerable AdditionalSupportedTypeUris { get; } + + /// + /// Gets or sets a value indicating whether this extension was + /// signed by the OpenID Provider. + /// + /// + /// true if this instance is signed by the provider; otherwise, false. + /// + bool IsSignedByProvider { get; set; } } } diff --git a/src/DotNetOpenAuth/OpenId/Messages/IndirectSignedResponse.cs b/src/DotNetOpenAuth/OpenId/Messages/IndirectSignedResponse.cs index e7a93ae..e7f70f5 100644 --- a/src/DotNetOpenAuth/OpenId/Messages/IndirectSignedResponse.cs +++ b/src/DotNetOpenAuth/OpenId/Messages/IndirectSignedResponse.cs @@ -238,6 +238,20 @@ namespace DotNetOpenAuth.OpenId.Messages { internal bool ReturnToParametersSignatureValidated { get; set; } /// + /// Gets the signed extensions on this message. + /// + internal IEnumerable SignedExtensions { + get { return this.extensions.OfType().Where(ext => ext.IsSignedByProvider); } + } + + /// + /// Gets the unsigned extensions on this message. + /// + internal IEnumerable UnsignedExtensions { + get { return this.extensions.OfType().Where(ext => !ext.IsSignedByProvider); } + } + + /// /// Gets or sets the nonce that will protect the message from replay attacks. /// /// diff --git a/src/DotNetOpenAuth/OpenId/RelyingParty/AuthenticationResponseSnapshot.cs b/src/DotNetOpenAuth/OpenId/RelyingParty/AuthenticationResponseSnapshot.cs index f70bbaa..5ab7ec4 100644 --- a/src/DotNetOpenAuth/OpenId/RelyingParty/AuthenticationResponseSnapshot.cs +++ b/src/DotNetOpenAuth/OpenId/RelyingParty/AuthenticationResponseSnapshot.cs @@ -109,6 +109,19 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { /// /// The extension, if it is found. Null otherwise. /// + /// + /// Extensions are returned only if the Provider signed them. + /// Relying parties that do not care if the values were modified in + /// transit should use the method + /// in order to allow the Provider to not sign the extension. + /// Unsigned extensions are completely unreliable and should be + /// used only to prefill user forms since the user or any other third + /// party may have tampered with the data carried by the extension. + /// Signed extensions are only reliable if the relying party + /// trusts the OpenID Provider that signed them. Signing does not mean + /// the relying party can trust the values -- it only means that the values + /// have not been tampered with since the Provider sent the message. + /// public T GetExtension() where T : IOpenIdMessageExtension { throw new NotSupportedException(OpenIdStrings.NotSupportedByAuthenticationSnapshot); } @@ -120,11 +133,73 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { /// /// The extension, if it is found. Null otherwise. /// + /// + /// Extensions are returned only if the Provider signed them. + /// Relying parties that do not care if the values were modified in + /// transit should use the method + /// in order to allow the Provider to not sign the extension. + /// Unsigned extensions are completely unreliable and should be + /// used only to prefill user forms since the user or any other third + /// party may have tampered with the data carried by the extension. + /// Signed extensions are only reliable if the relying party + /// trusts the OpenID Provider that signed them. Signing does not mean + /// the relying party can trust the values -- it only means that the values + /// have not been tampered with since the Provider sent the message. + /// public IOpenIdMessageExtension GetExtension(Type extensionType) { throw new NotSupportedException(OpenIdStrings.NotSupportedByAuthenticationSnapshot); } /// + /// Tries to get an OpenID extension that may be present in the response, without + /// requiring it to be signed by the Provider. + /// + /// The type of extension to look for in the response message. + /// + /// The extension, if it is found. Null otherwise. + /// + /// + /// Extensions are returned whether they are signed or not. + /// Use the method to retrieve + /// extension responses only if they are signed by the Provider to + /// protect against tampering. + /// Unsigned extensions are completely unreliable and should be + /// used only to prefill user forms since the user or any other third + /// party may have tampered with the data carried by the extension. + /// Signed extensions are only reliable if the relying party + /// trusts the OpenID Provider that signed them. Signing does not mean + /// the relying party can trust the values -- it only means that the values + /// have not been tampered with since the Provider sent the message. + /// + public T GetUntrustedExtension() where T : IOpenIdMessageExtension { + throw new NotSupportedException(OpenIdStrings.NotSupportedByAuthenticationSnapshot); + } + + /// + /// Tries to get an OpenID extension that may be present in the response. + /// + /// Type of the extension to look for in the response. + /// + /// The extension, if it is found. Null otherwise. + /// + /// + /// Extensions are returned whether they are signed or not. + /// Use the method to retrieve + /// extension responses only if they are signed by the Provider to + /// protect against tampering. + /// Unsigned extensions are completely unreliable and should be + /// used only to prefill user forms since the user or any other third + /// party may have tampered with the data carried by the extension. + /// Signed extensions are only reliable if the relying party + /// trusts the OpenID Provider that signed them. Signing does not mean + /// the relying party can trust the values -- it only means that the values + /// have not been tampered with since the Provider sent the message. + /// + public IOpenIdMessageExtension GetUntrustedExtension(Type extensionType) { + throw new NotSupportedException(OpenIdStrings.NotSupportedByAuthenticationSnapshot); + } + + /// /// Gets all the callback arguments that were previously added using /// or as a natural part /// of the return_to URL. diff --git a/src/DotNetOpenAuth/OpenId/RelyingParty/FailedAuthenticationResponse.cs b/src/DotNetOpenAuth/OpenId/RelyingParty/FailedAuthenticationResponse.cs index 391aa6e..0dc21bb 100644 --- a/src/DotNetOpenAuth/OpenId/RelyingParty/FailedAuthenticationResponse.cs +++ b/src/DotNetOpenAuth/OpenId/RelyingParty/FailedAuthenticationResponse.cs @@ -143,6 +143,19 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { /// /// The extension, if it is found. Null otherwise. /// + /// + /// Extensions are returned only if the Provider signed them. + /// Relying parties that do not care if the values were modified in + /// transit should use the method + /// in order to allow the Provider to not sign the extension. + /// Unsigned extensions are completely unreliable and should be + /// used only to prefill user forms since the user or any other third + /// party may have tampered with the data carried by the extension. + /// Signed extensions are only reliable if the relying party + /// trusts the OpenID Provider that signed them. Signing does not mean + /// the relying party can trust the values -- it only means that the values + /// have not been tampered with since the Provider sent the message. + /// public T GetExtension() where T : IOpenIdMessageExtension { return default(T); } @@ -154,10 +167,72 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { /// /// The extension, if it is found. Null otherwise. /// + /// + /// Extensions are returned only if the Provider signed them. + /// Relying parties that do not care if the values were modified in + /// transit should use the method + /// in order to allow the Provider to not sign the extension. + /// Unsigned extensions are completely unreliable and should be + /// used only to prefill user forms since the user or any other third + /// party may have tampered with the data carried by the extension. + /// Signed extensions are only reliable if the relying party + /// trusts the OpenID Provider that signed them. Signing does not mean + /// the relying party can trust the values -- it only means that the values + /// have not been tampered with since the Provider sent the message. + /// public IOpenIdMessageExtension GetExtension(Type extensionType) { return null; } + /// + /// Tries to get an OpenID extension that may be present in the response, without + /// requiring it to be signed by the Provider. + /// + /// The type of extension to look for in the response message. + /// + /// The extension, if it is found. Null otherwise. + /// + /// + /// Extensions are returned whether they are signed or not. + /// Use the method to retrieve + /// extension responses only if they are signed by the Provider to + /// protect against tampering. + /// Unsigned extensions are completely unreliable and should be + /// used only to prefill user forms since the user or any other third + /// party may have tampered with the data carried by the extension. + /// Signed extensions are only reliable if the relying party + /// trusts the OpenID Provider that signed them. Signing does not mean + /// the relying party can trust the values -- it only means that the values + /// have not been tampered with since the Provider sent the message. + /// + public T GetUntrustedExtension() where T : IOpenIdMessageExtension { + return default(T); + } + + /// + /// Tries to get an OpenID extension that may be present in the response. + /// + /// Type of the extension to look for in the response. + /// + /// The extension, if it is found. Null otherwise. + /// + /// + /// Extensions are returned whether they are signed or not. + /// Use the method to retrieve + /// extension responses only if they are signed by the Provider to + /// protect against tampering. + /// Unsigned extensions are completely unreliable and should be + /// used only to prefill user forms since the user or any other third + /// party may have tampered with the data carried by the extension. + /// Signed extensions are only reliable if the relying party + /// trusts the OpenID Provider that signed them. Signing does not mean + /// the relying party can trust the values -- it only means that the values + /// have not been tampered with since the Provider sent the message. + /// + public IOpenIdMessageExtension GetUntrustedExtension(Type extensionType) { + return null; + } + #endregion } } diff --git a/src/DotNetOpenAuth/OpenId/RelyingParty/IAuthenticationResponse.cs b/src/DotNetOpenAuth/OpenId/RelyingParty/IAuthenticationResponse.cs index 7df17b8..51c6f37 100644 --- a/src/DotNetOpenAuth/OpenId/RelyingParty/IAuthenticationResponse.cs +++ b/src/DotNetOpenAuth/OpenId/RelyingParty/IAuthenticationResponse.cs @@ -122,6 +122,19 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { /// /// The extension, if it is found. Null otherwise. /// + /// + /// Extensions are returned only if the Provider signed them. + /// Relying parties that do not care if the values were modified in + /// transit should use the method + /// in order to allow the Provider to not sign the extension. + /// Unsigned extensions are completely unreliable and should be + /// used only to prefill user forms since the user or any other third + /// party may have tampered with the data carried by the extension. + /// Signed extensions are only reliable if the relying party + /// trusts the OpenID Provider that signed them. Signing does not mean + /// the relying party can trust the values -- it only means that the values + /// have not been tampered with since the Provider sent the message. + /// [SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter", Justification = "No parameter at all is required. T is used for return type.")] T GetExtension() where T : IOpenIdMessageExtension; @@ -132,6 +145,65 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { /// /// The extension, if it is found. Null otherwise. /// + /// + /// Extensions are returned only if the Provider signed them. + /// Relying parties that do not care if the values were modified in + /// transit should use the method + /// in order to allow the Provider to not sign the extension. + /// Unsigned extensions are completely unreliable and should be + /// used only to prefill user forms since the user or any other third + /// party may have tampered with the data carried by the extension. + /// Signed extensions are only reliable if the relying party + /// trusts the OpenID Provider that signed them. Signing does not mean + /// the relying party can trust the values -- it only means that the values + /// have not been tampered with since the Provider sent the message. + /// IOpenIdMessageExtension GetExtension(Type extensionType); + + /// + /// Tries to get an OpenID extension that may be present in the response, without + /// requiring it to be signed by the Provider. + /// + /// The type of extension to look for in the response message. + /// + /// The extension, if it is found. Null otherwise. + /// + /// + /// Extensions are returned whether they are signed or not. + /// Use the method to retrieve + /// extension responses only if they are signed by the Provider to + /// protect against tampering. + /// Unsigned extensions are completely unreliable and should be + /// used only to prefill user forms since the user or any other third + /// party may have tampered with the data carried by the extension. + /// Signed extensions are only reliable if the relying party + /// trusts the OpenID Provider that signed them. Signing does not mean + /// the relying party can trust the values -- it only means that the values + /// have not been tampered with since the Provider sent the message. + /// + [SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter", Justification = "No parameter at all is required. T is used for return type.")] + T GetUntrustedExtension() where T : IOpenIdMessageExtension; + + /// + /// Tries to get an OpenID extension that may be present in the response. + /// + /// Type of the extension to look for in the response. + /// + /// The extension, if it is found. Null otherwise. + /// + /// + /// Extensions are returned whether they are signed or not. + /// Use the method to retrieve + /// extension responses only if they are signed by the Provider to + /// protect against tampering. + /// Unsigned extensions are completely unreliable and should be + /// used only to prefill user forms since the user or any other third + /// party may have tampered with the data carried by the extension. + /// Signed extensions are only reliable if the relying party + /// trusts the OpenID Provider that signed them. Signing does not mean + /// the relying party can trust the values -- it only means that the values + /// have not been tampered with since the Provider sent the message. + /// + IOpenIdMessageExtension GetUntrustedExtension(Type extensionType); } } diff --git a/src/DotNetOpenAuth/OpenId/RelyingParty/NegativeAuthenticationResponse.cs b/src/DotNetOpenAuth/OpenId/RelyingParty/NegativeAuthenticationResponse.cs index 0a335c8..cd68a81 100644 --- a/src/DotNetOpenAuth/OpenId/RelyingParty/NegativeAuthenticationResponse.cs +++ b/src/DotNetOpenAuth/OpenId/RelyingParty/NegativeAuthenticationResponse.cs @@ -168,6 +168,19 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { /// /// The extension, if it is found. Null otherwise. /// + /// + /// Extensions are returned only if the Provider signed them. + /// Relying parties that do not care if the values were modified in + /// transit should use the method + /// in order to allow the Provider to not sign the extension. + /// Unsigned extensions are completely unreliable and should be + /// used only to prefill user forms since the user or any other third + /// party may have tampered with the data carried by the extension. + /// Signed extensions are only reliable if the relying party + /// trusts the OpenID Provider that signed them. Signing does not mean + /// the relying party can trust the values -- it only means that the values + /// have not been tampered with since the Provider sent the message. + /// public T GetExtension() where T : IOpenIdMessageExtension { return default(T); } @@ -179,10 +192,72 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { /// /// The extension, if it is found. Null otherwise. /// + /// + /// Extensions are returned only if the Provider signed them. + /// Relying parties that do not care if the values were modified in + /// transit should use the method + /// in order to allow the Provider to not sign the extension. + /// Unsigned extensions are completely unreliable and should be + /// used only to prefill user forms since the user or any other third + /// party may have tampered with the data carried by the extension. + /// Signed extensions are only reliable if the relying party + /// trusts the OpenID Provider that signed them. Signing does not mean + /// the relying party can trust the values -- it only means that the values + /// have not been tampered with since the Provider sent the message. + /// public IOpenIdMessageExtension GetExtension(Type extensionType) { return null; } + /// + /// Tries to get an OpenID extension that may be present in the response, without + /// requiring it to be signed by the Provider. + /// + /// The type of extension to look for in the response message. + /// + /// The extension, if it is found. Null otherwise. + /// + /// + /// Extensions are returned whether they are signed or not. + /// Use the method to retrieve + /// extension responses only if they are signed by the Provider to + /// protect against tampering. + /// Unsigned extensions are completely unreliable and should be + /// used only to prefill user forms since the user or any other third + /// party may have tampered with the data carried by the extension. + /// Signed extensions are only reliable if the relying party + /// trusts the OpenID Provider that signed them. Signing does not mean + /// the relying party can trust the values -- it only means that the values + /// have not been tampered with since the Provider sent the message. + /// + public T GetUntrustedExtension() where T : IOpenIdMessageExtension { + return default(T); + } + + /// + /// Tries to get an OpenID extension that may be present in the response. + /// + /// Type of the extension to look for in the response. + /// + /// The extension, if it is found. Null otherwise. + /// + /// + /// Extensions are returned whether they are signed or not. + /// Use the method to retrieve + /// extension responses only if they are signed by the Provider to + /// protect against tampering. + /// Unsigned extensions are completely unreliable and should be + /// used only to prefill user forms since the user or any other third + /// party may have tampered with the data carried by the extension. + /// Signed extensions are only reliable if the relying party + /// trusts the OpenID Provider that signed them. Signing does not mean + /// the relying party can trust the values -- it only means that the values + /// have not been tampered with since the Provider sent the message. + /// + public IOpenIdMessageExtension GetUntrustedExtension(Type extensionType) { + return null; + } + #endregion } } diff --git a/src/DotNetOpenAuth/OpenId/RelyingParty/PositiveAuthenticationResponse.cs b/src/DotNetOpenAuth/OpenId/RelyingParty/PositiveAuthenticationResponse.cs index b62a7c8..32980f5 100644 --- a/src/DotNetOpenAuth/OpenId/RelyingParty/PositiveAuthenticationResponse.cs +++ b/src/DotNetOpenAuth/OpenId/RelyingParty/PositiveAuthenticationResponse.cs @@ -209,8 +209,21 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { /// /// The extension, if it is found. Null otherwise. /// + /// + /// Extensions are returned only if the Provider signed them. + /// Relying parties that do not care if the values were modified in + /// transit should use the method + /// in order to allow the Provider to not sign the extension. + /// Unsigned extensions are completely unreliable and should be + /// used only to prefill user forms since the user or any other third + /// party may have tampered with the data carried by the extension. + /// Signed extensions are only reliable if the relying party + /// trusts the OpenID Provider that signed them. Signing does not mean + /// the relying party can trust the values -- it only means that the values + /// have not been tampered with since the Provider sent the message. + /// public T GetExtension() where T : IOpenIdMessageExtension { - return this.response.Extensions.OfType().FirstOrDefault(); + return this.response.SignedExtensions.OfType().FirstOrDefault(); } /// @@ -220,8 +233,71 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { /// /// The extension, if it is found. Null otherwise. /// + /// + /// Extensions are returned only if the Provider signed them. + /// Relying parties that do not care if the values were modified in + /// transit should use the method + /// in order to allow the Provider to not sign the extension. + /// Unsigned extensions are completely unreliable and should be + /// used only to prefill user forms since the user or any other third + /// party may have tampered with the data carried by the extension. + /// Signed extensions are only reliable if the relying party + /// trusts the OpenID Provider that signed them. Signing does not mean + /// the relying party can trust the values -- it only means that the values + /// have not been tampered with since the Provider sent the message. + /// public IOpenIdMessageExtension GetExtension(Type extensionType) { ErrorUtilities.VerifyArgumentNotNull(extensionType, "extensionType"); + return this.response.SignedExtensions.OfType().Where(ext => extensionType.IsInstanceOfType(ext)).FirstOrDefault(); + } + + /// + /// Tries to get an OpenID extension that may be present in the response, without + /// requiring it to be signed by the Provider. + /// + /// The type of extension to look for in the response message. + /// + /// The extension, if it is found. Null otherwise. + /// + /// + /// Extensions are returned whether they are signed or not. + /// Use the method to retrieve + /// extension responses only if they are signed by the Provider to + /// protect against tampering. + /// Unsigned extensions are completely unreliable and should be + /// used only to prefill user forms since the user or any other third + /// party may have tampered with the data carried by the extension. + /// Signed extensions are only reliable if the relying party + /// trusts the OpenID Provider that signed them. Signing does not mean + /// the relying party can trust the values -- it only means that the values + /// have not been tampered with since the Provider sent the message. + /// + public T GetUntrustedExtension() where T : IOpenIdMessageExtension { + return this.response.Extensions.OfType().FirstOrDefault(); + } + + /// + /// Tries to get an OpenID extension that may be present in the response. + /// + /// Type of the extension to look for in the response. + /// + /// The extension, if it is found. Null otherwise. + /// + /// + /// Extensions are returned whether they are signed or not. + /// Use the method to retrieve + /// extension responses only if they are signed by the Provider to + /// protect against tampering. + /// Unsigned extensions are completely unreliable and should be + /// used only to prefill user forms since the user or any other third + /// party may have tampered with the data carried by the extension. + /// Signed extensions are only reliable if the relying party + /// trusts the OpenID Provider that signed them. Signing does not mean + /// the relying party can trust the values -- it only means that the values + /// have not been tampered with since the Provider sent the message. + /// + public IOpenIdMessageExtension GetUntrustedExtension(Type extensionType) { + ErrorUtilities.VerifyArgumentNotNull(extensionType, "extensionType"); return this.response.Extensions.OfType().Where(ext => extensionType.IsInstanceOfType(ext)).FirstOrDefault(); } diff --git a/src/DotNetOpenAuth/OpenId/RelyingParty/RelyingPartySecuritySettings.cs b/src/DotNetOpenAuth/OpenId/RelyingParty/RelyingPartySecuritySettings.cs index 64c6099..f7ac3c2 100644 --- a/src/DotNetOpenAuth/OpenId/RelyingParty/RelyingPartySecuritySettings.cs +++ b/src/DotNetOpenAuth/OpenId/RelyingParty/RelyingPartySecuritySettings.cs @@ -86,20 +86,6 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { public TimeSpan PrivateSecretMaximumAge { get; set; } /// - /// Gets or sets a value indicating whether unsigned extension responses will be deserialized. - /// - /// - /// false to ignore unsigned extension responses; true to accept them. - /// Default is false. - /// - /// - /// This is an internal-only property because not requiring signed extensions is - /// potentially dangerous. It is included here as an internal option primarily - /// to enable testing. - /// - internal bool AllowUnsignedIncomingExtensions { get; set; } - - /// /// Fires the event. /// private void OnRequireSslChanged() { -- cgit v1.1