diff options
Diffstat (limited to 'src')
46 files changed, 429 insertions, 136 deletions
diff --git a/src/DotNetOpenAuth.AspNet/Clients/OAuth/DotNetOpenAuthWebConsumer.cs b/src/DotNetOpenAuth.AspNet/Clients/OAuth/DotNetOpenAuthWebConsumer.cs index 09a56a8..d2449af 100644 --- a/src/DotNetOpenAuth.AspNet/Clients/OAuth/DotNetOpenAuthWebConsumer.cs +++ b/src/DotNetOpenAuth.AspNet/Clients/OAuth/DotNetOpenAuthWebConsumer.cs @@ -68,7 +68,7 @@ namespace DotNetOpenAuth.AspNet.Clients { /// <summary> /// The process user authorization. /// </summary> - /// <param name="cancellationToken"></param> + /// <param name="cancellationToken">The cancellation token.</param> /// <returns> /// The response message. /// </returns> diff --git a/src/DotNetOpenAuth.AspNet/Clients/OAuth2/OAuth2Client.cs b/src/DotNetOpenAuth.AspNet/Clients/OAuth2/OAuth2Client.cs index c9bfafc..6e49d51 100644 --- a/src/DotNetOpenAuth.AspNet/Clients/OAuth2/OAuth2Client.cs +++ b/src/DotNetOpenAuth.AspNet/Clients/OAuth2/OAuth2Client.cs @@ -81,7 +81,7 @@ namespace DotNetOpenAuth.AspNet.Clients { /// <returns> /// An instance of <see cref="AuthenticationResult" /> containing authentication result. /// </returns> - /// <exception cref="System.InvalidOperationException"></exception> + /// <exception cref="System.InvalidOperationException">Always thrown.</exception> public Task<AuthenticationResult> VerifyAuthenticationAsync(HttpContextBase context, CancellationToken cancellationToken = default(CancellationToken)) { throw new InvalidOperationException(WebResources.OAuthRequireReturnUrl); } diff --git a/src/DotNetOpenAuth.AspNet/Clients/OpenID/OpenIDClient.cs b/src/DotNetOpenAuth.AspNet/Clients/OpenID/OpenIDClient.cs index 68ea20f..f5914b4 100644 --- a/src/DotNetOpenAuth.AspNet/Clients/OpenID/OpenIDClient.cs +++ b/src/DotNetOpenAuth.AspNet/Clients/OpenID/OpenIDClient.cs @@ -109,7 +109,7 @@ namespace DotNetOpenAuth.AspNet.Clients { /// <returns> /// An instance of <see cref="AuthenticationResult" /> containing authentication result. /// </returns> - /// <exception cref="System.InvalidOperationException"></exception> + /// <exception cref="System.InvalidOperationException">Thrown if no OpenID response was found in the incoming HTTP request.</exception> public virtual async Task<AuthenticationResult> VerifyAuthenticationAsync(HttpContextBase context, CancellationToken cancellationToken = default(CancellationToken)) { IAuthenticationResponse response = await RelyingParty.GetResponseAsync(context.Request, cancellationToken); if (response == null) { diff --git a/src/DotNetOpenAuth.Core/Messaging/Bindings/StandardExpirationBindingElement.cs b/src/DotNetOpenAuth.Core/Messaging/Bindings/StandardExpirationBindingElement.cs index c706e42..f19d4bd 100644 --- a/src/DotNetOpenAuth.Core/Messaging/Bindings/StandardExpirationBindingElement.cs +++ b/src/DotNetOpenAuth.Core/Messaging/Bindings/StandardExpirationBindingElement.cs @@ -15,7 +15,14 @@ namespace DotNetOpenAuth.Messaging.Bindings { /// implementing the <see cref="IExpiringProtocolMessage"/> interface. /// </summary> internal class StandardExpirationBindingElement : IChannelBindingElement { + /// <summary> + /// A reusable pre-completed task that may be returned multiple times to reduce GC pressure. + /// </summary> private static readonly Task<MessageProtections?> NullTask = Task.FromResult<MessageProtections?>(null); + + /// <summary> + /// A reusable pre-completed task that may be returned multiple times to reduce GC pressure. + /// </summary> private static readonly Task<MessageProtections?> CompletedExpirationTask = Task.FromResult<MessageProtections?>(MessageProtections.Expiration); /// <summary> diff --git a/src/DotNetOpenAuth.Core/Messaging/Bindings/StandardReplayProtectionBindingElement.cs b/src/DotNetOpenAuth.Core/Messaging/Bindings/StandardReplayProtectionBindingElement.cs index 6c062d6..65c7882 100644 --- a/src/DotNetOpenAuth.Core/Messaging/Bindings/StandardReplayProtectionBindingElement.cs +++ b/src/DotNetOpenAuth.Core/Messaging/Bindings/StandardReplayProtectionBindingElement.cs @@ -15,7 +15,14 @@ namespace DotNetOpenAuth.Messaging.Bindings { /// A binding element that checks/verifies a nonce message part. /// </summary> internal class StandardReplayProtectionBindingElement : IChannelBindingElement { + /// <summary> + /// A reusable, precompleted task that can be returned many times to reduce GC pressure. + /// </summary> private static readonly Task<MessageProtections?> NullTask = Task.FromResult<MessageProtections?>(null); + + /// <summary> + /// A reusable, precompleted task that can be returned many times to reduce GC pressure. + /// </summary> private static readonly Task<MessageProtections?> CompletedReplayProtectionTask = Task.FromResult<MessageProtections?>(MessageProtections.ReplayProtection); /// <summary> diff --git a/src/DotNetOpenAuth.Core/Messaging/Channel.cs b/src/DotNetOpenAuth.Core/Messaging/Channel.cs index 6aaf8ea..a134180 100644 --- a/src/DotNetOpenAuth.Core/Messaging/Channel.cs +++ b/src/DotNetOpenAuth.Core/Messaging/Channel.cs @@ -330,11 +330,14 @@ namespace DotNetOpenAuth.Messaging { /// <summary> /// Gets the protocol message embedded in the given HTTP request, if present. /// </summary> - /// <returns>The deserialized message, if one is found. Null otherwise.</returns> + /// <param name="cancellationToken">The cancellation token.</param> + /// <returns> + /// The deserialized message, if one is found. Null otherwise. + /// </returns> + /// <exception cref="InvalidOperationException">Thrown when <see cref="HttpContext.Current" /> is null.</exception> /// <remarks> /// Requires an HttpContext.Current context. /// </remarks> - /// <exception cref="InvalidOperationException">Thrown when <see cref="HttpContext.Current"/> is null.</exception> public Task<IDirectedProtocolMessage> ReadFromRequestAsync(CancellationToken cancellationToken) { return this.ReadFromRequestAsync(this.GetRequestFromContext(), cancellationToken); } @@ -716,7 +719,15 @@ namespace DotNetOpenAuth.Messaging { } } + /// <summary> + /// Provides derived-types the opportunity to wrap an <see cref="HttpMessageHandler"/> with another one. + /// </summary> + /// <param name="innerHandler">The inner handler received from <see cref="IHostFactories"/></param> + /// <returns>The handler to use in <see cref="HttpClient"/> instances.</returns> protected virtual HttpMessageHandler WrapMessageHandler(HttpMessageHandler innerHandler) { + //TODO: make sure that everyone calls this to wrap their handlers rather than using the one directly returned + //from IHostFactories. + // No wrapping by default. return innerHandler; } @@ -971,7 +982,7 @@ namespace DotNetOpenAuth.Messaging { /// <returns> /// A task that completes with the asynchronous operation. /// </returns> - /// <exception cref="UnprotectedMessageException"></exception> + /// <exception cref="UnprotectedMessageException">Thrown if the message does not have the minimal required protections applied.</exception> /// <remarks> /// This method should NOT be called by derived types /// except when sending ONE WAY request messages. @@ -1145,7 +1156,7 @@ namespace DotNetOpenAuth.Messaging { /// <returns> /// A task that completes with the asynchronous operation. /// </returns> - /// <exception cref="UnprotectedMessageException"></exception> + /// <exception cref="UnprotectedMessageException">Thrown if the message does not have the minimal required protections applied.</exception> /// <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 async Task ProcessIncomingMessageAsync(IProtocolMessage message, CancellationToken cancellationToken) { diff --git a/src/DotNetOpenAuth.Core/Messaging/MessagingUtilities.cs b/src/DotNetOpenAuth.Core/Messaging/MessagingUtilities.cs index 5286f84..b84bd48 100644 --- a/src/DotNetOpenAuth.Core/Messaging/MessagingUtilities.cs +++ b/src/DotNetOpenAuth.Core/Messaging/MessagingUtilities.cs @@ -380,11 +380,25 @@ namespace DotNetOpenAuth.Messaging { return GetPublicFacingUrl(request, request.ServerVariables); } + /// <summary> + /// Wraps a response message as an MVC <see cref="ActionResult"/> so it can be conveniently returned from an MVC controller's action method. + /// </summary> + /// <param name="response">The response message.</param> + /// <returns>An <see cref="ActionResult"/> instance.</returns> public static ActionResult AsActionResult(this HttpResponseMessage response) { Requires.NotNull(response, "response"); return new HttpResponseMessageActionResult(response); } + /// <summary> + /// Sends a response message to the HTTP client. + /// </summary> + /// <param name="response">The response message.</param> + /// <param name="responseContext">The response context to send the response with.</param> + /// <param name="cancellationToken">The cancellation token.</param> + /// <returns> + /// A task that completes with the asynchronous operation. + /// </returns> public static async Task SendAsync(this HttpResponseMessage response, HttpResponseBase responseContext = null, CancellationToken cancellationToken = default(CancellationToken)) { Requires.NotNull(response, "response"); if (responseContext == null) { @@ -405,26 +419,41 @@ namespace DotNetOpenAuth.Messaging { } } - public static void Send(this HttpResponseMessage response, HttpContextBase context = null) { - Requires.NotNull(response, "response"); - if (context == null) { - ErrorUtilities.VerifyHttpContext(); - context = new HttpContextWrapper(HttpContext.Current); - } - - SendAsync(response, context.Response).GetAwaiter().GetResult(); + /// <summary> + /// Sends a response message to the HTTP client. + /// </summary> + /// <param name="response">The response message.</param> + /// <param name="responseContext">The response context to send the response with.</param> + /// <param name="cancellationToken">The cancellation token.</param> + public static void Send(this HttpResponseMessage response, HttpResponseBase responseContext = null, CancellationToken cancellationToken = default(CancellationToken)) { + SendAsync(response, responseContext, cancellationToken).GetAwaiter().GetResult(); } + /// <summary> + /// Disposes a value if it is not null. + /// </summary> + /// <param name="disposable">The disposable value.</param> internal static void DisposeIfNotNull(this IDisposable disposable) { if (disposable != null) { disposable.Dispose(); } } - internal static HttpRequestMessage Clone(this HttpRequestMessage original, Uri newRequestUri = null) { + /// <summary> + /// Clones the specified <see cref="HttpRequestMessage"/> so it can be re-sent. + /// </summary> + /// <param name="original">The original message.</param> + /// <returns>The cloned message</returns> + /// <remarks> + /// This is useful when an HTTP request fails, and after a little tweaking should be resent. + /// Since <see cref="HttpRequestMessage"/> remembers it was already sent, it will not permit being + /// sent a second time. This method clones the message so its contents are identical but allows + /// re-sending. + /// </remarks> + internal static HttpRequestMessage Clone(this HttpRequestMessage original) { Requires.NotNull(original, "original"); - var clone = new HttpRequestMessage(original.Method, newRequestUri ?? original.RequestUri); + var clone = new HttpRequestMessage(original.Method, original.RequestUri); clone.Content = original.Content; foreach (var header in original.Headers) { clone.Headers.Add(header.Key, header.Value); @@ -511,9 +540,10 @@ namespace DotNetOpenAuth.Messaging { /// <summary> /// Assembles the content of the HTTP Authorization or WWW-Authenticate header. /// </summary> - /// <param name="scheme">The scheme.</param> /// <param name="fields">The fields to include.</param> - /// <returns>A value prepared for an HTTP header.</returns> + /// <returns> + /// A value prepared for an HTTP header. + /// </returns> internal static string AssembleAuthorizationHeader(IEnumerable<KeyValuePair<string, string>> fields) { Requires.NotNull(fields, "fields"); @@ -639,6 +669,8 @@ namespace DotNetOpenAuth.Messaging { /// Adds a Set-Cookie HTTP header for the specified cookie. /// WARNING: support for cookie properties is currently VERY LIMITED. /// </summary> + /// <param name="headers">The headers.</param> + /// <param name="cookie">The cookie.</param> internal static void SetCookie(this HttpResponseHeaders headers, Cookie cookie) { Requires.NotNull(headers, "headers"); Requires.NotNull(cookie, "cookie"); @@ -1531,6 +1563,12 @@ namespace DotNetOpenAuth.Messaging { } } + /// <summary> + /// Gets the URI that contains the entire payload that would be sent by the browser for the specified redirect-based request message. + /// </summary> + /// <param name="response">The redirecting response message.</param> + /// <returns>The absolute URI that could be retrieved to send the same message the browser would.</returns> + /// <exception cref="System.NotSupportedException">Thrown if the message is not a redirect message.</exception> internal static Uri GetDirectUriRequest(this HttpResponseMessage response) { Requires.NotNull(response, "response"); Requires.Argument( @@ -2009,16 +2047,30 @@ namespace DotNetOpenAuth.Messaging { #endregion } + /// <summary> + /// An MVC <see cref="ActionResult"/> that wraps an <see cref="HttpResponseMessage"/> + /// </summary> private class HttpResponseMessageActionResult : ActionResult { + /// <summary> + /// The wrapped response. + /// </summary> private readonly HttpResponseMessage response; + /// <summary> + /// Initializes a new instance of the <see cref="HttpResponseMessageActionResult"/> class. + /// </summary> + /// <param name="response">The response.</param> internal HttpResponseMessageActionResult(HttpResponseMessage response) { Requires.NotNull(response, "response"); this.response = response; } + /// <summary> + /// Enables processing of the result of an action method by a custom type that inherits from the <see cref="T:System.Web.Mvc.ActionResult" /> class. + /// </summary> + /// <param name="context">The context in which the result is executed. The context information includes the controller, HTTP content, request context, and route data.</param> public override void ExecuteResult(ControllerContext context) { - this.response.Send(context.HttpContext); + this.response.Send(context.HttpContext.Response); } } } diff --git a/src/DotNetOpenAuth.Core/Messaging/MultipartContentMember.cs b/src/DotNetOpenAuth.Core/Messaging/MultipartContentMember.cs index cc9d806..fd5bfb5 100644 --- a/src/DotNetOpenAuth.Core/Messaging/MultipartContentMember.cs +++ b/src/DotNetOpenAuth.Core/Messaging/MultipartContentMember.cs @@ -12,7 +12,16 @@ namespace DotNetOpenAuth.Messaging { using System.Text; using System.Threading.Tasks; + /// <summary> + /// Describes a part from a multi-part POST. + /// </summary> public struct MultipartContentMember { + /// <summary> + /// Initializes a new instance of the <see cref="MultipartContentMember"/> struct. + /// </summary> + /// <param name="content">The content.</param> + /// <param name="name">The name of this part as it may come from an HTML form.</param> + /// <param name="fileName">Name of the file.</param> public MultipartContentMember(HttpContent content, string name = null, string fileName = null) : this() { this.Content = content; @@ -20,10 +29,28 @@ namespace DotNetOpenAuth.Messaging { this.FileName = fileName; } + /// <summary> + /// Gets or sets the content. + /// </summary> + /// <value> + /// The content. + /// </value> public HttpContent Content { get; set; } + /// <summary> + /// Gets or sets the HTML form name. + /// </summary> + /// <value> + /// The name. + /// </value> public string Name { get; set; } + /// <summary> + /// Gets or sets the name of the file. + /// </summary> + /// <value> + /// The name of the file. + /// </value> public string FileName { get; set; } } } diff --git a/src/DotNetOpenAuth.Core/Messaging/ProtocolFaultResponseException.cs b/src/DotNetOpenAuth.Core/Messaging/ProtocolFaultResponseException.cs index 9460417..b5cab3b 100644 --- a/src/DotNetOpenAuth.Core/Messaging/ProtocolFaultResponseException.cs +++ b/src/DotNetOpenAuth.Core/Messaging/ProtocolFaultResponseException.cs @@ -64,7 +64,10 @@ namespace DotNetOpenAuth.Messaging { /// <summary> /// Creates the HTTP response to forward to the client to report the error. /// </summary> - /// <returns>The HTTP response.</returns> + /// <param name="cancellationToken">The cancellation token.</param> + /// <returns> + /// The HTTP response. + /// </returns> public Task<HttpResponseMessage> CreateErrorResponseAsync(CancellationToken cancellationToken) { return this.channel.PrepareResponseAsync(this.ErrorResponseMessage, cancellationToken); } diff --git a/src/DotNetOpenAuth.Core/Util.cs b/src/DotNetOpenAuth.Core/Util.cs index ebbaaa4..00d033f 100644 --- a/src/DotNetOpenAuth.Core/Util.cs +++ b/src/DotNetOpenAuth.Core/Util.cs @@ -29,6 +29,9 @@ namespace DotNetOpenAuth { /// </summary> internal const string DefaultNamespace = "DotNetOpenAuth"; + /// <summary> + /// A lazily-assembled string that describes the version of the library. + /// </summary> private static readonly Lazy<string> libraryVersionLazy = new Lazy<string>(delegate { var assembly = Assembly.GetExecutingAssembly(); string assemblyFullName = assembly.FullName; @@ -40,16 +43,19 @@ namespace DotNetOpenAuth { }); /// <summary> - /// The web.config file-specified provider of web resource URLs. + /// A lazily-assembled string that describes the version of the library. /// </summary> - private static IEmbeddedResourceRetrieval embeddedResourceRetrieval = MessagingElement.Configuration.EmbeddedResourceRetrievalProvider.CreateInstance(null, false, null); - private static readonly Lazy<ProductInfoHeaderValue> libraryVersionHeaderLazy = new Lazy<ProductInfoHeaderValue>(delegate { var assemblyName = Assembly.GetExecutingAssembly().GetName(); return new ProductInfoHeaderValue(assemblyName.Name, AssemblyFileVersion); }); /// <summary> + /// The web.config file-specified provider of web resource URLs. + /// </summary> + private static IEmbeddedResourceRetrieval embeddedResourceRetrieval = MessagingElement.Configuration.EmbeddedResourceRetrievalProvider.CreateInstance(null, false, null); + + /// <summary> /// Gets a human-readable description of the library name and version, including /// whether the build is an official or private one. /// </summary> diff --git a/src/DotNetOpenAuth.OAuth.Consumer/OAuth/ConsumerBase.cs b/src/DotNetOpenAuth.OAuth.Consumer/OAuth/ConsumerBase.cs index afb4c95..dcde81c 100644 --- a/src/DotNetOpenAuth.OAuth.Consumer/OAuth/ConsumerBase.cs +++ b/src/DotNetOpenAuth.OAuth.Consumer/OAuth/ConsumerBase.cs @@ -225,18 +225,17 @@ namespace DotNetOpenAuth.OAuth { } /// <summary> - /// Prepares an OAuth message that begins an authorization request that will + /// Prepares an OAuth message that begins an authorization request that will /// redirect the user to the Service Provider to provide that authorization. /// </summary> - /// <param name="callback"> - /// An optional Consumer URL that the Service Provider should redirect the - /// User Agent to upon successful authorization. - /// </param> + /// <param name="callback">An optional Consumer URL that the Service Provider should redirect the + /// User Agent to upon successful authorization.</param> /// <param name="requestParameters">Extra parameters to add to the request token message. Optional.</param> /// <param name="redirectParameters">Extra parameters to add to the redirect to Service Provider message. Optional.</param> - /// <param name="requestToken">The request token that must be exchanged for an access token after the user has provided authorization.</param> /// <param name="cancellationToken">The cancellation token.</param> - /// <returns>The pending user agent redirect based message to be sent as an HttpResponse.</returns> + /// <returns> + /// The pending user agent redirect based message to be sent as an HttpResponse. + /// </returns> [SuppressMessage("Microsoft.Design", "CA1021:AvoidOutParameters", MessageId = "3#", Justification = "Two results")] protected internal async Task<UserAuthorizationRequest> PrepareRequestUserAuthorizationAsync(Uri callback, IDictionary<string, string> requestParameters, IDictionary<string, string> redirectParameters, CancellationToken cancellationToken = default(CancellationToken)) { // Obtain an unauthorized request token. Assume the OAuth version given in the service description. diff --git a/src/DotNetOpenAuth.OAuth.Consumer/OAuth/WebConsumer.cs b/src/DotNetOpenAuth.OAuth.Consumer/OAuth/WebConsumer.cs index 75a1217..49a54a0 100644 --- a/src/DotNetOpenAuth.OAuth.Consumer/OAuth/WebConsumer.cs +++ b/src/DotNetOpenAuth.OAuth.Consumer/OAuth/WebConsumer.cs @@ -59,7 +59,7 @@ namespace DotNetOpenAuth.OAuth { /// <param name="redirectParameters">Extra parameters to add to the redirect to Service Provider message. Optional.</param> /// <param name="cancellationToken">The cancellation token.</param> /// <returns>The pending user agent redirect based message to be sent as an HttpResponse.</returns> - public Task<UserAuthorizationRequest> PrepareRequestUserAuthorizationAsync(Uri callback, IDictionary<string, string> requestParameters, IDictionary<string, string> redirectParameters, CancellationToken cancellationToken = default(CancellationToken)) { + public new Task<UserAuthorizationRequest> PrepareRequestUserAuthorizationAsync(Uri callback, IDictionary<string, string> requestParameters, IDictionary<string, string> redirectParameters, CancellationToken cancellationToken = default(CancellationToken)) { return base.PrepareRequestUserAuthorizationAsync(callback, requestParameters, redirectParameters, cancellationToken); } diff --git a/src/DotNetOpenAuth.OAuth/OAuth/ChannelElements/OAuthHttpMethodBindingElement.cs b/src/DotNetOpenAuth.OAuth/OAuth/ChannelElements/OAuthHttpMethodBindingElement.cs index 67192ee..60df47f 100644 --- a/src/DotNetOpenAuth.OAuth/OAuth/ChannelElements/OAuthHttpMethodBindingElement.cs +++ b/src/DotNetOpenAuth.OAuth/OAuth/ChannelElements/OAuthHttpMethodBindingElement.cs @@ -17,6 +17,17 @@ namespace DotNetOpenAuth.OAuth.ChannelElements { /// Sets the HTTP Method property on a signed message before the signing module gets to it. /// </summary> internal class OAuthHttpMethodBindingElement : IChannelBindingElement { + /// <summary> + /// A reusable pre-completed task that may be returned multiple times to reduce GC pressure. + /// </summary> + private static readonly Task<MessageProtections?> NullTask = Task.FromResult<MessageProtections?>(null); + + /// <summary> + /// A reusable pre-completed task that may be returned multiple times to reduce GC pressure. + /// </summary> + private static readonly Task<MessageProtections?> NoneTask = + Task.FromResult<MessageProtections?>(MessageProtections.None); + #region IChannelBindingElement Members /// <summary> @@ -40,20 +51,20 @@ namespace DotNetOpenAuth.OAuth.ChannelElements { /// True if the <paramref name="message"/> applied to this binding element /// and the operation was successful. False otherwise. /// </returns> - public async Task<MessageProtections?> ProcessOutgoingMessageAsync(IProtocolMessage message, CancellationToken cancellationToken) { + public Task<MessageProtections?> ProcessOutgoingMessageAsync(IProtocolMessage message, CancellationToken cancellationToken) { var oauthMessage = message as ITamperResistantOAuthMessage; if (oauthMessage != null) { HttpDeliveryMethods transmissionMethod = oauthMessage.HttpMethods; try { oauthMessage.HttpMethod = MessagingUtilities.GetHttpVerb(transmissionMethod); - return MessageProtections.None; + return NoneTask; } catch (ArgumentException ex) { Logger.OAuth.Error("Unrecognized HttpDeliveryMethods value.", ex); - return null; + return NullTask; } } else { - return null; + return NullTask; } } diff --git a/src/DotNetOpenAuth.OAuth2.AuthorizationServer/OAuth2/ChannelElements/AuthServerBindingElementBase.cs b/src/DotNetOpenAuth.OAuth2.AuthorizationServer/OAuth2/ChannelElements/AuthServerBindingElementBase.cs index 001183a..f77ca91 100644 --- a/src/DotNetOpenAuth.OAuth2.AuthorizationServer/OAuth2/ChannelElements/AuthServerBindingElementBase.cs +++ b/src/DotNetOpenAuth.OAuth2.AuthorizationServer/OAuth2/ChannelElements/AuthServerBindingElementBase.cs @@ -58,7 +58,7 @@ namespace DotNetOpenAuth.OAuth2.ChannelElements { /// 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> - /// <param name="cancellationToken"></param> + /// <param name="cancellationToken">The cancellation token.</param> /// <returns> /// The protections (if any) that this binding element applied to the message. /// Null if this binding element did not even apply to this binding element. diff --git a/src/DotNetOpenAuth.OpenId.Provider.UI/OpenId/Provider/ProviderEndpoint.cs b/src/DotNetOpenAuth.OpenId.Provider.UI/OpenId/Provider/ProviderEndpoint.cs index 65086d7..c5c3540 100644 --- a/src/DotNetOpenAuth.OpenId.Provider.UI/OpenId/Provider/ProviderEndpoint.cs +++ b/src/DotNetOpenAuth.OpenId.Provider.UI/OpenId/Provider/ProviderEndpoint.cs @@ -231,7 +231,7 @@ namespace DotNetOpenAuth.OpenId.Provider { if (request.IsResponseReady) { PendingAuthenticationRequest = null; var response = await Provider.PrepareResponseAsync(request, CancellationToken.None); - response.Send(new HttpContextWrapper(this.Context)); + response.Send(new HttpContextWrapper(this.Context).Response); } } } diff --git a/src/DotNetOpenAuth.OpenId.Provider/OpenId/Provider/AnonymousRequest.cs b/src/DotNetOpenAuth.OpenId.Provider/OpenId/Provider/AnonymousRequest.cs index ecb8a40..f25a107 100644 --- a/src/DotNetOpenAuth.OpenId.Provider/OpenId/Provider/AnonymousRequest.cs +++ b/src/DotNetOpenAuth.OpenId.Provider/OpenId/Provider/AnonymousRequest.cs @@ -83,7 +83,7 @@ namespace DotNetOpenAuth.OpenId.Provider { /// <returns>The response message.</returns> protected override async Task<IProtocolMessage> GetResponseMessageAsync(CancellationToken cancellationToken) { if (this.IsApproved.HasValue) { - return this.IsApproved.Value ? (IProtocolMessage)this.positiveResponse : (await this.GetNegativeResponseAsync()); + return this.IsApproved.Value ? (IProtocolMessage)this.positiveResponse : await this.GetNegativeResponseAsync(); } else { return null; } diff --git a/src/DotNetOpenAuth.OpenId.Provider/OpenId/Provider/AuthenticationRequest.cs b/src/DotNetOpenAuth.OpenId.Provider/OpenId/Provider/AuthenticationRequest.cs index 7d66ff8..6e67f53 100644 --- a/src/DotNetOpenAuth.OpenId.Provider/OpenId/Provider/AuthenticationRequest.cs +++ b/src/DotNetOpenAuth.OpenId.Provider/OpenId/Provider/AuthenticationRequest.cs @@ -220,7 +220,7 @@ namespace DotNetOpenAuth.OpenId.Provider { /// <returns>The response message.</returns> protected override async Task<IProtocolMessage> GetResponseMessageAsync(CancellationToken cancellationToken) { if (this.IsAuthenticated.HasValue) { - return this.IsAuthenticated.Value ? (IProtocolMessage)this.positiveResponse : (await this.GetNegativeResponseAsync()); + return this.IsAuthenticated.Value ? (IProtocolMessage)this.positiveResponse : await this.GetNegativeResponseAsync(); } else { return null; } diff --git a/src/DotNetOpenAuth.OpenId.Provider/OpenId/Provider/Extensions/ExtensionsInteropHelper.cs b/src/DotNetOpenAuth.OpenId.Provider/OpenId/Provider/Extensions/ExtensionsInteropHelper.cs index aedf119..45a59d2 100644 --- a/src/DotNetOpenAuth.OpenId.Provider/OpenId/Provider/Extensions/ExtensionsInteropHelper.cs +++ b/src/DotNetOpenAuth.OpenId.Provider/OpenId/Provider/Extensions/ExtensionsInteropHelper.cs @@ -86,7 +86,8 @@ namespace DotNetOpenAuth.OpenId.Provider.Extensions { /// </remarks> internal static async Task ConvertSregToMatchRequestAsync(this Provider.IHostProcessedRequest request, CancellationToken cancellationToken) { var req = (Provider.HostProcessedRequest)request; - var response = (await req.GetResponseAsync(cancellationToken)) as IProtocolMessageWithExtensions; // negative responses don't support extensions. + var protocolMessage = await req.GetResponseAsync(cancellationToken); + var response = protocolMessage as IProtocolMessageWithExtensions; // negative responses don't support extensions. var sregRequest = request.GetExtension<ClaimsRequest>(); if (sregRequest != null && response != null) { if (sregRequest.Synthesized) { diff --git a/src/DotNetOpenAuth.OpenId.Provider/OpenId/Provider/HostProcessedRequest.cs b/src/DotNetOpenAuth.OpenId.Provider/OpenId/Provider/HostProcessedRequest.cs index c4c2674..7671194 100644 --- a/src/DotNetOpenAuth.OpenId.Provider/OpenId/Provider/HostProcessedRequest.cs +++ b/src/DotNetOpenAuth.OpenId.Provider/OpenId/Provider/HostProcessedRequest.cs @@ -119,6 +119,16 @@ namespace DotNetOpenAuth.OpenId.Provider { return this.realmDiscoveryResult.Value; } + #endregion + + /// <summary> + /// Gets the negative response. + /// </summary> + /// <returns>The negative assertion message.</returns> + protected Task<NegativeAssertionResponse> GetNegativeResponseAsync() { + return this.negativeResponse.Value; + } + /// <summary> /// Gets a value indicating whether verification of the return URL claimed by the Relying Party /// succeeded. @@ -172,15 +182,5 @@ namespace DotNetOpenAuth.OpenId.Provider { return RelyingPartyDiscoveryResult.NoMatchingReturnTo; } - - #endregion - - /// <summary> - /// Gets the negative response. - /// </summary> - /// <returns>The negative assertion message.</returns> - protected Task<NegativeAssertionResponse> GetNegativeResponseAsync() { - return this.negativeResponse.Value; - } } } diff --git a/src/DotNetOpenAuth.OpenId.Provider/OpenId/Provider/OpenIdProvider.cs b/src/DotNetOpenAuth.OpenId.Provider/OpenId/Provider/OpenIdProvider.cs index 3b44e59..b89aeca 100644 --- a/src/DotNetOpenAuth.OpenId.Provider/OpenId/Provider/OpenIdProvider.cs +++ b/src/DotNetOpenAuth.OpenId.Provider/OpenId/Provider/OpenIdProvider.cs @@ -202,15 +202,18 @@ namespace DotNetOpenAuth.OpenId.Provider { /// <summary> /// Gets the incoming OpenID request if there is one, or null if none was detected. /// </summary> - /// <returns>The request that the hosting Provider should possibly process and then transmit the response for.</returns> + /// <param name="cancellationToken">The cancellation token.</param> + /// <returns> + /// The request that the hosting Provider should possibly process and then transmit the response for. + /// </returns> + /// <exception cref="InvalidOperationException">Thrown if <see cref="HttpContext.Current">HttpContext.Current</see> == <c>null</c>.</exception> + /// <exception cref="ProtocolException">Thrown if the incoming message is recognized but deviates from the protocol specification irrecoverably.</exception> /// <remarks> - /// <para>Requests may be infrastructural to OpenID and allow auto-responses, or they may + /// <para>Requests may be infrastructural to OpenID and allow auto-responses, or they may /// be authentication requests where the Provider site has to make decisions based /// on its own user database and policies.</para> - /// <para>Requires an <see cref="HttpContext.Current">HttpContext.Current</see> context.</para> + /// <para>Requires an <see cref="HttpContext.Current">HttpContext.Current</see> context.</para> /// </remarks> - /// <exception cref="InvalidOperationException">Thrown if <see cref="HttpContext.Current">HttpContext.Current</see> == <c>null</c>.</exception> - /// <exception cref="ProtocolException">Thrown if the incoming message is recognized but deviates from the protocol specification irrecoverably.</exception> public Task<IRequest> GetRequestAsync(CancellationToken cancellationToken) { return this.GetRequestAsync(this.Channel.GetRequestFromContext(), cancellationToken); } diff --git a/src/DotNetOpenAuth.OpenId.RelyingParty.UI/OpenId/RelyingParty/OpenIdAjaxRelyingParty.cs b/src/DotNetOpenAuth.OpenId.RelyingParty.UI/OpenId/RelyingParty/OpenIdAjaxRelyingParty.cs index cef5017..52a204d 100644 --- a/src/DotNetOpenAuth.OpenId.RelyingParty.UI/OpenId/RelyingParty/OpenIdAjaxRelyingParty.cs +++ b/src/DotNetOpenAuth.OpenId.RelyingParty.UI/OpenId/RelyingParty/OpenIdAjaxRelyingParty.cs @@ -63,7 +63,7 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { /// <para>Any individual generated request can satisfy the authentication. /// The generated requests are sorted in preferred order. /// Each request is generated as it is enumerated to. Associations are created only as - /// <see cref="IAuthenticationRequest.RedirectingResponse" /> is called.</para> + /// <see cref="IAuthenticationRequest.GetRedirectingResponseAsync" /> is called.</para> /// <para>No exception is thrown if no OpenID endpoints were discovered. /// An empty enumerable is returned instead.</para> /// </remarks> diff --git a/src/DotNetOpenAuth.OpenId.RelyingParty.UI/OpenId/RelyingParty/OpenIdButton.cs b/src/DotNetOpenAuth.OpenId.RelyingParty.UI/OpenId/RelyingParty/OpenIdButton.cs index 958c721..d5e9e51 100644 --- a/src/DotNetOpenAuth.OpenId.RelyingParty.UI/OpenId/RelyingParty/OpenIdButton.cs +++ b/src/DotNetOpenAuth.OpenId.RelyingParty.UI/OpenId/RelyingParty/OpenIdButton.cs @@ -58,6 +58,9 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { #endregion + /// <summary> + /// Stores the asynchronously created message that can be used to initiate a redirection-based authentication request. + /// </summary> private HttpResponseMessage authenticationRequestRedirect; /// <summary> diff --git a/src/DotNetOpenAuth.OpenId.RelyingParty.UI/OpenId/RelyingParty/OpenIdLogin.cs b/src/DotNetOpenAuth.OpenId.RelyingParty.UI/OpenId/RelyingParty/OpenIdLogin.cs index d6ce3ce..f61f824 100644 --- a/src/DotNetOpenAuth.OpenId.RelyingParty.UI/OpenId/RelyingParty/OpenIdLogin.cs +++ b/src/DotNetOpenAuth.OpenId.RelyingParty.UI/OpenId/RelyingParty/OpenIdLogin.cs @@ -939,7 +939,8 @@ idselector_input_id = '" + this.ClientID + @"'; return; } - IAuthenticationRequest request = (await this.CreateRequestsAsync(CancellationToken.None)).FirstOrDefault(); + var authenticationRequests = await this.CreateRequestsAsync(CancellationToken.None); + IAuthenticationRequest request = authenticationRequests.FirstOrDefault(); if (request != null) { await this.LogOnAsync(request, CancellationToken.None); } else { diff --git a/src/DotNetOpenAuth.OpenId.RelyingParty.UI/OpenId/RelyingParty/OpenIdRelyingPartyAjaxControlBase.cs b/src/DotNetOpenAuth.OpenId.RelyingParty.UI/OpenId/RelyingParty/OpenIdRelyingPartyAjaxControlBase.cs index 9ad53b8..defd15c 100644 --- a/src/DotNetOpenAuth.OpenId.RelyingParty.UI/OpenId/RelyingParty/OpenIdRelyingPartyAjaxControlBase.cs +++ b/src/DotNetOpenAuth.OpenId.RelyingParty.UI/OpenId/RelyingParty/OpenIdRelyingPartyAjaxControlBase.cs @@ -68,7 +68,7 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { private const string AuthDataViewStateKey = "AuthData"; /// <summary> - /// The viewstate key to use for storing the value of the <see cref="AuthenticationResponse"/> property. + /// The viewstate key to use for storing the value of the <see cref="GetAuthenticationResponseAsync"/> method. /// </summary> private const string AuthenticationResponseViewStateKey = "AuthenticationResponse"; diff --git a/src/DotNetOpenAuth.OpenId.RelyingParty.UI/OpenId/RelyingParty/OpenIdRelyingPartyControlBase.cs b/src/DotNetOpenAuth.OpenId.RelyingParty.UI/OpenId/RelyingParty/OpenIdRelyingPartyControlBase.cs index 6026d1a..dc8ba54 100644 --- a/src/DotNetOpenAuth.OpenId.RelyingParty.UI/OpenId/RelyingParty/OpenIdRelyingPartyControlBase.cs +++ b/src/DotNetOpenAuth.OpenId.RelyingParty.UI/OpenId/RelyingParty/OpenIdRelyingPartyControlBase.cs @@ -518,7 +518,8 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { /// A task that completes with the asynchronous operation. /// </returns> public async Task LogOnAsync(CancellationToken cancellationToken) { - IAuthenticationRequest request = (await this.CreateRequestsAsync(cancellationToken)).FirstOrDefault(); + var authenticationRequests = await this.CreateRequestsAsync(cancellationToken); + IAuthenticationRequest request = authenticationRequests.FirstOrDefault(); ErrorUtilities.VerifyProtocol(request != null, OpenIdStrings.OpenIdEndpointNotFound); await this.LogOnAsync(request, cancellationToken); } @@ -609,11 +610,12 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { } /// <summary> - /// Creates the authentication requests for the value set in the <see cref="Identifier"/> property. + /// Creates the authentication requests for the value set in the <see cref="Identifier" /> property. /// </summary> + /// <param name="cancellationToken">The cancellation token.</param> /// <returns> /// A sequence of authentication requests, any one of which may be - /// used to determine the user's control of the <see cref="IAuthenticationRequest.ClaimedIdentifier"/>. + /// used to determine the user's control of the <see cref="IAuthenticationRequest.ClaimedIdentifier" />. /// </returns> protected Task<IEnumerable<IAuthenticationRequest>> CreateRequestsAsync(CancellationToken cancellationToken) { RequiresEx.ValidState(this.Identifier != null, OpenIdStrings.NoIdentifierSet); @@ -670,6 +672,10 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { /// <summary> /// Notifies the user agent via an AJAX response of a completed authentication attempt. /// </summary> + /// <param name="cancellationToken">The cancellation token.</param> + /// <returns> + /// A task that completes with the asynchronous operation. + /// </returns> protected virtual Task ScriptClosingPopupOrIFrameAsync(CancellationToken cancellationToken) { return this.RelyingParty.ProcessResponseFromPopupAsync(cancellationToken); } diff --git a/src/DotNetOpenAuth.OpenId.RelyingParty/OpenId/ChannelElements/RelyingPartySecurityOptions.cs b/src/DotNetOpenAuth.OpenId.RelyingParty/OpenId/ChannelElements/RelyingPartySecurityOptions.cs index 90910b7..b3a3f79 100644 --- a/src/DotNetOpenAuth.OpenId.RelyingParty/OpenId/ChannelElements/RelyingPartySecurityOptions.cs +++ b/src/DotNetOpenAuth.OpenId.RelyingParty/OpenId/ChannelElements/RelyingPartySecurityOptions.cs @@ -15,8 +15,14 @@ namespace DotNetOpenAuth.OpenId.ChannelElements { /// Helps ensure compliance to some properties in the <see cref="RelyingPartySecuritySettings"/>. /// </summary> internal class RelyingPartySecurityOptions : IChannelBindingElement { + /// <summary> + /// A reusable pre-completed task that may be returned multiple times to reduce GC pressure. + /// </summary> private static readonly Task<MessageProtections?> NullTask = Task.FromResult<MessageProtections?>(null); + /// <summary> + /// A reusable pre-completed task that may be returned multiple times to reduce GC pressure. + /// </summary> private static readonly Task<MessageProtections?> NoneTask = Task.FromResult<MessageProtections?>(MessageProtections.None); diff --git a/src/DotNetOpenAuth.OpenId.RelyingParty/OpenId/ChannelElements/ReturnToNonceBindingElement.cs b/src/DotNetOpenAuth.OpenId.RelyingParty/OpenId/ChannelElements/ReturnToNonceBindingElement.cs index 1948215..a919560 100644 --- a/src/DotNetOpenAuth.OpenId.RelyingParty/OpenId/ChannelElements/ReturnToNonceBindingElement.cs +++ b/src/DotNetOpenAuth.OpenId.RelyingParty/OpenId/ChannelElements/ReturnToNonceBindingElement.cs @@ -48,8 +48,14 @@ namespace DotNetOpenAuth.OpenId.ChannelElements { /// only on the RP side and only on some messages.</para> /// </remarks> internal class ReturnToNonceBindingElement : IChannelBindingElement { + /// <summary> + /// A reusable, precompleted task that can be returned many times to reduce GC pressure. + /// </summary> private static readonly Task<MessageProtections?> NullTask = Task.FromResult<MessageProtections?>(null); + /// <summary> + /// A reusable, precompleted task that can be returned many times to reduce GC pressure. + /// </summary> private static readonly Task<MessageProtections?> ReplayProtectionTask = Task.FromResult<MessageProtections?>(MessageProtections.ReplayProtection); diff --git a/src/DotNetOpenAuth.OpenId.RelyingParty/OpenId/HostMetaDiscoveryService.cs b/src/DotNetOpenAuth.OpenId.RelyingParty/OpenId/HostMetaDiscoveryService.cs index fb4006c..80a1665 100644 --- a/src/DotNetOpenAuth.OpenId.RelyingParty/OpenId/HostMetaDiscoveryService.cs +++ b/src/DotNetOpenAuth.OpenId.RelyingParty/OpenId/HostMetaDiscoveryService.cs @@ -193,6 +193,9 @@ namespace DotNetOpenAuth.OpenId { /// <param name="identifier">The identifier under discovery.</param> /// <param name="response">The response.</param> /// <param name="signingHost">The host name on the certificate that should be used to verify the signature in the XRDS.</param> + /// <returns> + /// A task that completes with the asynchronous operation. + /// </returns> /// <exception cref="ProtocolException">Thrown if the XRDS document has an invalid or a missing signature.</exception> [SuppressMessage("Microsoft.Naming", "CA2204:Literals should be spelled correctly", MessageId = "XmlDSig", Justification = "xml")] private static async Task ValidateXmlDSigAsync(XrdsDocument document, UriIdentifier identifier, HttpResponseMessage response, string signingHost) { @@ -259,6 +262,47 @@ namespace DotNetOpenAuth.OpenId { } /// <summary> + /// Verifies that a certificate chain is trusted. + /// </summary> + /// <param name="certificates">The chain of certificates to verify.</param> + private static void VerifyCertificateChain(IList<X509Certificate2> certificates) { + Requires.NotNullEmptyOrNullElements(certificates, "certificates"); + + // Before calling into the OS to validate the certificate, since that can for some bizzare reason hang for 5 seconds + // on some systems, check a cache of previously verified certificates first. + if (OpenIdElement.Configuration.RelyingParty.HostMetaDiscovery.EnableCertificateValidationCache) { + lock (ApprovedCertificateThumbprintCache) { + // HashSet<T> isn't thread-safe. + if (ApprovedCertificateThumbprintCache.Contains(certificates[0].Thumbprint)) { + return; + } + } + } + + // Verify that we trust the signer of the certificates. + // Start by trying to validate just the certificate used to sign the XRDS document, + // since we can do that with partial trust. + Logger.OpenId.Debug("Verifying that we trust the certificate used to sign the discovery document."); + if (!certificates[0].Verify()) { + // We couldn't verify just the signing certificate, so try to verify the whole certificate chain. + try { + Logger.OpenId.Debug("Verifying the whole certificate chain."); + VerifyCertChain(certificates); + Logger.OpenId.Debug("Certificate chain verified."); + } catch (SecurityException) { + Logger.Yadis.Warn("Signing certificate verification failed and we have insufficient code access security permissions to perform certificate chain validation."); + ErrorUtilities.ThrowProtocol(OpenIdStrings.X509CertificateNotTrusted); + } + } + + if (OpenIdElement.Configuration.RelyingParty.HostMetaDiscovery.EnableCertificateValidationCache) { + lock (ApprovedCertificateThumbprintCache) { + ApprovedCertificateThumbprintCache.Add(certificates[0].Thumbprint); + } + } + } + + /// <summary> /// Gets the services for an identifier that are described by an external XRDS document. /// </summary> /// <param name="xrds">The XRD elements to search for described-by services.</param> @@ -332,47 +376,6 @@ namespace DotNetOpenAuth.OpenId { } /// <summary> - /// Verifies that a certificate chain is trusted. - /// </summary> - /// <param name="certificates">The chain of certificates to verify.</param> - private static void VerifyCertificateChain(IList<X509Certificate2> certificates) { - Requires.NotNullEmptyOrNullElements(certificates, "certificates"); - - // Before calling into the OS to validate the certificate, since that can for some bizzare reason hang for 5 seconds - // on some systems, check a cache of previously verified certificates first. - if (OpenIdElement.Configuration.RelyingParty.HostMetaDiscovery.EnableCertificateValidationCache) { - lock (ApprovedCertificateThumbprintCache) { - // HashSet<T> isn't thread-safe. - if (ApprovedCertificateThumbprintCache.Contains(certificates[0].Thumbprint)) { - return; - } - } - } - - // Verify that we trust the signer of the certificates. - // Start by trying to validate just the certificate used to sign the XRDS document, - // since we can do that with partial trust. - Logger.OpenId.Debug("Verifying that we trust the certificate used to sign the discovery document."); - if (!certificates[0].Verify()) { - // We couldn't verify just the signing certificate, so try to verify the whole certificate chain. - try { - Logger.OpenId.Debug("Verifying the whole certificate chain."); - VerifyCertChain(certificates); - Logger.OpenId.Debug("Certificate chain verified."); - } catch (SecurityException) { - Logger.Yadis.Warn("Signing certificate verification failed and we have insufficient code access security permissions to perform certificate chain validation."); - ErrorUtilities.ThrowProtocol(OpenIdStrings.X509CertificateNotTrusted); - } - } - - if (OpenIdElement.Configuration.RelyingParty.HostMetaDiscovery.EnableCertificateValidationCache) { - lock (ApprovedCertificateThumbprintCache) { - ApprovedCertificateThumbprintCache.Add(certificates[0].Thumbprint); - } - } - } - - /// <summary> /// Gets the XRDS HTTP response for a given identifier. /// </summary> /// <param name="identifier">The identifier.</param> @@ -479,17 +482,35 @@ namespace DotNetOpenAuth.OpenId { return result; } + /// <summary> + /// A compound result of some value with the signing host. + /// </summary> + /// <typeparam name="T">The type of the primary result.</typeparam> private struct ResultWithSigningHost<T> : IDisposable { + /// <summary> + /// Initializes a new instance of the <see cref="ResultWithSigningHost{T}"/> struct. + /// </summary> + /// <param name="result">The result.</param> + /// <param name="signingHost">The signing host.</param> internal ResultWithSigningHost(T result, string signingHost) : this() { this.Result = result; this.SigningHost = signingHost; } + /// <summary> + /// Gets the result. + /// </summary> public T Result { get; private set; } + /// <summary> + /// Gets the signing host. + /// </summary> public string SigningHost { get; private set; } + /// <summary> + /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. + /// </summary> public void Dispose() { var disposable = this.Result as IDisposable; disposable.DisposeIfNotNull(); diff --git a/src/DotNetOpenAuth.OpenId.RelyingParty/OpenId/RelyingParty/AssociationManager.cs b/src/DotNetOpenAuth.OpenId.RelyingParty/OpenId/RelyingParty/AssociationManager.cs index 367c146..86f178b 100644 --- a/src/DotNetOpenAuth.OpenId.RelyingParty/OpenId/RelyingParty/AssociationManager.cs +++ b/src/DotNetOpenAuth.OpenId.RelyingParty/OpenId/RelyingParty/AssociationManager.cs @@ -187,7 +187,7 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { /// The newly created association, or null if no association can be created with /// the given Provider given the current security settings. /// </returns> - /// <exception cref="ProtocolException"></exception> + /// <exception cref="ProtocolException">Create if an error occurs while creating the new association.</exception> private async Task<Association> CreateNewAssociationAsync(IProviderEndpoint provider, AssociateRequest associateRequest, int retriesRemaining, CancellationToken cancellationToken) { Requires.NotNull(provider, "provider"); diff --git a/src/DotNetOpenAuth.OpenId.RelyingParty/OpenId/RelyingParty/AuthenticationRequest.cs b/src/DotNetOpenAuth.OpenId.RelyingParty/OpenId/RelyingParty/AuthenticationRequest.cs index 6298f9c..c7c1fe3 100644 --- a/src/DotNetOpenAuth.OpenId.RelyingParty/OpenId/RelyingParty/AuthenticationRequest.cs +++ b/src/DotNetOpenAuth.OpenId.RelyingParty/OpenId/RelyingParty/AuthenticationRequest.cs @@ -355,7 +355,8 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { // Perform discovery right now (not deferred). IEnumerable<IdentifierDiscoveryResult> serviceEndpoints; try { - var results = (await relyingParty.DiscoverAsync(userSuppliedIdentifier, cancellationToken)).CacheGeneratedResults(); + var identifierDiscoveryResults = await relyingParty.DiscoverAsync(userSuppliedIdentifier, cancellationToken); + var results = identifierDiscoveryResults.CacheGeneratedResults(); // If any OP Identifier service elements were found, we must not proceed // to use any Claimed Identifier services, per OpenID 2.0 sections 7.3.2.2 and 11.2. @@ -404,7 +405,7 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { } /// <summary> - /// Performs deferred request generation for the <see cref="Create" /> method. + /// Performs deferred request generation for the <see cref="CreateAsync" /> method. /// </summary> /// <param name="userSuppliedIdentifier">The user supplied identifier.</param> /// <param name="relyingParty">The relying party.</param> @@ -534,7 +535,10 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { /// Creates the request message to send to the Provider, /// based on the properties in this instance. /// </summary> - /// <returns>The message to send to the Provider.</returns> + /// <param name="cancellationToken">The cancellation token.</param> + /// <returns> + /// The message to send to the Provider. + /// </returns> private async Task<SignedResponseRequest> CreateRequestMessageAsync(CancellationToken cancellationToken) { Association association = await this.GetAssociationAsync(cancellationToken); @@ -565,7 +569,10 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { /// <summary> /// Gets the association to use for this authentication request. /// </summary> - /// <returns>The association to use; <c>null</c> to use 'dumb mode'.</returns> + /// <param name="cancellationToken">The cancellation token.</param> + /// <returns> + /// The association to use; <c>null</c> to use 'dumb mode'. + /// </returns> private async Task<Association> GetAssociationAsync(CancellationToken cancellationToken) { Association association = null; switch (this.associationPreference) { diff --git a/src/DotNetOpenAuth.OpenId.RelyingParty/OpenId/RelyingParty/ISetupRequiredAuthenticationResponse.cs b/src/DotNetOpenAuth.OpenId.RelyingParty/OpenId/RelyingParty/ISetupRequiredAuthenticationResponse.cs index af36a00..f4fdeb1 100644 --- a/src/DotNetOpenAuth.OpenId.RelyingParty/OpenId/RelyingParty/ISetupRequiredAuthenticationResponse.cs +++ b/src/DotNetOpenAuth.OpenId.RelyingParty/OpenId/RelyingParty/ISetupRequiredAuthenticationResponse.cs @@ -7,6 +7,7 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { using System; using System.Threading; + using System.Web; /// <summary> /// An interface to expose useful properties and functionality for handling diff --git a/src/DotNetOpenAuth.OpenId.RelyingParty/OpenId/RelyingParty/NegativeAuthenticationResponse.cs b/src/DotNetOpenAuth.OpenId.RelyingParty/OpenId/RelyingParty/NegativeAuthenticationResponse.cs index 79fc5de..fdd3529 100644 --- a/src/DotNetOpenAuth.OpenId.RelyingParty/OpenId/RelyingParty/NegativeAuthenticationResponse.cs +++ b/src/DotNetOpenAuth.OpenId.RelyingParty/OpenId/RelyingParty/NegativeAuthenticationResponse.cs @@ -8,6 +8,7 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { using System; using System.Collections.Generic; using System.Linq; + using System.Threading; using System.Threading.Tasks; using System.Web; using DotNetOpenAuth.Messaging; diff --git a/src/DotNetOpenAuth.OpenId.RelyingParty/OpenId/RelyingParty/OpenIdRelyingParty.cs b/src/DotNetOpenAuth.OpenId.RelyingParty/OpenId/RelyingParty/OpenIdRelyingParty.cs index db23cdb..ad20356 100644 --- a/src/DotNetOpenAuth.OpenId.RelyingParty/OpenId/RelyingParty/OpenIdRelyingParty.cs +++ b/src/DotNetOpenAuth.OpenId.RelyingParty/OpenId/RelyingParty/OpenIdRelyingParty.cs @@ -336,7 +336,8 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { Requires.NotNull(realm, "realm"); Requires.NotNull(returnToUrl, "returnToUrl"); try { - return (await this.CreateRequestsAsync(userSuppliedIdentifier, realm, returnToUrl)).First(); + var requests = await this.CreateRequestsAsync(userSuppliedIdentifier, realm, returnToUrl); + return requests.First(); } catch (InvalidOperationException ex) { throw ErrorUtilities.Wrap(ex, OpenIdStrings.OpenIdEndpointNotFound); } @@ -364,7 +365,8 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { Requires.NotNull(userSuppliedIdentifier, "userSuppliedIdentifier"); Requires.NotNull(realm, "realm"); try { - var result = (await this.CreateRequestsAsync(userSuppliedIdentifier, realm, cancellationToken: cancellationToken)).First(); + var request = await this.CreateRequestsAsync(userSuppliedIdentifier, realm, cancellationToken: cancellationToken); + var result = request.First(); Assumes.True(result != null); return result; } catch (InvalidOperationException ex) { @@ -391,7 +393,8 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { public async Task<IAuthenticationRequest> CreateRequestAsync(Identifier userSuppliedIdentifier, HttpRequestBase requestContext = null, CancellationToken cancellationToken = default(CancellationToken)) { Requires.NotNull(userSuppliedIdentifier, "userSuppliedIdentifier"); try { - return (await this.CreateRequestsAsync(userSuppliedIdentifier, requestContext, cancellationToken)).First(); + var authenticationRequests = await this.CreateRequestsAsync(userSuppliedIdentifier, requestContext, cancellationToken); + return authenticationRequests.First(); } catch (InvalidOperationException ex) { throw ErrorUtilities.Wrap(ex, OpenIdStrings.OpenIdEndpointNotFound); } @@ -495,7 +498,7 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { /// <para>Any individual generated request can satisfy the authentication. /// The generated requests are sorted in preferred order. /// Each request is generated as it is enumerated to. Associations are created only as - /// <see cref="IAuthenticationRequest.RedirectingResponse" /> is called.</para> + /// <see cref="IAuthenticationRequest.GetRedirectingResponseAsync" /> is called.</para> /// <para>No exception is thrown if no OpenID endpoints were discovered. /// An empty enumerable is returned instead.</para> /// <para>Requires an <see cref="HttpContext.Current">HttpContext.Current</see> context.</para> @@ -509,9 +512,12 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { /// <summary> /// Gets an authentication response from a Provider. /// </summary> - /// <returns>The processed authentication response if there is any; <c>null</c> otherwise.</returns> + /// <param name="cancellationToken">The cancellation token.</param> + /// <returns> + /// The processed authentication response if there is any; <c>null</c> otherwise. + /// </returns> /// <remarks> - /// <para>Requires an <see cref="HttpContext.Current">HttpContext.Current</see> context.</para> + /// Requires an <see cref="HttpContext.Current">HttpContext.Current</see> context. /// </remarks> public Task<IAuthenticationResponse> GetResponseAsync(CancellationToken cancellationToken) { RequiresEx.ValidState(HttpContext.Current != null && HttpContext.Current.Request != null, MessagingStrings.HttpContextRequired); @@ -565,9 +571,12 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { /// <summary> /// Processes the response received in a popup window or iframe to an AJAX-directed OpenID authentication. /// </summary> - /// <returns>The HTTP response to send to this HTTP request.</returns> + /// <param name="cancellationToken">The cancellation token.</param> + /// <returns> + /// The HTTP response to send to this HTTP request. + /// </returns> /// <remarks> - /// <para>Requires an <see cref="HttpContext.Current">HttpContext.Current</see> context.</para> + /// Requires an <see cref="HttpContext.Current">HttpContext.Current</see> context. /// </remarks> public Task<HttpResponseMessage> ProcessResponseFromPopupAsync(CancellationToken cancellationToken) { RequiresEx.ValidState(HttpContext.Current != null && HttpContext.Current.Request != null, MessagingStrings.HttpContextRequired); @@ -597,7 +606,7 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { /// <typeparam name="T">The extension <i>response</i> type that will read data from the assertion.</typeparam> /// <param name="propertyName">The property name on the openid_identifier input box object that will be used to store the extension data. For example: sreg</param> /// <remarks> - /// This method should be called before <see cref="ProcessResponseFromPopup()"/>. + /// This method should be called before <see cref="ProcessResponseFromPopupAsync()"/>. /// </remarks> [SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter", Justification = "By design")] public void RegisterClientScriptExtension<T>(string propertyName) where T : IClientScriptExtensionResponse { diff --git a/src/DotNetOpenAuth.OpenId.RelyingParty/OpenId/RelyingParty/PositiveAuthenticationResponse.cs b/src/DotNetOpenAuth.OpenId.RelyingParty/OpenId/RelyingParty/PositiveAuthenticationResponse.cs index d73d45f..79e9f65 100644 --- a/src/DotNetOpenAuth.OpenId.RelyingParty/OpenId/RelyingParty/PositiveAuthenticationResponse.cs +++ b/src/DotNetOpenAuth.OpenId.RelyingParty/OpenId/RelyingParty/PositiveAuthenticationResponse.cs @@ -16,7 +16,7 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { using Validation; /// <summary> - /// Wraps a positive assertion response in an <see cref="IAuthenticationResponse"/> instance + /// Wraps a positive assertion response in an <see cref="IAuthenticationResponse" /> instance /// for public consumption by the host web site. /// </summary> [DebuggerDisplay("Status: {Status}, ClaimedIdentifier: {ClaimedIdentifier}")] @@ -123,6 +123,14 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { get { return (PositiveAssertionResponse)base.Response; } } + /// <summary> + /// Initializes a new instance of the <see cref="PositiveAuthenticationResponse"/> class + /// after verifying that discovery on the identifier matches the asserted data. + /// </summary> + /// <param name="response">The response.</param> + /// <param name="relyingParty">The relying party.</param> + /// <param name="cancellationToken">The cancellation token.</param> + /// <returns>The newly initialized instance.</returns> internal static async Task<PositiveAuthenticationResponse> CreateAsync( PositiveAssertionResponse response, OpenIdRelyingParty relyingParty, CancellationToken cancellationToken) { var result = new PositiveAuthenticationResponse(response, relyingParty); diff --git a/src/DotNetOpenAuth.OpenId/OpenId/ChannelElements/BackwardCompatibilityBindingElement.cs b/src/DotNetOpenAuth.OpenId/OpenId/ChannelElements/BackwardCompatibilityBindingElement.cs index 3fe3fe2..4c55360 100644 --- a/src/DotNetOpenAuth.OpenId/OpenId/ChannelElements/BackwardCompatibilityBindingElement.cs +++ b/src/DotNetOpenAuth.OpenId/OpenId/ChannelElements/BackwardCompatibilityBindingElement.cs @@ -18,8 +18,14 @@ namespace DotNetOpenAuth.OpenId.ChannelElements { /// are required to send back with positive assertions. /// </summary> internal class BackwardCompatibilityBindingElement : IChannelBindingElement { + /// <summary> + /// A reusable pre-completed task that may be returned multiple times to reduce GC pressure. + /// </summary> private static readonly Task<MessageProtections?> NullTask = Task.FromResult<MessageProtections?>(null); + /// <summary> + /// A reusable pre-completed task that may be returned multiple times to reduce GC pressure. + /// </summary> private static readonly Task<MessageProtections?> NoneTask = Task.FromResult<MessageProtections?>(MessageProtections.None); diff --git a/src/DotNetOpenAuth.OpenId/OpenId/ChannelElements/ExtensionsBindingElement.cs b/src/DotNetOpenAuth.OpenId/OpenId/ChannelElements/ExtensionsBindingElement.cs index 5d6a51e..727dad7 100644 --- a/src/DotNetOpenAuth.OpenId/OpenId/ChannelElements/ExtensionsBindingElement.cs +++ b/src/DotNetOpenAuth.OpenId/OpenId/ChannelElements/ExtensionsBindingElement.cs @@ -23,8 +23,14 @@ namespace DotNetOpenAuth.OpenId.ChannelElements { /// their carrying OpenID messages. /// </summary> internal class ExtensionsBindingElement : IChannelBindingElement { + /// <summary> + /// A reusable pre-completed task that may be returned multiple times to reduce GC pressure. + /// </summary> private static readonly Task<MessageProtections?> NullTask = Task.FromResult<MessageProtections?>(null); + /// <summary> + /// A reusable pre-completed task that may be returned multiple times to reduce GC pressure. + /// </summary> private static readonly Task<MessageProtections?> NoneTask = Task.FromResult<MessageProtections?>(MessageProtections.None); diff --git a/src/DotNetOpenAuth.OpenId/OpenId/ChannelElements/OpenIdChannel.cs b/src/DotNetOpenAuth.OpenId/OpenId/ChannelElements/OpenIdChannel.cs index 3b650fc..6d4df61 100644 --- a/src/DotNetOpenAuth.OpenId/OpenId/ChannelElements/OpenIdChannel.cs +++ b/src/DotNetOpenAuth.OpenId/OpenId/ChannelElements/OpenIdChannel.cs @@ -200,15 +200,38 @@ namespace DotNetOpenAuth.OpenId.ChannelElements { return preparedResponse; } + /// <summary> + /// Provides derived-types the opportunity to wrap an <see cref="HttpMessageHandler" /> with another one. + /// </summary> + /// <param name="innerHandler">The inner handler received from <see cref="IHostFactories" /></param> + /// <returns> + /// The handler to use in <see cref="HttpClient" /> instances. + /// </returns> protected override HttpMessageHandler WrapMessageHandler(HttpMessageHandler innerHandler) { return new ErrorFilteringMessageHandler(base.WrapMessageHandler(innerHandler)); } + /// <summary> + /// An HTTP handler that throws an exception if the response message's HTTP status code doesn't fall + /// within those allowed by the OpenID spec. + /// </summary> private class ErrorFilteringMessageHandler : DelegatingHandler { + /// <summary> + /// Initializes a new instance of the <see cref="ErrorFilteringMessageHandler" /> class. + /// </summary> + /// <param name="innerHandler">The inner handler which is responsible for processing the HTTP response messages.</param> internal ErrorFilteringMessageHandler(HttpMessageHandler innerHandler) : base(innerHandler) { } + /// <summary> + /// Sends an HTTP request to the inner handler to send to the server as an asynchronous operation. + /// </summary> + /// <param name="request">The HTTP request message to send to the server.</param> + /// <param name="cancellationToken">A cancellation token to cancel operation.</param> + /// <returns> + /// Returns <see cref="T:System.Threading.Tasks.Task`1" />. The task object representing the asynchronous operation. + /// </returns> protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, System.Threading.CancellationToken cancellationToken) { var response = await base.SendAsync(request, cancellationToken); diff --git a/src/DotNetOpenAuth.OpenId/OpenId/ChannelElements/ReturnToSignatureBindingElement.cs b/src/DotNetOpenAuth.OpenId/OpenId/ChannelElements/ReturnToSignatureBindingElement.cs index 5ea5136..2aad922 100644 --- a/src/DotNetOpenAuth.OpenId/OpenId/ChannelElements/ReturnToSignatureBindingElement.cs +++ b/src/DotNetOpenAuth.OpenId/OpenId/ChannelElements/ReturnToSignatureBindingElement.cs @@ -33,8 +33,14 @@ namespace DotNetOpenAuth.OpenId.ChannelElements { /// anything except a particular message part.</para> /// </remarks> internal class ReturnToSignatureBindingElement : IChannelBindingElement { + /// <summary> + /// A reusable pre-completed task that may be returned multiple times to reduce GC pressure. + /// </summary> private static readonly Task<MessageProtections?> NullTask = Task.FromResult<MessageProtections?>(null); + /// <summary> + /// A reusable pre-completed task that may be returned multiple times to reduce GC pressure. + /// </summary> private static readonly Task<MessageProtections?> NoneTask = Task.FromResult<MessageProtections?>(MessageProtections.None); diff --git a/src/DotNetOpenAuth.OpenId/OpenId/ChannelElements/SigningBindingElement.cs b/src/DotNetOpenAuth.OpenId/OpenId/ChannelElements/SigningBindingElement.cs index 769b2e2..8f602cf 100644 --- a/src/DotNetOpenAuth.OpenId/OpenId/ChannelElements/SigningBindingElement.cs +++ b/src/DotNetOpenAuth.OpenId/OpenId/ChannelElements/SigningBindingElement.cs @@ -25,6 +25,9 @@ namespace DotNetOpenAuth.OpenId.ChannelElements { /// Signs and verifies authentication assertions. /// </summary> internal abstract class SigningBindingElement : IChannelBindingElement { + /// <summary> + /// A reusable pre-completed task that may be returned multiple times to reduce GC pressure. + /// </summary> private static readonly Task<MessageProtections?> NullTask = Task.FromResult<MessageProtections?>(null); #region IChannelBindingElement Properties diff --git a/src/DotNetOpenAuth.OpenId/OpenId/ChannelElements/SkipSecurityBindingElement.cs b/src/DotNetOpenAuth.OpenId/OpenId/ChannelElements/SkipSecurityBindingElement.cs index e55b7e2..ad8d59e 100644 --- a/src/DotNetOpenAuth.OpenId/OpenId/ChannelElements/SkipSecurityBindingElement.cs +++ b/src/DotNetOpenAuth.OpenId/OpenId/ChannelElements/SkipSecurityBindingElement.cs @@ -18,6 +18,9 @@ namespace DotNetOpenAuth.OpenId.ChannelElements { /// Spoofs security checks on incoming OpenID messages. /// </summary> internal class SkipSecurityBindingElement : IChannelBindingElement { + /// <summary> + /// A reusable pre-completed task that may be returned multiple times to reduce GC pressure. + /// </summary> private static readonly Task<MessageProtections?> NullTask = Task.FromResult<MessageProtections?>(null); #region IChannelBindingElement Members diff --git a/src/DotNetOpenAuth.OpenId/OpenId/Messages/NegativeAssertionResponse.cs b/src/DotNetOpenAuth.OpenId/OpenId/Messages/NegativeAssertionResponse.cs index 469c7ca..01be03b 100644 --- a/src/DotNetOpenAuth.OpenId/OpenId/Messages/NegativeAssertionResponse.cs +++ b/src/DotNetOpenAuth.OpenId/OpenId/Messages/NegativeAssertionResponse.cs @@ -23,14 +23,6 @@ namespace DotNetOpenAuth.OpenId.Messages { /// <summary> /// Initializes a new instance of the <see cref="NegativeAssertionResponse"/> class. /// </summary> - /// <param name="request">The request.</param> - private NegativeAssertionResponse(SignedResponseRequest request) - : base(request, GetMode(request)) { - } - - /// <summary> - /// Initializes a new instance of the <see cref="NegativeAssertionResponse"/> class. - /// </summary> /// <param name="version">The version.</param> /// <param name="relyingPartyReturnTo">The relying party return to.</param> /// <param name="mode">The value of the openid.mode parameter.</param> @@ -39,6 +31,14 @@ namespace DotNetOpenAuth.OpenId.Messages { } /// <summary> + /// Initializes a new instance of the <see cref="NegativeAssertionResponse"/> class. + /// </summary> + /// <param name="request">The request.</param> + private NegativeAssertionResponse(SignedResponseRequest request) + : base(request, GetMode(request)) { + } + + /// <summary> /// Gets or sets the URL the relying party can use to upgrade their authentication /// request from an immediate to a setup message. /// </summary> diff --git a/src/DotNetOpenAuth.OpenId/OpenId/OpenIdUtilities.cs b/src/DotNetOpenAuth.OpenId/OpenId/OpenIdUtilities.cs index dcea83a..e111655 100644 --- a/src/DotNetOpenAuth.OpenId/OpenId/OpenIdUtilities.cs +++ b/src/DotNetOpenAuth.OpenId/OpenId/OpenIdUtilities.cs @@ -82,13 +82,22 @@ namespace DotNetOpenAuth.OpenId { return string.Format(CultureInfo.InvariantCulture, "{{{0}}}{{{1}}}", DateTime.UtcNow.Ticks, uniq); } + /// <summary> + /// Immediately sends a redirect response to the browser to initiate an authentication request. + /// </summary> + /// <param name="authenticationRequest">The authentication request to send via redirect.</param> + /// <param name="context">The context.</param> + /// <param name="cancellationToken">The cancellation token.</param> + /// <returns> + /// A task that completes with the asynchronous operation. + /// </returns> public static async Task RedirectToProviderAsync(this IAuthenticationRequest authenticationRequest, HttpContextBase context = null, CancellationToken cancellationToken = default(CancellationToken)) { Requires.NotNull(authenticationRequest, "authenticationRequest"); Verify.Operation(context != null || HttpContext.Current != null, MessagingStrings.HttpContextRequired); context = context ?? new HttpContextWrapper(HttpContext.Current); var response = await authenticationRequest.GetRedirectingResponseAsync(cancellationToken); - response.Send(context); + await response.SendAsync(context.Response); } /// <summary> @@ -196,6 +205,13 @@ namespace DotNetOpenAuth.OpenId { return fullyQualifiedRealm; } + /// <summary> + /// Creates a new HTTP client for use by OpenID relying parties and providers. + /// </summary> + /// <param name="hostFactories">The host factories.</param> + /// <param name="requireSsl">if set to <c>true</c> [require SSL].</param> + /// <param name="cachePolicy">The cache policy.</param> + /// <returns>An HttpClient instance with appropriate caching policies set for OpenID operations.</returns> internal static HttpClient CreateHttpClient(this IHostFactories hostFactories, bool requireSsl, RequestCachePolicy cachePolicy = null) { Requires.NotNull(hostFactories, "hostFactories"); diff --git a/src/DotNetOpenAuth.OpenId/OpenId/Realm.cs b/src/DotNetOpenAuth.OpenId/OpenId/Realm.cs index 8628160..f6b4129 100644 --- a/src/DotNetOpenAuth.OpenId/OpenId/Realm.cs +++ b/src/DotNetOpenAuth.OpenId/OpenId/Realm.cs @@ -440,7 +440,6 @@ namespace DotNetOpenAuth.OpenId { /// </summary> /// <param name="hostFactories">The host factories.</param> /// <param name="allowRedirects">Whether redirects may be followed when discovering the Realm. - /// <param name="cancellationToken">The cancellation token.</param> /// This may be true when creating an unsolicited assertion, but must be /// false when performing return URL verification per 2.0 spec section 9.2.1.</param> /// <param name="cancellationToken">The cancellation token.</param> diff --git a/src/DotNetOpenAuth.OpenId/OpenId/UntrustedWebRequestHandler.cs b/src/DotNetOpenAuth.OpenId/OpenId/UntrustedWebRequestHandler.cs index 25d4bb6..b76d6ad 100644 --- a/src/DotNetOpenAuth.OpenId/OpenId/UntrustedWebRequestHandler.cs +++ b/src/DotNetOpenAuth.OpenId/OpenId/UntrustedWebRequestHandler.cs @@ -68,6 +68,9 @@ namespace DotNetOpenAuth.OpenId { [DebuggerBrowsable(DebuggerBrowsableState.Never)] private int maximumRedirections = Configuration.MaximumRedirections; + /// <summary> + /// The inner handler. + /// </summary> private readonly InternalWebRequestHandler innerHandler; /// <summary> @@ -97,10 +100,6 @@ namespace DotNetOpenAuth.OpenId { } } - protected WebRequestHandler InnerWebRequestHandler { - get { return (WebRequestHandler)this.innerHandler.InnerHandler; } - } - /// <summary> /// Gets or sets a value indicating whether all requests must use SSL. /// </summary> @@ -186,12 +185,26 @@ namespace DotNetOpenAuth.OpenId { } /// <summary> + /// Gets the inner web request handler. + /// </summary> + /// <value> + /// The inner web request handler. + /// </value> + protected WebRequestHandler InnerWebRequestHandler { + get { return (WebRequestHandler)this.innerHandler.InnerHandler; } + } + + /// <summary> /// Gets the configuration for this class that is specified in the host's .config file. /// </summary> private static UntrustedWebRequestElement Configuration { get { return DotNetOpenAuthSection.Messaging.UntrustedWebRequest; } } + /// <summary> + /// Creates an HTTP client that uses this instance as an HTTP handler. + /// </summary> + /// <returns>The initialized instance.</returns> public HttpClient CreateClient() { var client = new HttpClient(this); client.MaxResponseContentBufferSize = Configuration.MaximumBytesToRead; @@ -232,6 +245,14 @@ namespace DotNetOpenAuth.OpenId { return false; } + /// <summary> + /// Send an HTTP request as an asynchronous operation. + /// </summary> + /// <param name="request">The HTTP request message to send.</param> + /// <param name="cancellationToken">The cancellation token to cancel operation.</param> + /// <returns> + /// Returns <see cref="T:System.Threading.Tasks.Task`1" />.The task object representing the asynchronous operation. + /// </returns> protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) { this.EnsureAllowableRequestUri(request.RequestUri); @@ -250,7 +271,8 @@ namespace DotNetOpenAuth.OpenId { // cloned HttpWebRequest, so we have to bail. ErrorUtilities.VerifyProtocol(request.Method != HttpMethod.Post, MessagingStrings.UntrustedRedirectsOnPOSTNotSupported); Uri redirectUri = new Uri(request.RequestUri, response.Headers.Location); - request = request.Clone(redirectUri); + request = request.Clone(); + request.RequestUri = redirectUri; continue; } @@ -347,7 +369,6 @@ namespace DotNetOpenAuth.OpenId { /// Verify that the request qualifies under our security policies /// </summary> /// <param name="requestUri">The request URI.</param> - /// <param name="requireSsl">If set to <c>true</c>, only web requests that can be made entirely over SSL will succeed.</param> /// <exception cref="ProtocolException">Thrown when the URI is disallowed for security reasons.</exception> private void EnsureAllowableRequestUri(Uri requestUri) { ErrorUtilities.VerifyProtocol( @@ -422,9 +443,13 @@ namespace DotNetOpenAuth.OpenId { } /// <summary> - /// A <see cref="DelegatingHandler"/> derived type that makes its SendAsync method available internally. + /// A <see cref="DelegatingHandler" /> derived type that makes its SendAsync method available internally. /// </summary> private class InternalWebRequestHandler : DelegatingHandler { + /// <summary> + /// Initializes a new instance of the <see cref="InternalWebRequestHandler"/> class. + /// </summary> + /// <param name="innerHandler">The inner handler which is responsible for processing the HTTP response messages.</param> internal InternalWebRequestHandler(HttpMessageHandler innerHandler) : base(innerHandler) { } diff --git a/src/DotNetOpenAuth.OpenId/OpenId/XriDiscoveryProxyService.cs b/src/DotNetOpenAuth.OpenId/OpenId/XriDiscoveryProxyService.cs index a04f568..c8c126e 100644 --- a/src/DotNetOpenAuth.OpenId/OpenId/XriDiscoveryProxyService.cs +++ b/src/DotNetOpenAuth.OpenId/OpenId/XriDiscoveryProxyService.cs @@ -46,6 +46,9 @@ namespace DotNetOpenAuth.OpenId { public XriDiscoveryProxyService() { } + /// <summary> + /// Gets or sets the host factories used by this instance. + /// </summary> public IHostFactories HostFactories { get; set; } #region IDiscoveryService Members diff --git a/src/DotNetOpenAuth.OpenId/Yadis/DiscoveryResult.cs b/src/DotNetOpenAuth.OpenId/Yadis/DiscoveryResult.cs index c56a170..8266ff0 100644 --- a/src/DotNetOpenAuth.OpenId/Yadis/DiscoveryResult.cs +++ b/src/DotNetOpenAuth.OpenId/Yadis/DiscoveryResult.cs @@ -28,7 +28,7 @@ namespace DotNetOpenAuth.Yadis { private HttpResponseMessage htmlFallback; /// <summary> - /// Initializes a new instance of the <see cref="DiscoveryResult" /> class. + /// Prevents a default instance of the <see cref="DiscoveryResult" /> class from being created. /// </summary> private DiscoveryResult() { } @@ -70,6 +70,13 @@ namespace DotNetOpenAuth.Yadis { /// </summary> public bool IsXrds { get; private set; } + /// <summary> + /// Initializes a new instance of the <see cref="DiscoveryResult"/> class. + /// </summary> + /// <param name="requestUri">The request URI.</param> + /// <param name="initialResponse">The initial response.</param> + /// <param name="finalResponse">The final response.</param> + /// <returns>The newly initialized instance.</returns> internal static async Task<DiscoveryResult> CreateAsync(Uri requestUri, HttpResponseMessage initialResponse, HttpResponseMessage finalResponse) { var result = new DiscoveryResult(); result.RequestUri = requestUri; |