diff options
Diffstat (limited to 'src')
3 files changed, 78 insertions, 98 deletions
diff --git a/src/DotNetOpenAuth/Messaging/MessagingUtilities.cs b/src/DotNetOpenAuth/Messaging/MessagingUtilities.cs index a52f51b..8ae228d 100644 --- a/src/DotNetOpenAuth/Messaging/MessagingUtilities.cs +++ b/src/DotNetOpenAuth/Messaging/MessagingUtilities.cs @@ -473,6 +473,20 @@ namespace DotNetOpenAuth.Messaging { } /// <summary> + /// Flattens the specified sequence of sequences. + /// </summary> + /// <typeparam name="T">The type of element contained in the sequence.</typeparam> + /// <param name="sequence">The sequence of sequences to flatten.</param> + /// <returns>A sequence of the contained items.</returns> + internal static IEnumerable<T> Flatten<T>(this IEnumerable<IEnumerable<T>> sequence) { + foreach (IEnumerable<T> subsequence in sequence) { + foreach (T item in subsequence) { + yield return item; + } + } + } + + /// <summary> /// Tests whether two arrays are equal in contents and ordering. /// </summary> /// <typeparam name="T">The type of elements in the arrays.</typeparam> diff --git a/src/DotNetOpenAuth/OpenId/RelyingParty/OpenIdAjaxRelyingParty.cs b/src/DotNetOpenAuth/OpenId/RelyingParty/OpenIdAjaxRelyingParty.cs index e2ddf16..536019b 100644 --- a/src/DotNetOpenAuth/OpenId/RelyingParty/OpenIdAjaxRelyingParty.cs +++ b/src/DotNetOpenAuth/OpenId/RelyingParty/OpenIdAjaxRelyingParty.cs @@ -112,9 +112,9 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { } /// <summary> - /// Performs discovery on some identifier on behalf of Javascript running on the browser. + /// Serializes discovery results on some <i>single</i> identifier on behalf of Javascript running on the browser. /// </summary> - /// <param name="requests">The identifier discovery results to serialize as a JSON response.</param> + /// <param name="requests">The discovery results from just <i>one</i> identifier to serialize as a JSON response.</param> /// <returns> /// The JSON result to return to the user agent. /// </returns> @@ -139,36 +139,81 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { public OutgoingWebResponse AsAjaxDiscoveryResult(IEnumerable<IAuthenticationRequest> requests) { Contract.Requires<ArgumentNullException>(requests != null); + var serializer = new JavaScriptSerializer(); return new OutgoingWebResponse { - Body = this.AsJsonDiscoveryResult(requests), + Body = serializer.Serialize(this.AsJsonDiscoveryResult(requests)), }; } /// <summary> + /// Serializes discovery on a set of identifiers for preloading into an HTML page that carries + /// an AJAX-aware OpenID control. + /// </summary> + /// <param name="requests">The discovery results to serialize as a JSON response.</param> + /// <returns> + /// The JSON result to return to the user agent. + /// </returns> + public string AsAjaxPreloadedDiscoveryResult(IEnumerable<IAuthenticationRequest> requests) { + Contract.Requires<ArgumentNullException>(requests != null); + + var serializer = new JavaScriptSerializer(); + string json = serializer.Serialize(this.AsJsonPreloadedDiscoveryResult(requests)); + + string script = "window.dnoa_internal.loadPreloadedDiscoveryResults(" + json + ");"; + return script; + } + + /// <summary> /// Converts a sequence of authentication requests to a JSON object for seeding an AJAX-enabled login page. /// </summary> - /// <param name="requests">The authentication requests.</param> - /// <returns>A JSON string.</returns> - private string AsJsonDiscoveryResult(IEnumerable<IAuthenticationRequest> requests) { + /// <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) { + Contract.Requires<ArgumentNullException>(requests != null); + requests = requests.CacheGeneratedResults(); - JavaScriptSerializer serializer = new JavaScriptSerializer(); - string json; if (requests.Any()) { - json = serializer.Serialize(new { + return new { claimedIdentifier = requests.First().ClaimedIdentifier, requests = requests.Select(req => new { endpoint = req.Provider.Uri.AbsoluteUri, immediate = this.GetRedirectUrl(req, true), setup = this.GetRedirectUrl(req, false), }).ToArray() - }); + }; } else { - json = serializer.Serialize(new { + return new { requests = new object[0], error = OpenIdStrings.OpenIdEndpointNotFound, - }); + }; } + } + + /// <summary> + /// Serializes discovery on a set of identifiers for preloading into an HTML page that carries + /// an AJAX-aware OpenID control. + /// </summary> + /// <param name="requests">The discovery results to serialize as a JSON response.</param> + /// <returns> + /// A JSON object, not yet serialized to a string. + /// </returns> + private object AsJsonPreloadedDiscoveryResult(IEnumerable<IAuthenticationRequest> requests) { + Contract.Requires<ArgumentNullException>(requests != null); + + // We prepare a JSON object with this interface: + // Array discoveryWrappers; + // Where each element in the above array has this interface: + // class discoveryWrapper { + // 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 = requestsByIdentifier.Key.ToString(), + discoveryResult = this.AsJsonDiscoveryResult(requestsByIdentifier), + }).ToArray(); return json; } diff --git a/src/DotNetOpenAuth/OpenId/RelyingParty/OpenIdRelyingPartyAjaxControlBase.cs b/src/DotNetOpenAuth/OpenId/RelyingParty/OpenIdRelyingPartyAjaxControlBase.cs index 7153aa2..37ba8c1 100644 --- a/src/DotNetOpenAuth/OpenId/RelyingParty/OpenIdRelyingPartyAjaxControlBase.cs +++ b/src/DotNetOpenAuth/OpenId/RelyingParty/OpenIdRelyingPartyAjaxControlBase.cs @@ -16,6 +16,7 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { using System.Linq; using System.Text; using System.Web; + using System.Web.Script.Serialization; using System.Web.UI; using DotNetOpenAuth.Configuration; using DotNetOpenAuth.Messaging; @@ -289,7 +290,10 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { Logger.OpenId.InfoFormat("AJAX discovery on {0} requested.", userSuppliedIdentifier); this.Identifier = userSuppliedIdentifier; - this.discoveryResult = this.SerializeDiscoveryAsJson(this.Identifier); + + var serializer = new JavaScriptSerializer(); + IEnumerable<IAuthenticationRequest> requests = this.CreateRequests(this.Identifier); + this.discoveryResult = serializer.Serialize(this.AjaxRelyingParty.AsJsonDiscoveryResult(requests)); } /// <summary> @@ -316,8 +320,8 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { /// </summary> /// <param name="identifiers">The identifiers to perform discovery on.</param> protected void PreloadDiscovery(IEnumerable<Identifier> identifiers) { - string discoveryResults = this.SerializeDiscoveryAsJson(identifiers); - string script = "window.dnoa_internal.loadPreloadedDiscoveryResults(" + discoveryResults + ");"; + string script = this.AjaxRelyingParty.AsAjaxPreloadedDiscoveryResult( + identifiers.Select(id => this.CreateRequests(id)).Flatten()); this.Page.ClientScript.RegisterClientScriptBlock(typeof(OpenIdRelyingPartyAjaxControlBase), this.ClientID, script, true); } @@ -427,89 +431,6 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { } /// <summary> - /// Serializes the discovery of multiple identifiers as a JSON object. - /// </summary> - /// <param name="identifiers">The identifiers to perform discovery on and create requests for.</param> - /// <returns>The serialized JSON object.</returns> - private string SerializeDiscoveryAsJson(IEnumerable<Identifier> identifiers) { - ErrorUtilities.VerifyArgumentNotNull(identifiers, "identifiers"); - - // We prepare a JSON object with this interface: - // Array discoveryWrappers; - // Where each element in the above array has this interface: - // class discoveryWrapper { - // string userSuppliedIdentifier; - // jsonResponse discoveryResult; // contains result of call to SerializeDiscoveryAsJson(Identifier) - // } - StringBuilder discoveryResultBuilder = new StringBuilder(); - discoveryResultBuilder.Append("["); - foreach (var identifier in identifiers) { // TODO: parallelize discovery on these identifiers - discoveryResultBuilder.Append("{"); - discoveryResultBuilder.AppendFormat("userSuppliedIdentifier: {0},", MessagingUtilities.GetSafeJavascriptValue(identifier)); - discoveryResultBuilder.AppendFormat("discoveryResult: {0}", this.SerializeDiscoveryAsJson(identifier)); - discoveryResultBuilder.Append("},"); - } - - discoveryResultBuilder.Length -= 1; // trim last comma - discoveryResultBuilder.Append("]"); - return discoveryResultBuilder.ToString(); - } - - /// <summary> - /// Serializes the results of discovery and the created auth requests as a JSON object - /// for the user agent to initiate. - /// </summary> - /// <param name="identifier">The identifier to perform discovery on.</param> - /// <returns>The JSON string.</returns> - private string SerializeDiscoveryAsJson(Identifier identifier) { - ErrorUtilities.VerifyArgumentNotNull(identifier, "identifier"); - - // We prepare a JSON object with this interface: - // class jsonResponse { - // string claimedIdentifier; - // Array requests; // never null - // string error; // null if no error - // } - // Each element in the requests array looks like this: - // class jsonAuthRequest { - // string endpoint; // URL to the OP endpoint - // string immediate; // URL to initiate an immediate request - // string setup; // URL to initiate a setup request. - // } - StringBuilder discoveryResultBuilder = new StringBuilder(); - discoveryResultBuilder.Append("{"); - try { - IEnumerable<IAuthenticationRequest> requests = this.CreateRequests(identifier).CacheGeneratedResults(); - if (requests.Any()) { - discoveryResultBuilder.AppendFormat("claimedIdentifier: {0},", MessagingUtilities.GetSafeJavascriptValue(requests.First().ClaimedIdentifier)); - discoveryResultBuilder.Append("requests: ["); - foreach (IAuthenticationRequest request in requests) { - discoveryResultBuilder.Append("{"); - discoveryResultBuilder.AppendFormat("endpoint: {0},", MessagingUtilities.GetSafeJavascriptValue(request.Provider.Uri.AbsoluteUri)); - request.Mode = AuthenticationRequestMode.Immediate; - OutgoingWebResponse response = request.RedirectingResponse; - discoveryResultBuilder.AppendFormat("immediate: {0},", MessagingUtilities.GetSafeJavascriptValue(response.GetDirectUriRequest(this.RelyingParty.Channel).AbsoluteUri)); - request.Mode = AuthenticationRequestMode.Setup; - response = request.RedirectingResponse; - discoveryResultBuilder.AppendFormat("setup: {0}", MessagingUtilities.GetSafeJavascriptValue(response.GetDirectUriRequest(this.RelyingParty.Channel).AbsoluteUri)); - discoveryResultBuilder.Append("},"); - } - discoveryResultBuilder.Length -= 1; // trim off last comma - discoveryResultBuilder.Append("]"); - } else { - discoveryResultBuilder.Append("requests: [],"); - discoveryResultBuilder.AppendFormat("error: {0}", MessagingUtilities.GetSafeJavascriptValue(OpenIdStrings.OpenIdEndpointNotFound)); - } - } catch (ProtocolException ex) { - discoveryResultBuilder.Append("requests: [],"); - discoveryResultBuilder.AppendFormat("error: {0}", MessagingUtilities.GetSafeJavascriptValue(ex.Message)); - } - - discoveryResultBuilder.Append("}"); - return discoveryResultBuilder.ToString(); - } - - /// <summary> /// Constructs a function that will initiate an AJAX callback. /// </summary> /// <param name="async">if set to <c>true</c> causes the AJAX callback to be a little more asynchronous. Note that <c>false</c> does not mean the call is absolutely synchronous.</param> |