summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/DotNetOpenAuth/Messaging/MessagingUtilities.cs70
-rw-r--r--src/DotNetOpenAuth/OpenId/Extensions/SimpleRegistration/ClaimsResponse.cs81
-rw-r--r--src/DotNetOpenAuth/OpenId/RelyingParty/OpenIdAjaxTextBox.cs42
-rw-r--r--src/DotNetOpenAuth/Util.cs45
4 files changed, 129 insertions, 109 deletions
diff --git a/src/DotNetOpenAuth/Messaging/MessagingUtilities.cs b/src/DotNetOpenAuth/Messaging/MessagingUtilities.cs
index 6c40fba..48922f6 100644
--- a/src/DotNetOpenAuth/Messaging/MessagingUtilities.cs
+++ b/src/DotNetOpenAuth/Messaging/MessagingUtilities.cs
@@ -9,6 +9,7 @@ namespace DotNetOpenAuth.Messaging {
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Diagnostics.CodeAnalysis;
+ using System.Globalization;
using System.IO;
using System.Linq;
using System.Net;
@@ -28,6 +29,29 @@ namespace DotNetOpenAuth.Messaging {
internal static readonly RandomNumberGenerator CryptoRandomDataGenerator = new RNGCryptoServiceProvider();
/// <summary>
+ /// A set of escaping mappings that help secure a string from javscript execution.
+ /// </summary>
+ /// <remarks>
+ /// The characters to escape here are inspired by
+ /// http://code.google.com/p/doctype/wiki/ArticleXSSInJavaScript
+ /// </remarks>
+ private static readonly Dictionary<string, string> javascriptStaticStringEscaping = new Dictionary<string, string> {
+ { "\\", @"\\" }, // this WAS just above the & substitution but we moved it here to prevent double-escaping
+ { "\t", @"\t" },
+ { "\n", @"\n" },
+ { "\r", @"\r" },
+ { "\u0085", @"\u0085" },
+ { "\u2028", @"\u2028" },
+ { "\u2029", @"\u2029" },
+ { "'", @"\x27" },
+ { "\"", @"\x22" },
+ { "&", @"\x26" },
+ { "<", @"\x3c" },
+ { ">", @"\x3e" },
+ { "=", @"\x3d" },
+ };
+
+ /// <summary>
/// Gets the original request URL, as seen from the browser before any URL rewrites on the server if any.
/// Cookieless session directory (if applicable) is also included.
/// </summary>
@@ -558,6 +582,52 @@ namespace DotNetOpenAuth.Messaging {
}
/// <summary>
+ /// Constructs a Javascript expression that will create an object
+ /// on the user agent when assigned to a variable.
+ /// </summary>
+ /// <param name="namesAndValues">The untrusted names and untrusted values to inject into the JSON object.</param>
+ /// <returns>The Javascript JSON object as a string.</returns>
+ internal static string CreateJsonObject(IEnumerable<KeyValuePair<string, string>> namesAndValues) {
+ StringBuilder builder = new StringBuilder();
+ builder.Append("{ ");
+
+ foreach (var pair in namesAndValues) {
+ builder.Append(MessagingUtilities.GetSafeJavascriptValue(pair.Key));
+ builder.Append(": ");
+ builder.Append(MessagingUtilities.GetSafeJavascriptValue(pair.Value));
+ builder.Append(",");
+ }
+
+ if (builder[builder.Length - 1] == ',') {
+ builder.Length -= 1;
+ }
+ builder.Append("}");
+ return builder.ToString();
+ }
+
+ /// <summary>
+ /// Prepares what SHOULD be simply a string value for safe injection into Javascript
+ /// by using appropriate character escaping.
+ /// </summary>
+ /// <param name="value">The untrusted string value to be escaped to protected against XSS attacks. May be null.</param>
+ /// <returns>The escaped string.</returns>
+ internal static string GetSafeJavascriptValue(string value) {
+ if (value == null) {
+ return "null";
+ }
+
+ // We use a StringBuilder because we have potentially many replacements to do,
+ // and we don't want to create a new string for every intermediate replacement step.
+ StringBuilder builder = new StringBuilder(value);
+ foreach (var pair in javascriptStaticStringEscaping) {
+ builder.Replace(pair.Key, pair.Value);
+ }
+ builder.Insert(0, '\'');
+ builder.Append('\'');
+ return builder.ToString();
+ }
+
+ /// <summary>
/// A class to convert a <see cref="Comparison&lt;T&gt;"/> into an <see cref="IComparer&lt;T&gt;"/>.
/// </summary>
/// <typeparam name="T">The type of objects being compared.</typeparam>
diff --git a/src/DotNetOpenAuth/OpenId/Extensions/SimpleRegistration/ClaimsResponse.cs b/src/DotNetOpenAuth/OpenId/Extensions/SimpleRegistration/ClaimsResponse.cs
index 082fd52..876315e 100644
--- a/src/DotNetOpenAuth/OpenId/Extensions/SimpleRegistration/ClaimsResponse.cs
+++ b/src/DotNetOpenAuth/OpenId/Extensions/SimpleRegistration/ClaimsResponse.cs
@@ -20,7 +20,7 @@ namespace DotNetOpenAuth.OpenId.Extensions.SimpleRegistration {
/// A struct storing Simple Registration field values describing an
/// authenticating user.
/// </summary>
- public sealed class ClaimsResponse : ExtensionBase {
+ public sealed class ClaimsResponse : ExtensionBase, IClientScriptExtensionResponse {
/// <summary>
/// The factory method that may be used in deserialization of this message.
/// </summary>
@@ -221,48 +221,6 @@ namespace DotNetOpenAuth.OpenId.Extensions.SimpleRegistration {
}
}
- #region IClientScriptExtension Members
-
- // TODO: re-enable this
- ////string IClientScriptExtensionResponse.InitializeJavaScriptData(IDictionary<string, string> sreg, IAuthenticationResponse response, string typeUri) {
- //// StringBuilder builder = new StringBuilder();
- //// builder.Append("{ ");
-
- //// string nickname, email, fullName, dob, genderString, postalCode, country, language, timeZone;
- //// if (sreg.TryGetValue(Constants.nickname, out nickname)) {
- //// builder.Append(createAddFieldJS(Constants.nickname, nickname));
- //// }
- //// if (sreg.TryGetValue(Constants.email, out email)) {
- //// builder.Append(createAddFieldJS(Constants.email, email));
- //// }
- //// if (sreg.TryGetValue(Constants.fullname, out fullName)) {
- //// builder.Append(createAddFieldJS(Constants.fullname, fullName));
- //// }
- //// if (sreg.TryGetValue(Constants.dob, out dob)) {
- //// builder.Append(createAddFieldJS(Constants.dob, dob));
- //// }
- //// if (sreg.TryGetValue(Constants.gender, out genderString)) {
- //// builder.Append(createAddFieldJS(Constants.gender, genderString));
- //// }
- //// if (sreg.TryGetValue(Constants.postcode, out postalCode)) {
- //// builder.Append(createAddFieldJS(Constants.postcode, postalCode));
- //// }
- //// if (sreg.TryGetValue(Constants.country, out country)) {
- //// builder.Append(createAddFieldJS(Constants.country, country));
- //// }
- //// if (sreg.TryGetValue(Constants.language, out language)) {
- //// builder.Append(createAddFieldJS(Constants.language, language));
- //// }
- //// if (sreg.TryGetValue(Constants.timezone, out timeZone)) {
- //// builder.Append(createAddFieldJS(Constants.timezone, timeZone));
- //// }
- //// if (builder[builder.Length - 1] == ',') builder.Length -= 1;
- //// builder.Append("}");
- //// return builder.ToString();
- ////}
-
- #endregion
-
/// <summary>
/// Tests equality of two <see cref="ClaimsResponse"/> objects.
/// </summary>
@@ -320,5 +278,42 @@ namespace DotNetOpenAuth.OpenId.Extensions.SimpleRegistration {
public override int GetHashCode() {
return (this.Nickname != null) ? this.Nickname.GetHashCode() : base.GetHashCode();
}
+
+ #region IClientScriptExtension Members
+
+ /// <summary>
+ /// Reads the extension information on an authentication response from the provider.
+ /// </summary>
+ /// <param name="response">The incoming OpenID response carrying the extension.</param>
+ /// <returns>
+ /// A Javascript snippet that when executed on the user agent returns an object with
+ /// the information deserialized from the extension response.
+ /// </returns>
+ /// <remarks>
+ /// This method is called <b>before</b> the signature on the assertion response has been
+ /// verified. Therefore all information in these fields should be assumed unreliable
+ /// and potentially falsified.
+ /// </remarks>
+ string IClientScriptExtensionResponse.InitializeJavaScriptData(IProtocolMessageWithExtensions response) {
+ var sreg = new Dictionary<string, string>(15);
+
+ // Although we could probably whip up a trip with MessageDictionary
+ // to avoid explicitly setting each field, doing so would likely
+ // open ourselves up to security exploits from the OP as it would
+ // make possible sending arbitrary javascript in arbitrary field names.
+ sreg[Constants.nickname] = this.Nickname;
+ sreg[Constants.email] = this.Email;
+ sreg[Constants.fullname] = this.FullName;
+ sreg[Constants.dob] = this.BirthDateRaw;
+ sreg[Constants.gender] = this.Gender.HasValue ? this.Gender.Value.ToString() : null;
+ sreg[Constants.postcode] = this.PostalCode;
+ sreg[Constants.country] = this.Country;
+ sreg[Constants.language] = this.Language;
+ sreg[Constants.timezone] = this.TimeZone;
+
+ return MessagingUtilities.CreateJsonObject(sreg);
+ }
+
+ #endregion
}
} \ No newline at end of file
diff --git a/src/DotNetOpenAuth/OpenId/RelyingParty/OpenIdAjaxTextBox.cs b/src/DotNetOpenAuth/OpenId/RelyingParty/OpenIdAjaxTextBox.cs
index 9bdf2f8..5172800 100644
--- a/src/DotNetOpenAuth/OpenId/RelyingParty/OpenIdAjaxTextBox.cs
+++ b/src/DotNetOpenAuth/OpenId/RelyingParty/OpenIdAjaxTextBox.cs
@@ -871,29 +871,29 @@ namespace DotNetOpenAuth.OpenId.RelyingParty {
try {
List<IAuthenticationRequest> requests = this.CreateRequests(userSuppliedIdentifier, true);
if (requests.Count > 0) {
- discoveryResultBuilder.AppendFormat("claimedIdentifier: {0},", Util.GetSafeJavascriptValue(requests[0].ClaimedIdentifier));
+ discoveryResultBuilder.AppendFormat("claimedIdentifier: {0},", MessagingUtilities.GetSafeJavascriptValue(requests[0].ClaimedIdentifier));
discoveryResultBuilder.Append("requests: [");
foreach (IAuthenticationRequest request in requests) {
this.OnLoggingIn(request);
discoveryResultBuilder.Append("{");
- discoveryResultBuilder.AppendFormat("endpoint: {0},", Util.GetSafeJavascriptValue(request.Provider.Uri.AbsoluteUri));
+ discoveryResultBuilder.AppendFormat("endpoint: {0},", MessagingUtilities.GetSafeJavascriptValue(request.Provider.Uri.AbsoluteUri));
request.Mode = AuthenticationRequestMode.Immediate;
UserAgentResponse response = request.RedirectingResponse;
- discoveryResultBuilder.AppendFormat("immediate: {0},", Util.GetSafeJavascriptValue(response.DirectUriRequest.AbsoluteUri));
+ discoveryResultBuilder.AppendFormat("immediate: {0},", MessagingUtilities.GetSafeJavascriptValue(response.DirectUriRequest.AbsoluteUri));
request.Mode = AuthenticationRequestMode.Setup;
response = request.RedirectingResponse;
- discoveryResultBuilder.AppendFormat("setup: {0}", Util.GetSafeJavascriptValue(response.DirectUriRequest.AbsoluteUri));
+ discoveryResultBuilder.AppendFormat("setup: {0}", MessagingUtilities.GetSafeJavascriptValue(response.DirectUriRequest.AbsoluteUri));
discoveryResultBuilder.Append("},");
}
discoveryResultBuilder.Length -= 1; // trim off last comma
discoveryResultBuilder.Append("]");
} else {
discoveryResultBuilder.Append("requests: new Array(),");
- discoveryResultBuilder.AppendFormat("error: {0}", Util.GetSafeJavascriptValue(OpenIdStrings.OpenIdEndpointNotFound));
+ discoveryResultBuilder.AppendFormat("error: {0}", MessagingUtilities.GetSafeJavascriptValue(OpenIdStrings.OpenIdEndpointNotFound));
}
} catch (ProtocolException ex) {
discoveryResultBuilder.Append("requests: new Array(),");
- discoveryResultBuilder.AppendFormat("error: {0}", Util.GetSafeJavascriptValue(ex.Message));
+ discoveryResultBuilder.AppendFormat("error: {0}", MessagingUtilities.GetSafeJavascriptValue(ex.Message));
}
discoveryResultBuilder.Append("}");
this.discoveryResult = discoveryResultBuilder.ToString();
@@ -1122,24 +1122,24 @@ namespace DotNetOpenAuth.OpenId.RelyingParty {
startupScript.AppendFormat(
CultureInfo.InvariantCulture,
"initAjaxOpenId(box, {0}, {1}, {2}, {3}, {4}, {5}, {6}, {7}, {8}, {9}, {10}, {11}, {12}, {13}, {14}, {15}, {16}, {17}, function({18}, {19}, {20}) {{{21}}});{22}",
- Util.GetSafeJavascriptValue(this.Page.ClientScript.GetWebResourceUrl(this.GetType(), OpenIdTextBox.EmbeddedLogoResourceName)),
- Util.GetSafeJavascriptValue(this.Page.ClientScript.GetWebResourceUrl(this.GetType(), EmbeddedDotNetOpenIdLogoResourceName)),
- Util.GetSafeJavascriptValue(this.Page.ClientScript.GetWebResourceUrl(this.GetType(), EmbeddedSpinnerResourceName)),
- Util.GetSafeJavascriptValue(this.Page.ClientScript.GetWebResourceUrl(this.GetType(), EmbeddedLoginSuccessResourceName)),
- Util.GetSafeJavascriptValue(this.Page.ClientScript.GetWebResourceUrl(this.GetType(), EmbeddedLoginFailureResourceName)),
+ MessagingUtilities.GetSafeJavascriptValue(this.Page.ClientScript.GetWebResourceUrl(this.GetType(), OpenIdTextBox.EmbeddedLogoResourceName)),
+ MessagingUtilities.GetSafeJavascriptValue(this.Page.ClientScript.GetWebResourceUrl(this.GetType(), EmbeddedDotNetOpenIdLogoResourceName)),
+ MessagingUtilities.GetSafeJavascriptValue(this.Page.ClientScript.GetWebResourceUrl(this.GetType(), EmbeddedSpinnerResourceName)),
+ MessagingUtilities.GetSafeJavascriptValue(this.Page.ClientScript.GetWebResourceUrl(this.GetType(), EmbeddedLoginSuccessResourceName)),
+ MessagingUtilities.GetSafeJavascriptValue(this.Page.ClientScript.GetWebResourceUrl(this.GetType(), EmbeddedLoginFailureResourceName)),
this.Throttle,
this.Timeout.TotalMilliseconds,
string.IsNullOrEmpty(this.OnClientAssertionReceived) ? "null" : "'" + this.OnClientAssertionReceived.Replace(@"\", @"\\").Replace("'", @"\'") + "'",
- Util.GetSafeJavascriptValue(this.LogOnText),
- Util.GetSafeJavascriptValue(this.LogOnToolTip),
- Util.GetSafeJavascriptValue(this.RetryText),
- Util.GetSafeJavascriptValue(this.RetryToolTip),
- Util.GetSafeJavascriptValue(this.BusyToolTip),
- Util.GetSafeJavascriptValue(this.IdentifierRequiredMessage),
- Util.GetSafeJavascriptValue(this.LogOnInProgressMessage),
- Util.GetSafeJavascriptValue(this.AuthenticationSucceededToolTip),
- Util.GetSafeJavascriptValue(this.AuthenticatedAsToolTip),
- Util.GetSafeJavascriptValue(this.AuthenticationFailedToolTip),
+ MessagingUtilities.GetSafeJavascriptValue(this.LogOnText),
+ MessagingUtilities.GetSafeJavascriptValue(this.LogOnToolTip),
+ MessagingUtilities.GetSafeJavascriptValue(this.RetryText),
+ MessagingUtilities.GetSafeJavascriptValue(this.RetryToolTip),
+ MessagingUtilities.GetSafeJavascriptValue(this.BusyToolTip),
+ MessagingUtilities.GetSafeJavascriptValue(this.IdentifierRequiredMessage),
+ MessagingUtilities.GetSafeJavascriptValue(this.LogOnInProgressMessage),
+ MessagingUtilities.GetSafeJavascriptValue(this.AuthenticationSucceededToolTip),
+ MessagingUtilities.GetSafeJavascriptValue(this.AuthenticatedAsToolTip),
+ MessagingUtilities.GetSafeJavascriptValue(this.AuthenticationFailedToolTip),
identifierParameterName,
discoveryCallbackResultParameterName,
discoveryErrorCallbackParameterName,
diff --git a/src/DotNetOpenAuth/Util.cs b/src/DotNetOpenAuth/Util.cs
index 9004cbc..cb5581f 100644
--- a/src/DotNetOpenAuth/Util.cs
+++ b/src/DotNetOpenAuth/Util.cs
@@ -21,29 +21,6 @@ namespace DotNetOpenAuth {
internal const string DefaultNamespace = "DotNetOpenAuth";
/// <summary>
- /// A set of escaping mappings that help secure a string from javscript execution.
- /// </summary>
- /// <remarks>
- /// The characters to escape here are inspired by
- /// http://code.google.com/p/doctype/wiki/ArticleXSSInJavaScript
- /// </remarks>
- private static readonly Dictionary<string, string> javascriptStaticStringEscaping = new Dictionary<string, string> {
- { "\\", @"\\" }, // this WAS just above the & substitution but we moved it here to prevent double-escaping
- { "\t", @"\t" },
- { "\n", @"\n" },
- { "\r", @"\r" },
- { "\u0085", @"\u0085" },
- { "\u2028", @"\u2028" },
- { "\u2029", @"\u2029" },
- { "'", @"\x27" },
- { "\"", @"\x22" },
- { "&", @"\x26" },
- { "<", @"\x3c" },
- { ">", @"\x3e" },
- { "=", @"\x3d" },
- };
-
- /// <summary>
/// Gets a human-readable description of the library name and version, including
/// whether the build is an official or private one.
/// </summary>
@@ -80,28 +57,6 @@ namespace DotNetOpenAuth {
}
/// <summary>
- /// Prepares what SHOULD be simply a string value for safe injection into Javascript
- /// by using appropriate character escaping.
- /// </summary>
- /// <param name="value">The untrusted string value to be escaped to protected against XSS attacks.</param>
- /// <returns>The escaped string.</returns>
- internal static string GetSafeJavascriptValue(string value) {
- if (value == null) {
- return "null";
- }
-
- // We use a StringBuilder because we have potentially many replacements to do,
- // and we don't want to create a new string for every intermediate replacement step.
- StringBuilder builder = new StringBuilder(value);
- foreach (var pair in javascriptStaticStringEscaping) {
- builder.Replace(pair.Key, pair.Value);
- }
- builder.Insert(0, '\'');
- builder.Append('\'');
- return builder.ToString();
- }
-
- /// <summary>
/// Prepares a dictionary for printing as a string.
/// </summary>
/// <typeparam name="K">The type of the key.</typeparam>