Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

HTML discovery can now generate multiple endpoints.

This provides a workaround to Google Code Issue 180.
  • Loading branch information...
commit 7d339d343f83ce69e6ed876911c834927b8ca88f 1 parent 59fed63
@AArnott AArnott authored
View
84 src/DotNetOpenId.Test/UriIdentifierTests.cs
@@ -1,4 +1,5 @@
using System;
+using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Web;
@@ -139,10 +140,10 @@ public class UriIdentifierTests {
Assert.AreEqual(Uri.EscapeUriString(unicodeUrl), id.ToString());
}
- void discover(string url, ProtocolVersion version, Identifier expectedLocalId, bool expectSreg, bool useRedirect) {
- discover(url, version, expectedLocalId, expectSreg, useRedirect, null);
+ void discover(string url, ProtocolVersion version, Identifier expectedLocalId, Uri providerEndpoint, bool expectSreg, bool useRedirect) {
+ discover(url, version, expectedLocalId, providerEndpoint, expectSreg, useRedirect, null);
}
- void discover(string url, ProtocolVersion version, Identifier expectedLocalId, bool expectSreg, bool useRedirect, WebHeaderCollection headers) {
+ void discover(string url, ProtocolVersion version, Identifier expectedLocalId, Uri providerEndpoint, bool expectSreg, bool useRedirect, WebHeaderCollection headers) {
Protocol protocol = Protocol.Lookup(version);
UriIdentifier claimedId = TestSupport.GetFullUrl(url);
UriIdentifier userSuppliedIdentifier = TestSupport.GetFullUrl(
@@ -161,30 +162,38 @@ public class UriIdentifierTests {
MockHttpRequest.RegisterMockResponse(new Uri(idToDiscover), claimedId, contentType,
headers ?? new WebHeaderCollection(), TestSupport.LoadEmbeddedFile(url));
- ServiceEndpoint se = idToDiscover.Discover().FirstOrDefault();
+ ServiceEndpoint expected = ServiceEndpoint.CreateForClaimedIdentifier(
+ claimedId,
+ expectedLocalId,
+ providerEndpoint,
+ new string[] { protocol.ClaimedIdentifierServiceTypeURI }, // this isn't checked by Equals
+ null,
+ null);
+
+ ServiceEndpoint se = idToDiscover.Discover().FirstOrDefault(ep => ep.Equals(expected));
Assert.IsNotNull(se, url + " failed to be discovered.");
- Assert.AreSame(protocol, se.Protocol);
- Assert.AreEqual(claimedId, se.ClaimedIdentifier);
- Assert.AreEqual(expectedLocalId, se.ProviderLocalIdentifier);
+
+ // Do extra checking of service type URIs, which aren't included in
+ // the ServiceEndpoint.Equals method.
Assert.AreEqual(expectSreg ? 2 : 1, se.ProviderSupportedServiceTypeUris.Length);
Assert.IsTrue(Array.IndexOf(se.ProviderSupportedServiceTypeUris, protocol.ClaimedIdentifierServiceTypeURI) >= 0);
Assert.AreEqual(expectSreg, se.IsExtensionSupported(new ClaimsRequest()));
}
- void discoverXrds(string page, ProtocolVersion version, Identifier expectedLocalId) {
- discoverXrds(page, version, expectedLocalId, null);
+ void discoverXrds(string page, ProtocolVersion version, Identifier expectedLocalId, string providerEndpoint) {
+ discoverXrds(page, version, expectedLocalId, providerEndpoint, null);
}
- void discoverXrds(string page, ProtocolVersion version, Identifier expectedLocalId, WebHeaderCollection headers) {
+ void discoverXrds(string page, ProtocolVersion version, Identifier expectedLocalId, string providerEndpoint, WebHeaderCollection headers) {
if (!page.Contains(".")) page += ".xml";
- discover("/Discovery/xrdsdiscovery/" + page, version, expectedLocalId, true, false, headers);
- discover("/Discovery/xrdsdiscovery/" + page, version, expectedLocalId, true, true, headers);
+ discover("/Discovery/xrdsdiscovery/" + page, version, expectedLocalId, new Uri(providerEndpoint), true, false, headers);
+ discover("/Discovery/xrdsdiscovery/" + page, version, expectedLocalId, new Uri(providerEndpoint), true, true, headers);
}
- void discoverHtml(string page, ProtocolVersion version, Identifier expectedLocalId, bool useRedirect) {
- discover("/Discovery/htmldiscovery/" + page, version, expectedLocalId, false, useRedirect);
+ void discoverHtml(string page, ProtocolVersion version, Identifier expectedLocalId, string providerEndpoint, bool useRedirect) {
+ discover("/Discovery/htmldiscovery/" + page, version, expectedLocalId, new Uri(providerEndpoint), false, useRedirect);
}
- void discoverHtml(string scenario, ProtocolVersion version, Identifier expectedLocalId) {
+ void discoverHtml(string scenario, ProtocolVersion version, Identifier expectedLocalId, string providerEndpoint) {
string page = scenario + ".html";
- discoverHtml(page, version, expectedLocalId, false);
- discoverHtml(page, version, expectedLocalId, true);
+ discoverHtml(page, version, expectedLocalId, providerEndpoint, false);
+ discoverHtml(page, version, expectedLocalId, providerEndpoint, true);
}
void failDiscover(string url) {
UriIdentifier userSuppliedId = TestSupport.GetFullUrl(url);
@@ -202,27 +211,34 @@ public class UriIdentifierTests {
}
[Test]
public void HtmlDiscover_11() {
- discoverHtml("html10prov", ProtocolVersion.V11, null);
- discoverHtml("html10both", ProtocolVersion.V11, "http://c/d");
+ discoverHtml("html10prov", ProtocolVersion.V11, null, "http://a/b");
+ discoverHtml("html10both", ProtocolVersion.V11, "http://c/d", "http://a/b");
failDiscoverHtml("html10del");
+
+ // Verify that HTML discovery generates the 1.x endpoints when appropriate
+ discoverHtml("html2010", ProtocolVersion.V11, "http://g/h", "http://e/f");
+ discoverHtml("html1020", ProtocolVersion.V11, "http://g/h", "http://e/f");
+ discoverHtml("html2010combinedA", ProtocolVersion.V11, "http://c/d", "http://a/b");
+ discoverHtml("html2010combinedB", ProtocolVersion.V11, "http://c/d", "http://a/b");
+ discoverHtml("html2010combinedC", ProtocolVersion.V11, "http://c/d", "http://a/b");
}
[Test]
public void HtmlDiscover_20() {
- discoverHtml("html20prov", ProtocolVersion.V20, null);
- discoverHtml("html20both", ProtocolVersion.V20, "http://c/d");
+ discoverHtml("html20prov", ProtocolVersion.V20, null, "http://a/b");
+ discoverHtml("html20both", ProtocolVersion.V20, "http://c/d", "http://a/b");
failDiscoverHtml("html20del");
- discoverHtml("html2010", ProtocolVersion.V20, "http://c/d");
- discoverHtml("html1020", ProtocolVersion.V20, "http://c/d");
- discoverHtml("html2010combinedA", ProtocolVersion.V20, "http://c/d");
- discoverHtml("html2010combinedB", ProtocolVersion.V20, "http://c/d");
- discoverHtml("html2010combinedC", ProtocolVersion.V20, "http://c/d");
+ discoverHtml("html2010", ProtocolVersion.V20, "http://c/d", "http://a/b");
+ discoverHtml("html1020", ProtocolVersion.V20, "http://c/d", "http://a/b");
+ discoverHtml("html2010combinedA", ProtocolVersion.V20, "http://c/d", "http://a/b");
+ discoverHtml("html2010combinedB", ProtocolVersion.V20, "http://c/d", "http://a/b");
+ discoverHtml("html2010combinedC", ProtocolVersion.V20, "http://c/d", "http://a/b");
failDiscoverHtml("html20relative");
}
[Test]
public void XrdsDiscoveryFromHead() {
Mocks.MockHttpRequest.RegisterMockResponse(new Uri("http://localhost/xrds1020.xml"),
"application/xrds+xml", TestSupport.LoadEmbeddedFile("/Discovery/xrdsdiscovery/xrds1020.xml"));
- discoverXrds("XrdsReferencedInHead.html", ProtocolVersion.V10, null);
+ discoverXrds("XrdsReferencedInHead.html", ProtocolVersion.V10, null, "http://a/b");
}
[Test]
public void XrdsDiscoveryFromHttpHeader() {
@@ -230,20 +246,20 @@ public class UriIdentifierTests {
headers.Add("X-XRDS-Location", TestSupport.GetFullUrl("http://localhost/xrds1020.xml").AbsoluteUri);
Mocks.MockHttpRequest.RegisterMockResponse(new Uri("http://localhost/xrds1020.xml"),
"application/xrds+xml", TestSupport.LoadEmbeddedFile("/Discovery/xrdsdiscovery/xrds1020.xml"));
- discoverXrds("XrdsReferencedInHttpHeader.html", ProtocolVersion.V10, null, headers);
+ discoverXrds("XrdsReferencedInHttpHeader.html", ProtocolVersion.V10, null, "http://a/b", headers);
}
[Test]
public void XrdsDirectDiscovery_10() {
failDiscoverXrds("xrds-irrelevant");
- discoverXrds("xrds10", ProtocolVersion.V10, null);
- discoverXrds("xrds11", ProtocolVersion.V11, null);
- discoverXrds("xrds1020", ProtocolVersion.V10, null);
+ discoverXrds("xrds10", ProtocolVersion.V10, null, "http://a/b");
+ discoverXrds("xrds11", ProtocolVersion.V11, null, "http://a/b");
+ discoverXrds("xrds1020", ProtocolVersion.V10, null, "http://a/b");
}
[Test]
public void XrdsDirectDiscovery_20() {
- discoverXrds("xrds20", ProtocolVersion.V20, null);
- discoverXrds("xrds2010a", ProtocolVersion.V20, null);
- discoverXrds("xrds2010b", ProtocolVersion.V20, null);
+ discoverXrds("xrds20", ProtocolVersion.V20, null, "http://a/b");
+ discoverXrds("xrds2010a", ProtocolVersion.V20, null, "http://a/b");
+ discoverXrds("xrds2010b", ProtocolVersion.V20, null, "http://a/b");
}
[Test]
View
82 src/DotNetOpenId/UriIdentifier.cs
@@ -143,50 +143,43 @@ internal UriIdentifier(Uri uri, bool requireSslDiscovery)
/// </param>
/// <param name="html">The HTML that was downloaded and should be searched.</param>
/// <returns>
- /// An initialized ServiceEndpoint if the OpenID Provider information was
- /// found. Otherwise null.
+ /// A sequence of any discovered ServiceEndpoints.
/// </returns>
- /// <remarks>
- /// OpenID 2.0 tags are always used if they are present, otherwise
- /// OpenID 1.x tags are used if present.
- /// </remarks>
- private static ServiceEndpoint DiscoverFromHtml(Uri claimedIdentifier, string html) {
- Uri providerEndpoint = null;
- Protocol discoveredProtocol = null;
- Identifier providerLocalIdentifier = null;
+ private static IEnumerable<ServiceEndpoint> DiscoverFromHtml(Uri claimedIdentifier, string html) {
var linkTags = new List<HtmlLink>(Yadis.HtmlParser.HeadTags<HtmlLink>(html));
foreach (var protocol in Protocol.AllVersions) {
- foreach (var linkTag in linkTags) {
- // rel attributes are supposed to be interpreted with case INsensitivity,
- // and is a space-delimited list of values. (http://www.htmlhelp.com/reference/html40/values.html#linktypes)
- if (Regex.IsMatch(linkTag.Attributes["rel"], @"\b" + Regex.Escape(protocol.HtmlDiscoveryProviderKey) + @"\b", RegexOptions.IgnoreCase)) {
- if (Uri.TryCreate(linkTag.Href, UriKind.Absolute, out providerEndpoint)) {
- discoveredProtocol = protocol;
- break;
- }
- }
+ if (protocol.Equals(Protocol.v10)) {
+ // For HTML discovery, this is redunant with v1.1, so skip.
+ continue;
}
- if (providerEndpoint != null) break;
- }
- if (providerEndpoint == null)
- return null; // html did not contain openid.server link
- // See if a LocalId tag of the discovered version exists
- foreach (var linkTag in linkTags) {
- if (Regex.IsMatch(linkTag.Attributes["rel"], @"\b" + Regex.Escape(discoveredProtocol.HtmlDiscoveryLocalIdKey) + @"\b", RegexOptions.IgnoreCase)) {
- if (Identifier.IsValid(linkTag.Href)) {
- providerLocalIdentifier = linkTag.Href;
- break;
- } else {
- Logger.WarnFormat("Skipping endpoint data because local id is badly formed ({0}).", linkTag.Href);
- return null; // badly formed URL used as LocalId
+
+ // rel attributes are supposed to be interpreted with case INsensitivity,
+ // and is a space-delimited list of values. (http://www.htmlhelp.com/reference/html40/values.html#linktypes)
+ var serverLinkTag = Util.FirstOrDefault(linkTags, tag => Regex.IsMatch(tag.Attributes["rel"], @"\b" + Regex.Escape(protocol.HtmlDiscoveryProviderKey) + @"\b", RegexOptions.IgnoreCase));
+ if (serverLinkTag == null) {
+ continue;
+ }
+
+ Uri providerEndpoint = null;
+ if (Uri.TryCreate(serverLinkTag.Href, UriKind.Absolute, out providerEndpoint)) {
+ // See if a LocalId tag of the discovered version exists
+ Identifier providerLocalIdentifier = null;
+ var delegateLinkTag = Util.FirstOrDefault(linkTags, tag => Regex.IsMatch(tag.Attributes["rel"], @"\b" + Regex.Escape(protocol.HtmlDiscoveryLocalIdKey) + @"\b", RegexOptions.IgnoreCase));
+ if (delegateLinkTag != null) {
+ if (Identifier.IsValid(delegateLinkTag.Href)) {
+ providerLocalIdentifier = delegateLinkTag.Href;
+ } else {
+ Logger.WarnFormat("Skipping endpoint data because local id is badly formed ({0}).", delegateLinkTag.Href);
+ continue; // skip to next version
+ }
}
+
+ // Choose the TypeURI to match the OpenID version detected.
+ string[] typeURIs = { protocol.ClaimedIdentifierServiceTypeURI };
+ yield return ServiceEndpoint.CreateForClaimedIdentifier(claimedIdentifier, providerLocalIdentifier,
+ providerEndpoint, typeURIs, (int?)null, (int?)null);
}
}
-
- // Choose the TypeURI to match the OpenID version detected.
- string[] typeURIs = { discoveredProtocol.ClaimedIdentifierServiceTypeURI };
- return ServiceEndpoint.CreateForClaimedIdentifier(claimedIdentifier, providerLocalIdentifier,
- providerEndpoint, typeURIs, (int?)null, (int?)null);
}
internal override IEnumerable<ServiceEndpoint> Discover() {
@@ -205,14 +198,13 @@ internal UriIdentifier(Uri uri, bool requireSslDiscovery)
}
// Failing YADIS discovery of an XRDS document, we try HTML discovery.
if (endpoints.Count == 0) {
- ServiceEndpoint ep = DiscoverFromHtml(yadisResult.NormalizedUri, yadisResult.ResponseText);
- if (ep != null) {
- Logger.Debug("HTML discovery found a service endpoint.");
- Logger.Debug(ep);
- if (!IsDiscoverySecureEndToEnd || ep.IsSecure) {
- endpoints.Add(ep);
- } else {
- Logger.Info("Skipping HTML discovered endpoint because it is not secure.");
+ var htmlEndpoints = new List<ServiceEndpoint>(DiscoverFromHtml(yadisResult.NormalizedUri, yadisResult.ResponseText));
+ if (htmlEndpoints.Count > 0) {
+ Logger.DebugFormat("Total services discovered in HTML: {0}", htmlEndpoints.Count);
+ Logger.Debug(Util.ToString(htmlEndpoints, true));
+ endpoints.AddRange(Util.Where(htmlEndpoints, ep => !IsDiscoverySecureEndToEnd || ep.IsSecure));
+ if (endpoints.Count == 0) {
+ Logger.Info("No HTML discovered endpoints met the security requirements.");
}
} else {
Logger.Debug("HTML discovery failed to find any endpoints.");
Please sign in to comment.
Something went wrong with that request. Please try again.