diff options
Diffstat (limited to 'src/DotNetOpenAuth')
15 files changed, 303 insertions, 40 deletions
diff --git a/src/DotNetOpenAuth/DotNetOpenAuth.csproj b/src/DotNetOpenAuth/DotNetOpenAuth.csproj index 7686ff6..0feb900 100644 --- a/src/DotNetOpenAuth/DotNetOpenAuth.csproj +++ b/src/DotNetOpenAuth/DotNetOpenAuth.csproj @@ -219,6 +219,7 @@ <Compile Include="OpenId\Messages\CheckAuthenticationRequest.cs" /> <Compile Include="OpenId\Messages\CheckAuthenticationResponse.cs" /> <Compile Include="OpenId\Messages\CheckIdRequest.cs" /> + <Compile Include="OpenId\Messages\IErrorMessage.cs" /> <Compile Include="OpenId\Messages\IndirectResponseBase.cs" /> <Compile Include="OpenId\Messages\IndirectSignedResponse.cs" /> <Compile Include="OpenId\Messages\IOpenIdMessageExtension.cs" /> @@ -234,6 +235,7 @@ <Compile Include="OpenId\Provider\IAuthenticationRequest.cs" /> <Compile Include="OpenId\Provider\IdentityEndpoint.cs" /> <Compile Include="OpenId\Provider\IdentityEndpointNormalizationEventArgs.cs" /> + <Compile Include="OpenId\Provider\IErrorReporting.cs" /> <Compile Include="OpenId\Provider\IProviderApplicationStore.cs" /> <Compile Include="OpenId\Provider\IRequest.cs" /> <Compile Include="OpenId\Provider\ProviderEndpoint.cs" /> diff --git a/src/DotNetOpenAuth/Messaging/MessagingStrings.Designer.cs b/src/DotNetOpenAuth/Messaging/MessagingStrings.Designer.cs index d9fddcc..b1931dc 100644 --- a/src/DotNetOpenAuth/Messaging/MessagingStrings.Designer.cs +++ b/src/DotNetOpenAuth/Messaging/MessagingStrings.Designer.cs @@ -151,6 +151,15 @@ namespace DotNetOpenAuth.Messaging { } /// <summary> + /// Looks up a localized string similar to This exception must be instantiated with a recipient that will receive the error message, or a direct request message instance that this exception will respond to.. + /// </summary> + internal static string ExceptionUndeliverable { + get { + return ResourceManager.GetString("ExceptionUndeliverable", resourceCulture); + } + } + + /// <summary> /// Looks up a localized string similar to Expected {0} message but received no recognizable message.. /// </summary> internal static string ExpectedMessageNotReceived { diff --git a/src/DotNetOpenAuth/Messaging/MessagingStrings.resx b/src/DotNetOpenAuth/Messaging/MessagingStrings.resx index aa5419f..a17988a 100644 --- a/src/DotNetOpenAuth/Messaging/MessagingStrings.resx +++ b/src/DotNetOpenAuth/Messaging/MessagingStrings.resx @@ -279,4 +279,7 @@ <data name="WebRequestFailed" xml:space="preserve"> <value>Web request to '{0}' failed.</value> </data> + <data name="ExceptionUndeliverable" xml:space="preserve"> + <value>This exception must be instantiated with a recipient that will receive the error message, or a direct request message instance that this exception will respond to.</value> + </data> </root>
\ No newline at end of file diff --git a/src/DotNetOpenAuth/Messaging/MessagingUtilities.cs b/src/DotNetOpenAuth/Messaging/MessagingUtilities.cs index 1861c41..0292107 100644 --- a/src/DotNetOpenAuth/Messaging/MessagingUtilities.cs +++ b/src/DotNetOpenAuth/Messaging/MessagingUtilities.cs @@ -13,6 +13,7 @@ namespace DotNetOpenAuth.Messaging { using System.IO; using System.Linq; using System.Net; + using System.Reflection; using System.Security.Cryptography; using System.Text; using System.Web; @@ -136,6 +137,31 @@ namespace DotNetOpenAuth.Messaging { } /// <summary> + /// Assemblies a message comprised of the message on a given exception and all inner exceptions. + /// </summary> + /// <param name="exception">The exception.</param> + /// <returns>The assembled message.</returns> + internal static string GetAllMessages(this Exception exception) { + // The input being null is probably bad, but since this method is called + // from a catch block, we don't really want to throw a new exception and + // hide the details of this one. + if (exception == null) { + Logger.Error("MessagingUtilities.GetAllMessages called with null input."); + } + + StringBuilder message = new StringBuilder(); + while (exception != null) { + message.Append(exception.Message); + exception = exception.InnerException; + if (exception != null) { + message.Append(" "); + } + } + + return message.ToString(); + } + + /// <summary> /// Gets a cryptographically strong random sequence of values. /// </summary> /// <param name="length">The length of the sequence to generate.</param> diff --git a/src/DotNetOpenAuth/Messaging/ProtocolException.cs b/src/DotNetOpenAuth/Messaging/ProtocolException.cs index e9f4ab7..daf13d7 100644 --- a/src/DotNetOpenAuth/Messaging/ProtocolException.cs +++ b/src/DotNetOpenAuth/Messaging/ProtocolException.cs @@ -40,13 +40,10 @@ namespace DotNetOpenAuth.Messaging { /// such that it can be sent as a protocol message response to a remote caller. /// </summary> /// <param name="message">The human-readable exception message.</param> - /// <param name="faultedMessage">The message that was the cause of the exception. May not be null.</param> - internal ProtocolException(string message, IProtocolMessage faultedMessage) + /// <param name="faultedMessage">The message that was the cause of the exception. Must not be null.</param> + protected internal ProtocolException(string message, IProtocolMessage faultedMessage) : base(message) { - if (faultedMessage == null) { - throw new ArgumentNullException("faultedMessage"); - } - + ErrorUtilities.VerifyArgumentNotNull(faultedMessage, "faultedMessage"); this.FaultedMessage = faultedMessage; } diff --git a/src/DotNetOpenAuth/OpenId/ChannelElements/OpenIdMessageFactory.cs b/src/DotNetOpenAuth/OpenId/ChannelElements/OpenIdMessageFactory.cs index 1b2e46d..e0c3a1b 100644 --- a/src/DotNetOpenAuth/OpenId/ChannelElements/OpenIdMessageFactory.cs +++ b/src/DotNetOpenAuth/OpenId/ChannelElements/OpenIdMessageFactory.cs @@ -70,6 +70,8 @@ namespace DotNetOpenAuth.OpenId.ChannelElements { } } else if (string.Equals(mode, protocol.Args.Mode.check_authentication)) { message = new CheckAuthenticationRequest(protocol.Version, recipient.Location); + } else if (string.Equals(mode, protocol.Args.Mode.error)) { + message = new IndirectErrorResponse(protocol.Version, recipient.Location); } else { ErrorUtilities.ThrowProtocol(MessagingStrings.UnexpectedMessagePartValue, protocol.openid.mode, mode); } @@ -106,11 +108,17 @@ namespace DotNetOpenAuth.OpenId.ChannelElements { protocol = Protocol.V20; } + // Handle error messages generally. + if (fields.ContainsKey(protocol.openidnp.error)) { + message = new DirectErrorResponse(request); + } + var associateRequest = request as AssociateRequest; if (associateRequest != null) { if (protocol.Version.Major >= 2 && fields.ContainsKey(protocol.openidnp.error_code)) { + // This is a special recognized error case that we create a special message for. message = new AssociateUnsuccessfulResponse(associateRequest); - } else { + } else if (message == null) { var associateDiffieHellmanRequest = request as AssociateDiffieHellmanRequest; var associateUnencryptedRequest = request as AssociateUnencryptedRequest; @@ -125,7 +133,7 @@ namespace DotNetOpenAuth.OpenId.ChannelElements { } var checkAuthenticationRequest = request as CheckAuthenticationRequest; - if (checkAuthenticationRequest != null) { + if (checkAuthenticationRequest != null && message == null) { message = new CheckAuthenticationResponse(checkAuthenticationRequest); } diff --git a/src/DotNetOpenAuth/OpenId/Messages/DirectErrorResponse.cs b/src/DotNetOpenAuth/OpenId/Messages/DirectErrorResponse.cs index ed272d3..9731e43 100644 --- a/src/DotNetOpenAuth/OpenId/Messages/DirectErrorResponse.cs +++ b/src/DotNetOpenAuth/OpenId/Messages/DirectErrorResponse.cs @@ -5,6 +5,7 @@ //----------------------------------------------------------------------- namespace DotNetOpenAuth.OpenId.Messages { + using System; using DotNetOpenAuth.Messaging; /// <summary> @@ -14,7 +15,7 @@ namespace DotNetOpenAuth.OpenId.Messages { /// This message must be sent with an HTTP status code of 400. /// This class satisfies OpenID 2.0 section 5.1.2.2. /// </remarks> - internal class DirectErrorResponse : DirectResponseBase, IHttpDirectResponse { + internal class DirectErrorResponse : DirectResponseBase, IErrorMessage, IHttpDirectResponse { /// <summary> /// Initializes a new instance of the <see cref="DirectErrorResponse"/> class. /// </summary> @@ -23,6 +24,14 @@ namespace DotNetOpenAuth.OpenId.Messages { : base(originatingRequest) { } + /// <summary> + /// Initializes a new instance of the <see cref="DirectErrorResponse"/> class. + /// </summary> + /// <param name="version">The OpenID version this message should comply with.</param> + internal DirectErrorResponse(Version version) + : base(version) { + } + #region IHttpDirectResponse Members /// <summary> @@ -39,19 +48,19 @@ namespace DotNetOpenAuth.OpenId.Messages { /// Gets or sets a human-readable message indicating why the request failed. /// </summary> [MessagePart("error", IsRequired = true, AllowEmpty = true)] - internal string ErrorMessage { get; set; } + public string ErrorMessage { get; set; } /// <summary> /// Gets or sets the contact address for the administrator of the server. /// </summary> /// <value>The contact address may take any form, as it is intended to be displayed to a person. </value> [MessagePart("contact", IsRequired = false, AllowEmpty = true)] - internal string Contact { get; set; } + public string Contact { get; set; } /// <summary> /// Gets or sets a reference token, such as a support ticket number or a URL to a news blog, etc. /// </summary> [MessagePart("reference", IsRequired = false, AllowEmpty = true)] - internal string Reference { get; set; } + public string Reference { get; set; } } } diff --git a/src/DotNetOpenAuth/OpenId/Messages/DirectResponseBase.cs b/src/DotNetOpenAuth/OpenId/Messages/DirectResponseBase.cs index 141669c..bf357d3 100644 --- a/src/DotNetOpenAuth/OpenId/Messages/DirectResponseBase.cs +++ b/src/DotNetOpenAuth/OpenId/Messages/DirectResponseBase.cs @@ -58,6 +58,15 @@ namespace DotNetOpenAuth.OpenId.Messages { this.Version = originatingRequest.Version; } + /// <summary> + /// Initializes a new instance of the <see cref="DirectResponseBase"/> class. + /// </summary> + /// <param name="version">The OpenID version to comply with.</param> + protected DirectResponseBase(Version version) { + ErrorUtilities.VerifyArgumentNotNull(version, "version"); + this.Version = version; + } + #region IProtocolMessage Properties /// <summary> @@ -96,6 +105,9 @@ namespace DotNetOpenAuth.OpenId.Messages { /// <summary> /// Gets the originating request message that caused this response to be formed. /// </summary> + /// <remarks> + /// This property may be null if the request message was undecipherable. + /// </remarks> IDirectedProtocolMessage IDirectResponseProtocolMessage.OriginatingRequest { get { return this.originatingRequest; } } diff --git a/src/DotNetOpenAuth/OpenId/Messages/IErrorMessage.cs b/src/DotNetOpenAuth/OpenId/Messages/IErrorMessage.cs new file mode 100644 index 0000000..549b327 --- /dev/null +++ b/src/DotNetOpenAuth/OpenId/Messages/IErrorMessage.cs @@ -0,0 +1,32 @@ +//----------------------------------------------------------------------- +// <copyright file="IErrorMessage.cs" company="Andrew Arnott"> +// Copyright (c) Andrew Arnott. All rights reserved. +// </copyright> +//----------------------------------------------------------------------- + +namespace DotNetOpenAuth.OpenId.Messages { + using DotNetOpenAuth.Messaging; + + /// <summary> + /// Members found on error response messages sent from a Provider + /// to a Relying Party in response to direct and indirect message + /// requests that result in an error. + /// </summary> + internal interface IErrorMessage : IProtocolMessage { + /// <summary> + /// Gets or sets a human-readable message indicating why the request failed. + /// </summary> + string ErrorMessage { get; set; } + + /// <summary> + /// Gets or sets the contact address for the administrator of the server. + /// </summary> + /// <value>The contact address may take any form, as it is intended to be displayed to a person. </value> + string Contact { get; set; } + + /// <summary> + /// Gets or sets a reference token, such as a support ticket number or a URL to a news blog, etc. + /// </summary> + string Reference { get; set; } + } +} diff --git a/src/DotNetOpenAuth/OpenId/Messages/IndirectErrorResponse.cs b/src/DotNetOpenAuth/OpenId/Messages/IndirectErrorResponse.cs index ffc73f8..eb006db 100644 --- a/src/DotNetOpenAuth/OpenId/Messages/IndirectErrorResponse.cs +++ b/src/DotNetOpenAuth/OpenId/Messages/IndirectErrorResponse.cs @@ -17,32 +17,41 @@ namespace DotNetOpenAuth.OpenId.Messages { /// <remarks> /// This class satisfies OpenID 2.0 section 5.2.3. /// </remarks> - internal class IndirectErrorResponse : IndirectResponseBase { + internal class IndirectErrorResponse : IndirectResponseBase, IErrorMessage { /// <summary> /// Initializes a new instance of the <see cref="IndirectErrorResponse"/> class. /// </summary> /// <param name="request">The request that resulted in this error on the Provider.</param> - internal IndirectErrorResponse(CheckIdRequest request) - : base(request, "error") { + internal IndirectErrorResponse(SignedResponseRequest request) + : base(request, Protocol.Lookup(GetVersion(request)).openidnp.error) { + } + + /// <summary> + /// Initializes a new instance of the <see cref="IndirectErrorResponse"/> class. + /// </summary> + /// <param name="version">The OpenID version this message should comply with.</param> + /// <param name="recipient">The recipient of this message.</param> + internal IndirectErrorResponse(Version version, Uri recipient) + : base(version, recipient, Protocol.Lookup(version).openidnp.error) { } /// <summary> /// Gets or sets a human-readable message indicating why the request failed. /// </summary> [MessagePart("openid.error", IsRequired = true, AllowEmpty = true)] - internal string ErrorMessage { get; set; } + public string ErrorMessage { get; set; } /// <summary> /// Gets or sets the contact address for the administrator of the server. /// </summary> /// <value>The contact address may take any form, as it is intended to be displayed to a person. </value> [MessagePart("openid.contact", IsRequired = false, AllowEmpty = true)] - internal string Contact { get; set; } + public string Contact { get; set; } /// <summary> /// Gets or sets a reference token, such as a support ticket number or a URL to a news blog, etc. /// </summary> [MessagePart("openid.reference", IsRequired = false, AllowEmpty = true)] - internal string Reference { get; set; } + public string Reference { get; set; } } } diff --git a/src/DotNetOpenAuth/OpenId/Messages/IndirectResponseBase.cs b/src/DotNetOpenAuth/OpenId/Messages/IndirectResponseBase.cs index 3c5bd6a..322ec60 100644 --- a/src/DotNetOpenAuth/OpenId/Messages/IndirectResponseBase.cs +++ b/src/DotNetOpenAuth/OpenId/Messages/IndirectResponseBase.cs @@ -54,7 +54,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> - protected static Version GetVersion(IProtocolMessage message) { + internal static Version GetVersion(IProtocolMessage message) { ErrorUtilities.VerifyArgumentNotNull(message, "message"); return message.Version; } diff --git a/src/DotNetOpenAuth/OpenId/Provider/AutoResponsiveRequest.cs b/src/DotNetOpenAuth/OpenId/Provider/AutoResponsiveRequest.cs index 53998dc..e2f3992 100644 --- a/src/DotNetOpenAuth/OpenId/Provider/AutoResponsiveRequest.cs +++ b/src/DotNetOpenAuth/OpenId/Provider/AutoResponsiveRequest.cs @@ -10,6 +10,7 @@ namespace DotNetOpenAuth.OpenId.Provider { using System.Linq; using System.Text; using DotNetOpenAuth.Messaging; + using DotNetOpenAuth.OpenId.Messages; /// <summary> /// Handles messages coming into an OpenID Provider for which the entire @@ -36,6 +37,19 @@ namespace DotNetOpenAuth.OpenId.Provider { } /// <summary> + /// Initializes a new instance of the <see cref="AutoResponsiveRequest"/> class + /// for a response to an unrecognizable request. + /// </summary> + /// <param name="provider">The provider that received the request message.</param> + /// <param name="response">The response that is ready for transmittal.</param> + internal AutoResponsiveRequest(OpenIdProvider provider, IProtocolMessage response) + : base(provider, IndirectResponseBase.GetVersion(response)) { + ErrorUtilities.VerifyArgumentNotNull(response, "response"); + + this.response = response; + } + + /// <summary> /// Gets a value indicating whether the response is ready to be sent to the user agent. /// </summary> /// <remarks> diff --git a/src/DotNetOpenAuth/OpenId/Provider/IErrorReporting.cs b/src/DotNetOpenAuth/OpenId/Provider/IErrorReporting.cs new file mode 100644 index 0000000..7221e94 --- /dev/null +++ b/src/DotNetOpenAuth/OpenId/Provider/IErrorReporting.cs @@ -0,0 +1,43 @@ +//----------------------------------------------------------------------- +// <copyright file="IErrorReporting.cs" company="Andrew Arnott"> +// Copyright (c) Andrew Arnott. All rights reserved. +// </copyright> +//----------------------------------------------------------------------- + +namespace DotNetOpenAuth.OpenId.Provider { + using System; + using DotNetOpenAuth.Messaging; + + /// <summary> + /// An interface that a Provider site may implement in order to better + /// control error reporting. + /// </summary> + public interface IErrorReporting { + /// <summary> + /// Gets the message that can be sent in an error response + /// with information on who the remote party can contact + /// for help resolving the error. + /// </summary> + /// <value> + /// The contact address may take any form, as it is intended to be displayed to a person. + /// </value> + string Contact { get; } + + /// <summary> + /// Logs the details of an exception for later reference in diagnosing the problem. + /// </summary> + /// <param name="error">The exception that was generated from the error.</param> + /// <returns> + /// A unique identifier for this particular error that the remote party can + /// reference when contacting <see cref="Contact"/> for help with this error. + /// May be null. + /// </returns> + /// <remarks> + /// The implementation of this method should never throw an unhandled exception + /// as that would preclude the ability to send the error response to the remote + /// party. When this method is not implemented, it should return null rather + /// than throwing <see cref="NotImplementedException"/>. + /// </remarks> + string LogError(ProtocolException error); + } +} diff --git a/src/DotNetOpenAuth/OpenId/Provider/OpenIdProvider.cs b/src/DotNetOpenAuth/OpenId/Provider/OpenIdProvider.cs index 2bea543..4ed0fb1 100644 --- a/src/DotNetOpenAuth/OpenId/Provider/OpenIdProvider.cs +++ b/src/DotNetOpenAuth/OpenId/Provider/OpenIdProvider.cs @@ -104,6 +104,12 @@ namespace DotNetOpenAuth.OpenId.Provider { } /// <summary> + /// Gets or sets the mechanism a host site can use to receive + /// notifications of errors when communicating with remote parties. + /// </summary> + public IErrorReporting ErrorReporting { get; set; } + + /// <summary> /// Gets the association store. /// </summary> internal IAssociationStore<AssociationRelyingPartyType> AssociationStore { get; private set; } @@ -145,31 +151,49 @@ namespace DotNetOpenAuth.OpenId.Provider { /// be authentication requests where the Provider site has to make decisions based /// on its own user database and policies. /// </remarks> - /// <exception cref="ProtocolException">Thrown if the incoming message is recognized but deviates from the protocol specification irrecoverably.</exception> + /// <exception cref="ProtocolException">Thrown if the incoming message is recognized + /// but deviates from the protocol specification irrecoverably.</exception> public IRequest GetRequest(HttpRequestInfo httpRequestInfo) { ErrorUtilities.VerifyArgumentNotNull(httpRequestInfo, "httpRequestInfo"); + IDirectedProtocolMessage incomingMessage = null; - IDirectedProtocolMessage incomingMessage = this.Channel.ReadFromRequest(httpRequestInfo); - if (incomingMessage == null) { - return null; - } + try { + incomingMessage = this.Channel.ReadFromRequest(httpRequestInfo); + if (incomingMessage == null) { + // If the incoming request does not resemble an OpenID message at all, + // it's probably a user who just navigated to this URL, and we should + // just return null so the host can display a message to the user. + if (httpRequestInfo.HttpMethod == "GET" && !httpRequestInfo.Url.QueryStringContainPrefixedParameters(Protocol.Default.openid.Prefix)) { + return null; + } - var checkIdMessage = incomingMessage as CheckIdRequest; - if (checkIdMessage != null) { - return new AuthenticationRequest(this, checkIdMessage); - } + ErrorUtilities.ThrowProtocol(MessagingStrings.UnexpectedMessageReceivedOfMany); + } - var checkAuthMessage = incomingMessage as CheckAuthenticationRequest; - if (checkAuthMessage != null) { - return new AutoResponsiveRequest(this, incomingMessage, new CheckAuthenticationResponse(checkAuthMessage, this)); - } + var checkIdMessage = incomingMessage as CheckIdRequest; + if (checkIdMessage != null) { + return new AuthenticationRequest(this, checkIdMessage); + } - var associateMessage = incomingMessage as AssociateRequest; - if (associateMessage != null) { - return new AutoResponsiveRequest(this, incomingMessage, associateMessage.CreateResponse(this.AssociationStore, this.SecuritySettings)); - } + var checkAuthMessage = incomingMessage as CheckAuthenticationRequest; + if (checkAuthMessage != null) { + return new AutoResponsiveRequest(this, incomingMessage, new CheckAuthenticationResponse(checkAuthMessage, this)); + } - throw ErrorUtilities.ThrowProtocol(MessagingStrings.UnexpectedMessageReceivedOfMany); + var associateMessage = incomingMessage as AssociateRequest; + if (associateMessage != null) { + return new AutoResponsiveRequest(this, incomingMessage, associateMessage.CreateResponse(this.AssociationStore, this.SecuritySettings)); + } + + throw ErrorUtilities.ThrowProtocol(MessagingStrings.UnexpectedMessageReceivedOfMany); + } catch (ProtocolException ex) { + IRequest errorResponse = this.GetErrorResponse(ex, httpRequestInfo, incomingMessage); + if (errorResponse == null) { + throw; + } + + return errorResponse; + } } /// <summary> @@ -258,5 +282,67 @@ namespace DotNetOpenAuth.OpenId.Provider { } #endregion + + /// <summary> + /// Prepares the return value for the GetRequest method in the event of an exception. + /// </summary> + /// <param name="ex">The exception that forms the basis of the error response. Must not be null.</param> + /// <param name="httpRequestInfo">The incoming HTTP request. Must not be null.</param> + /// <param name="incomingMessage">The incoming message. May be null in the case that it was malformed.</param> + /// <returns> + /// Either the <see cref="IRequest"/> to return to the host site or null to indicate no response could be reasonably created and that the caller should rethrow the exception. + /// </returns> + private IRequest GetErrorResponse(ProtocolException ex, HttpRequestInfo httpRequestInfo, IDirectedProtocolMessage incomingMessage) { + ErrorUtilities.VerifyArgumentNotNull(ex, "ex"); + ErrorUtilities.VerifyArgumentNotNull(httpRequestInfo, "httpRequestInfo"); + + Logger.Error("An exception was generated while processing an incoming OpenID request.", ex); + IErrorMessage errorMessage; + + // We must create the appropriate error message type (direct vs. indirect) + // based on what we see in the request. + if (httpRequestInfo.QueryString[Protocol.Default.openid.return_to] != null) { + // An indirect request message from the RP + // We need to return an indirect response error message so the RP can consume it. + // Consistent with OpenID 2.0 section 5.2.3. + var indirectRequest = incomingMessage as SignedResponseRequest; + if (indirectRequest != null) { + errorMessage = new IndirectErrorResponse(indirectRequest); + } else { + errorMessage = new IndirectErrorResponse(Protocol.Default.Version, new Uri(httpRequestInfo.QueryString[Protocol.Default.openid.return_to])); + } + } else if (httpRequestInfo.HttpMethod == "POST") { + // A direct request message from the RP + // We need to return a direct response error message so the RP can consume it. + // Consistent with OpenID 2.0 section 5.1.2.2. + if (incomingMessage != null) { + errorMessage = new DirectErrorResponse(incomingMessage); + } else { + errorMessage = new DirectErrorResponse(Protocol.Default.Version); + } + } else { + // This may be an indirect request from an RP that was so badly + // formed that we cannot even return an error to the RP. + // The best we can do is display an error to the user. + // Returning null cues the caller to "throw;" + return null; + } + + errorMessage.ErrorMessage = ex.GetAllMessages(); + + // Allow host to log this error and issue a ticket #. + // We tear off the field to a local var for thread safety. + IErrorReporting hostErrorHandler = this.ErrorReporting; + if (hostErrorHandler != null) { + errorMessage.Contact = hostErrorHandler.Contact; + errorMessage.Reference = hostErrorHandler.LogError(ex); + } + + if (incomingMessage != null) { + return new AutoResponsiveRequest(this, incomingMessage, errorMessage); + } else { + return new AutoResponsiveRequest(this, errorMessage); + } + } } } diff --git a/src/DotNetOpenAuth/OpenId/Provider/Request.cs b/src/DotNetOpenAuth/OpenId/Provider/Request.cs index 6546e38..e1ccce1 100644 --- a/src/DotNetOpenAuth/OpenId/Provider/Request.cs +++ b/src/DotNetOpenAuth/OpenId/Provider/Request.cs @@ -55,9 +55,23 @@ namespace DotNetOpenAuth.OpenId.Provider { this.provider = provider; this.request = request; + this.Protocol = Protocol.Lookup(this.request.Version); this.extensibleMessage = request as IProtocolMessageWithExtensions; } + /// <summary> + /// Initializes a new instance of the <see cref="Request"/> class. + /// </summary> + /// <param name="provider">The provider.</param> + /// <param name="version">The version.</param> + protected Request(OpenIdProvider provider, Version version) { + ErrorUtilities.VerifyArgumentNotNull(provider, "provider"); + ErrorUtilities.VerifyArgumentNotNull(version, "version"); + + this.provider = provider; + this.Protocol = Protocol.Lookup(version); + } + #region IRequest Members /// <summary> @@ -110,6 +124,7 @@ namespace DotNetOpenAuth.OpenId.Provider { /// <summary> /// Gets the original request message. /// </summary> + /// <value>This may be null in the case of an unrecognizable message.</value> protected IDirectedProtocolMessage RequestMessage { get { return this.request; } } @@ -122,9 +137,7 @@ namespace DotNetOpenAuth.OpenId.Provider { /// <summary> /// Gets the protocol version used in the request.. /// </summary> - protected Protocol Protocol { - get { return Protocol.Lookup(this.RequestMessage.Version); } - } + protected Protocol Protocol { get; private set; } #region IRequest Methods |