diff options
Diffstat (limited to 'src')
11 files changed, 205 insertions, 142 deletions
diff --git a/src/DotNetOpenAuth.OpenId.RelyingParty.UI/DotNetOpenAuth.OpenId.RelyingParty.UI.csproj b/src/DotNetOpenAuth.OpenId.RelyingParty.UI/DotNetOpenAuth.OpenId.RelyingParty.UI.csproj index 0d83940..e65d1c4 100644 --- a/src/DotNetOpenAuth.OpenId.RelyingParty.UI/DotNetOpenAuth.OpenId.RelyingParty.UI.csproj +++ b/src/DotNetOpenAuth.OpenId.RelyingParty.UI/DotNetOpenAuth.OpenId.RelyingParty.UI.csproj @@ -67,6 +67,8 @@ <HintPath>..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll</HintPath> </Reference> <Reference Include="System" /> + <Reference Include="System.Net.Http" /> + <Reference Include="System.Net.Http.WebRequest" /> <Reference Include="System.Web.Helpers, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL"> <Private>True</Private> <HintPath>..\packages\Microsoft.AspNet.WebPages.1.0.20105.408\lib\net40\System.Web.Helpers.dll</HintPath> diff --git a/src/DotNetOpenAuth.OpenId.RelyingParty.UI/OpenId/RelyingParty/OpenIdAjaxRelyingParty.cs b/src/DotNetOpenAuth.OpenId.RelyingParty.UI/OpenId/RelyingParty/OpenIdAjaxRelyingParty.cs index 918efdf..b6cab0e 100644 --- a/src/DotNetOpenAuth.OpenId.RelyingParty.UI/OpenId/RelyingParty/OpenIdAjaxRelyingParty.cs +++ b/src/DotNetOpenAuth.OpenId.RelyingParty.UI/OpenId/RelyingParty/OpenIdAjaxRelyingParty.cs @@ -11,11 +11,14 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { using System.Globalization; using System.Linq; using System.Net; + using System.Net.Http; + using System.Net.Http.Headers; using System.Net.Mime; using System.Text; + using System.Threading; + using System.Threading.Tasks; using System.Web; using System.Web.Script.Serialization; - using DotNetOpenAuth.Configuration; using DotNetOpenAuth.Messaging; using DotNetOpenAuth.OpenId.Extensions; @@ -63,8 +66,9 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { /// <para>No exception is thrown if no OpenID endpoints were discovered. /// An empty enumerable is returned instead.</para> /// </remarks> - public override IEnumerable<IAuthenticationRequest> CreateRequests(Identifier userSuppliedIdentifier, Realm realm, Uri returnToUrl) { - var requests = base.CreateRequests(userSuppliedIdentifier, realm, returnToUrl); + public override async Task<IEnumerable<IAuthenticationRequest>> CreateRequestsAsync(Identifier userSuppliedIdentifier, Realm realm, Uri returnToUrl, CancellationToken cancellationToken) { + var requests = await base.CreateRequestsAsync(userSuppliedIdentifier, realm, returnToUrl, cancellationToken); + var results = new List<IAuthenticationRequest>(); // Alter the requests so that have AJAX characteristics. // Some OPs may be listed multiple times (one with HTTPS and the other with HTTP, for example). @@ -113,8 +117,10 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { // http://www.nabble.com/Re:-Defining-how-OpenID-should-behave-with-fragments-in-the-return_to-url-p22694227.html ////TODO: - yield return req; + results.Add(req); } + + return results; } /// <summary> @@ -142,13 +148,15 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { /// } /// </code> /// </remarks> - public OutgoingWebResponse AsAjaxDiscoveryResult(IEnumerable<IAuthenticationRequest> requests) { + public async Task<HttpResponseMessage> AsAjaxDiscoveryResultAsync(IEnumerable<IAuthenticationRequest> requests, CancellationToken cancellationToken) { Requires.NotNull(requests, "requests"); var serializer = new JavaScriptSerializer(); - return new OutgoingWebResponse { - Body = serializer.Serialize(this.AsJsonDiscoveryResult(requests)), + var response = new HttpResponseMessage { + Content = new StringContent(serializer.Serialize(await this.AsJsonDiscoveryResultAsync(requests, cancellationToken))), }; + response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/json"); + return response; } /// <summary> @@ -159,11 +167,11 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { /// <returns> /// The JSON result to return to the user agent. /// </returns> - public string AsAjaxPreloadedDiscoveryResult(IEnumerable<IAuthenticationRequest> requests) { + public async Task<string> AsAjaxPreloadedDiscoveryResultAsync(IEnumerable<IAuthenticationRequest> requests, CancellationToken cancellationToken) { Requires.NotNull(requests, "requests"); var serializer = new JavaScriptSerializer(); - string json = serializer.Serialize(this.AsJsonPreloadedDiscoveryResult(requests)); + string json = serializer.Serialize(await this.AsJsonPreloadedDiscoveryResultAsync(requests, cancellationToken)); string script = "window.dnoa_internal.loadPreloadedDiscoveryResults(" + json + ");"; return script; @@ -174,18 +182,27 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { /// </summary> /// <param name="requests">The discovery results from just <i>one</i> identifier to serialize as a JSON response.</param> /// <returns>A JSON object, not yet serialized.</returns> - internal object AsJsonDiscoveryResult(IEnumerable<IAuthenticationRequest> requests) { + internal async Task<object> AsJsonDiscoveryResultAsync(IEnumerable<IAuthenticationRequest> requests, CancellationToken cancellationToken) { Requires.NotNull(requests, "requests"); requests = requests.CacheGeneratedResults(); if (requests.Any()) { + var requestUrls = + requests.Select( + req => + new { + endpoint = req.Provider.Uri.AbsoluteUri, + immediate = this.GetRedirectUrlAsync(req, true, cancellationToken), + setup = this.GetRedirectUrlAsync(req, false, cancellationToken), + }).ToList(); + await Task.WhenAll(requestUrls.Select(r => r.immediate).Concat(requestUrls.Select(r => r.setup))); return new { claimedIdentifier = (string)requests.First().ClaimedIdentifier, - requests = requests.Select(req => new { - endpoint = req.Provider.Uri.AbsoluteUri, - immediate = this.GetRedirectUrl(req, true), - setup = this.GetRedirectUrl(req, false), + requests = requestUrls.Select(req => new { + endpoint = req.endpoint, + immediate = req.immediate.Result, // await already took place + setup = req.setup.Result, // await already took place }).ToArray() }; } else { @@ -204,7 +221,7 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { /// <returns> /// A JSON object, not yet serialized to a string. /// </returns> - private object AsJsonPreloadedDiscoveryResult(IEnumerable<IAuthenticationRequest> requests) { + private async Task<object> AsJsonPreloadedDiscoveryResultAsync(IEnumerable<IAuthenticationRequest> requests, CancellationToken cancellationToken) { Requires.NotNull(requests, "requests"); // We prepare a JSON object with this interface: @@ -214,13 +231,18 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { // string userSuppliedIdentifier; // jsonResponse discoveryResult; // contains result of call to SerializeDiscoveryAsJson(Identifier) // } - var json = (from request in requests - group request by request.DiscoveryResult.UserSuppliedIdentifier into requestsByIdentifier - select new { - userSuppliedIdentifier = (string)requestsByIdentifier.Key, - discoveryResult = this.AsJsonDiscoveryResult(requestsByIdentifier), - }).ToArray(); - + var jsonAsync = (from request in requests + group request by request.DiscoveryResult.UserSuppliedIdentifier into requestsByIdentifier + select new { + userSuppliedIdentifier = (string)requestsByIdentifier.Key, + discoveryResult = this.AsJsonDiscoveryResultAsync(requestsByIdentifier, cancellationToken), + }).ToArray(); + await Task.WhenAll(jsonAsync.Select(j => j.discoveryResult)); + var json = from j in jsonAsync + select new { + userSuppliedIdentifier = j.userSuppliedIdentifier, + discoveryResult = j.discoveryResult.Result, // await happened previously + }; return json; } @@ -232,11 +254,12 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { /// <param name="immediate"><c>true</c>to create a checkid_immediate request; /// <c>false</c> to create a checkid_setup request.</param> /// <returns>The absolute URL that carries the entire OpenID message.</returns> - private Uri GetRedirectUrl(IAuthenticationRequest request, bool immediate) { + private async Task<Uri> GetRedirectUrlAsync(IAuthenticationRequest request, bool immediate, CancellationToken cancellationToken) { Requires.NotNull(request, "request"); request.Mode = immediate ? AuthenticationRequestMode.Immediate : AuthenticationRequestMode.Setup; - return request.RedirectingResponse.GetDirectUriRequest(this.Channel); + var response = await request.GetRedirectingResponseAsync(cancellationToken); + return response.GetDirectUriRequest(); } } } diff --git a/src/DotNetOpenAuth.OpenId.RelyingParty.UI/OpenId/RelyingParty/OpenIdAjaxTextBox.cs b/src/DotNetOpenAuth.OpenId.RelyingParty.UI/OpenId/RelyingParty/OpenIdAjaxTextBox.cs index b5b6162..5900e7b 100644 --- a/src/DotNetOpenAuth.OpenId.RelyingParty.UI/OpenId/RelyingParty/OpenIdAjaxTextBox.cs +++ b/src/DotNetOpenAuth.OpenId.RelyingParty.UI/OpenId/RelyingParty/OpenIdAjaxTextBox.cs @@ -22,6 +22,8 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { using System.Drawing.Design; using System.Globalization; using System.Text; + using System.Threading; + using System.Threading.Tasks; using System.Web.UI; using System.Web.UI.HtmlControls; using DotNetOpenAuth.Messaging; @@ -716,7 +718,8 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { loader.insert(); } } catch (e) { }"; - this.Page.ClientScript.RegisterClientScriptInclude("yuiloader", this.Page.Request.Url.IsTransportSecure() ? YuiLoaderHttps : YuiLoaderHttp); + this.Page.ClientScript.RegisterClientScriptInclude( + "yuiloader", this.Page.Request.Url.IsTransportSecure() ? YuiLoaderHttps : YuiLoaderHttp); this.Page.ClientScript.RegisterClientScriptBlock(this.GetType(), "requiredYuiComponents", yuiLoadScript, true); } @@ -737,8 +740,9 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { // If an Identifier is preset on this control, preload discovery on that identifier, // but only if we're not already persisting an authentication result since that would // be redundant. - if (this.Identifier != null && this.AuthenticationResponse == null) { - this.PreloadDiscovery(this.Identifier); + var response = Task.Run(() => this.GetAuthenticationResponseAsync(CancellationToken.None)).GetAwaiter().GetResult(); + if (this.Identifier != null && response == null) { + this.PreloadDiscoveryAsync(this.Identifier, CancellationToken.None).Wait(); } } diff --git a/src/DotNetOpenAuth.OpenId.RelyingParty.UI/OpenId/RelyingParty/OpenIdButton.cs b/src/DotNetOpenAuth.OpenId.RelyingParty.UI/OpenId/RelyingParty/OpenIdButton.cs index 505461a..ae962ed 100644 --- a/src/DotNetOpenAuth.OpenId.RelyingParty.UI/OpenId/RelyingParty/OpenIdButton.cs +++ b/src/DotNetOpenAuth.OpenId.RelyingParty.UI/OpenId/RelyingParty/OpenIdButton.cs @@ -13,6 +13,9 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { using System.Globalization; using System.Linq; using System.Text; + using System.Threading; + using System.Threading.Tasks; + using System.Web; using System.Web.UI; using DotNetOpenAuth.Messaging; @@ -117,8 +120,13 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { protected override void RaisePostBackEvent(string eventArgument) { if (!this.PrecreateRequest) { try { - IAuthenticationRequest request = this.CreateRequests().First(); - request.RedirectToProvider(); + // We have to use Task.Run here to escape our SynchronizationContext + Task.Run( + async delegate { + var requests = await this.CreateRequestsAsync(CancellationToken.None); + var request = requests.First(); + await request.RedirectToProviderAsync(new HttpContextWrapper(this.Context)); + }).GetAwaiter().GetResult(); } catch (InvalidOperationException ex) { throw ErrorUtilities.Wrap(ex, OpenIdStrings.OpenIdEndpointNotFound); } @@ -148,9 +156,9 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { } else { string tooltip = this.Text; if (this.PrecreateRequest && !this.DesignMode) { - IAuthenticationRequest request = this.CreateRequests().FirstOrDefault(); + IAuthenticationRequest request = Task.Run(() => this.CreateRequestsAsync(CancellationToken.None)).GetAwaiter().GetResult().FirstOrDefault(); if (request != null) { - RenderOpenIdMessageTransmissionAsAnchorAttributes(writer, request, tooltip); + this.RenderOpenIdMessageTransmissionAsAnchorAttributesAsync(writer, request, tooltip, CancellationToken.None).Wait(); } else { tooltip = OpenIdStrings.OpenIdEndpointNotFound; } diff --git a/src/DotNetOpenAuth.OpenId.RelyingParty.UI/OpenId/RelyingParty/OpenIdLogin.cs b/src/DotNetOpenAuth.OpenId.RelyingParty.UI/OpenId/RelyingParty/OpenIdLogin.cs index 16f9462..d6ce3ce 100644 --- a/src/DotNetOpenAuth.OpenId.RelyingParty.UI/OpenId/RelyingParty/OpenIdLogin.cs +++ b/src/DotNetOpenAuth.OpenId.RelyingParty.UI/OpenId/RelyingParty/OpenIdLogin.cs @@ -10,6 +10,7 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Linq; + using System.Threading; using System.Web.UI; using System.Web.UI.HtmlControls; using System.Web.UI.WebControls; @@ -933,14 +934,14 @@ idselector_input_id = '" + this.ClientID + @"'; /// </summary> /// <param name="sender">The source of the event.</param> /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param> - private void LoginButton_Click(object sender, EventArgs e) { + private async void LoginButton_Click(object sender, EventArgs e) { if (!this.Page.IsValid) { return; } - IAuthenticationRequest request = this.CreateRequests().FirstOrDefault(); + IAuthenticationRequest request = (await this.CreateRequestsAsync(CancellationToken.None)).FirstOrDefault(); if (request != null) { - this.LogOn(request); + await this.LogOnAsync(request, CancellationToken.None); } else { if (!string.IsNullOrEmpty(this.FailedMessageText)) { this.errorLabel.Text = string.Format(CultureInfo.CurrentCulture, this.FailedMessageText, OpenIdStrings.OpenIdEndpointNotFound); diff --git a/src/DotNetOpenAuth.OpenId.RelyingParty.UI/OpenId/RelyingParty/OpenIdRelyingPartyAjaxControlBase.cs b/src/DotNetOpenAuth.OpenId.RelyingParty.UI/OpenId/RelyingParty/OpenIdRelyingPartyAjaxControlBase.cs index 9b4d271..0d5435d 100644 --- a/src/DotNetOpenAuth.OpenId.RelyingParty.UI/OpenId/RelyingParty/OpenIdRelyingPartyAjaxControlBase.cs +++ b/src/DotNetOpenAuth.OpenId.RelyingParty.UI/OpenId/RelyingParty/OpenIdRelyingPartyAjaxControlBase.cs @@ -13,7 +13,10 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Linq; + using System.Net.Http; using System.Text; + using System.Threading; + using System.Threading.Tasks; using System.Web; using System.Web.Script.Serialization; using System.Web.UI; @@ -169,38 +172,36 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { /// <summary> /// Gets the completed authentication response. /// </summary> - public IAuthenticationResponse AuthenticationResponse { - get { - if (this.authenticationResponse == null) { - // We will either validate a new response and return a live AuthenticationResponse - // or we will try to deserialize a previous IAuthenticationResponse (snapshot) - // from viewstate and return that. - IAuthenticationResponse viewstateResponse = this.ViewState[AuthenticationResponseViewStateKey] as IAuthenticationResponse; - string viewstateAuthData = this.ViewState[AuthDataViewStateKey] as string; - string formAuthData = this.Page.Request.Form[this.OpenIdAuthDataFormKey]; - - // First see if there is fresh auth data to be processed into a response. - if (!string.IsNullOrEmpty(formAuthData) && !string.Equals(viewstateAuthData, formAuthData, StringComparison.Ordinal)) { - this.ViewState[AuthDataViewStateKey] = formAuthData; - - HttpRequestBase clientResponseInfo = new HttpRequestInfo("GET", new Uri(formAuthData)); - this.authenticationResponse = this.RelyingParty.GetResponse(clientResponseInfo); - Logger.Controls.DebugFormat( - "The {0} control checked for an authentication response and found: {1}", - this.ID, - this.authenticationResponse.Status); - this.AuthenticationProcessedAlready = false; - - // Save out the authentication response to viewstate so we can find it on - // a subsequent postback. - this.ViewState[AuthenticationResponseViewStateKey] = new PositiveAuthenticationResponseSnapshot(this.authenticationResponse); - } else { - this.authenticationResponse = viewstateResponse; - } + public async Task<IAuthenticationResponse> GetAuthenticationResponseAsync(CancellationToken cancellationToken) { + if (this.authenticationResponse == null) { + // We will either validate a new response and return a live AuthenticationResponse + // or we will try to deserialize a previous IAuthenticationResponse (snapshot) + // from viewstate and return that. + IAuthenticationResponse viewstateResponse = this.ViewState[AuthenticationResponseViewStateKey] as IAuthenticationResponse; + string viewstateAuthData = this.ViewState[AuthDataViewStateKey] as string; + string formAuthData = this.Page.Request.Form[this.OpenIdAuthDataFormKey]; + + // First see if there is fresh auth data to be processed into a response. + if (!string.IsNullOrEmpty(formAuthData) && !string.Equals(viewstateAuthData, formAuthData, StringComparison.Ordinal)) { + this.ViewState[AuthDataViewStateKey] = formAuthData; + + HttpRequestBase clientResponseInfo = new HttpRequestInfo("GET", new Uri(formAuthData)); + this.authenticationResponse = await this.RelyingParty.GetResponseAsync(clientResponseInfo, cancellationToken); + Logger.Controls.DebugFormat( + "The {0} control checked for an authentication response and found: {1}", + this.ID, + this.authenticationResponse.Status); + this.AuthenticationProcessedAlready = false; + + // Save out the authentication response to viewstate so we can find it on + // a subsequent postback. + this.ViewState[AuthenticationResponseViewStateKey] = new PositiveAuthenticationResponseSnapshot(this.authenticationResponse); + } else { + this.authenticationResponse = viewstateResponse; } - - return this.authenticationResponse; } + + return this.authenticationResponse; } /// <summary> @@ -278,7 +279,8 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { /// Processes a callback event that targets a control. /// </summary> /// <param name="eventArgument">A string that represents an event argument to pass to the event handler.</param> - [SuppressMessage("Microsoft.Design", "CA1030:UseEventsWhereAppropriate", Justification = "We want to preserve the signature of the interface.")] + [SuppressMessage("Microsoft.Design", "CA1030:UseEventsWhereAppropriate", + Justification = "We want to preserve the signature of the interface.")] protected virtual void RaiseCallbackEvent(string eventArgument) { string userSuppliedIdentifier = eventArgument; @@ -288,8 +290,10 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { this.Identifier = userSuppliedIdentifier; var serializer = new JavaScriptSerializer(); - IEnumerable<IAuthenticationRequest> requests = this.CreateRequests(this.Identifier); - this.discoveryResult = serializer.Serialize(this.AjaxRelyingParty.AsJsonDiscoveryResult(requests)); + this.discoveryResult = Task.Run(async delegate { + IEnumerable<IAuthenticationRequest> requests = await this.CreateRequestsAsync(this.Identifier, CancellationToken.None); + return serializer.Serialize(await this.AjaxRelyingParty.AsJsonDiscoveryResultAsync(requests, CancellationToken.None)); + }).GetAwaiter().GetResult(); } /// <summary> @@ -306,8 +310,8 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { /// user agent for javascript as soon as the page loads. /// </summary> /// <param name="identifier">The identifier.</param> - protected void PreloadDiscovery(Identifier identifier) { - this.PreloadDiscovery(new[] { identifier }); + protected Task PreloadDiscoveryAsync(Identifier identifier, CancellationToken cancellationToken) { + return this.PreloadDiscoveryAsync(new[] { identifier }, cancellationToken); } /// <summary> @@ -315,9 +319,9 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { /// user agent for javascript as soon as the page loads. /// </summary> /// <param name="identifiers">The identifiers to perform discovery on.</param> - protected void PreloadDiscovery(IEnumerable<Identifier> identifiers) { - string script = this.AjaxRelyingParty.AsAjaxPreloadedDiscoveryResult( - identifiers.SelectMany(id => this.CreateRequests(id))); + protected async Task PreloadDiscoveryAsync(IEnumerable<Identifier> identifiers, CancellationToken cancellationToken) { + var requests = await Task.WhenAll(identifiers.Select(id => this.CreateRequestsAsync(id, cancellationToken))); + string script = await this.AjaxRelyingParty.AsAjaxPreloadedDiscoveryResultAsync(requests.SelectMany(r => r), cancellationToken); this.Page.ClientScript.RegisterClientScriptBlock(typeof(OpenIdRelyingPartyAjaxControlBase), this.ClientID, script, true); } @@ -342,12 +346,13 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { // but our AJAX controls hide an old OpenID message in a postback payload, // so we deserialize it and process it when appropriate. if (this.Page.IsPostBack) { - if (this.AuthenticationResponse != null && !this.AuthenticationProcessedAlready) { + var response = Task.Run(() => this.GetAuthenticationResponseAsync(CancellationToken.None)).GetAwaiter().GetResult(); + if (response != null && !this.AuthenticationProcessedAlready) { // Only process messages targeted at this control. // Note that Stateless mode causes no receiver to be indicated. - string receiver = this.AuthenticationResponse.GetUntrustedCallbackArgument(ReturnToReceivingControlId); + string receiver = response.GetUntrustedCallbackArgument(ReturnToReceivingControlId); if (receiver == null || receiver == this.ClientID) { - this.ProcessResponse(this.AuthenticationResponse); + this.ProcessResponse(response); this.AuthenticationProcessedAlready = true; } } @@ -413,16 +418,17 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { /// <summary> /// Notifies the user agent via an AJAX response of a completed authentication attempt. /// </summary> - protected override void ScriptClosingPopupOrIFrame() { + protected override async Task ScriptClosingPopupOrIFrameAsync(CancellationToken cancellationToken) { Action<AuthenticationStatus> callback = status => { if (status == AuthenticationStatus.Authenticated) { this.OnUnconfirmedPositiveAssertion(); // event handler will fill the clientScriptExtensions collection. } }; - OutgoingWebResponse response = this.RelyingParty.ProcessResponseFromPopup( - this.RelyingParty.Channel.GetRequestFromContext(), - callback); + HttpResponseMessage response = await this.RelyingParty.ProcessResponseFromPopupAsync( + new HttpRequestWrapper(this.Context.Request), + callback, + cancellationToken); response.Send(); } diff --git a/src/DotNetOpenAuth.OpenId.RelyingParty.UI/OpenId/RelyingParty/OpenIdRelyingPartyControlBase.cs b/src/DotNetOpenAuth.OpenId.RelyingParty.UI/OpenId/RelyingParty/OpenIdRelyingPartyControlBase.cs index 7d616d2..14adf3c 100644 --- a/src/DotNetOpenAuth.OpenId.RelyingParty.UI/OpenId/RelyingParty/OpenIdRelyingPartyControlBase.cs +++ b/src/DotNetOpenAuth.OpenId.RelyingParty.UI/OpenId/RelyingParty/OpenIdRelyingPartyControlBase.cs @@ -17,6 +17,8 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { using System.Linq; using System.Text; using System.Text.RegularExpressions; + using System.Threading; + using System.Threading.Tasks; using System.Web; using System.Web.Security; using System.Web.UI; @@ -363,7 +365,7 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { if (Page != null && !DesignMode) { // Validate new value by trying to construct a Realm object based on it. - new Realm(OpenIdUtilities.GetResolvedRealm(this.Page, value, this.RelyingParty.Channel.GetRequestFromContext())); // throws an exception on failure. + new Realm(OpenIdUtilities.GetResolvedRealm(this.Page, value, new HttpRequestWrapper(this.Context.Request))); // throws an exception on failure. } else { // We can't fully test it, but it should start with either ~/ or a protocol. if (Regex.IsMatch(value, @"^https?://")) { @@ -395,7 +397,7 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { set { if (this.Page != null && !this.DesignMode) { // Validate new value by trying to construct a Uri based on it. - new Uri(this.RelyingParty.Channel.GetRequestFromContext().GetPublicFacingUrl(), this.Page.ResolveUrl(value)); // throws an exception on failure. + new Uri(new HttpRequestWrapper(this.Context.Request).GetPublicFacingUrl(), this.Page.ResolveUrl(value)); // throws an exception on failure. } else { // We can't fully test it, but it should start with either ~/ or a protocol. if (Regex.IsMatch(value, @"^https?://")) { @@ -510,10 +512,10 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { /// Immediately redirects to the OpenID Provider to verify the Identifier /// provided in the text box. /// </summary> - public void LogOn() { - IAuthenticationRequest request = this.CreateRequests().FirstOrDefault(); + public async Task LogOnAsync(CancellationToken cancellationToken) { + IAuthenticationRequest request = (await this.CreateRequestsAsync(cancellationToken)).FirstOrDefault(); ErrorUtilities.VerifyProtocol(request != null, OpenIdStrings.OpenIdEndpointNotFound); - this.LogOn(request); + await this.LogOnAsync(request, cancellationToken); } /// <summary> @@ -521,13 +523,13 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { /// provided in the text box. /// </summary> /// <param name="request">The request.</param> - public void LogOn(IAuthenticationRequest request) { + public async Task LogOnAsync(IAuthenticationRequest request, CancellationToken cancellationToken) { Requires.NotNull(request, "request"); if (this.IsPopupAppropriate(request)) { - this.ScriptPopupWindow(request); + await this.ScriptPopupWindowAsync(request, cancellationToken); } else { - request.RedirectToProvider(); + await request.RedirectToProviderAsync(cancellationToken: cancellationToken); } } @@ -561,17 +563,17 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { /// A sequence of authentication requests, any one of which may be /// used to determine the user's control of the <see cref="IAuthenticationRequest.ClaimedIdentifier"/>. /// </returns> - protected internal virtual IEnumerable<IAuthenticationRequest> CreateRequests(Identifier identifier) { + protected internal virtual Task<IEnumerable<IAuthenticationRequest>> CreateRequestsAsync(Identifier identifier, CancellationToken cancellationToken) { Requires.NotNull(identifier, "identifier"); // If this control is actually a member of another OpenID RP control, // delegate creation of requests to the parent control. var parentOwner = this.ParentControls.OfType<OpenIdRelyingPartyControlBase>().FirstOrDefault(); if (parentOwner != null) { - return parentOwner.CreateRequests(identifier); + return parentOwner.CreateRequestsAsync(identifier, cancellationToken); } else { // Delegate to a private method to keep 'yield return' and Code Contract separate. - return this.CreateRequestsCore(identifier); + return this.CreateRequestsCoreAsync(identifier, cancellationToken); } } @@ -603,9 +605,9 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { /// A sequence of authentication requests, any one of which may be /// used to determine the user's control of the <see cref="IAuthenticationRequest.ClaimedIdentifier"/>. /// </returns> - protected IEnumerable<IAuthenticationRequest> CreateRequests() { + protected Task<IEnumerable<IAuthenticationRequest>> CreateRequestsAsync(CancellationToken cancellationToken) { RequiresEx.ValidState(this.Identifier != null, OpenIdStrings.NoIdentifierSet); - return this.CreateRequests(this.Identifier); + return this.CreateRequestsAsync(this.Identifier, cancellationToken); } /// <summary> @@ -626,10 +628,11 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { // Take an unreliable sneek peek to see if we're in a popup and an OpenID // assertion is coming in. We shouldn't process assertions in a popup window. - if (this.Page.Request.QueryString[UIPopupCallbackKey] == "1" && this.Page.Request.QueryString[UIPopupCallbackParentKey] == null) { + if (this.Page.Request.QueryString[UIPopupCallbackKey] == "1" + && this.Page.Request.QueryString[UIPopupCallbackParentKey] == null) { // We're in a popup window. We need to close it and pass the // message back to the parent window for processing. - this.ScriptClosingPopupOrIFrame(); + this.ScriptClosingPopupOrIFrameAsync(CancellationToken.None).Wait(); return; // don't do any more processing on it now } @@ -637,9 +640,10 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { // Note that Stateless mode causes no receiver to be indicated, and // we want to handle that, but only if there isn't a parent control that // will be handling that. - string receiver = this.Page.Request.QueryString[ReturnToReceivingControlId] ?? this.Page.Request.Form[ReturnToReceivingControlId]; + string receiver = this.Page.Request.QueryString[ReturnToReceivingControlId] + ?? this.Page.Request.Form[ReturnToReceivingControlId]; if (receiver == this.ClientID || (receiver == null && !this.IsEmbeddedInParentOpenIdControl)) { - var response = this.RelyingParty.GetResponse(); + var response = Task.Run(() => this.RelyingParty.GetResponseAsync(new HttpRequestWrapper(this.Context.Request), CancellationToken.None)).GetAwaiter().GetResult(); Logger.Controls.DebugFormat( "The {0} control checked for an authentication response and found: {1}", this.ID, @@ -651,8 +655,8 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { /// <summary> /// Notifies the user agent via an AJAX response of a completed authentication attempt. /// </summary> - protected virtual void ScriptClosingPopupOrIFrame() { - this.RelyingParty.ProcessResponseFromPopup(); + protected virtual Task ScriptClosingPopupOrIFrameAsync(CancellationToken cancellationToken) { + return this.RelyingParty.ProcessResponseFromPopupAsync(cancellationToken); } /// <summary> @@ -792,7 +796,7 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { /// </summary> /// <returns>The instantiated relying party.</returns> protected OpenIdRelyingParty CreateRelyingParty() { - IOpenIdApplicationStore store = this.Stateless ? null : OpenIdElement.Configuration.RelyingParty.ApplicationStore.CreateInstance(OpenIdRelyingParty.HttpApplicationStore); + IOpenIdApplicationStore store = this.Stateless ? null : OpenIdElement.Configuration.RelyingParty.ApplicationStore.CreateInstance(OpenIdRelyingParty.GetHttpApplicationStore(new HttpContextWrapper(this.Context)), null); return this.CreateRelyingParty(store); } @@ -849,15 +853,16 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { /// <param name="writer">The HTML writer.</param> /// <param name="request">The outgoing authentication request.</param> /// <param name="windowStatus">The text to try to display in the status bar on mouse hover.</param> - protected void RenderOpenIdMessageTransmissionAsAnchorAttributes(HtmlTextWriter writer, IAuthenticationRequest request, string windowStatus) { + protected async Task RenderOpenIdMessageTransmissionAsAnchorAttributesAsync(HtmlTextWriter writer, IAuthenticationRequest request, string windowStatus, CancellationToken cancellationToken) { Requires.NotNull(writer, "writer"); Requires.NotNull(request, "request"); // We render a standard HREF attribute for non-javascript browsers. - writer.AddAttribute(HtmlTextWriterAttribute.Href, request.RedirectingResponse.GetDirectUriRequest(this.RelyingParty.Channel).AbsoluteUri); + var response = await request.GetRedirectingResponseAsync(cancellationToken); + writer.AddAttribute(HtmlTextWriterAttribute.Href, response.GetDirectUriRequest().AbsoluteUri); // And for the Javascript ones we do the extra work to use form POST where necessary. - writer.AddAttribute(HtmlTextWriterAttribute.Onclick, this.CreateGetOrPostAHrefValue(request) + " return false;"); + writer.AddAttribute(HtmlTextWriterAttribute.Onclick, await this.CreateGetOrPostAHrefValueAsync(request, cancellationToken) + " return false;"); writer.AddStyleAttribute(HtmlTextWriterStyle.Cursor, "pointer"); if (!string.IsNullOrEmpty(windowStatus)) { @@ -910,16 +915,18 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { /// A sequence of authentication requests, any one of which may be /// used to determine the user's control of the <see cref="IAuthenticationRequest.ClaimedIdentifier"/>. /// </returns> - private IEnumerable<IAuthenticationRequest> CreateRequestsCore(Identifier identifier) { + private async Task<IEnumerable<IAuthenticationRequest>> CreateRequestsCoreAsync(Identifier identifier, CancellationToken cancellationToken) { ErrorUtilities.VerifyArgumentNotNull(identifier, "identifier"); // NO CODE CONTRACTS! (yield return used here) IEnumerable<IAuthenticationRequest> requests; + var requestContext = new HttpRequestWrapper(this.Context.Request); + var results = new List<IAuthenticationRequest>(); // Approximate the returnTo (either based on the customize property or the page URL) // so we can use it to help with Realm resolution. Uri returnToApproximation; if (this.ReturnToUrl != null) { string returnToResolvedPath = this.ResolveUrl(this.ReturnToUrl); - returnToApproximation = new Uri(this.RelyingParty.Channel.GetRequestFromContext().GetPublicFacingUrl(), returnToResolvedPath); + returnToApproximation = new Uri(requestContext.GetPublicFacingUrl(), returnToResolvedPath); } else { returnToApproximation = this.Page.Request.Url; } @@ -927,7 +934,7 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { // Resolve the trust root, and swap out the scheme and port if necessary to match the // return_to URL, since this match is required by OpenID, and the consumer app // may be using HTTP at some times and HTTPS at others. - UriBuilder realm = OpenIdUtilities.GetResolvedRealm(this.Page, this.RealmUrl, this.RelyingParty.Channel.GetRequestFromContext()); + UriBuilder realm = OpenIdUtilities.GetResolvedRealm(this.Page, this.RealmUrl, requestContext); realm.Scheme = returnToApproximation.Scheme; realm.Port = returnToApproximation.Port; @@ -936,11 +943,11 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { // might slip through our validator control if it is disabled. Realm typedRealm = new Realm(realm); if (string.IsNullOrEmpty(this.ReturnToUrl)) { - requests = this.RelyingParty.CreateRequests(identifier, typedRealm); + requests = await this.RelyingParty.CreateRequestsAsync(identifier, typedRealm, requestContext); } else { // Since the user actually gave us a return_to value, // the "approximation" is exactly what we want. - requests = this.RelyingParty.CreateRequests(identifier, typedRealm, returnToApproximation); + requests = await this.RelyingParty.CreateRequestsAsync(identifier, typedRealm, returnToApproximation, cancellationToken); } // Some OPs may be listed multiple times (one with HTTPS and the other with HTTP, for example). @@ -993,9 +1000,11 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { // change its value and have that value saved. req.SetUntrustedCallbackArgument(UsePersistentCookieCallbackKey, this.UsePersistentCookie.ToString()); - yield return req; + results.Add(req); } } + + return results; } /// <summary> @@ -1003,10 +1012,11 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { /// </summary> /// <param name="request">The authentication request to send.</param> /// <returns>The javascript that should execute.</returns> - private string CreateGetOrPostAHrefValue(IAuthenticationRequest request) { + private async Task<string> CreateGetOrPostAHrefValueAsync(IAuthenticationRequest request, CancellationToken cancellationToken) { Requires.NotNull(request, "request"); - Uri directUri = request.RedirectingResponse.GetDirectUriRequest(this.RelyingParty.Channel); + var response = await request.GetRedirectingResponseAsync(cancellationToken); + Uri directUri = response.GetDirectUriRequest(); return "window.dnoa_internal.GetOrPost(" + MessagingUtilities.GetSafeJavascriptValue(directUri.AbsoluteUri) + ");"; } @@ -1014,7 +1024,7 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { /// Wires the return page to immediately display a popup window with the Provider in it. /// </summary> /// <param name="request">The request.</param> - private void ScriptPopupWindow(IAuthenticationRequest request) { + private async Task ScriptPopupWindowAsync(IAuthenticationRequest request, CancellationToken cancellationToken) { Requires.NotNull(request, "request"); RequiresEx.ValidState(this.RelyingParty != null); @@ -1027,7 +1037,7 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { startupScript.AppendLine("window.dnoa_internal.popupWindow = function() {"); startupScript.AppendFormat( @"\tvar openidPopup = {0}", - OpenId.RelyingParty.Extensions.UI.UIUtilities.GetWindowPopupScript(this.RelyingParty, request, "openidPopup")); + await OpenId.RelyingParty.Extensions.UI.UIUtilities.GetWindowPopupScriptAsync(this.RelyingParty, request, "openidPopup", cancellationToken)); startupScript.AppendLine("};"); this.Page.ClientScript.RegisterClientScriptBlock(this.GetType(), "loginPopup", startupScript.ToString(), true); diff --git a/src/DotNetOpenAuth.OpenId.RelyingParty.UI/OpenId/RelyingParty/OpenIdSelector.cs b/src/DotNetOpenAuth.OpenId.RelyingParty.UI/OpenId/RelyingParty/OpenIdSelector.cs index 7881a8b..a1c4510 100644 --- a/src/DotNetOpenAuth.OpenId.RelyingParty.UI/OpenId/RelyingParty/OpenIdSelector.cs +++ b/src/DotNetOpenAuth.OpenId.RelyingParty.UI/OpenId/RelyingParty/OpenIdSelector.cs @@ -16,6 +16,7 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { using System.IdentityModel.Claims; using System.Linq; using System.Text; + using System.Threading; using System.Web; using System.Web.UI; using System.Web.UI.HtmlControls; @@ -317,7 +318,9 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { this.positiveAssertionField.ClientID); this.Page.ClientScript.RegisterClientScriptBlock(this.GetType(), "Postback", script, true); - this.PreloadDiscovery(this.Buttons.OfType<SelectorProviderButton>().Select(op => op.OPIdentifier).Where(id => id != null)); + this.PreloadDiscoveryAsync( + this.Buttons.OfType<SelectorProviderButton>().Select(op => op.OPIdentifier).Where(id => id != null), + CancellationToken.None).Wait(); this.textBox.Visible = this.OpenIdTextBoxVisible; } diff --git a/src/DotNetOpenAuth.OpenId.RelyingParty.UI/OpenId/RelyingParty/OpenIdTextBox.cs b/src/DotNetOpenAuth.OpenId.RelyingParty.UI/OpenId/RelyingParty/OpenIdTextBox.cs index 7474854..9a5daf8 100644 --- a/src/DotNetOpenAuth.OpenId.RelyingParty.UI/OpenId/RelyingParty/OpenIdTextBox.cs +++ b/src/DotNetOpenAuth.OpenId.RelyingParty.UI/OpenId/RelyingParty/OpenIdTextBox.cs @@ -20,6 +20,8 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { using System.Net; using System.Text; using System.Text.RegularExpressions; + using System.Threading; + using System.Threading.Tasks; using System.Web; using System.Web.Security; using System.Web.UI; @@ -550,12 +552,12 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { /// A sequence of authentication requests, any one of which may be /// used to determine the user's control of the <see cref="IAuthenticationRequest.ClaimedIdentifier"/>. /// </returns> - protected internal override IEnumerable<IAuthenticationRequest> CreateRequests(Identifier identifier) { + protected internal override async Task<IEnumerable<IAuthenticationRequest>> CreateRequestsAsync(Identifier identifier, CancellationToken cancellationToken) { ErrorUtilities.VerifyArgumentNotNull(identifier, "identifier"); // We delegate all our logic to another method, since invoking base. methods // within an iterator method results in unverifiable code. - return this.CreateRequestsCore(base.CreateRequests(identifier)); + return this.CreateRequestsCore(await base.CreateRequestsAsync(identifier, cancellationToken)); } /// <summary> @@ -696,7 +698,7 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { Language = this.RequestLanguage, TimeZone = this.RequestTimeZone, PolicyUrl = string.IsNullOrEmpty(this.PolicyUrl) ? - null : new Uri(this.RelyingParty.Channel.GetRequestFromContext().GetPublicFacingUrl(), this.Page.ResolveUrl(this.PolicyUrl)), + null : new Uri(new HttpRequestWrapper(this.Context.Request).GetPublicFacingUrl(), this.Page.ResolveUrl(this.PolicyUrl)), }; // Only actually add the extension request if fields are actually being requested. diff --git a/src/DotNetOpenAuth.OpenId.RelyingParty.UI/packages.config b/src/DotNetOpenAuth.OpenId.RelyingParty.UI/packages.config index e68b4a4..d0cb981 100644 --- a/src/DotNetOpenAuth.OpenId.RelyingParty.UI/packages.config +++ b/src/DotNetOpenAuth.OpenId.RelyingParty.UI/packages.config @@ -3,6 +3,7 @@ <package id="Microsoft.AspNet.Mvc" version="3.0.20105.1" targetFramework="net45" /> <package id="Microsoft.AspNet.Razor" version="1.0.20105.408" targetFramework="net45" /> <package id="Microsoft.AspNet.WebPages" version="1.0.20105.408" targetFramework="net45" /> + <package id="Microsoft.Net.Http" version="2.0.20710.0" targetFramework="net45" /> <package id="Microsoft.Web.Infrastructure" version="1.0.0.0" targetFramework="net45" /> <package id="Validation" version="2.0.1.12362" targetFramework="net45" /> </packages>
\ No newline at end of file diff --git a/src/DotNetOpenAuth.OpenId.RelyingParty/OpenId/RelyingParty/OpenIdRelyingParty.cs b/src/DotNetOpenAuth.OpenId.RelyingParty/OpenId/RelyingParty/OpenIdRelyingParty.cs index 2ffc016..1841f6a 100644 --- a/src/DotNetOpenAuth.OpenId.RelyingParty/OpenId/RelyingParty/OpenIdRelyingParty.cs +++ b/src/DotNetOpenAuth.OpenId.RelyingParty/OpenId/RelyingParty/OpenIdRelyingParty.cs @@ -96,7 +96,7 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { /// Initializes a new instance of the <see cref="OpenIdRelyingParty"/> class. /// </summary> public OpenIdRelyingParty() - : this(OpenIdElement.Configuration.RelyingParty.ApplicationStore.CreateInstance(HttpApplicationStore, null)) { + : this(OpenIdElement.Configuration.RelyingParty.ApplicationStore.CreateInstance(GetHttpApplicationStore(), null)) { } /// <summary> @@ -161,24 +161,25 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { /// HttpApplication state dictionary to store associations and nonces. /// </summary> [EditorBrowsable(EditorBrowsableState.Advanced)] - public static IOpenIdApplicationStore HttpApplicationStore { - get { - HttpContext context = HttpContext.Current; - ErrorUtilities.VerifyOperation(context != null, Strings.StoreRequiredWhenNoHttpContextAvailable, typeof(IOpenIdApplicationStore).Name); - var store = (IOpenIdApplicationStore)context.Application[ApplicationStoreKey]; - if (store == null) { - context.Application.Lock(); - try { - if ((store = (IOpenIdApplicationStore)context.Application[ApplicationStoreKey]) == null) { - context.Application[ApplicationStoreKey] = store = new StandardRelyingPartyApplicationStore(); - } - } finally { - context.Application.UnLock(); + public static IOpenIdApplicationStore GetHttpApplicationStore(HttpContextBase context = null) { + if (context == null) { + ErrorUtilities.VerifyOperation(HttpContext.Current != null, Strings.StoreRequiredWhenNoHttpContextAvailable, typeof(IOpenIdApplicationStore).Name); + context = new HttpContextWrapper(HttpContext.Current); + } + + var store = (IOpenIdApplicationStore)context.Application[ApplicationStoreKey]; + if (store == null) { + context.Application.Lock(); + try { + if ((store = (IOpenIdApplicationStore)context.Application[ApplicationStoreKey]) == null) { + context.Application[ApplicationStoreKey] = store = new StandardRelyingPartyApplicationStore(); } + } finally { + context.Application.UnLock(); } - - return store; } + + return store; } /// <summary> @@ -394,10 +395,10 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { /// </remarks> /// <exception cref="ProtocolException">Thrown if no OpenID endpoint could be found.</exception> /// <exception cref="InvalidOperationException">Thrown if <see cref="HttpContext.Current">HttpContext.Current</see> == <c>null</c>.</exception> - public async Task<IAuthenticationRequest> CreateRequestAsync(Identifier userSuppliedIdentifier) { + public async Task<IAuthenticationRequest> CreateRequestAsync(Identifier userSuppliedIdentifier, HttpRequestBase requestContext = null) { Requires.NotNull(userSuppliedIdentifier, "userSuppliedIdentifier"); try { - return (await this.CreateRequestsAsync(userSuppliedIdentifier)).First(); + return (await this.CreateRequestsAsync(userSuppliedIdentifier, requestContext)).First(); } catch (InvalidOperationException ex) { throw ErrorUtilities.Wrap(ex, OpenIdStrings.OpenIdEndpointNotFound); } @@ -464,30 +465,33 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { /// <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> - public async Task<IEnumerable<IAuthenticationRequest>> CreateRequestsAsync(Identifier userSuppliedIdentifier, Realm realm) { - RequiresEx.ValidState(HttpContext.Current != null && HttpContext.Current.Request != null, MessagingStrings.HttpContextRequired); + public async Task<IEnumerable<IAuthenticationRequest>> CreateRequestsAsync(Identifier userSuppliedIdentifier, Realm realm, HttpRequestBase requestContext = null, CancellationToken cancellationToken = default(CancellationToken)) { + RequiresEx.ValidState(requestContext != null || (HttpContext.Current != null && HttpContext.Current.Request != null), MessagingStrings.HttpContextRequired); Requires.NotNull(userSuppliedIdentifier, "userSuppliedIdentifier"); Requires.NotNull(realm, "realm"); + requestContext = requestContext ?? this.channel.GetRequestFromContext(); + // This next code contract is a BAD idea, because it causes each authentication request to be generated // at least an extra time. //// // Build the return_to URL - UriBuilder returnTo = new UriBuilder(this.Channel.GetRequestFromContext().GetPublicFacingUrl()); + UriBuilder returnTo = new UriBuilder(requestContext.GetPublicFacingUrl()); // Trim off any parameters with an "openid." prefix, and a few known others // to avoid carrying state from a prior login attempt. returnTo.Query = string.Empty; - NameValueCollection queryParams = this.Channel.GetRequestFromContext().GetQueryStringBeforeRewriting(); + NameValueCollection queryParams = requestContext.GetQueryStringBeforeRewriting(); var returnToParams = new Dictionary<string, string>(queryParams.Count); foreach (string key in queryParams) { if (!IsOpenIdSupportingParameter(key) && key != null) { returnToParams.Add(key, queryParams[key]); } } + returnTo.AppendQueryArgs(returnToParams); - return await this.CreateRequestsAsync(userSuppliedIdentifier, realm, returnTo.Uri); + return await this.CreateRequestsAsync(userSuppliedIdentifier, realm, returnTo.Uri, cancellationToken); } /// <summary> @@ -510,11 +514,10 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { /// <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> - public async Task<IEnumerable<IAuthenticationRequest>> CreateRequestsAsync(Identifier userSuppliedIdentifier) { + public async Task<IEnumerable<IAuthenticationRequest>> CreateRequestsAsync(Identifier userSuppliedIdentifier, HttpRequestBase requestContext = null, CancellationToken cancellationToken = default(CancellationToken)) { Requires.NotNull(userSuppliedIdentifier, "userSuppliedIdentifier"); - RequiresEx.ValidState(HttpContext.Current != null && HttpContext.Current.Request != null, MessagingStrings.HttpContextRequired); - return await this.CreateRequestsAsync(userSuppliedIdentifier, Realm.AutoDetect); + return await this.CreateRequestsAsync(userSuppliedIdentifier, Realm.AutoDetect, requestContext, cancellationToken); } /// <summary> |