summaryrefslogtreecommitdiffstats
path: root/src/DotNetOpenAuth/Yadis/Yadis.cs
diff options
context:
space:
mode:
Diffstat (limited to 'src/DotNetOpenAuth/Yadis/Yadis.cs')
-rw-r--r--src/DotNetOpenAuth/Yadis/Yadis.cs139
1 files changed, 139 insertions, 0 deletions
diff --git a/src/DotNetOpenAuth/Yadis/Yadis.cs b/src/DotNetOpenAuth/Yadis/Yadis.cs
new file mode 100644
index 0000000..7765575
--- /dev/null
+++ b/src/DotNetOpenAuth/Yadis/Yadis.cs
@@ -0,0 +1,139 @@
+//-----------------------------------------------------------------------
+// <copyright file="Yadis.cs" company="Andrew Arnott, Scott Hanselman">
+// Copyright (c) Andrew Arnott, Scott Hanselman. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOpenAuth.Yadis {
+ using System;
+ using System.IO;
+ using System.Net.Mime;
+ using System.Web.UI.HtmlControls;
+ using System.Xml;
+ using DotNetOpenAuth.OpenId;
+ using DotNetOpenAuth.Messaging;
+ using DotNetOpenAuth.Xrds;
+ using System.Net.Cache;
+ using System.Net;
+
+ internal class Yadis {
+ internal const string HeaderName = "X-XRDS-Location";
+
+ private static readonly IDirectWebRequestHandler discoveryRequestHandlerSsl = new UntrustedWebRequestHandler(true);
+ private static readonly IDirectWebRequestHandler discoveryRequestHandler = new UntrustedWebRequestHandler(false);
+
+ /// <summary>
+ /// Gets or sets the cache that can be used for HTTP requests made during identifier discovery.
+ /// </summary>
+ internal readonly static RequestCachePolicy IdentifierDiscoveryCachePolicy = new HttpRequestCachePolicy(HttpRequestCacheLevel.CacheIfAvailable);
+
+ internal static DirectWebResponse Request(Uri uri, bool requireSsl, params string[] acceptTypes) {
+ ErrorUtilities.VerifyArgumentNotNull(uri, "uri");
+
+ HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri);
+ request.CachePolicy = IdentifierDiscoveryCachePolicy;
+ if (acceptTypes != null) {
+ request.Accept = string.Join(",", acceptTypes);
+ }
+
+ IDirectWebRequestHandler handler = requireSsl ? discoveryRequestHandlerSsl : discoveryRequestHandler;
+ return handler.GetResponse(request);
+ }
+
+ /// <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) {
+ DirectWebResponse 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 = Request(uri, requireSsl, ContentTypes.Html, ContentTypes.XHtml, ContentTypes.Xrds);
+ if (response.Status != System.Net.HttpStatusCode.OK) {
+ return null;
+ }
+ } catch (ArgumentException ex) {
+ // Unsafe URLs generate this
+ Logger.WarnFormat("Unsafe OpenId URL detected ({0}). Request aborted. {1}", uri, ex);
+ return null;
+ }
+ DirectWebResponse response2 = null;
+ 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) {
+ 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) {
+ url = FindYadisDocumentLocationInHtmlMetaTags(response.Body);
+ if (url != null) {
+ Logger.DebugFormat("{0} found in HTML Http-Equiv tag. Preparing to pull XRDS from {1}", HeaderName, url);
+ }
+ }
+ if (url != null) {
+ if (!requireSsl || string.Equals(url.Scheme, Uri.UriSchemeHttps, StringComparison.OrdinalIgnoreCase)) {
+ response2 = Request(url, requireSsl);
+ if (response2.Status != 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(DirectWebResponse 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.Body));
+ while (reader.Read() && reader.NodeType != XmlNodeType.Element) {
+ // intentionally blank
+ }
+ 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;
+ /// tag and returns the content of YadisURL.
+ /// </summary>
+ public static Uri FindYadisDocumentLocationInHtmlMetaTags(string html) {
+ foreach (var metaTag in HtmlParser.HeadTags<HtmlMeta>(html)) {
+ if (HeaderName.Equals(metaTag.HttpEquiv, StringComparison.OrdinalIgnoreCase)) {
+ if (metaTag.Content != null) {
+ Uri uri;
+ if (Uri.TryCreate(metaTag.Content, UriKind.Absolute, out uri))
+ return uri;
+ }
+ }
+ }
+ return null;
+ }
+ }
+}