summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndrew Arnott <andrewarnott@gmail.com>2009-02-14 14:16:54 -0800
committerAndrew Arnott <andrewarnott@gmail.com>2009-02-14 14:31:00 -0800
commit3fc46ddde2dfca5368c59e5df1933f8c08f4fbff (patch)
treefc39b249678dbd2f077496490b8460d02b58d3e6
parent404e7ff2c44ee18b1412238a1154f34891140325 (diff)
downloadDotNetOpenAuth-3fc46ddde2dfca5368c59e5df1933f8c08f4fbff.zip
DotNetOpenAuth-3fc46ddde2dfca5368c59e5df1933f8c08f4fbff.tar.gz
DotNetOpenAuth-3fc46ddde2dfca5368c59e5df1933f8c08f4fbff.tar.bz2
HTML discovery can now generate multiple endpoints.
This provides a workaround to Google Code Issue 180. See also 7d339d343f83ce69e6ed876911c834927b8ca88f, which fixes this in the v2.5 branch.
-rw-r--r--src/DotNetOpenAuth.Test/OpenId/UriIdentifierTests.cs84
-rw-r--r--src/DotNetOpenAuth/OpenId/UriIdentifier.cs85
2 files changed, 86 insertions, 83 deletions
diff --git a/src/DotNetOpenAuth.Test/OpenId/UriIdentifierTests.cs b/src/DotNetOpenAuth.Test/OpenId/UriIdentifierTests.cs
index f3ed95e..0aa43d4 100644
--- a/src/DotNetOpenAuth.Test/OpenId/UriIdentifierTests.cs
+++ b/src/DotNetOpenAuth.Test/OpenId/UriIdentifierTests.cs
@@ -142,28 +142,35 @@ namespace DotNetOpenAuth.Test.OpenId {
[TestMethod]
public void HtmlDiscover_11() {
- this.DiscoverHtml("html10prov", ProtocolVersion.V11, null);
- this.DiscoverHtml("html10both", ProtocolVersion.V11, "http://c/d");
+ this.DiscoverHtml("html10prov", ProtocolVersion.V11, null, "http://a/b");
+ this.DiscoverHtml("html10both", ProtocolVersion.V11, "http://c/d", "http://a/b");
this.FailDiscoverHtml("html10del");
+
+ // Verify that HTML discovery generates the 1.x endpoints when appropriate
+ this.DiscoverHtml("html2010", ProtocolVersion.V11, "http://g/h", "http://e/f");
+ this.DiscoverHtml("html1020", ProtocolVersion.V11, "http://g/h", "http://e/f");
+ this.DiscoverHtml("html2010combinedA", ProtocolVersion.V11, "http://c/d", "http://a/b");
+ this.DiscoverHtml("html2010combinedB", ProtocolVersion.V11, "http://c/d", "http://a/b");
+ this.DiscoverHtml("html2010combinedC", ProtocolVersion.V11, "http://c/d", "http://a/b");
}
[TestMethod]
public void HtmlDiscover_20() {
- this.DiscoverHtml("html20prov", ProtocolVersion.V20, null);
- this.DiscoverHtml("html20both", ProtocolVersion.V20, "http://c/d");
+ this.DiscoverHtml("html20prov", ProtocolVersion.V20, null, "http://a/b");
+ this.DiscoverHtml("html20both", ProtocolVersion.V20, "http://c/d", "http://a/b");
this.FailDiscoverHtml("html20del");
- this.DiscoverHtml("html2010", ProtocolVersion.V20, "http://c/d");
- this.DiscoverHtml("html1020", ProtocolVersion.V20, "http://c/d");
- this.DiscoverHtml("html2010combinedA", ProtocolVersion.V20, "http://c/d");
- this.DiscoverHtml("html2010combinedB", ProtocolVersion.V20, "http://c/d");
- this.DiscoverHtml("html2010combinedC", ProtocolVersion.V20, "http://c/d");
+ this.DiscoverHtml("html2010", ProtocolVersion.V20, "http://c/d", "http://a/b");
+ this.DiscoverHtml("html1020", ProtocolVersion.V20, "http://c/d", "http://a/b");
+ this.DiscoverHtml("html2010combinedA", ProtocolVersion.V20, "http://c/d", "http://a/b");
+ this.DiscoverHtml("html2010combinedB", ProtocolVersion.V20, "http://c/d", "http://a/b");
+ this.DiscoverHtml("html2010combinedC", ProtocolVersion.V20, "http://c/d", "http://a/b");
this.FailDiscoverHtml("html20relative");
}
[TestMethod]
public void XrdsDiscoveryFromHead() {
this.MockResponder.RegisterMockResponse(new Uri("http://localhost/xrds1020.xml"), "application/xrds+xml", LoadEmbeddedFile("/Discovery/xrdsdiscovery/xrds1020.xml"));
- this.DiscoverXrds("XrdsReferencedInHead.html", ProtocolVersion.V10, null);
+ this.DiscoverXrds("XrdsReferencedInHead.html", ProtocolVersion.V10, null, "http://a/b");
}
[TestMethod]
@@ -171,22 +178,22 @@ namespace DotNetOpenAuth.Test.OpenId {
WebHeaderCollection headers = new WebHeaderCollection();
headers.Add("X-XRDS-Location", new Uri("http://localhost/xrds1020.xml").AbsoluteUri);
this.MockResponder.RegisterMockResponse(new Uri("http://localhost/xrds1020.xml"), "application/xrds+xml", LoadEmbeddedFile("/Discovery/xrdsdiscovery/xrds1020.xml"));
- this.DiscoverXrds("XrdsReferencedInHttpHeader.html", ProtocolVersion.V10, null, headers);
+ this.DiscoverXrds("XrdsReferencedInHttpHeader.html", ProtocolVersion.V10, null, "http://a/b", headers);
}
[TestMethod]
public void XrdsDirectDiscovery_10() {
this.FailDiscoverXrds("xrds-irrelevant");
- this.DiscoverXrds("xrds10", ProtocolVersion.V10, null);
- this.DiscoverXrds("xrds11", ProtocolVersion.V11, null);
- this.DiscoverXrds("xrds1020", ProtocolVersion.V10, null);
+ this.DiscoverXrds("xrds10", ProtocolVersion.V10, null, "http://a/b");
+ this.DiscoverXrds("xrds11", ProtocolVersion.V11, null, "http://a/b");
+ this.DiscoverXrds("xrds1020", ProtocolVersion.V10, null, "http://a/b");
}
[TestMethod]
public void XrdsDirectDiscovery_20() {
- this.DiscoverXrds("xrds20", ProtocolVersion.V20, null);
- this.DiscoverXrds("xrds2010a", ProtocolVersion.V20, null);
- this.DiscoverXrds("xrds2010b", ProtocolVersion.V20, null);
+ this.DiscoverXrds("xrds20", ProtocolVersion.V20, null, "http://a/b");
+ this.DiscoverXrds("xrds2010a", ProtocolVersion.V20, null, "http://a/b");
+ this.DiscoverXrds("xrds2010b", ProtocolVersion.V20, null, "http://a/b");
}
[TestMethod]
@@ -346,11 +353,11 @@ namespace DotNetOpenAuth.Test.OpenId {
Assert.AreEqual(secureEndpoint.ProviderLocalIdentifier, secureClaimedId.Discover(this.RequestHandler).Single().ProviderLocalIdentifier);
}
- private void Discover(string url, ProtocolVersion version, Identifier expectedLocalId, bool expectSreg, bool useRedirect) {
- this.Discover(url, version, expectedLocalId, expectSreg, useRedirect, null);
+ private void Discover(string url, ProtocolVersion version, Identifier expectedLocalId, string providerEndpoint, bool expectSreg, bool useRedirect) {
+ this.Discover(url, version, expectedLocalId, providerEndpoint, expectSreg, useRedirect, null);
}
- private void Discover(string url, ProtocolVersion version, Identifier expectedLocalId, bool expectSreg, bool useRedirect, WebHeaderCollection headers) {
+ private void Discover(string url, ProtocolVersion version, Identifier expectedLocalId, string providerEndpoint, bool expectSreg, bool useRedirect, WebHeaderCollection headers) {
Protocol protocol = Protocol.Lookup(version);
Uri baseUrl = new Uri("http://localhost/");
UriIdentifier claimedId = new Uri(baseUrl, url);
@@ -370,36 +377,45 @@ namespace DotNetOpenAuth.Test.OpenId {
}
this.MockResponder.RegisterMockResponse(new Uri(idToDiscover), claimedId, contentType, headers ?? new WebHeaderCollection(), LoadEmbeddedFile(url));
- ServiceEndpoint se = idToDiscover.Discover(this.RequestHandler).FirstOrDefault();
+ ServiceEndpoint expected = ServiceEndpoint.CreateForClaimedIdentifier(
+ claimedId,
+ expectedLocalId,
+ new ProviderEndpointDescription(
+ new Uri(providerEndpoint),
+ new string[] { protocol.ClaimedIdentifierServiceTypeURI }), // this isn't checked by Equals
+ null,
+ null);
+
+ ServiceEndpoint se = idToDiscover.Discover(this.RequestHandler).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.Count);
Assert.IsTrue(se.ProviderSupportedServiceTypeUris.Contains(protocol.ClaimedIdentifierServiceTypeURI));
Assert.AreEqual(expectSreg, se.IsExtensionSupported(new ClaimsRequest()));
}
- private void DiscoverXrds(string page, ProtocolVersion version, Identifier expectedLocalId) {
- this.DiscoverXrds(page, version, expectedLocalId, null);
+ private void DiscoverXrds(string page, ProtocolVersion version, Identifier expectedLocalId, string providerEndpoint) {
+ this.DiscoverXrds(page, version, expectedLocalId, providerEndpoint, null);
}
- private void DiscoverXrds(string page, ProtocolVersion version, Identifier expectedLocalId, WebHeaderCollection headers) {
+ private void DiscoverXrds(string page, ProtocolVersion version, Identifier expectedLocalId, string providerEndpoint, WebHeaderCollection headers) {
if (!page.Contains(".")) {
page += ".xml";
}
- this.Discover("/Discovery/xrdsdiscovery/" + page, version, expectedLocalId, true, false, headers);
- this.Discover("/Discovery/xrdsdiscovery/" + page, version, expectedLocalId, true, true, headers);
+ this.Discover("/Discovery/xrdsdiscovery/" + page, version, expectedLocalId, providerEndpoint, true, false, headers);
+ this.Discover("/Discovery/xrdsdiscovery/" + page, version, expectedLocalId, providerEndpoint, true, true, headers);
}
- private void DiscoverHtml(string page, ProtocolVersion version, Identifier expectedLocalId, bool useRedirect) {
- this.Discover("/Discovery/htmldiscovery/" + page, version, expectedLocalId, false, useRedirect);
+ private void DiscoverHtml(string page, ProtocolVersion version, Identifier expectedLocalId, string providerEndpoint, bool useRedirect) {
+ this.Discover("/Discovery/htmldiscovery/" + page, version, expectedLocalId, providerEndpoint, false, useRedirect);
}
- private void DiscoverHtml(string scenario, ProtocolVersion version, Identifier expectedLocalId) {
+ private void DiscoverHtml(string scenario, ProtocolVersion version, Identifier expectedLocalId, string providerEndpoint) {
string page = scenario + ".html";
- this.DiscoverHtml(page, version, expectedLocalId, false);
- this.DiscoverHtml(page, version, expectedLocalId, true);
+ this.DiscoverHtml(page, version, expectedLocalId, providerEndpoint, false);
+ this.DiscoverHtml(page, version, expectedLocalId, providerEndpoint, true);
}
private void FailDiscover(string url) {
diff --git a/src/DotNetOpenAuth/OpenId/UriIdentifier.cs b/src/DotNetOpenAuth/OpenId/UriIdentifier.cs
index a55f1d8..4718d8a 100644
--- a/src/DotNetOpenAuth/OpenId/UriIdentifier.cs
+++ b/src/DotNetOpenAuth/OpenId/UriIdentifier.cs
@@ -222,14 +222,13 @@ namespace DotNetOpenAuth.OpenId {
// Failing YADIS discovery of an XRDS document, we try HTML discovery.
if (endpoints.Count == 0) {
- ServiceEndpoint ep = DiscoverFromHtml(yadisResult.NormalizedUri, this, 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, this, yadisResult.ResponseText));
+ if (htmlEndpoints.Any()) {
+ Logger.DebugFormat("Total services discovered in HTML: {0}", htmlEndpoints.Count);
+ Logger.Debug(htmlEndpoints.ToStringDeferred(true));
+ endpoints.AddRange(htmlEndpoints.Where(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.");
@@ -313,54 +312,42 @@ namespace DotNetOpenAuth.OpenId {
/// <param name="userSuppliedIdentifier">The user supplied identifier.</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, UriIdentifier userSuppliedIdentifier, string html) {
- Uri providerEndpoint = null;
- Protocol discoveredProtocol = null;
- Identifier providerLocalIdentifier = null;
+ private static IEnumerable<ServiceEndpoint> DiscoverFromHtml(Uri claimedIdentifier, UriIdentifier userSuppliedIdentifier, string html) {
var linkTags = new List<HtmlLink>(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 (providerEndpoint != null) {
- break;
+ foreach (var protocol in Protocol.AllPracticalVersions) {
+ // 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 = linkTags.FirstOrDefault(tag => Regex.IsMatch(tag.Attributes["rel"], @"\b" + Regex.Escape(protocol.HtmlDiscoveryProviderKey) + @"\b", RegexOptions.IgnoreCase));
+ if (serverLinkTag == null) {
+ continue;
}
- }
- 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
+ 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 = linkTags.FirstOrDefault(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,
+ new ProviderEndpointDescription(providerEndpoint, typeURIs),
+ (int?)null,
+ (int?)null);
}
}
-
- // Choose the TypeURI to match the OpenID version detected.
- string[] typeURIs = { discoveredProtocol.ClaimedIdentifierServiceTypeURI };
- var providerDescription = new ProviderEndpointDescription(providerEndpoint, typeURIs);
- return ServiceEndpoint.CreateForClaimedIdentifier(claimedIdentifier, userSuppliedIdentifier, providerLocalIdentifier, providerDescription, (int?)null, (int?)null);
}
/// <summary>