summaryrefslogtreecommitdiffstats
path: root/src/DotNetOpenId/Yadis/Yadis.cs
diff options
context:
space:
mode:
Diffstat (limited to 'src/DotNetOpenId/Yadis/Yadis.cs')
-rw-r--r--src/DotNetOpenId/Yadis/Yadis.cs87
1 files changed, 70 insertions, 17 deletions
diff --git a/src/DotNetOpenId/Yadis/Yadis.cs b/src/DotNetOpenId/Yadis/Yadis.cs
index b658cf6..37a58e4 100644
--- a/src/DotNetOpenId/Yadis/Yadis.cs
+++ b/src/DotNetOpenId/Yadis/Yadis.cs
@@ -7,37 +7,90 @@ using System.Xml;
using System.Xml.Serialization;
using System.Net.Mime;
using System.Web.UI.HtmlControls;
+using System.Diagnostics;
namespace DotNetOpenId.Yadis {
class Yadis {
internal const string HeaderName = "X-XRDS-Location";
- public static DiscoveryResult Discover(UriIdentifier uri) {
- var response = UntrustedWebRequest.Request(uri, null,
- new[] { ContentTypes.Html, ContentTypes.XHtml, ContentTypes.Xrds });
- if (response.StatusCode != System.Net.HttpStatusCode.OK) {
+ /// <summary>
+ /// Performs YADIS discovery on some identifier.
+ /// </summary>
+ /// <param name="uri">The URI to perform discovery on.</param>
+ /// <param name="requireSsl">Whether discovery should fail if any step of it is not encrypted.</param>
+ /// <returns>
+ /// The result of discovery on the given URL.
+ /// Null may be returned if an error occurs,
+ /// or if <paramref name="requireSsl"/> is true but part of discovery
+ /// is not protected by SSL.
+ /// </returns>
+ public static DiscoveryResult Discover(UriIdentifier uri, bool requireSsl) {
+ UntrustedWebResponse response;
+ try {
+ if (requireSsl && !string.Equals(uri.Uri.Scheme, Uri.UriSchemeHttps, StringComparison.OrdinalIgnoreCase)) {
+ Logger.WarnFormat("Discovery on insecure identifier '{0}' aborted.", uri);
+ return null;
+ }
+ response = UntrustedWebRequest.Request(uri, null,
+ new[] { ContentTypes.Html, ContentTypes.XHtml, ContentTypes.Xrds }, requireSsl);
+ if (response.StatusCode != System.Net.HttpStatusCode.OK) {
+ Logger.ErrorFormat("HTTP error {0} {1} while performing discovery on {2}.", (int)response.StatusCode, response.StatusCode, uri);
+ return null;
+ }
+ } catch (ArgumentException ex) {
+ // Unsafe URLs generate this
+ Logger.WarnFormat("Unsafe OpenId URL detected ({0}). Request aborted. {1}", uri, ex);
return null;
}
UntrustedWebResponse response2 = null;
- if (response.ContentType.MediaType == ContentTypes.Xrds) {
+ if (isXrdsDocument(response)) {
+ Logger.Debug("An XRDS response was received from GET at user-supplied identifier.");
response2 = response;
} else {
string uriString = response.Headers.Get(HeaderName);
Uri url = null;
- if (uriString != null)
- Uri.TryCreate(uriString, UriKind.Absolute, out url);
- if (url == null && response.ContentType.MediaType == ContentTypes.Html)
+ if (uriString != null) {
+ if (Uri.TryCreate(uriString, UriKind.Absolute, out url)) {
+ Logger.DebugFormat("{0} found in HTTP header. Preparing to pull XRDS from {1}", HeaderName, url);
+ }
+ }
+ if (url == null && (response.ContentType.MediaType == ContentTypes.Html || response.ContentType.MediaType == ContentTypes.XHtml)) {
url = FindYadisDocumentLocationInHtmlMetaTags(response.ReadResponseString());
+ if (url != null) {
+ Logger.DebugFormat("{0} found in HTML Http-Equiv tag. Preparing to pull XRDS from {1}", HeaderName, url);
+ }
+ }
if (url != null) {
- response2 = UntrustedWebRequest.Request(url);
- if (response2.StatusCode != System.Net.HttpStatusCode.OK) {
- return null;
+ if (!requireSsl || string.Equals(url.Scheme, Uri.UriSchemeHttps, StringComparison.OrdinalIgnoreCase)) {
+ response2 = UntrustedWebRequest.Request(url, null, new[] { ContentTypes.Xrds }, requireSsl);
+ if (response2.StatusCode != System.Net.HttpStatusCode.OK) {
+ return null;
+ }
+ } else {
+ Logger.WarnFormat("XRDS document at insecure location '{0}'. Aborting YADIS discovery.", url);
}
}
}
return new DiscoveryResult(uri, response, response2);
}
+ private static bool isXrdsDocument(UntrustedWebResponse response) {
+ if (response.ContentType.MediaType == ContentTypes.Xrds) {
+ return true;
+ }
+
+ if (response.ContentType.MediaType == ContentTypes.Xml) {
+ // This COULD be an XRDS document with an imprecise content-type.
+ XmlReader reader = XmlReader.Create(new StringReader(response.ReadResponseString()));
+ while (reader.Read() && reader.NodeType != XmlNodeType.Element) ;
+ if (reader.NamespaceURI == XrdsNode.XrdsNamespace && reader.Name == "XRDS") {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
/// <summary>
/// Searches an HTML document for a
/// &lt;meta http-equiv="X-XRDS-Location" content="{YadisURL}"&gt;
@@ -64,12 +117,14 @@ namespace DotNetOpenId.Yadis {
if (finalResponse == null) {
ContentType = initialResponse.ContentType;
ResponseText = initialResponse.ReadResponseString();
+ IsXrds = ContentType.MediaType == ContentTypes.Xrds;
} else {
ContentType = finalResponse.ContentType;
ResponseText = finalResponse.ReadResponseString();
- }
- if ((initialResponse != finalResponse) && (finalResponse != null)) {
- YadisLocation = finalResponse.RequestUri;
+ IsXrds = true;
+ if (initialResponse != finalResponse) {
+ YadisLocation = finalResponse.RequestUri;
+ }
}
}
@@ -103,9 +158,7 @@ namespace DotNetOpenId.Yadis {
/// Whether the <see cref="ResponseText"/> represents an XRDS document.
/// False if the response is an HTML document.
/// </summary>
- public bool IsXrds {
- get { return UsedYadisLocation || ContentType.MediaType == ContentTypes.Xrds; }
- }
+ public bool IsXrds { get; private set; }
/// <summary>
/// True if the response to the userSuppliedIdentifier pointed to a different URL
/// for the XRDS document.