diff options
Diffstat (limited to 'src/DotNetOpenAuth.Test')
20 files changed, 1055 insertions, 898 deletions
diff --git a/src/DotNetOpenAuth.Test/DotNetOpenAuth.Test.csproj b/src/DotNetOpenAuth.Test/DotNetOpenAuth.Test.csproj index 27ea955..7c0a3cb 100644 --- a/src/DotNetOpenAuth.Test/DotNetOpenAuth.Test.csproj +++ b/src/DotNetOpenAuth.Test/DotNetOpenAuth.Test.csproj @@ -187,6 +187,7 @@ <Compile Include="Mocks\InMemoryTokenManager.cs" /> <Compile Include="Mocks\MockHttpRequest.cs" /> <Compile Include="Mocks\MockIdentifier.cs" /> + <Compile Include="Mocks\MockIdentifierDiscoveryService.cs" /> <Compile Include="Mocks\MockOpenIdExtension.cs" /> <Compile Include="Mocks\MockRealm.cs" /> <Compile Include="Mocks\MockTransformationBindingElement.cs" /> @@ -221,6 +222,8 @@ <Compile Include="Messaging\Bindings\StandardReplayProtectionBindingElementTests.cs" /> <Compile Include="OpenId\ChannelElements\SigningBindingElementTests.cs" /> <Compile Include="OpenId\DiffieHellmanTests.cs" /> + <Compile Include="OpenId\DiscoveryServices\UriDiscoveryServiceTests.cs" /> + <Compile Include="OpenId\DiscoveryServices\XriDiscoveryProxyServiceTests.cs" /> <Compile Include="OpenId\Extensions\AttributeExchange\FetchRequestTests.cs" /> <Compile Include="OpenId\Extensions\AttributeExchange\FetchResponseTests.cs" /> <Compile Include="OpenId\Extensions\AttributeExchange\AttributeExchangeRoundtripTests.cs" /> @@ -257,6 +260,7 @@ <Compile Include="OpenId\OpenIdCoordinator.cs" /> <Compile Include="OpenId\AssociationHandshakeTests.cs" /> <Compile Include="OpenId\OpenIdTestBase.cs" /> + <Compile Include="OpenId\OpenIdUtilitiesTests.cs" /> <Compile Include="OpenId\Provider\PerformanceTests.cs" /> <Compile Include="OpenId\ProviderEndpointDescriptionTests.cs" /> <Compile Include="OpenId\Provider\AnonymousRequestTests.cs" /> @@ -272,7 +276,7 @@ <Compile Include="OpenId\RelyingParty\PositiveAuthenticationResponseTests.cs" /> <Compile Include="OpenId\RelyingParty\OpenIdRelyingPartyTests.cs" /> <Compile Include="OpenId\RelyingParty\RelyingPartySecuritySettingsTests.cs" /> - <Compile Include="OpenId\RelyingParty\ServiceEndpointTests.cs" /> + <Compile Include="OpenId\RelyingParty\IdentifierDiscoveryResultTests.cs" /> <Compile Include="OpenId\UriIdentifierTests.cs" /> <Compile Include="OpenId\XriIdentifierTests.cs" /> <Compile Include="Properties\AssemblyInfo.cs" /> @@ -327,8 +331,11 @@ <None Include="App.config" /> </ItemGroup> <ItemGroup> + <EmbeddedResource Include="OpenId\Discovery\xrdsdiscovery\xrds20dual.xml" /> + </ItemGroup> + <ItemGroup> <Folder Include="OpenId\UI\" /> </ItemGroup> <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" /> <Import Project="..\..\tools\DotNetOpenAuth.Versioning.targets" /> -</Project> +</Project>
\ No newline at end of file diff --git a/src/DotNetOpenAuth.Test/Mocks/MockHttpRequest.cs b/src/DotNetOpenAuth.Test/Mocks/MockHttpRequest.cs index 0213a33..c18ea33 100644 --- a/src/DotNetOpenAuth.Test/Mocks/MockHttpRequest.cs +++ b/src/DotNetOpenAuth.Test/Mocks/MockHttpRequest.cs @@ -83,7 +83,7 @@ namespace DotNetOpenAuth.Test.Mocks { } } - internal void RegisterMockXrdsResponse(ServiceEndpoint endpoint) { + internal void RegisterMockXrdsResponse(IdentifierDiscoveryResult endpoint) { Contract.Requires<ArgumentNullException>(endpoint != null); string identityUri; @@ -92,10 +92,10 @@ namespace DotNetOpenAuth.Test.Mocks { } else { identityUri = endpoint.UserSuppliedIdentifier ?? endpoint.ClaimedIdentifier; } - this.RegisterMockXrdsResponse(new Uri(identityUri), new ServiceEndpoint[] { endpoint }); + this.RegisterMockXrdsResponse(new Uri(identityUri), new IdentifierDiscoveryResult[] { endpoint }); } - internal void RegisterMockXrdsResponse(Uri respondingUri, IEnumerable<ServiceEndpoint> endpoints) { + internal void RegisterMockXrdsResponse(Uri respondingUri, IEnumerable<IdentifierDiscoveryResult> endpoints) { Contract.Requires<ArgumentNullException>(endpoints != null); StringBuilder xrds = new StringBuilder(); @@ -130,12 +130,12 @@ namespace DotNetOpenAuth.Test.Mocks { this.RegisterMockResponse(respondingUri, ContentTypes.Xrds, xrds.ToString()); } - internal void RegisterMockXrdsResponse(UriIdentifier directedIdentityAssignedIdentifier, ServiceEndpoint providerEndpoint) { - ServiceEndpoint identityEndpoint = ServiceEndpoint.CreateForClaimedIdentifier( + internal void RegisterMockXrdsResponse(UriIdentifier directedIdentityAssignedIdentifier, IdentifierDiscoveryResult providerEndpoint) { + IdentifierDiscoveryResult identityEndpoint = IdentifierDiscoveryResult.CreateForClaimedIdentifier( directedIdentityAssignedIdentifier, directedIdentityAssignedIdentifier, - providerEndpoint.ProviderEndpoint, - providerEndpoint.ProviderDescription, + providerEndpoint.ProviderLocalIdentifier, + new ProviderEndpointDescription(providerEndpoint.ProviderEndpoint, providerEndpoint.Capabilities), 10, 10); this.RegisterMockXrdsResponse(identityEndpoint); diff --git a/src/DotNetOpenAuth.Test/Mocks/MockIdentifier.cs b/src/DotNetOpenAuth.Test/Mocks/MockIdentifier.cs index 346dde9..9f032b8 100644 --- a/src/DotNetOpenAuth.Test/Mocks/MockIdentifier.cs +++ b/src/DotNetOpenAuth.Test/Mocks/MockIdentifier.cs @@ -18,13 +18,13 @@ namespace DotNetOpenAuth.Test.Mocks { /// having a dependency on a hosted web site to actually perform discovery on. /// </summary> internal class MockIdentifier : Identifier { - private IEnumerable<ServiceEndpoint> endpoints; + private IEnumerable<IdentifierDiscoveryResult> endpoints; private MockHttpRequest mockHttpRequest; private Identifier wrappedIdentifier; - public MockIdentifier(Identifier wrappedIdentifier, MockHttpRequest mockHttpRequest, IEnumerable<ServiceEndpoint> endpoints) + public MockIdentifier(Identifier wrappedIdentifier, MockHttpRequest mockHttpRequest, IEnumerable<IdentifierDiscoveryResult> endpoints) : base(wrappedIdentifier.OriginalString, false) { Contract.Requires<ArgumentNullException>(wrappedIdentifier != null); Contract.Requires<ArgumentNullException>(mockHttpRequest != null); @@ -39,6 +39,10 @@ namespace DotNetOpenAuth.Test.Mocks { mockHttpRequest.RegisterMockXrdsResponse(new Uri(wrappedIdentifier.ToString()), endpoints); } + internal IEnumerable<IdentifierDiscoveryResult> DiscoveryEndpoints { + get { return this.endpoints; } + } + public override string ToString() { return this.wrappedIdentifier.ToString(); } @@ -51,10 +55,6 @@ namespace DotNetOpenAuth.Test.Mocks { return this.wrappedIdentifier.GetHashCode(); } - internal override IEnumerable<ServiceEndpoint> Discover(IDirectWebRequestHandler requestHandler) { - return this.endpoints; - } - internal override Identifier TrimFragment() { return this; } diff --git a/src/DotNetOpenAuth.Test/Mocks/MockIdentifierDiscoveryService.cs b/src/DotNetOpenAuth.Test/Mocks/MockIdentifierDiscoveryService.cs new file mode 100644 index 0000000..d74258d --- /dev/null +++ b/src/DotNetOpenAuth.Test/Mocks/MockIdentifierDiscoveryService.cs @@ -0,0 +1,47 @@ +//----------------------------------------------------------------------- +// <copyright file="MockIdentifierDiscoveryService.cs" company="Andrew Arnott"> +// Copyright (c) Andrew Arnott. All rights reserved. +// </copyright> +//----------------------------------------------------------------------- + +namespace DotNetOpenAuth.Test.Mocks { + using System; + using System.Collections.Generic; + using System.Linq; + using System.Text; + using DotNetOpenAuth.Messaging; + using DotNetOpenAuth.OpenId; + using DotNetOpenAuth.OpenId.RelyingParty; + + internal class MockIdentifierDiscoveryService : IIdentifierDiscoveryService { + /// <summary> + /// Initializes a new instance of the <see cref="MockIdentifierDiscoveryService"/> class. + /// </summary> + public MockIdentifierDiscoveryService() { + } + + #region IIdentifierDiscoveryService Members + + /// <summary> + /// Performs discovery on the specified identifier. + /// </summary> + /// <param name="identifier">The identifier to perform discovery on.</param> + /// <param name="requestHandler">The means to place outgoing HTTP requests.</param> + /// <param name="abortDiscoveryChain">if set to <c>true</c>, no further discovery services will be called for this identifier.</param> + /// <returns> + /// A sequence of service endpoints yielded by discovery. Must not be null, but may be empty. + /// </returns> + public IEnumerable<IdentifierDiscoveryResult> Discover(Identifier identifier, IDirectWebRequestHandler requestHandler, out bool abortDiscoveryChain) { + var mockIdentifier = identifier as MockIdentifier; + if (mockIdentifier == null) { + abortDiscoveryChain = false; + return Enumerable.Empty<IdentifierDiscoveryResult>(); + } + + abortDiscoveryChain = true; + return mockIdentifier.DiscoveryEndpoints; + } + + #endregion + } +} diff --git a/src/DotNetOpenAuth.Test/OpenId/AssociationHandshakeTests.cs b/src/DotNetOpenAuth.Test/OpenId/AssociationHandshakeTests.cs index af3b1b1..a9d2f56 100644 --- a/src/DotNetOpenAuth.Test/OpenId/AssociationHandshakeTests.cs +++ b/src/DotNetOpenAuth.Test/OpenId/AssociationHandshakeTests.cs @@ -318,9 +318,9 @@ namespace DotNetOpenAuth.Test.OpenId { private void ParameterizedAssociationTest( ProviderEndpointDescription opDescription, string expectedAssociationType) { - Protocol protocol = Protocol.Lookup(opDescription.ProtocolVersion); + Protocol protocol = Protocol.Lookup(Protocol.Lookup(opDescription.Version).ProtocolVersion); bool expectSuccess = expectedAssociationType != null; - bool expectDiffieHellman = !opDescription.Endpoint.IsTransportSecure(); + bool expectDiffieHellman = !opDescription.Uri.IsTransportSecure(); Association rpAssociation = null, opAssociation; AssociateSuccessfulResponse associateSuccessfulResponse = null; AssociateUnsuccessfulResponse associateUnsuccessfulResponse = null; @@ -337,7 +337,7 @@ namespace DotNetOpenAuth.Test.OpenId { op.SendResponse(req); }); coordinator.IncomingMessageFilter = message => { - Assert.AreSame(opDescription.ProtocolVersion, message.Version, "The message was recognized as version {0} but was expected to be {1}.", message.Version, opDescription.ProtocolVersion); + Assert.AreSame(opDescription.Version, message.Version, "The message was recognized as version {0} but was expected to be {1}.", message.Version, Protocol.Lookup(opDescription.Version).ProtocolVersion); var associateSuccess = message as AssociateSuccessfulResponse; var associateFailed = message as AssociateUnsuccessfulResponse; if (associateSuccess != null) { @@ -348,7 +348,7 @@ namespace DotNetOpenAuth.Test.OpenId { } }; coordinator.OutgoingMessageFilter = message => { - Assert.AreSame(opDescription.ProtocolVersion, message.Version, "The message was for version {0} but was expected to be for {1}.", message.Version, opDescription.ProtocolVersion); + Assert.AreEqual(opDescription.Version, message.Version, "The message was for version {0} but was expected to be for {1}.", message.Version, opDescription.Version); }; coordinator.Run(); @@ -356,7 +356,7 @@ namespace DotNetOpenAuth.Test.OpenId { if (expectSuccess) { Assert.IsNotNull(rpAssociation); - Assert.AreSame(rpAssociation, associationManagerAccessor.associationStore.GetAssociation(opDescription.Endpoint, rpAssociation.Handle)); + Assert.AreSame(rpAssociation, associationManagerAccessor.associationStore.GetAssociation(opDescription.Uri, rpAssociation.Handle)); opAssociation = coordinator.Provider.AssociationStore.GetAssociation(AssociationRelyingPartyType.Smart, rpAssociation.Handle); Assert.IsNotNull(opAssociation, "The Provider should have stored the association."); @@ -375,7 +375,7 @@ namespace DotNetOpenAuth.Test.OpenId { var unencryptedResponse = (AssociateUnencryptedResponse)associateSuccessfulResponse; } } else { - Assert.IsNull(associationManagerAccessor.associationStore.GetAssociation(opDescription.Endpoint, new RelyingPartySecuritySettings())); + Assert.IsNull(associationManagerAccessor.associationStore.GetAssociation(opDescription.Uri, new RelyingPartySecuritySettings())); Assert.IsNull(coordinator.Provider.AssociationStore.GetAssociation(AssociationRelyingPartyType.Smart, new ProviderSecuritySettings())); } } diff --git a/src/DotNetOpenAuth.Test/OpenId/Discovery/xrdsdiscovery/xrds20dual.xml b/src/DotNetOpenAuth.Test/OpenId/Discovery/xrdsdiscovery/xrds20dual.xml new file mode 100644 index 0000000..9e6a66b --- /dev/null +++ b/src/DotNetOpenAuth.Test/OpenId/Discovery/xrdsdiscovery/xrds20dual.xml @@ -0,0 +1,13 @@ +<?xml version="1.0" encoding="UTF-8"?> +<xrds:XRDS + xmlns:xrds="xri://$xrds" + xmlns:openid="http://openid.net/xmlns/1.0" + xmlns="xri://$xrd*($v*2.0)"> + <XRD> + <Service priority="10"> + <Type>http://specs.openid.net/auth/2.0/signon</Type> + <Type>http://specs.openid.net/auth/2.0/server</Type> + <URI>http://a/b</URI> + </Service> + </XRD> +</xrds:XRDS> diff --git a/src/DotNetOpenAuth.Test/OpenId/DiscoveryServices/UriDiscoveryServiceTests.cs b/src/DotNetOpenAuth.Test/OpenId/DiscoveryServices/UriDiscoveryServiceTests.cs new file mode 100644 index 0000000..5d0ec89 --- /dev/null +++ b/src/DotNetOpenAuth.Test/OpenId/DiscoveryServices/UriDiscoveryServiceTests.cs @@ -0,0 +1,272 @@ +//----------------------------------------------------------------------- +// <copyright file="UriDiscoveryServiceTests.cs" company="Andrew Arnott"> +// Copyright (c) Andrew Arnott. All rights reserved. +// </copyright> +//----------------------------------------------------------------------- + +namespace DotNetOpenAuth.Test.OpenId.DiscoveryServices { + using System; + using System.Collections.Generic; + using System.Linq; + using System.Net; + using System.Text; + using System.Web; + using DotNetOpenAuth.Messaging; + using DotNetOpenAuth.OpenId; + using DotNetOpenAuth.OpenId.Extensions.SimpleRegistration; + using DotNetOpenAuth.OpenId.RelyingParty; + using Microsoft.VisualStudio.TestTools.UnitTesting; + + [TestClass] + public class UriDiscoveryServiceTests : OpenIdTestBase { + [TestMethod] + public void DiscoveryWithRedirects() { + Identifier claimedId = this.GetMockIdentifier(ProtocolVersion.V20, false); + + // Add a couple of chained redirect pages that lead to the claimedId. + Uri userSuppliedUri = new Uri("https://localhost/someSecurePage"); + Uri insecureMidpointUri = new Uri("http://localhost/insecureStop"); + this.MockResponder.RegisterMockRedirect(userSuppliedUri, insecureMidpointUri); + this.MockResponder.RegisterMockRedirect(insecureMidpointUri, new Uri(claimedId.ToString())); + + // don't require secure SSL discovery for this test. + Identifier userSuppliedIdentifier = new UriIdentifier(userSuppliedUri, false); + Assert.AreEqual(1, this.Discover(userSuppliedIdentifier).Count()); + } + + [TestMethod] + public void DiscoverRequireSslWithSecureRedirects() { + Identifier claimedId = this.GetMockIdentifier(ProtocolVersion.V20, true); + + // Add a couple of chained redirect pages that lead to the claimedId. + // All redirects should be secure. + Uri userSuppliedUri = new Uri("https://localhost/someSecurePage"); + Uri secureMidpointUri = new Uri("https://localhost/secureStop"); + this.MockResponder.RegisterMockRedirect(userSuppliedUri, secureMidpointUri); + this.MockResponder.RegisterMockRedirect(secureMidpointUri, new Uri(claimedId.ToString())); + + Identifier userSuppliedIdentifier = new UriIdentifier(userSuppliedUri, true); + Assert.AreEqual(1, this.Discover(userSuppliedIdentifier).Count()); + } + + [TestMethod, ExpectedException(typeof(ProtocolException))] + public void DiscoverRequireSslWithInsecureRedirect() { + Identifier claimedId = this.GetMockIdentifier(ProtocolVersion.V20, true); + + // Add a couple of chained redirect pages that lead to the claimedId. + // Include an insecure HTTP jump in those redirects to verify that + // the ultimate endpoint is never found as a result of high security profile. + Uri userSuppliedUri = new Uri("https://localhost/someSecurePage"); + Uri insecureMidpointUri = new Uri("http://localhost/insecureStop"); + this.MockResponder.RegisterMockRedirect(userSuppliedUri, insecureMidpointUri); + this.MockResponder.RegisterMockRedirect(insecureMidpointUri, new Uri(claimedId.ToString())); + + Identifier userSuppliedIdentifier = new UriIdentifier(userSuppliedUri, true); + this.Discover(userSuppliedIdentifier); + } + + [TestMethod] + public void DiscoveryRequireSslWithInsecureXrdsInSecureHtmlHead() { + var insecureXrdsSource = this.GetMockIdentifier(ProtocolVersion.V20, false); + Uri secureClaimedUri = new Uri("https://localhost/secureId"); + + string html = string.Format("<html><head><meta http-equiv='X-XRDS-Location' content='{0}'/></head><body></body></html>", insecureXrdsSource); + this.MockResponder.RegisterMockResponse(secureClaimedUri, "text/html", html); + + Identifier userSuppliedIdentifier = new UriIdentifier(secureClaimedUri, true); + Assert.AreEqual(0, this.Discover(userSuppliedIdentifier).Count()); + } + + [TestMethod] + public void DiscoveryRequireSslWithInsecureXrdsInSecureHttpHeader() { + var insecureXrdsSource = this.GetMockIdentifier(ProtocolVersion.V20, false); + + string html = "<html><head></head><body></body></html>"; + WebHeaderCollection headers = new WebHeaderCollection { + { "X-XRDS-Location", insecureXrdsSource } + }; + this.MockResponder.RegisterMockResponse(VanityUriSsl, VanityUriSsl, "text/html", headers, html); + + Identifier userSuppliedIdentifier = new UriIdentifier(VanityUriSsl, true); + Assert.AreEqual(0, this.Discover(userSuppliedIdentifier).Count()); + } + + [TestMethod] + public void DiscoveryRequireSslWithInsecureXrdsButSecureLinkTags() { + var insecureXrdsSource = this.GetMockIdentifier(ProtocolVersion.V20, false); + string html = string.Format( + @" + <html><head> + <meta http-equiv='X-XRDS-Location' content='{0}'/> <!-- this one will be insecure and ignored --> + <link rel='openid2.provider' href='{1}' /> + <link rel='openid2.local_id' href='{2}' /> + </head><body></body></html>", + HttpUtility.HtmlEncode(insecureXrdsSource), + HttpUtility.HtmlEncode(OPUriSsl.AbsoluteUri), + HttpUtility.HtmlEncode(OPLocalIdentifiersSsl[1].AbsoluteUri)); + this.MockResponder.RegisterMockResponse(VanityUriSsl, "text/html", html); + + Identifier userSuppliedIdentifier = new UriIdentifier(VanityUriSsl, true); + + // We verify that the XRDS was ignored and the LINK tags were used + // because the XRDS OP-LocalIdentifier uses different local identifiers. + Assert.AreEqual(OPLocalIdentifiersSsl[1], this.Discover(userSuppliedIdentifier).Single().ProviderLocalIdentifier); + } + + [TestMethod] + public void DiscoveryRequiresSslIgnoresInsecureEndpointsInXrds() { + var insecureEndpoint = GetServiceEndpoint(0, ProtocolVersion.V20, 10, false); + var secureEndpoint = GetServiceEndpoint(1, ProtocolVersion.V20, 20, true); + UriIdentifier secureClaimedId = new UriIdentifier(VanityUriSsl, true); + this.MockResponder.RegisterMockXrdsResponse(secureClaimedId, new IdentifierDiscoveryResult[] { insecureEndpoint, secureEndpoint }); + Assert.AreEqual(secureEndpoint.ProviderLocalIdentifier, this.Discover(secureClaimedId).Single().ProviderLocalIdentifier); + } + + [TestMethod] + public void XrdsDirectDiscovery_10() { + this.FailDiscoverXrds("xrds-irrelevant"); + 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, "http://a/b"); + this.DiscoverXrds("xrds2010a", ProtocolVersion.V20, null, "http://a/b"); + this.DiscoverXrds("xrds2010b", ProtocolVersion.V20, null, "http://a/b"); + } + + [TestMethod] + public void HtmlDiscover_11() { + 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, "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", "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, "http://a/b"); + } + + [TestMethod] + public void XrdsDiscoveryFromHttpHeader() { + 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, "http://a/b", headers); + } + + /// <summary> + /// Verifies that a dual identifier yields two service endpoints. + /// </summary> + [TestMethod] + public void DualIdentifier() { + this.MockResponder.RegisterMockResponse(VanityUri, "application/xrds+xml", LoadEmbeddedFile("/Discovery/xrdsdiscovery/xrds20dual.xml")); + var results = this.Discover(VanityUri).ToList(); + Assert.AreEqual(1, results.Count(r => r.ClaimedIdentifier == r.Protocol.ClaimedIdentifierForOPIdentifier), "OP Identifier missing from discovery results."); + Assert.AreEqual(1, results.Count(r => r.ClaimedIdentifier == VanityUri), "Claimed identifier missing from discovery results."); + Assert.AreEqual(2, results.Count, "Unexpected additional services discovered."); + } + + 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, 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); + UriIdentifier userSuppliedIdentifier = new Uri(baseUrl, "Discovery/htmldiscovery/redirect.aspx?target=" + url); + if (expectedLocalId == null) { + expectedLocalId = claimedId; + } + Identifier idToDiscover = useRedirect ? userSuppliedIdentifier : claimedId; + + string contentType; + if (url.EndsWith("html")) { + contentType = "text/html"; + } else if (url.EndsWith("xml")) { + contentType = "application/xrds+xml"; + } else { + throw new InvalidOperationException(); + } + this.MockResponder.RegisterMockResponse(new Uri(idToDiscover), claimedId, contentType, headers ?? new WebHeaderCollection(), LoadEmbeddedFile(url)); + + IdentifierDiscoveryResult expected = IdentifierDiscoveryResult.CreateForClaimedIdentifier( + claimedId, + expectedLocalId, + new ProviderEndpointDescription(new Uri(providerEndpoint), new string[] { protocol.ClaimedIdentifierServiceTypeURI }), // services aren't checked by Equals + null, + null); + + IdentifierDiscoveryResult se = this.Discover(idToDiscover).FirstOrDefault(ep => ep.Equals(expected)); + Assert.IsNotNull(se, url + " failed to be discovered."); + + // Do extra checking of service type URIs, which aren't included in + // the ServiceEndpoint.Equals method. + Assert.AreEqual(expectSreg ? 2 : 1, se.Capabilities.Count); + Assert.IsTrue(se.Capabilities.Contains(protocol.ClaimedIdentifierServiceTypeURI)); + Assert.AreEqual(expectSreg, se.IsExtensionSupported<ClaimsRequest>()); + } + + 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, string providerEndpoint, WebHeaderCollection headers) { + if (!page.Contains(".")) { + page += ".xml"; + } + 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, string providerEndpoint, bool useRedirect) { + this.Discover("/Discovery/htmldiscovery/" + page, version, expectedLocalId, providerEndpoint, false, useRedirect); + } + + private void DiscoverHtml(string scenario, ProtocolVersion version, Identifier expectedLocalId, string providerEndpoint) { + string page = scenario + ".html"; + this.DiscoverHtml(page, version, expectedLocalId, providerEndpoint, false); + this.DiscoverHtml(page, version, expectedLocalId, providerEndpoint, true); + } + + private void FailDiscover(string url) { + UriIdentifier userSuppliedId = new Uri(new Uri("http://localhost"), url); + + this.MockResponder.RegisterMockResponse(new Uri(userSuppliedId), userSuppliedId, "text/html", LoadEmbeddedFile(url)); + + Assert.AreEqual(0, this.Discover(userSuppliedId).Count()); // ... but that no endpoint info is discoverable + } + + private void FailDiscoverHtml(string scenario) { + this.FailDiscover("/Discovery/htmldiscovery/" + scenario + ".html"); + } + + private void FailDiscoverXrds(string scenario) { + this.FailDiscover("/Discovery/xrdsdiscovery/" + scenario + ".xml"); + } + } +} diff --git a/src/DotNetOpenAuth.Test/OpenId/DiscoveryServices/XriDiscoveryProxyServiceTests.cs b/src/DotNetOpenAuth.Test/OpenId/DiscoveryServices/XriDiscoveryProxyServiceTests.cs new file mode 100644 index 0000000..9247bb6 --- /dev/null +++ b/src/DotNetOpenAuth.Test/OpenId/DiscoveryServices/XriDiscoveryProxyServiceTests.cs @@ -0,0 +1,394 @@ +//----------------------------------------------------------------------- +// <copyright file="XriDiscoveryProxyServiceTests.cs" company="Andrew Arnott"> +// Copyright (c) Andrew Arnott. All rights reserved. +// </copyright> +//----------------------------------------------------------------------- + +namespace DotNetOpenAuth.Test.OpenId.DiscoveryServices { + using System; + using System.Collections.Generic; + using System.Linq; + using System.Text; + using DotNetOpenAuth.OpenId; + using DotNetOpenAuth.OpenId.RelyingParty; + using Microsoft.VisualStudio.TestTools.UnitTesting; + + [TestClass] + public class XriDiscoveryProxyServiceTests : OpenIdTestBase { + [TestMethod] + public void Discover() { + string xrds = @"<?xml version='1.0' encoding='UTF-8'?> +<XRD version='2.0' xmlns='xri://$xrd*($v*2.0)'> + <Query>*Arnott</Query> + <Status ceid='off' cid='verified' code='100'/> + <Expires>2008-07-14T02:03:24.000Z</Expires> + <ProviderID>xri://=</ProviderID> + <LocalID>!9b72.7dd1.50a9.5ccd</LocalID> + <CanonicalID>=!9B72.7DD1.50A9.5CCD</CanonicalID> + + <Service priority='10'> + <ProviderID>xri://!!1008</ProviderID> + <Type select='true'>xri://+i-service*(+contact)*($v*1.0)</Type> + <Type match='default' select='false'/> + <Path select='true'>(+contact)</Path> + <Path match='null' select='false'/> + <URI append='qxri' priority='1'>http://1id.com/contact/</URI> + + </Service> + <Service priority='10'> + <ProviderID>xri://!!1008</ProviderID> + <Type select='true'>xri://+i-service*(+forwarding)*($v*1.0)</Type> + <Type match='null' select='false'/> + <URI append='qxri' priority='1'>http://1id.com/</URI> + </Service> + + <Service priority='10'> + <ProviderID>xri://!!1008</ProviderID> + <Type select='true'>http://openid.net/signon/1.0</Type> + <URI append='none' priority='10'>http://1id.com/sso</URI> + </Service> +</XRD>"; + Dictionary<string, string> mocks = new Dictionary<string, string> { + { "https://xri.net/=Arnott?_xrd_r=application/xrd%2Bxml;sep=false", xrds }, + { "https://xri.net/=!9B72.7DD1.50A9.5CCD?_xrd_r=application/xrd%2Bxml;sep=false", xrds }, + }; + this.MockResponder.RegisterMockXrdsResponses(mocks); + + string expectedCanonicalId = "=!9B72.7DD1.50A9.5CCD"; + IdentifierDiscoveryResult se = this.VerifyCanonicalId("=Arnott", expectedCanonicalId); + Assert.AreEqual(Protocol.V10, Protocol.Lookup(se.Version)); + Assert.AreEqual("http://1id.com/sso", se.ProviderEndpoint.ToString()); + Assert.AreEqual(se.ClaimedIdentifier, se.ProviderLocalIdentifier); + Assert.AreEqual("=Arnott", se.FriendlyIdentifierForDisplay); + } + + [TestMethod] + public void DiscoverCommunityInameCanonicalIDs() { + string llliResponse = @"<?xml version='1.0' encoding='UTF-8'?> +<XRD version='2.0' xmlns='xri://$xrd*($v*2.0)'> + <Query>*llli</Query> + <Status ceid='off' cid='verified' code='100'/> + <Expires>2008-07-14T02:21:06.000Z</Expires> + <ProviderID>xri://@</ProviderID> + <LocalID>!72cd.a072.157e.a9c6</LocalID> + <CanonicalID>@!72CD.A072.157E.A9C6</CanonicalID> + <Service priority='10'> + <ProviderID>xri://!!1003!103</ProviderID> + <Type select='true'>http://openid.net/signon/1.0</Type> + <URI append='none' priority='1'>https://login.llli.org/server/</URI> + </Service> + <Service priority='1'> + <ProviderID>xri://!!1003!103</ProviderID> + <Type match='null' select='false'/> + <Type select='true'>xri://+i-service*(+forwarding)*($v*1.0)</Type> + <Path match='default'/> + <Path>(+index)</Path> + <URI append='qxri' priority='1'>http://linksafe-forward.ezibroker.net/forwarding/</URI> + </Service> + <Service priority='10'> + <ProviderID>xri://!!1003!103</ProviderID> + <Type select='true'>xri://$res*auth*($v*2.0)</Type> + <MediaType>application/xrds+xml;trust=none</MediaType> + <URI priority='10'>http://resolve.ezibroker.net/resolve/@llli/</URI> + </Service> + <Service priority='10'> + <ProviderID>xri://!!1003!103</ProviderID> + <Type select='true'>xri://+i-service*(+contact)*($v*1.0)</Type> + <Type match='null'/> + <Path select='true'>(+contact)</Path> + <Path match='null'/> + <URI append='authority' priority='1'>http://linksafe-contact.ezibroker.net/contact/</URI> + </Service> +</XRD> +"; + string llliAreaResponse = @"<?xml version='1.0' encoding='UTF-8'?> +<XRD xmlns='xri://$xrd*($v*2.0)'> + <Query>*area</Query> + <Status cid='verified' code='100'>SUCCESS</Status> + <ServerStatus code='100'>SUCCESS</ServerStatus> + <Expires>2008-07-15T01:21:07.000Z</Expires> + <ProviderID>xri://!!1003</ProviderID> + <LocalID>0000.0000.3B9A.CA0C</LocalID> + <CanonicalID>@!72CD.A072.157E.A9C6!0000.0000.3B9A.CA0C</CanonicalID> + <Service> + <ProviderID>xri://!!1003!103</ProviderID> + <Type select='true'>http://openid.net/signon/1.0</Type> + <URI append='none' priority='1'>https://login.llli.org/server/</URI> + </Service> + <Service> + <ProviderID>xri://!!1003!103</ProviderID> + <Type select='true'>xri://+i-service*(+contact)*($v*1.0)</Type> + <Type match='null'/> + <Path select='true'>(+contact)</Path> + <Path match='null'/> + <URI append='authority' priority='1'>http://linksafe-contact.ezibroker.net/contact/</URI> + </Service> + <Service priority='1'> + <ProviderID>xri://!!1003!103</ProviderID> + <Type select='true'>xri://+i-service*(+forwarding)*($v*1.0)</Type> + <Type match='null' select='false'/> + <Path>(+index)</Path> + <Path match='default'/> + <URI append='qxri' priority='1'>http://linksafe-forward.ezibroker.net/forwarding/</URI> + </Service> + <Service> + <ProviderID>xri://!!1003!103</ProviderID> + <Type select='true'>xri://$res*auth*($v*2.0)</Type> + <MediaType>application/xrds+xml;trust=none</MediaType> + <URI>http://resolve.ezibroker.net/resolve/@llli*area/</URI> + </Service> +</XRD>"; + string llliAreaCanadaUnattachedResponse = @"<?xml version='1.0' encoding='UTF-8'?> +<XRD xmlns='xri://$xrd*($v*2.0)'> + <Query>*canada.unattached</Query> + <Status cid='verified' code='100'>SUCCESS</Status> + <ServerStatus code='100'>SUCCESS</ServerStatus> + <Expires>2008-07-15T01:21:08.000Z</Expires> + <ProviderID>xri://!!1003</ProviderID> + <LocalID>0000.0000.3B9A.CA41</LocalID> + <CanonicalID>@!72CD.A072.157E.A9C6!0000.0000.3B9A.CA0C!0000.0000.3B9A.CA41</CanonicalID> + <Service> + <ProviderID>xri://!!1003!103</ProviderID> + <Type select='true'>http://openid.net/signon/1.0</Type> + <URI append='none' priority='1'>https://login.llli.org/server/</URI> + </Service> + <Service> + <ProviderID>xri://!!1003!103</ProviderID> + <Type select='true'>xri://+i-service*(+contact)*($v*1.0)</Type> + <Type match='null'/> + <Path select='true'>(+contact)</Path> + <Path match='null'/> + <URI append='authority' priority='1'>http://linksafe-contact.ezibroker.net/contact/</URI> + </Service> + <Service priority='1'> + <ProviderID>xri://!!1003!103</ProviderID> + <Type select='true'>xri://+i-service*(+forwarding)*($v*1.0)</Type> + <Type match='null' select='false'/> + <Path>(+index)</Path> + <Path match='default'/> + <URI append='qxri' priority='1'>http://linksafe-forward.ezibroker.net/forwarding/</URI> + </Service> + <Service> + <ProviderID>xri://!!1003!103</ProviderID> + <Type select='true'>xri://$res*auth*($v*2.0)</Type> + <MediaType>application/xrds+xml;trust=none</MediaType> + <URI>http://resolve.ezibroker.net/resolve/@llli*area*canada.unattached/</URI> + </Service> +</XRD>"; + string llliAreaCanadaUnattachedAdaResponse = @"<?xml version='1.0' encoding='UTF-8'?> +<XRD xmlns='xri://$xrd*($v*2.0)'> + <Query>*ada</Query> + <Status cid='verified' code='100'>SUCCESS</Status> + <ServerStatus code='100'>SUCCESS</ServerStatus> + <Expires>2008-07-15T01:21:10.000Z</Expires> + <ProviderID>xri://!!1003</ProviderID> + <LocalID>0000.0000.3B9A.CA01</LocalID> + <CanonicalID>@!72CD.A072.157E.A9C6!0000.0000.3B9A.CA0C!0000.0000.3B9A.CA41!0000.0000.3B9A.CA01</CanonicalID> + <Service> + <ProviderID>xri://!!1003!103</ProviderID> + <Type select='true'>http://openid.net/signon/1.0</Type> + <URI append='none' priority='1'>https://login.llli.org/server/</URI> + </Service> + <Service> + <ProviderID>xri://!!1003!103</ProviderID> + <Type select='true'>xri://+i-service*(+contact)*($v*1.0)</Type> + <Type match='null'/> + <Path select='true'>(+contact)</Path> + <Path match='null'/> + <URI append='authority' priority='1'>http://linksafe-contact.ezibroker.net/contact/</URI> + </Service> + <Service priority='1'> + <ProviderID>xri://!!1003!103</ProviderID> + <Type select='true'>xri://+i-service*(+forwarding)*($v*1.0)</Type> + <Type match='null' select='false'/> + <Path>(+index)</Path> + <Path match='default'/> + <URI append='qxri' priority='1'>http://linksafe-forward.ezibroker.net/forwarding/</URI> + </Service> +</XRD>"; + string webResponse = @"<?xml version='1.0' encoding='UTF-8'?> +<XRD version='2.0' xmlns='xri://$xrd*($v*2.0)'> + <Query>*Web</Query> + <Status ceid='off' cid='verified' code='100'/> + <Expires>2008-07-14T02:21:12.000Z</Expires> + <ProviderID>xri://=</ProviderID> + <LocalID>!91f2.8153.f600.ae24</LocalID> + <CanonicalID>=!91F2.8153.F600.AE24</CanonicalID> + <Service priority='10'> + <Type select='true'>xri://+i-service*(+locator)*($v*1.0)</Type> + <Path select='true'>(+locator)</Path> + <MediaType match='default' select='false'/> + <URI append='qxri'>http://locator.fullxri.com/locator/</URI> + </Service> + <Service priority='10'> + <ProviderID>xri://=web</ProviderID> + <Type select='true'>xri://$res*auth*($v*2.0)</Type> + <Type select='true'>xri://$res*auth*($v*2.0)</Type> + <MediaType select='true'>application/xrds+xml</MediaType> + <URI append='qxri' priority='1'>https://resolve.freexri.com/ns/=web/</URI> + <URI append='qxri' priority='2'>http://resolve.freexri.com/ns/=web/</URI> + </Service> + <Service priority='10'> + <Type select='true'>http://openid.net/signon/1.0</Type> + <Type select='true'>http://specs.openid.net/auth/2.0/signon</Type> + <Path select='true'>(+login)</Path> + <Path match='default' select='false'/> + <MediaType match='default' select='false'/> + <URI append='none' priority='2'>http://authn.fullxri.com/authentication/</URI> + <URI append='none' priority='1'>https://authn.fullxri.com/authentication/</URI> + </Service> + <Service priority='10'> + <Type select='true'>xri://+i-service*(+contact)*($v*1.0)</Type> + <Type match='null' select='false'/> + <Path select='true'>(+contact)</Path> + <Path match='null' select='false'/> + <MediaType match='default' select='false'/> + <URI append='qxri'>http://contact.fullxri.com/contact/</URI> + </Service> + <KeyInfo xmlns='http://www.w3.org/2000/09/xmldsig#'> + <X509Data> + <X509Certificate> +MIIExzCCA6+gAwIBAgIJAM+MlFr0Sth6MA0GCSqGSIb3DQEBBQUAMIGdMR8wHQYD +VQQDExZTdXBlcnZpbGxhaW46IFRoZSBSb290MQswCQYDVQQGEwJVUzERMA8GA1UE +CBMITmV3IFlvcmsxDzANBgNVBAcTBkdvdGhhbTEgMB4GA1UEChMXU3VwZXJ2aWxs +YWluIFVuaXZlcnNpdHkxJzAlBgkqhkiG9w0BCQEWGHBlbmd1aW5Ac3VwZXJ2aWxs +YWluLmVkdTAeFw0wNjA4MTcxOTU5NTNaFw0xMTA4MTYxOTU5NTNaMIGdMR8wHQYD +VQQDExZTdXBlcnZpbGxhaW46IFRoZSBSb290MQswCQYDVQQGEwJVUzERMA8GA1UE +CBMITmV3IFlvcmsxDzANBgNVBAcTBkdvdGhhbTEgMB4GA1UEChMXU3VwZXJ2aWxs +YWluIFVuaXZlcnNpdHkxJzAlBgkqhkiG9w0BCQEWGHBlbmd1aW5Ac3VwZXJ2aWxs +YWluLmVkdTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL6uFqas4dK6 +A2wTZL0viRQNJrPyFnFBDSZGib/2ijhgzed/vvmZIBM9sFpwahcuR5hvyKUe37/c +/RSZXoNDi/eiNOx4qb0l9UB6bd8qvc4V1PnLE7L+ZYcmwrvTKm4x8qXMgEv1wca2 +FPsreHNPdLiTUZ8v0tDTWi3Mgi7y47VTzJaTkcfmO1nL6xAtln5sLdH0PbMM3LAp +T1d3nwI3VdbhqqZ+6+OKEuC8gk5iH4lfrbr6C9bYS6vzIKrotHpZ3N2aIC3NMjJD +PMw/mfCuADfRNlHXgZW+0zyUkwGTMDea8qgsoAMWJGdeTIw8I1I3RhnbgLzdsNQl +b/1ZXx1uJRUCAwEAAaOCAQYwggECMB0GA1UdDgQWBBQe+xSjYTrlfraJARjMxscb +j36jvDCB0gYDVR0jBIHKMIHHgBQe+xSjYTrlfraJARjMxscbj36jvKGBo6SBoDCB +nTEfMB0GA1UEAxMWU3VwZXJ2aWxsYWluOiBUaGUgUm9vdDELMAkGA1UEBhMCVVMx +ETAPBgNVBAgTCE5ldyBZb3JrMQ8wDQYDVQQHEwZHb3RoYW0xIDAeBgNVBAoTF1N1 +cGVydmlsbGFpbiBVbml2ZXJzaXR5MScwJQYJKoZIhvcNAQkBFhhwZW5ndWluQHN1 +cGVydmlsbGFpbi5lZHWCCQDPjJRa9ErYejAMBgNVHRMEBTADAQH/MA0GCSqGSIb3 +DQEBBQUAA4IBAQC4SPBDGYAxfbXd8N5OvG0drM7a5hjXfcCZpiILlPSRpxp79yh7 +I5vVWxBxUfolwbei7PTBVy7CE27SUbSICeqWjcDCfjNjiZk6mLS80rm/TdLrHSyM ++Ujlw9MGcBGaLI+sdziDUMtTQDpeAyQTaGVbh1mx5874Hlo1VXqGYNo0RwR+iLfs +x48VuO6GbWVyxtktkE2ypz1KLWiyI056YynydRvuBCBHeRqGUixPlH9CrmeSCP2S +sfbiKnMOGXjIYbvbsTAMdW2iqg6IWa/fgxhvZoAXChM9bkhisJQc0qD0J5TJQwgr +uEyb50RJ7DWmXctSC0b3eymZ2lSXxAWNOsNy + </X509Certificate> + </X509Data> + </KeyInfo> +</XRD>"; + this.MockResponder.RegisterMockXrdsResponses(new Dictionary<string, string> { + { "https://xri.net/@llli?_xrd_r=application/xrd%2Bxml;sep=false", llliResponse }, + { "https://xri.net/@llli*area?_xrd_r=application/xrd%2Bxml;sep=false", llliAreaResponse }, + { "https://xri.net/@llli*area*canada.unattached?_xrd_r=application/xrd%2Bxml;sep=false", llliAreaCanadaUnattachedResponse }, + { "https://xri.net/@llli*area*canada.unattached*ada?_xrd_r=application/xrd%2Bxml;sep=false", llliAreaCanadaUnattachedAdaResponse }, + { "https://xri.net/=Web?_xrd_r=application/xrd%2Bxml;sep=false", webResponse }, + }); + this.VerifyCanonicalId("@llli", "@!72CD.A072.157E.A9C6"); + this.VerifyCanonicalId("@llli*area", "@!72CD.A072.157E.A9C6!0000.0000.3B9A.CA0C"); + this.VerifyCanonicalId("@llli*area*canada.unattached", "@!72CD.A072.157E.A9C6!0000.0000.3B9A.CA0C!0000.0000.3B9A.CA41"); + this.VerifyCanonicalId("@llli*area*canada.unattached*ada", "@!72CD.A072.157E.A9C6!0000.0000.3B9A.CA0C!0000.0000.3B9A.CA41!0000.0000.3B9A.CA01"); + this.VerifyCanonicalId("=Web", "=!91F2.8153.F600.AE24"); + } + + [TestMethod] + public void DiscoveryCommunityInameDelegateWithoutCanonicalID() { + this.MockResponder.RegisterMockXrdsResponses(new Dictionary<string, string> { + { "https://xri.net/=Web*andrew.arnott?_xrd_r=application/xrd%2Bxml;sep=false", @"<?xml version='1.0' encoding='UTF-8'?> +<XRD xmlns='xri://$xrd*($v*2.0)'> + <Query>*andrew.arnott</Query> + <Status cid='absent' code='100'>Success</Status> + <ServerStatus code='100'>Success</ServerStatus> + <Expires>2008-07-14T03:30:59.722Z</Expires> + <ProviderID>=!91F2.8153.F600.AE24</ProviderID> + <Service> + <Type select='true'>http://openid.net/signon/1.0</Type> + <Path select='true'>(+login)</Path> + <Path match='default'/> + <MediaType match='default'/> + <URI append='none' priority='2'>http://www.myopenid.com/server</URI> + <openid:Delegate xmlns:openid='http://openid.net/xmlns/1.0'>http://blog.nerdbank.net</openid:Delegate> + </Service> + <Service> + <ProviderID>@!7F6F.F50.A4E4.1133</ProviderID> + <Type select='true'>xri://+i-service*(+contact)*($v*1.0)</Type> + <Type match='null'/> + <Path select='true'>(+contact)</Path> + <Path match='null'/> + <MediaType match='default'/> + <URI append='qxri'>http://contact.freexri.com/contact/</URI> + </Service> + <Service> + <ProviderID>@!7F6F.F50.A4E4.1133</ProviderID> + <Type select='true'>xri://+i-service*(+forwarding)*($v*1.0)</Type> + <Path select='true'>(+index)</Path> + <Path match='default'/> + <MediaType match='default'/> + <URI append='qxri'>http://forwarding.freexri.com/forwarding/</URI> + </Service> + <Service> + <ProviderID>@!7F6F.F50.A4E4.1133</ProviderID> + <Type select='true'>http://openid.net/signon/1.0</Type> + <Path select='true'>(+login)</Path> + <Path match='default'/> + <MediaType match='default'/> + <URI append='none' priority='2'>http://authn.freexri.com/authentication/</URI> + <URI append='none' priority='1'>https://authn.freexri.com/authentication/</URI> + </Service> + <ServedBy>OpenXRI</ServedBy> +</XRD>" }, + { "https://xri.net/@id*andrewarnott?_xrd_r=application/xrd%2Bxml;sep=false", @"<?xml version='1.0' encoding='UTF-8'?> +<XRD xmlns='xri://$xrd*($v*2.0)'> + <Query>*andrewarnott</Query> + <Status cid='absent' code='100'>Success</Status> + <ServerStatus code='100'>Success</ServerStatus> + <Expires>2008-07-14T03:31:00.466Z</Expires> + <ProviderID>@!B1E8.C27B.E41C.25C3</ProviderID> + <Service> + <Type select='true'>http://openid.net/signon/1.0</Type> + <Path select='true'>(+login)</Path> + <Path match='default'/> + <MediaType match='default'/> + <URI append='none' priority='2'>http://www.myopenid.com/server</URI> + <openid:Delegate xmlns:openid='http://openid.net/xmlns/1.0'>http://blog.nerdbank.net</openid:Delegate> + </Service> + <Service> + <ProviderID>@!7F6F.F50.A4E4.1133</ProviderID> + <Type select='true'>xri://+i-service*(+contact)*($v*1.0)</Type> + <Type match='null'/> + <Path select='true'>(+contact)</Path> + <Path match='null'/> + <MediaType match='default'/> + <URI append='qxri'>http://contact.freexri.com/contact/</URI> + </Service> + <Service> + <ProviderID>@!7F6F.F50.A4E4.1133</ProviderID> + <Type select='true'>xri://+i-service*(+forwarding)*($v*1.0)</Type> + <Path select='true'>(+index)</Path> + <Path match='default'/> + <MediaType match='default'/> + <URI append='qxri'>http://forwarding.freexri.com/forwarding/</URI> + </Service> + <ServedBy>OpenXRI</ServedBy> +</XRD>" }, + }); + // Consistent with spec section 7.3.2.3, we do not permit + // delegation on XRI discovery when there is no CanonicalID present. + this.VerifyCanonicalId("=Web*andrew.arnott", null); + this.VerifyCanonicalId("@id*andrewarnott", null); + } + + private IdentifierDiscoveryResult VerifyCanonicalId(Identifier iname, string expectedClaimedIdentifier) { + var se = this.Discover(iname).FirstOrDefault(); + if (expectedClaimedIdentifier != null) { + Assert.IsNotNull(se); + Assert.AreEqual(expectedClaimedIdentifier, se.ClaimedIdentifier.ToString(), "i-name {0} discovery resulted in unexpected CanonicalId", iname); + Assert.IsTrue(se.Capabilities.Count > 0); + } else { + Assert.IsNull(se); + } + return se; + } + } +} diff --git a/src/DotNetOpenAuth.Test/OpenId/Extensions/ExtensionsInteropHelperRPRequestTests.cs b/src/DotNetOpenAuth.Test/OpenId/Extensions/ExtensionsInteropHelperRPRequestTests.cs index ba5e335..ea960b5 100644 --- a/src/DotNetOpenAuth.Test/OpenId/Extensions/ExtensionsInteropHelperRPRequestTests.cs +++ b/src/DotNetOpenAuth.Test/OpenId/Extensions/ExtensionsInteropHelperRPRequestTests.cs @@ -5,6 +5,7 @@ //----------------------------------------------------------------------- namespace DotNetOpenAuth.Test.OpenId { + using System.Collections.ObjectModel; using System.Linq; using DotNetOpenAuth.OpenId; using DotNetOpenAuth.OpenId.Extensions; @@ -118,11 +119,9 @@ namespace DotNetOpenAuth.Test.OpenId { /// </summary> /// <param name="typeUri">The type URI.</param> private void InjectAdvertisedTypeUri(string typeUri) { - var serviceEndpoint = ServiceEndpoint_Accessor.AttachShadow(((ServiceEndpoint)this.authReq.Provider)); - serviceEndpoint.ProviderDescription = ProviderEndpointDescription_Accessor.AttachShadow( - new ProviderEndpointDescription( - serviceEndpoint.ProviderDescription.Endpoint, - serviceEndpoint.ProviderDescription.Capabilities.Concat(new[] { typeUri }))); + var serviceEndpoint = IdentifierDiscoveryResult_Accessor.AttachShadow(this.authReq.Provider); + serviceEndpoint.Capabilities = new ReadOnlyCollection<string>( + serviceEndpoint.Capabilities.Concat(new[] { typeUri }).ToList()); } } } diff --git a/src/DotNetOpenAuth.Test/OpenId/OpenIdCoordinator.cs b/src/DotNetOpenAuth.Test/OpenId/OpenIdCoordinator.cs index 0f9d472..d4884e8 100644 --- a/src/DotNetOpenAuth.Test/OpenId/OpenIdCoordinator.cs +++ b/src/DotNetOpenAuth.Test/OpenId/OpenIdCoordinator.cs @@ -57,10 +57,12 @@ namespace DotNetOpenAuth.Test.OpenId { private void EnsurePartiesAreInitialized() { if (this.RelyingParty == null) { this.RelyingParty = new OpenIdRelyingParty(new StandardRelyingPartyApplicationStore()); + this.RelyingParty.DiscoveryServices.Add(new MockIdentifierDiscoveryService()); } if (this.Provider == null) { this.Provider = new OpenIdProvider(new StandardProviderApplicationStore()); + this.Provider.DiscoveryServices.Add(new MockIdentifierDiscoveryService()); } } } diff --git a/src/DotNetOpenAuth.Test/OpenId/OpenIdTestBase.cs b/src/DotNetOpenAuth.Test/OpenId/OpenIdTestBase.cs index 5034b7e..5e92895 100644 --- a/src/DotNetOpenAuth.Test/OpenId/OpenIdTestBase.cs +++ b/src/DotNetOpenAuth.Test/OpenId/OpenIdTestBase.cs @@ -6,6 +6,7 @@ namespace DotNetOpenAuth.Test.OpenId { using System; + using System.Collections.Generic; using System.IO; using System.Reflection; using DotNetOpenAuth.Configuration; @@ -116,17 +117,17 @@ namespace DotNetOpenAuth.Test.OpenId { } } - internal static ServiceEndpoint GetServiceEndpoint(int user, ProtocolVersion providerVersion, int servicePriority, bool useSsl) { + internal static IdentifierDiscoveryResult GetServiceEndpoint(int user, ProtocolVersion providerVersion, int servicePriority, bool useSsl) { return GetServiceEndpoint(user, providerVersion, servicePriority, useSsl, false); } - internal static ServiceEndpoint GetServiceEndpoint(int user, ProtocolVersion providerVersion, int servicePriority, bool useSsl, bool delegating) { + internal static IdentifierDiscoveryResult GetServiceEndpoint(int user, ProtocolVersion providerVersion, int servicePriority, bool useSsl, bool delegating) { var providerEndpoint = new ProviderEndpointDescription( useSsl ? OpenIdTestBase.OPUriSsl : OpenIdTestBase.OPUri, new string[] { Protocol.Lookup(providerVersion).ClaimedIdentifierServiceTypeURI }); var local_id = useSsl ? OPLocalIdentifiersSsl[user] : OPLocalIdentifiers[user]; var claimed_id = delegating ? (useSsl ? VanityUriSsl : VanityUri) : local_id; - return ServiceEndpoint.CreateForClaimedIdentifier( + return IdentifierDiscoveryResult.CreateForClaimedIdentifier( claimed_id, claimed_id, local_id, @@ -176,6 +177,12 @@ namespace DotNetOpenAuth.Test.OpenId { } } + internal IEnumerable<IdentifierDiscoveryResult> Discover(Identifier identifier) { + var rp = this.CreateRelyingParty(true); + rp.Channel.WebRequestHandler = this.RequestHandler; + return rp.Discover(identifier); + } + protected Realm GetMockRealm(bool useSsl) { var rpDescription = new RelyingPartyEndpointDescription(useSsl ? RPUriSsl : RPUri, new string[] { Protocol.V20.RPReturnToTypeURI }); return new MockRealm(useSsl ? RPRealmUriSsl : RPRealmUri, rpDescription); @@ -190,9 +197,21 @@ namespace DotNetOpenAuth.Test.OpenId { } protected Identifier GetMockIdentifier(ProtocolVersion providerVersion, bool useSsl, bool delegating) { - ServiceEndpoint se = GetServiceEndpoint(0, providerVersion, 10, useSsl, delegating); + var se = GetServiceEndpoint(0, providerVersion, 10, useSsl, delegating); UriIdentifier identityUri = (UriIdentifier)se.ClaimedIdentifier; - return new MockIdentifier(identityUri, this.MockResponder, new ServiceEndpoint[] { se }); + return new MockIdentifier(identityUri, this.MockResponder, new IdentifierDiscoveryResult[] { se }); + } + + protected Identifier GetMockDualIdentifier() { + Protocol protocol = Protocol.Default; + var opDesc = new ProviderEndpointDescription(OPUri, protocol.Version); + var dualResults = new IdentifierDiscoveryResult[] { + IdentifierDiscoveryResult.CreateForClaimedIdentifier(VanityUri.AbsoluteUri, VanityUri.AbsoluteUri, opDesc, 10, 10), + IdentifierDiscoveryResult.CreateForProviderIdentifier(protocol.ClaimedIdentifierForOPIdentifier, opDesc, 20, 20), + }; + + Identifier dualId = new MockIdentifier(VanityUri, this.MockResponder, dualResults); + return dualId; } /// <summary> @@ -211,6 +230,7 @@ namespace DotNetOpenAuth.Test.OpenId { protected OpenIdRelyingParty CreateRelyingParty(bool stateless) { var rp = new OpenIdRelyingParty(stateless ? null : new StandardRelyingPartyApplicationStore()); rp.Channel.WebRequestHandler = this.MockResponder.MockWebRequestHandler; + rp.DiscoveryServices.Add(new MockIdentifierDiscoveryService()); return rp; } @@ -221,6 +241,7 @@ namespace DotNetOpenAuth.Test.OpenId { protected OpenIdProvider CreateProvider() { var op = new OpenIdProvider(new StandardProviderApplicationStore()); op.Channel.WebRequestHandler = this.MockResponder.MockWebRequestHandler; + op.DiscoveryServices.Add(new MockIdentifierDiscoveryService()); return op; } } diff --git a/src/DotNetOpenAuth.Test/OpenId/OpenIdUtilitiesTests.cs b/src/DotNetOpenAuth.Test/OpenId/OpenIdUtilitiesTests.cs new file mode 100644 index 0000000..389ef81 --- /dev/null +++ b/src/DotNetOpenAuth.Test/OpenId/OpenIdUtilitiesTests.cs @@ -0,0 +1,20 @@ +//----------------------------------------------------------------------- +// <copyright file="OpenIdUtilitiesTests.cs" company="Andrew Arnott"> +// Copyright (c) Andrew Arnott. All rights reserved. +// </copyright> +//----------------------------------------------------------------------- + +namespace DotNetOpenAuth.Test.OpenId { + using System; + using System.Collections.Generic; + using System.Linq; + using System.Text; + using DotNetOpenAuth.OpenId; + using DotNetOpenAuth.OpenId.Extensions.SimpleRegistration; + using DotNetOpenAuth.OpenId.Messages; + using Microsoft.VisualStudio.TestTools.UnitTesting; + + [TestClass] + public class OpenIdUtilitiesTests : OpenIdTestBase { + } +} diff --git a/src/DotNetOpenAuth.Test/OpenId/ProviderEndpointDescriptionTests.cs b/src/DotNetOpenAuth.Test/OpenId/ProviderEndpointDescriptionTests.cs index 089265f..60cd25f 100644 --- a/src/DotNetOpenAuth.Test/OpenId/ProviderEndpointDescriptionTests.cs +++ b/src/DotNetOpenAuth.Test/OpenId/ProviderEndpointDescriptionTests.cs @@ -6,6 +6,7 @@ namespace DotNetOpenAuth.Test.OpenId { using System; + using DotNetOpenAuth.Messaging; using DotNetOpenAuth.OpenId; using DotNetOpenAuth.OpenId.Extensions.SimpleRegistration; using DotNetOpenAuth.OpenId.Messages; @@ -13,50 +14,15 @@ namespace DotNetOpenAuth.Test.OpenId { [TestClass] public class ProviderEndpointDescriptionTests : OpenIdTestBase { - private ProviderEndpointDescription se; - - private string[] v20TypeUris = { Protocol.V20.ClaimedIdentifierServiceTypeURI }; - - [TestInitialize] - public override void SetUp() { - base.SetUp(); - - this.se = new ProviderEndpointDescription(OPUri, Protocol.V20.Version); - } - - [TestMethod, ExpectedException(typeof(ArgumentNullException))] - public void IsExtensionSupportedNullType() { - this.se.IsExtensionSupported((Type)null); - } - - [TestMethod, ExpectedException(typeof(ArgumentException))] - public void IsExtensionSupportedNullString() { - this.se.IsExtensionSupported((string)null); - } - - [TestMethod, ExpectedException(typeof(ArgumentException))] - public void IsExtensionSupportedEmptyString() { - this.se.IsExtensionSupported(string.Empty); - } - - [TestMethod, ExpectedException(typeof(ArgumentNullException))] - public void IsExtensionSupportedNullExtension() { - this.se.IsExtensionSupported((IOpenIdMessageExtension)null); - } - [TestMethod] - public void IsExtensionSupported() { - this.se = new ProviderEndpointDescription(OPUri, this.v20TypeUris); - Assert.IsFalse(this.se.IsExtensionSupported<ClaimsRequest>()); - Assert.IsFalse(this.se.IsExtensionSupported(new ClaimsRequest())); - Assert.IsFalse(this.se.IsExtensionSupported("http://someextension/typeuri")); + public void NonNullCapabilities() { + var epd = new ProviderEndpointDescription(OPUri, Protocol.Default.Version); + Assert.IsNotNull(epd.Capabilities); + } - this.se = new ProviderEndpointDescription( - OPUri, - new[] { Protocol.V20.ClaimedIdentifierServiceTypeURI, "http://someextension", Constants.sreg_ns }); - Assert.IsTrue(this.se.IsExtensionSupported<ClaimsRequest>()); - Assert.IsTrue(this.se.IsExtensionSupported(new ClaimsRequest())); - Assert.IsTrue(this.se.IsExtensionSupported("http://someextension")); + [TestMethod, ExpectedException(typeof(ProtocolException))] + public void ProtocolDetectionWithoutClues() { + new ProviderEndpointDescription(OPUri, new[] { Protocol.V20.HtmlDiscoveryLocalIdKey }); // random type URI irrelevant to detection } } } diff --git a/src/DotNetOpenAuth.Test/OpenId/RelyingParty/AuthenticationRequestTests.cs b/src/DotNetOpenAuth.Test/OpenId/RelyingParty/AuthenticationRequestTests.cs index 10497b2..f243a69 100644 --- a/src/DotNetOpenAuth.Test/OpenId/RelyingParty/AuthenticationRequestTests.cs +++ b/src/DotNetOpenAuth.Test/OpenId/RelyingParty/AuthenticationRequestTests.cs @@ -16,6 +16,7 @@ namespace DotNetOpenAuth.Test.OpenId.RelyingParty { using DotNetOpenAuth.OpenId.Extensions.SimpleRegistration; using DotNetOpenAuth.OpenId.Messages; using DotNetOpenAuth.OpenId.RelyingParty; + using DotNetOpenAuth.Test.Mocks; using Microsoft.VisualStudio.TestTools.UnitTesting; [TestClass] @@ -37,7 +38,7 @@ namespace DotNetOpenAuth.Test.OpenId.RelyingParty { /// </summary> [TestMethod] public void IsDirectedIdentity() { - IAuthenticationRequest_Accessor iauthRequest = this.CreateAuthenticationRequest(this.claimedId, this.claimedId); + var iauthRequest = this.CreateAuthenticationRequest(this.claimedId, this.claimedId); Assert.IsFalse(iauthRequest.IsDirectedIdentity); iauthRequest = this.CreateAuthenticationRequest(IdentifierSelect, IdentifierSelect); @@ -49,7 +50,7 @@ namespace DotNetOpenAuth.Test.OpenId.RelyingParty { /// </summary> [TestMethod] public void ClaimedIdentifier() { - IAuthenticationRequest_Accessor iauthRequest = this.CreateAuthenticationRequest(this.claimedId, this.delegatedLocalId); + var iauthRequest = this.CreateAuthenticationRequest(this.claimedId, this.delegatedLocalId); Assert.AreEqual(this.claimedId, iauthRequest.ClaimedIdentifier); iauthRequest = this.CreateAuthenticationRequest(IdentifierSelect, IdentifierSelect); @@ -62,7 +63,7 @@ namespace DotNetOpenAuth.Test.OpenId.RelyingParty { [TestMethod] public void ProviderVersion() { var authRequest = this.CreateAuthenticationRequest(this.claimedId, this.claimedId); - Assert.AreEqual(this.protocol.Version, authRequest.endpoint.Protocol.Version); + Assert.AreEqual(this.protocol.Version, authRequest.DiscoveryResult.Version); } /// <summary> @@ -124,7 +125,7 @@ namespace DotNetOpenAuth.Test.OpenId.RelyingParty { /// </summary> [TestMethod] public void Provider() { - IAuthenticationRequest_Accessor authRequest = this.CreateAuthenticationRequest(this.claimedId, this.claimedId); + var authRequest = this.CreateAuthenticationRequest(this.claimedId, this.claimedId); Assert.IsNotNull(authRequest.Provider); Assert.AreEqual(OPUri, authRequest.Provider.Uri); Assert.AreEqual(this.protocol.Version, authRequest.Provider.Version); @@ -135,7 +136,7 @@ namespace DotNetOpenAuth.Test.OpenId.RelyingParty { /// </summary> [TestMethod] public void AddCallbackArgument() { - IAuthenticationRequest_Accessor authRequest = this.CreateAuthenticationRequest(this.claimedId, this.claimedId); + var authRequest = this.CreateAuthenticationRequest(this.claimedId, this.claimedId); Assert.AreEqual(this.returnTo, authRequest.ReturnToUrl); authRequest.AddCallbackArguments("p1", "v1"); var req = (SignedResponseRequest)authRequest.RedirectingResponse.OriginalMessage; @@ -152,7 +153,7 @@ namespace DotNetOpenAuth.Test.OpenId.RelyingParty { UriBuilder returnToWithArgs = new UriBuilder(this.returnTo); returnToWithArgs.AppendQueryArgs(new Dictionary<string, string> { { "p1", "v1" } }); this.returnTo = returnToWithArgs.Uri; - IAuthenticationRequest_Accessor authRequest = this.CreateAuthenticationRequest(this.claimedId, this.claimedId); + var authRequest = this.CreateAuthenticationRequest(this.claimedId, this.claimedId); authRequest.AddCallbackArguments("p1", "v2"); var req = (SignedResponseRequest)authRequest.RedirectingResponse.OriginalMessage; NameValueCollection query = HttpUtility.ParseQueryString(req.ReturnTo.Query); @@ -164,7 +165,7 @@ namespace DotNetOpenAuth.Test.OpenId.RelyingParty { /// </summary> [TestMethod] public void NonIdentityRequest() { - IAuthenticationRequest_Accessor authRequest = this.CreateAuthenticationRequest(this.claimedId, this.claimedId); + var authRequest = this.CreateAuthenticationRequest(this.claimedId, this.claimedId); authRequest.IsExtensionOnly = true; Assert.IsTrue(authRequest.IsExtensionOnly); var req = (SignedResponseRequest)authRequest.RedirectingResponse.OriginalMessage; @@ -172,6 +173,17 @@ namespace DotNetOpenAuth.Test.OpenId.RelyingParty { } /// <summary> + /// Verifies that discovery on identifiers that serve as OP identifiers and claimed identifiers + /// only generate OP Identifier auth requests. + /// </summary> + [TestMethod] + public void DualIdentifierUsedOnlyAsOPIdentifierForAuthRequest() { + var results = AuthenticationRequest.Create(GetMockDualIdentifier(), this.CreateRelyingParty(true), this.realm, this.returnTo, false).ToList(); + Assert.AreEqual(1, results.Count); + Assert.IsTrue(results[0].IsDirectedIdentity); + } + + /// <summary> /// Verifies that authentication requests are generated first for OPs that respond /// to authentication requests. /// </summary> @@ -181,13 +193,11 @@ namespace DotNetOpenAuth.Test.OpenId.RelyingParty { Assert.Inconclusive("Not yet implemented."); } - private AuthenticationRequest_Accessor CreateAuthenticationRequest(Identifier claimedIdentifier, Identifier providerLocalIdentifier) { + private AuthenticationRequest CreateAuthenticationRequest(Identifier claimedIdentifier, Identifier providerLocalIdentifier) { ProviderEndpointDescription providerEndpoint = new ProviderEndpointDescription(OPUri, this.protocol.Version); - ServiceEndpoint endpoint = ServiceEndpoint.CreateForClaimedIdentifier(claimedIdentifier, providerLocalIdentifier, providerEndpoint, 10, 5); - ServiceEndpoint_Accessor endpointAccessor = ServiceEndpoint_Accessor.AttachShadow(endpoint); + IdentifierDiscoveryResult endpoint = IdentifierDiscoveryResult.CreateForClaimedIdentifier(claimedIdentifier, providerLocalIdentifier, providerEndpoint, 10, 5); OpenIdRelyingParty rp = this.CreateRelyingParty(); - AuthenticationRequest_Accessor authRequest = new AuthenticationRequest_Accessor(endpointAccessor, this.realm, this.returnTo, rp); - return authRequest; + return AuthenticationRequest.CreateForTest(endpoint, this.realm, this.returnTo, rp); } } } diff --git a/src/DotNetOpenAuth.Test/OpenId/RelyingParty/IdentifierDiscoveryResultTests.cs b/src/DotNetOpenAuth.Test/OpenId/RelyingParty/IdentifierDiscoveryResultTests.cs new file mode 100644 index 0000000..1ed281c --- /dev/null +++ b/src/DotNetOpenAuth.Test/OpenId/RelyingParty/IdentifierDiscoveryResultTests.cs @@ -0,0 +1,199 @@ +//----------------------------------------------------------------------- +// <copyright file="IdentifierDiscoveryResultTests.cs" company="Andrew Arnott"> +// Copyright (c) Andrew Arnott. All rights reserved. +// </copyright> +//----------------------------------------------------------------------- + +namespace DotNetOpenAuth.Test.OpenId.RelyingParty { + using System; + using System.Collections.Generic; + using System.Diagnostics; + using System.IO; + using System.Text; + using DotNetOpenAuth.Messaging; + using DotNetOpenAuth.OpenId; + using DotNetOpenAuth.OpenId.Extensions.SimpleRegistration; + using DotNetOpenAuth.OpenId.Messages; + using DotNetOpenAuth.OpenId.RelyingParty; + using DotNetOpenAuth.Test.Messaging; + using Microsoft.VisualStudio.TestTools.UnitTesting; + + [TestClass] + public class IdentifierDiscoveryResultTests : OpenIdTestBase { + private UriIdentifier claimedId = new UriIdentifier("http://claimedid.justatest.com"); + private XriIdentifier claimedXri = new XriIdentifier("=!9B72.7DD1.50A9.5CCD"); + private XriIdentifier userSuppliedXri = new XriIdentifier("=Arnot"); + private Uri providerEndpoint = new Uri("http://someprovider.com"); + private Identifier localId = "http://localid.someprovider.com"; + private string[] v20TypeUris = { Protocol.V20.ClaimedIdentifierServiceTypeURI }; + private string[] v11TypeUris = { Protocol.V11.ClaimedIdentifierServiceTypeURI }; + private int servicePriority = 10; + private int uriPriority = 10; + + [TestInitialize] + public override void SetUp() { + base.SetUp(); + } + + [TestMethod] + public void Ctor() { + IdentifierDiscoveryResult se = IdentifierDiscoveryResult.CreateForClaimedIdentifier(this.claimedId, this.localId, new ProviderEndpointDescription(this.providerEndpoint, this.v20TypeUris), this.servicePriority, this.uriPriority); + Assert.AreEqual(this.claimedId, se.ClaimedIdentifier); + Assert.AreSame(this.providerEndpoint, se.ProviderEndpoint); + Assert.AreSame(this.localId, se.ProviderLocalIdentifier); + CollectionAssert<string>.AreEquivalent(this.v20TypeUris, se.Capabilities); + Assert.AreEqual(this.servicePriority, se.ServicePriority); + } + + [TestMethod] + public void CtorImpliedLocalIdentifier() { + IdentifierDiscoveryResult se = IdentifierDiscoveryResult.CreateForClaimedIdentifier(this.claimedId, null, new ProviderEndpointDescription(this.providerEndpoint, this.v20TypeUris), this.servicePriority, this.uriPriority); + Assert.AreEqual(this.claimedId, se.ClaimedIdentifier); + Assert.AreSame(this.providerEndpoint, se.ProviderEndpoint); + Assert.AreSame(this.claimedId, se.ProviderLocalIdentifier); + CollectionAssert<string>.AreEquivalent(this.v20TypeUris, se.Capabilities); + } + + [TestMethod] + public void ProtocolDetection() { + IdentifierDiscoveryResult se = IdentifierDiscoveryResult.CreateForClaimedIdentifier(this.claimedId, this.localId, new ProviderEndpointDescription(this.providerEndpoint, this.v20TypeUris), this.servicePriority, this.uriPriority); + Assert.AreSame(Protocol.V20, se.Protocol); + se = IdentifierDiscoveryResult.CreateForClaimedIdentifier( + this.claimedId, + this.localId, + new ProviderEndpointDescription(this.providerEndpoint, new[] { Protocol.V20.OPIdentifierServiceTypeURI }), + this.servicePriority, + this.uriPriority); + Assert.AreSame(Protocol.V20, se.Protocol); + se = IdentifierDiscoveryResult.CreateForClaimedIdentifier(this.claimedId, this.localId, new ProviderEndpointDescription(this.providerEndpoint, this.v11TypeUris), this.servicePriority, this.uriPriority); + Assert.AreSame(Protocol.V11, se.Protocol); + } + + [TestMethod] + public void EqualsTests() { + IdentifierDiscoveryResult se = IdentifierDiscoveryResult.CreateForClaimedIdentifier(this.claimedId, this.localId, new ProviderEndpointDescription(this.providerEndpoint, this.v20TypeUris), this.servicePriority, this.uriPriority); + IdentifierDiscoveryResult se2 = IdentifierDiscoveryResult.CreateForClaimedIdentifier(this.claimedId, this.localId, new ProviderEndpointDescription(this.providerEndpoint, this.v20TypeUris), (int?)null, (int?)null); + Assert.AreEqual(se2, se); + Assert.AreNotEqual(se, null); + Assert.AreNotEqual(null, se); + + IdentifierDiscoveryResult se3 = IdentifierDiscoveryResult.CreateForClaimedIdentifier(new UriIdentifier(this.claimedId + "a"), this.localId, new ProviderEndpointDescription(this.providerEndpoint, this.v20TypeUris), this.servicePriority, this.uriPriority); + Assert.AreNotEqual(se, se3); + se3 = IdentifierDiscoveryResult.CreateForClaimedIdentifier(this.claimedId, this.localId, new ProviderEndpointDescription(new Uri(this.providerEndpoint.AbsoluteUri + "a"), this.v20TypeUris), this.servicePriority, this.uriPriority); + Assert.AreNotEqual(se, se3); + se3 = IdentifierDiscoveryResult.CreateForClaimedIdentifier(this.claimedId, this.localId + "a", new ProviderEndpointDescription(this.providerEndpoint, this.v20TypeUris), this.servicePriority, this.uriPriority); + Assert.AreNotEqual(se, se3); + se3 = IdentifierDiscoveryResult.CreateForClaimedIdentifier(this.claimedId, this.localId, new ProviderEndpointDescription(this.providerEndpoint, this.v11TypeUris), this.servicePriority, this.uriPriority); + Assert.AreNotEqual(se, se3); + + // make sure that Collection<T>.Contains works as desired. + var list = new List<IdentifierDiscoveryResult>(); + list.Add(se); + Assert.IsTrue(list.Contains(se2)); + } + + [TestMethod] + public void GetFriendlyIdentifierForDisplay() { + Uri providerEndpoint = new Uri("http://someprovider"); + Identifier localId = "someuser"; + string[] serviceTypeUris = new string[] { + Protocol.V20.ClaimedIdentifierServiceTypeURI, + }; + IdentifierDiscoveryResult se; + + // strip of protocol, port, query and fragment + se = IdentifierDiscoveryResult.CreateForClaimedIdentifier( + "http://someprovider.somedomain.com:79/someuser?query#frag", + localId, + new ProviderEndpointDescription(providerEndpoint, serviceTypeUris), + null, + null); + Assert.AreEqual("someprovider.somedomain.com/someuser", se.FriendlyIdentifierForDisplay); + + // unescape characters + Uri foreignUri = new Uri("http://server崎/村"); + se = IdentifierDiscoveryResult.CreateForClaimedIdentifier(foreignUri, localId, new ProviderEndpointDescription(providerEndpoint, serviceTypeUris), null, null); + Assert.AreEqual("server崎/村", se.FriendlyIdentifierForDisplay); + + // restore user supplied identifier to XRIs + se = IdentifierDiscoveryResult.CreateForClaimedIdentifier( + new XriIdentifier("=!9B72.7DD1.50A9.5CCD"), + new XriIdentifier("=Arnott崎村"), + localId, + new ProviderEndpointDescription(providerEndpoint, serviceTypeUris), + null, + null); + Assert.AreEqual("=Arnott崎村", se.FriendlyIdentifierForDisplay); + + // If UserSuppliedIdentifier is the same as the ClaimedIdentifier, don't display it twice... + se = IdentifierDiscoveryResult.CreateForClaimedIdentifier( + new XriIdentifier("=!9B72.7DD1.50A9.5CCD"), + new XriIdentifier("=!9B72.7DD1.50A9.5CCD"), + localId, + new ProviderEndpointDescription(providerEndpoint, serviceTypeUris), + null, + null); + Assert.AreEqual("=!9B72.7DD1.50A9.5CCD", se.FriendlyIdentifierForDisplay); + } + + [TestMethod] + public void IsTypeUriPresent() { + IdentifierDiscoveryResult se = IdentifierDiscoveryResult.CreateForClaimedIdentifier(this.claimedXri, this.userSuppliedXri, this.localId, new ProviderEndpointDescription(this.providerEndpoint, this.v20TypeUris), this.servicePriority, this.uriPriority); + Assert.IsTrue(se.IsTypeUriPresent(Protocol.Default.ClaimedIdentifierServiceTypeURI)); + Assert.IsFalse(se.IsTypeUriPresent("http://someother")); + } + + [TestMethod, ExpectedException(typeof(ArgumentException))] + public void IsTypeUriPresentNull() { + IdentifierDiscoveryResult se = IdentifierDiscoveryResult.CreateForClaimedIdentifier(this.claimedXri, this.userSuppliedXri, this.localId, new ProviderEndpointDescription(this.providerEndpoint, this.v20TypeUris), this.servicePriority, this.uriPriority); + se.IsTypeUriPresent(null); + } + + [TestMethod, ExpectedException(typeof(ArgumentException))] + public void IsTypeUriPresentEmpty() { + IdentifierDiscoveryResult se = IdentifierDiscoveryResult.CreateForClaimedIdentifier(this.claimedXri, this.userSuppliedXri, this.localId, new ProviderEndpointDescription(this.providerEndpoint, this.v20TypeUris), this.servicePriority, this.uriPriority); + se.IsTypeUriPresent(string.Empty); + } + + [TestMethod, ExpectedException(typeof(ArgumentNullException))] + public void IsExtensionSupportedNullType() { + var se = IdentifierDiscoveryResult.CreateForProviderIdentifier(OPUri, new ProviderEndpointDescription(OPUri, this.v20TypeUris), null, null); + se.IsExtensionSupported((Type)null); + } + + [TestMethod, ExpectedException(typeof(ArgumentException))] + public void IsTypeUriPresentNullString() { + var se = IdentifierDiscoveryResult.CreateForProviderIdentifier(OPUri, new ProviderEndpointDescription(OPUri, this.v20TypeUris), null, null); + se.IsTypeUriPresent((string)null); + } + + [TestMethod, ExpectedException(typeof(ArgumentException))] + public void IsTypeUriPresentEmptyString() { + var se = IdentifierDiscoveryResult.CreateForProviderIdentifier(OPUri, new ProviderEndpointDescription(OPUri, this.v20TypeUris), null, null); + se.IsTypeUriPresent(string.Empty); + } + + [TestMethod, ExpectedException(typeof(ArgumentNullException))] + public void IsExtensionSupportedNullExtension() { + var se = IdentifierDiscoveryResult.CreateForProviderIdentifier(OPUri, new ProviderEndpointDescription(OPUri, this.v20TypeUris), null, null); + se.IsExtensionSupported((IOpenIdMessageExtension)null); + } + + [TestMethod] + public void IsExtensionSupported() { + var se = IdentifierDiscoveryResult.CreateForProviderIdentifier(OPUri, new ProviderEndpointDescription(OPUri, this.v20TypeUris), null, null); + Assert.IsFalse(se.IsExtensionSupported<ClaimsRequest>()); + Assert.IsFalse(se.IsExtensionSupported(new ClaimsRequest())); + Assert.IsFalse(se.IsTypeUriPresent("http://someextension/typeuri")); + + se = IdentifierDiscoveryResult.CreateForProviderIdentifier( + OPUri, + new ProviderEndpointDescription(OPUri, new[] { Protocol.V20.ClaimedIdentifierServiceTypeURI, "http://someextension", Constants.sreg_ns }), + null, + null); + Assert.IsTrue(se.IsExtensionSupported<ClaimsRequest>()); + Assert.IsTrue(se.IsExtensionSupported(new ClaimsRequest())); + Assert.IsTrue(se.IsTypeUriPresent("http://someextension")); + } + } +} diff --git a/src/DotNetOpenAuth.Test/OpenId/RelyingParty/OpenIdRelyingPartyTests.cs b/src/DotNetOpenAuth.Test/OpenId/RelyingParty/OpenIdRelyingPartyTests.cs index f6a57e7..7f0eb81 100644 --- a/src/DotNetOpenAuth.Test/OpenId/RelyingParty/OpenIdRelyingPartyTests.cs +++ b/src/DotNetOpenAuth.Test/OpenId/RelyingParty/OpenIdRelyingPartyTests.cs @@ -23,7 +23,7 @@ namespace DotNetOpenAuth.Test.OpenId.RelyingParty { [TestMethod] public void CreateRequestDumbMode() { - var rp = new OpenIdRelyingParty(null); + var rp = this.CreateRelyingParty(true); Identifier id = this.GetMockIdentifier(ProtocolVersion.V20); var authReq = rp.CreateRequest(id, RPRealmUri, RPUri); CheckIdRequest requestMessage = (CheckIdRequest)authReq.RedirectingResponse.OriginalMessage; diff --git a/src/DotNetOpenAuth.Test/OpenId/RelyingParty/PositiveAuthenticationResponseTests.cs b/src/DotNetOpenAuth.Test/OpenId/RelyingParty/PositiveAuthenticationResponseTests.cs index 701bcae..f79cb68 100644 --- a/src/DotNetOpenAuth.Test/OpenId/RelyingParty/PositiveAuthenticationResponseTests.cs +++ b/src/DotNetOpenAuth.Test/OpenId/RelyingParty/PositiveAuthenticationResponseTests.cs @@ -46,6 +46,18 @@ namespace DotNetOpenAuth.Test.OpenId.RelyingParty { } /// <summary> + /// Verifies that discovery verification of a positive assertion can match a dual identifier. + /// </summary> + [TestMethod] + public void DualIdentifierMatchesInAssertionVerification() { + PositiveAssertionResponse assertion = this.GetPositiveAssertion(); + ClaimsResponse extension = new ClaimsResponse(); + assertion.Extensions.Add(extension); + var rp = CreateRelyingParty(); + new PositiveAuthenticationResponse(assertion, rp); // this will throw if it fails to find a match + } + + /// <summary> /// Verifies that the RP rejects signed solicited assertions by an OP that /// makes up a claimed Id that was not part of the original request, and /// that the OP has no authority to assert positively regarding. @@ -95,9 +107,13 @@ namespace DotNetOpenAuth.Test.OpenId.RelyingParty { } private PositiveAssertionResponse GetPositiveAssertion() { + return this.GetPositiveAssertion(false); + } + + private PositiveAssertionResponse GetPositiveAssertion(bool dualIdentifier) { Protocol protocol = Protocol.Default; PositiveAssertionResponse assertion = new PositiveAssertionResponse(protocol.Version, this.returnTo); - assertion.ClaimedIdentifier = this.GetMockIdentifier(protocol.ProtocolVersion, false); + assertion.ClaimedIdentifier = dualIdentifier ? this.GetMockDualIdentifier() : this.GetMockIdentifier(protocol.ProtocolVersion, false); assertion.LocalIdentifier = OPLocalIdentifiers[0]; assertion.ReturnTo = this.returnTo; assertion.ProviderEndpoint = OPUri; diff --git a/src/DotNetOpenAuth.Test/OpenId/RelyingParty/ServiceEndpointTests.cs b/src/DotNetOpenAuth.Test/OpenId/RelyingParty/ServiceEndpointTests.cs deleted file mode 100644 index ff15aa3..0000000 --- a/src/DotNetOpenAuth.Test/OpenId/RelyingParty/ServiceEndpointTests.cs +++ /dev/null @@ -1,195 +0,0 @@ -//----------------------------------------------------------------------- -// <copyright file="ServiceEndpointTests.cs" company="Andrew Arnott"> -// Copyright (c) Andrew Arnott. All rights reserved. -// </copyright> -//----------------------------------------------------------------------- - -namespace DotNetOpenAuth.Test.OpenId.RelyingParty { - using System; - using System.Collections.Generic; - using System.Diagnostics; - using System.IO; - using System.Text; - using DotNetOpenAuth.Messaging; - using DotNetOpenAuth.OpenId; - using DotNetOpenAuth.OpenId.Extensions.SimpleRegistration; - using DotNetOpenAuth.OpenId.Messages; - using DotNetOpenAuth.OpenId.RelyingParty; - using DotNetOpenAuth.Test.Messaging; - using Microsoft.VisualStudio.TestTools.UnitTesting; - - [TestClass] - public class ServiceEndpointTests : OpenIdTestBase { - private UriIdentifier claimedId = new UriIdentifier("http://claimedid.justatest.com"); - private XriIdentifier claimedXri = new XriIdentifier("=!9B72.7DD1.50A9.5CCD"); - private XriIdentifier userSuppliedXri = new XriIdentifier("=Arnot"); - private Uri providerEndpoint = new Uri("http://someprovider.com"); - private Identifier localId = "http://localid.someprovider.com"; - private string[] v20TypeUris = { Protocol.V20.ClaimedIdentifierServiceTypeURI }; - private string[] v11TypeUris = { Protocol.V11.ClaimedIdentifierServiceTypeURI }; - private int servicePriority = 10; - private int uriPriority = 10; - - [TestMethod] - public void Ctor() { - ServiceEndpoint se = ServiceEndpoint.CreateForClaimedIdentifier(this.claimedId, this.localId, new ProviderEndpointDescription(this.providerEndpoint, this.v20TypeUris), this.servicePriority, this.uriPriority); - Assert.AreEqual(this.claimedId, se.ClaimedIdentifier); - Assert.AreSame(this.providerEndpoint, se.ProviderEndpoint); - Assert.AreSame(this.localId, se.ProviderLocalIdentifier); - CollectionAssert<string>.AreEquivalent(this.v20TypeUris, se.ProviderSupportedServiceTypeUris); - Assert.AreEqual(this.servicePriority, ((IXrdsProviderEndpoint)se).ServicePriority); - } - - [TestMethod] - public void CtorImpliedLocalIdentifier() { - ServiceEndpoint se = ServiceEndpoint.CreateForClaimedIdentifier(this.claimedId, null, new ProviderEndpointDescription(this.providerEndpoint, this.v20TypeUris), this.servicePriority, this.uriPriority); - Assert.AreEqual(this.claimedId, se.ClaimedIdentifier); - Assert.AreSame(this.providerEndpoint, se.ProviderEndpoint); - Assert.AreSame(this.claimedId, se.ProviderLocalIdentifier); - CollectionAssert<string>.AreEquivalent(this.v20TypeUris, se.ProviderSupportedServiceTypeUris); - } - - [TestMethod] - public void ProtocolDetection() { - ServiceEndpoint se = ServiceEndpoint.CreateForClaimedIdentifier(this.claimedId, this.localId, new ProviderEndpointDescription(this.providerEndpoint, this.v20TypeUris), this.servicePriority, this.uriPriority); - Assert.AreSame(Protocol.V20, se.Protocol); - se = ServiceEndpoint.CreateForClaimedIdentifier( - this.claimedId, - this.localId, - new ProviderEndpointDescription(this.providerEndpoint, new[] { Protocol.V20.OPIdentifierServiceTypeURI }), - this.servicePriority, - this.uriPriority); - Assert.AreSame(Protocol.V20, se.Protocol); - se = ServiceEndpoint.CreateForClaimedIdentifier(this.claimedId, this.localId, new ProviderEndpointDescription(this.providerEndpoint, this.v11TypeUris), this.servicePriority, this.uriPriority); - Assert.AreSame(Protocol.V11, se.Protocol); - } - - [TestMethod, ExpectedException(typeof(ProtocolException))] - public void ProtocolDetectionWithoutClues() { - ServiceEndpoint se = ServiceEndpoint.CreateForClaimedIdentifier( - this.claimedId, - this.localId, - new ProviderEndpointDescription(this.providerEndpoint, new[] { Protocol.V20.HtmlDiscoveryLocalIdKey }), // random type URI irrelevant to detection - this.servicePriority, - this.uriPriority); - } - - [TestMethod] - public void SerializationWithUri() { - ServiceEndpoint se = ServiceEndpoint.CreateForClaimedIdentifier(this.claimedId, this.localId, new ProviderEndpointDescription(this.providerEndpoint, this.v20TypeUris), this.servicePriority, this.uriPriority); - StringBuilder sb = new StringBuilder(); - using (StringWriter sw = new StringWriter(sb)) { - se.Serialize(sw); - } - using (StringReader sr = new StringReader(sb.ToString())) { - ServiceEndpoint se2 = ServiceEndpoint.Deserialize(sr); - Assert.AreEqual(se, se2); - Assert.AreEqual(se.Protocol.Version, se2.Protocol.Version, "Particularly interested in this, since type URIs are not serialized but version info is."); - Assert.AreEqual(se.UserSuppliedIdentifier, se2.UserSuppliedIdentifier); - Assert.AreEqual(se.FriendlyIdentifierForDisplay, se2.FriendlyIdentifierForDisplay); - } - } - - [TestMethod] - public void SerializationWithXri() { - ServiceEndpoint se = ServiceEndpoint.CreateForClaimedIdentifier(this.claimedXri, this.userSuppliedXri, this.localId, new ProviderEndpointDescription(this.providerEndpoint, this.v20TypeUris), this.servicePriority, this.uriPriority); - StringBuilder sb = new StringBuilder(); - using (StringWriter sw = new StringWriter(sb)) { - se.Serialize(sw); - } - using (StringReader sr = new StringReader(sb.ToString())) { - ServiceEndpoint se2 = ServiceEndpoint.Deserialize(sr); - Assert.AreEqual(se, se2); - Assert.AreEqual(se.Protocol.Version, se2.Protocol.Version, "Particularly interested in this, since type URIs are not serialized but version info is."); - Assert.AreEqual(se.UserSuppliedIdentifier, se2.UserSuppliedIdentifier); - Assert.AreEqual(se.FriendlyIdentifierForDisplay, se2.FriendlyIdentifierForDisplay); - } - } - - [TestMethod] - public void EqualsTests() { - ServiceEndpoint se = ServiceEndpoint.CreateForClaimedIdentifier(this.claimedId, this.localId, new ProviderEndpointDescription(this.providerEndpoint, this.v20TypeUris), this.servicePriority, this.uriPriority); - ServiceEndpoint se2 = ServiceEndpoint.CreateForClaimedIdentifier(this.claimedId, this.localId, new ProviderEndpointDescription(this.providerEndpoint, this.v20TypeUris), (int?)null, (int?)null); - Assert.AreEqual(se2, se); - Assert.AreNotEqual(se, null); - Assert.AreNotEqual(null, se); - - ServiceEndpoint se3 = ServiceEndpoint.CreateForClaimedIdentifier(new UriIdentifier(this.claimedId + "a"), this.localId, new ProviderEndpointDescription(this.providerEndpoint, this.v20TypeUris), this.servicePriority, this.uriPriority); - Assert.AreNotEqual(se, se3); - se3 = ServiceEndpoint.CreateForClaimedIdentifier(this.claimedId, this.localId, new ProviderEndpointDescription(new Uri(this.providerEndpoint.AbsoluteUri + "a"), this.v20TypeUris), this.servicePriority, this.uriPriority); - Assert.AreNotEqual(se, se3); - se3 = ServiceEndpoint.CreateForClaimedIdentifier(this.claimedId, this.localId + "a", new ProviderEndpointDescription(this.providerEndpoint, this.v20TypeUris), this.servicePriority, this.uriPriority); - Assert.AreNotEqual(se, se3); - se3 = ServiceEndpoint.CreateForClaimedIdentifier(this.claimedId, this.localId, new ProviderEndpointDescription(this.providerEndpoint, this.v11TypeUris), this.servicePriority, this.uriPriority); - Assert.AreNotEqual(se, se3); - - // make sure that Collection<T>.Contains works as desired. - List<ServiceEndpoint> list = new List<ServiceEndpoint>(); - list.Add(se); - Assert.IsTrue(list.Contains(se2)); - } - - [TestMethod] - public void FriendlyIdentifierForDisplay() { - Uri providerEndpoint = new Uri("http://someprovider"); - Identifier localId = "someuser"; - string[] serviceTypeUris = new string[] { - Protocol.V20.ClaimedIdentifierServiceTypeURI, - }; - ServiceEndpoint se; - - // strip of protocol, port, query and fragment - se = ServiceEndpoint.CreateForClaimedIdentifier( - "http://someprovider.somedomain.com:79/someuser?query#frag", - localId, - new ProviderEndpointDescription(providerEndpoint, serviceTypeUris), - null, - null); - Assert.AreEqual("someprovider.somedomain.com/someuser", se.FriendlyIdentifierForDisplay); - - // unescape characters - Uri foreignUri = new Uri("http://server崎/村"); - se = ServiceEndpoint.CreateForClaimedIdentifier(foreignUri, localId, new ProviderEndpointDescription(providerEndpoint, serviceTypeUris), null, null); - Assert.AreEqual("server崎/村", se.FriendlyIdentifierForDisplay); - - // restore user supplied identifier to XRIs - se = ServiceEndpoint.CreateForClaimedIdentifier( - new XriIdentifier("=!9B72.7DD1.50A9.5CCD"), - new XriIdentifier("=Arnott崎村"), - localId, - new ProviderEndpointDescription(providerEndpoint, serviceTypeUris), - null, - null); - Assert.AreEqual("=Arnott崎村", se.FriendlyIdentifierForDisplay); - - // If UserSuppliedIdentifier is the same as the ClaimedIdentifier, don't display it twice... - se = ServiceEndpoint.CreateForClaimedIdentifier( - new XriIdentifier("=!9B72.7DD1.50A9.5CCD"), - new XriIdentifier("=!9B72.7DD1.50A9.5CCD"), - localId, - new ProviderEndpointDescription(providerEndpoint, serviceTypeUris), - null, - null); - Assert.AreEqual("=!9B72.7DD1.50A9.5CCD", se.FriendlyIdentifierForDisplay); - } - - [TestMethod] - public void IsTypeUriPresent() { - ServiceEndpoint se = ServiceEndpoint.CreateForClaimedIdentifier(this.claimedXri, this.userSuppliedXri, this.localId, new ProviderEndpointDescription(this.providerEndpoint, this.v20TypeUris), this.servicePriority, this.uriPriority); - Assert.IsTrue(se.IsTypeUriPresent(Protocol.Default.ClaimedIdentifierServiceTypeURI)); - Assert.IsFalse(se.IsTypeUriPresent("http://someother")); - } - - [TestMethod, ExpectedException(typeof(ArgumentException))] - public void IsTypeUriPresentNull() { - ServiceEndpoint se = ServiceEndpoint.CreateForClaimedIdentifier(this.claimedXri, this.userSuppliedXri, this.localId, new ProviderEndpointDescription(this.providerEndpoint, this.v20TypeUris), this.servicePriority, this.uriPriority); - se.IsTypeUriPresent(null); - } - - [TestMethod, ExpectedException(typeof(ArgumentException))] - public void IsTypeUriPresentEmpty() { - ServiceEndpoint se = ServiceEndpoint.CreateForClaimedIdentifier(this.claimedXri, this.userSuppliedXri, this.localId, new ProviderEndpointDescription(this.providerEndpoint, this.v20TypeUris), this.servicePriority, this.uriPriority); - se.IsTypeUriPresent(string.Empty); - } - } -} diff --git a/src/DotNetOpenAuth.Test/OpenId/UriIdentifierTests.cs b/src/DotNetOpenAuth.Test/OpenId/UriIdentifierTests.cs index 5a5182f..d504cdf 100644 --- a/src/DotNetOpenAuth.Test/OpenId/UriIdentifierTests.cs +++ b/src/DotNetOpenAuth.Test/OpenId/UriIdentifierTests.cs @@ -141,62 +141,6 @@ namespace DotNetOpenAuth.Test.OpenId { } [TestMethod] - public void HtmlDiscover_11() { - 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, "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", "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, "http://a/b"); - } - - [TestMethod] - public void XrdsDiscoveryFromHttpHeader() { - 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, "http://a/b", headers); - } - - [TestMethod] - public void XrdsDirectDiscovery_10() { - this.FailDiscoverXrds("xrds-irrelevant"); - 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, "http://a/b"); - this.DiscoverXrds("xrds2010a", ProtocolVersion.V20, null, "http://a/b"); - this.DiscoverXrds("xrds2010b", ProtocolVersion.V20, null, "http://a/b"); - } - - [TestMethod] public void NormalizeCase() { // only the host name can be normalized in casing safely. Identifier id = "http://HOST:80/PaTH?KeY=VaLUE#fRag"; @@ -221,21 +165,6 @@ namespace DotNetOpenAuth.Test.OpenId { } [TestMethod] - public void DiscoveryWithRedirects() { - Identifier claimedId = this.GetMockIdentifier(ProtocolVersion.V20, false); - - // Add a couple of chained redirect pages that lead to the claimedId. - Uri userSuppliedUri = new Uri("https://localhost/someSecurePage"); - Uri insecureMidpointUri = new Uri("http://localhost/insecureStop"); - this.MockResponder.RegisterMockRedirect(userSuppliedUri, insecureMidpointUri); - this.MockResponder.RegisterMockRedirect(insecureMidpointUri, new Uri(claimedId.ToString())); - - // don't require secure SSL discovery for this test. - Identifier userSuppliedIdentifier = new UriIdentifier(userSuppliedUri, false); - Assert.AreEqual(1, userSuppliedIdentifier.Discover(this.RequestHandler).Count()); - } - - [TestMethod] public void TryRequireSslAdjustsIdentifier() { Identifier secureId; // Try Parse and ctor without explicit scheme @@ -256,180 +185,13 @@ namespace DotNetOpenAuth.Test.OpenId { Assert.IsFalse(id.TryRequireSsl(out secureId)); Assert.IsTrue(secureId.IsDiscoverySecureEndToEnd, "Although the TryRequireSsl failed, the created identifier should retain the Ssl status."); Assert.AreEqual("http://www.yahoo.com/", secureId.ToString()); - Assert.AreEqual(0, secureId.Discover(this.RequestHandler).Count(), "Since TryRequireSsl failed, the created Identifier should never discover anything."); + Assert.AreEqual(0, Discover(secureId).Count(), "Since TryRequireSsl failed, the created Identifier should never discover anything."); id = new UriIdentifier("http://www.yahoo.com"); Assert.IsFalse(id.TryRequireSsl(out secureId)); Assert.IsTrue(secureId.IsDiscoverySecureEndToEnd); Assert.AreEqual("http://www.yahoo.com/", secureId.ToString()); - Assert.AreEqual(0, secureId.Discover(this.RequestHandler).Count()); - } - - [TestMethod] - public void DiscoverRequireSslWithSecureRedirects() { - Identifier claimedId = this.GetMockIdentifier(ProtocolVersion.V20, true); - - // Add a couple of chained redirect pages that lead to the claimedId. - // All redirects should be secure. - Uri userSuppliedUri = new Uri("https://localhost/someSecurePage"); - Uri secureMidpointUri = new Uri("https://localhost/secureStop"); - this.MockResponder.RegisterMockRedirect(userSuppliedUri, secureMidpointUri); - this.MockResponder.RegisterMockRedirect(secureMidpointUri, new Uri(claimedId.ToString())); - - Identifier userSuppliedIdentifier = new UriIdentifier(userSuppliedUri, true); - Assert.AreEqual(1, userSuppliedIdentifier.Discover(this.RequestHandler).Count()); - } - - [TestMethod, ExpectedException(typeof(ProtocolException))] - public void DiscoverRequireSslWithInsecureRedirect() { - Identifier claimedId = this.GetMockIdentifier(ProtocolVersion.V20, true); - - // Add a couple of chained redirect pages that lead to the claimedId. - // Include an insecure HTTP jump in those redirects to verify that - // the ultimate endpoint is never found as a result of high security profile. - Uri userSuppliedUri = new Uri("https://localhost/someSecurePage"); - Uri insecureMidpointUri = new Uri("http://localhost/insecureStop"); - this.MockResponder.RegisterMockRedirect(userSuppliedUri, insecureMidpointUri); - this.MockResponder.RegisterMockRedirect(insecureMidpointUri, new Uri(claimedId.ToString())); - - Identifier userSuppliedIdentifier = new UriIdentifier(userSuppliedUri, true); - userSuppliedIdentifier.Discover(this.RequestHandler); - } - - [TestMethod] - public void DiscoveryRequireSslWithInsecureXrdsInSecureHtmlHead() { - var insecureXrdsSource = this.GetMockIdentifier(ProtocolVersion.V20, false); - Uri secureClaimedUri = new Uri("https://localhost/secureId"); - - string html = string.Format("<html><head><meta http-equiv='X-XRDS-Location' content='{0}'/></head><body></body></html>", insecureXrdsSource); - this.MockResponder.RegisterMockResponse(secureClaimedUri, "text/html", html); - - Identifier userSuppliedIdentifier = new UriIdentifier(secureClaimedUri, true); - Assert.AreEqual(0, userSuppliedIdentifier.Discover(this.RequestHandler).Count()); - } - - [TestMethod] - public void DiscoveryRequireSslWithInsecureXrdsInSecureHttpHeader() { - var insecureXrdsSource = this.GetMockIdentifier(ProtocolVersion.V20, false); - - string html = "<html><head></head><body></body></html>"; - WebHeaderCollection headers = new WebHeaderCollection { - { "X-XRDS-Location", insecureXrdsSource } - }; - this.MockResponder.RegisterMockResponse(VanityUriSsl, VanityUriSsl, "text/html", headers, html); - - Identifier userSuppliedIdentifier = new UriIdentifier(VanityUriSsl, true); - Assert.AreEqual(0, userSuppliedIdentifier.Discover(this.RequestHandler).Count()); - } - - [TestMethod] - public void DiscoveryRequireSslWithInsecureXrdsButSecureLinkTags() { - var insecureXrdsSource = this.GetMockIdentifier(ProtocolVersion.V20, false); - string html = string.Format( - @" - <html><head> - <meta http-equiv='X-XRDS-Location' content='{0}'/> <!-- this one will be insecure and ignored --> - <link rel='openid2.provider' href='{1}' /> - <link rel='openid2.local_id' href='{2}' /> - </head><body></body></html>", - HttpUtility.HtmlEncode(insecureXrdsSource), - HttpUtility.HtmlEncode(OPUriSsl.AbsoluteUri), - HttpUtility.HtmlEncode(OPLocalIdentifiersSsl[1].AbsoluteUri)); - this.MockResponder.RegisterMockResponse(VanityUriSsl, "text/html", html); - - Identifier userSuppliedIdentifier = new UriIdentifier(VanityUriSsl, true); - - // We verify that the XRDS was ignored and the LINK tags were used - // because the XRDS OP-LocalIdentifier uses different local identifiers. - Assert.AreEqual(OPLocalIdentifiersSsl[1], userSuppliedIdentifier.Discover(this.RequestHandler).Single().ProviderLocalIdentifier); - } - - [TestMethod] - public void DiscoveryRequiresSslIgnoresInsecureEndpointsInXrds() { - var insecureEndpoint = GetServiceEndpoint(0, ProtocolVersion.V20, 10, false); - var secureEndpoint = GetServiceEndpoint(1, ProtocolVersion.V20, 20, true); - UriIdentifier secureClaimedId = new UriIdentifier(VanityUriSsl, true); - this.MockResponder.RegisterMockXrdsResponse(secureClaimedId, new ServiceEndpoint[] { insecureEndpoint, secureEndpoint }); - Assert.AreEqual(secureEndpoint.ProviderLocalIdentifier, secureClaimedId.Discover(this.RequestHandler).Single().ProviderLocalIdentifier); - } - - 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, 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); - UriIdentifier userSuppliedIdentifier = new Uri(baseUrl, "Discovery/htmldiscovery/redirect.aspx?target=" + url); - if (expectedLocalId == null) { - expectedLocalId = claimedId; - } - Identifier idToDiscover = useRedirect ? userSuppliedIdentifier : claimedId; - - string contentType; - if (url.EndsWith("html")) { - contentType = "text/html"; - } else if (url.EndsWith("xml")) { - contentType = "application/xrds+xml"; - } else { - throw new InvalidOperationException(); - } - this.MockResponder.RegisterMockResponse(new Uri(idToDiscover), claimedId, contentType, headers ?? new WebHeaderCollection(), LoadEmbeddedFile(url)); - - ServiceEndpoint expected = ServiceEndpoint.CreateForClaimedIdentifier( - claimedId, - expectedLocalId, - new ProviderEndpointDescription(new Uri(providerEndpoint), new string[] { protocol.ClaimedIdentifierServiceTypeURI }), // services aren'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."); - - // 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<ClaimsRequest>()); - } - - 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, string providerEndpoint, WebHeaderCollection headers) { - if (!page.Contains(".")) { - page += ".xml"; - } - 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, string providerEndpoint, bool useRedirect) { - this.Discover("/Discovery/htmldiscovery/" + page, version, expectedLocalId, providerEndpoint, false, useRedirect); - } - - private void DiscoverHtml(string scenario, ProtocolVersion version, Identifier expectedLocalId, string providerEndpoint) { - string page = scenario + ".html"; - this.DiscoverHtml(page, version, expectedLocalId, providerEndpoint, false); - this.DiscoverHtml(page, version, expectedLocalId, providerEndpoint, true); - } - - private void FailDiscover(string url) { - UriIdentifier userSuppliedId = new Uri(new Uri("http://localhost"), url); - - this.MockResponder.RegisterMockResponse(new Uri(userSuppliedId), userSuppliedId, "text/html", LoadEmbeddedFile(url)); - - Assert.AreEqual(0, userSuppliedId.Discover(this.RequestHandler).Count()); // ... but that no endpoint info is discoverable - } - - private void FailDiscoverHtml(string scenario) { - this.FailDiscover("/Discovery/htmldiscovery/" + scenario + ".html"); - } - - private void FailDiscoverXrds(string scenario) { - this.FailDiscover("/Discovery/xrdsdiscovery/" + scenario + ".xml"); + Assert.AreEqual(0, Discover(secureId).Count()); } } } diff --git a/src/DotNetOpenAuth.Test/OpenId/XriIdentifierTests.cs b/src/DotNetOpenAuth.Test/OpenId/XriIdentifierTests.cs index 46427bb..d5a51cf 100644 --- a/src/DotNetOpenAuth.Test/OpenId/XriIdentifierTests.cs +++ b/src/DotNetOpenAuth.Test/OpenId/XriIdentifierTests.cs @@ -88,386 +88,10 @@ namespace DotNetOpenAuth.Test.OpenId { Assert.AreEqual(this.goodXri, new XriIdentifier(this.goodXri)); } - [TestMethod] - public void Discover() { - string xrds = @"<?xml version='1.0' encoding='UTF-8'?> -<XRD version='2.0' xmlns='xri://$xrd*($v*2.0)'> - <Query>*Arnott</Query> - <Status ceid='off' cid='verified' code='100'/> - <Expires>2008-07-14T02:03:24.000Z</Expires> - <ProviderID>xri://=</ProviderID> - <LocalID>!9b72.7dd1.50a9.5ccd</LocalID> - <CanonicalID>=!9B72.7DD1.50A9.5CCD</CanonicalID> - - <Service priority='10'> - <ProviderID>xri://!!1008</ProviderID> - <Type select='true'>xri://+i-service*(+contact)*($v*1.0)</Type> - <Type match='default' select='false'/> - <Path select='true'>(+contact)</Path> - <Path match='null' select='false'/> - <URI append='qxri' priority='1'>http://1id.com/contact/</URI> - - </Service> - <Service priority='10'> - <ProviderID>xri://!!1008</ProviderID> - <Type select='true'>xri://+i-service*(+forwarding)*($v*1.0)</Type> - <Type match='null' select='false'/> - <URI append='qxri' priority='1'>http://1id.com/</URI> - </Service> - - <Service priority='10'> - <ProviderID>xri://!!1008</ProviderID> - <Type select='true'>http://openid.net/signon/1.0</Type> - <URI append='none' priority='10'>http://1id.com/sso</URI> - </Service> -</XRD>"; - Dictionary<string, string> mocks = new Dictionary<string, string> { - { "https://xri.net/=Arnott?_xrd_r=application/xrd%2Bxml;sep=false", xrds }, - { "https://xri.net/=!9B72.7DD1.50A9.5CCD?_xrd_r=application/xrd%2Bxml;sep=false", xrds }, - }; - this.MockResponder.RegisterMockXrdsResponses(mocks); - - string expectedCanonicalId = "=!9B72.7DD1.50A9.5CCD"; - ServiceEndpoint se = this.VerifyCanonicalId("=Arnott", expectedCanonicalId); - Assert.AreEqual(Protocol.V10, se.Protocol); - Assert.AreEqual("http://1id.com/sso", se.ProviderEndpoint.ToString()); - Assert.AreEqual(se.ClaimedIdentifier, se.ProviderLocalIdentifier); - Assert.AreEqual("=Arnott", se.FriendlyIdentifierForDisplay); - } - - [TestMethod] - public void DiscoverCommunityInameCanonicalIDs() { - string llliResponse = @"<?xml version='1.0' encoding='UTF-8'?> -<XRD version='2.0' xmlns='xri://$xrd*($v*2.0)'> - <Query>*llli</Query> - <Status ceid='off' cid='verified' code='100'/> - <Expires>2008-07-14T02:21:06.000Z</Expires> - <ProviderID>xri://@</ProviderID> - <LocalID>!72cd.a072.157e.a9c6</LocalID> - <CanonicalID>@!72CD.A072.157E.A9C6</CanonicalID> - <Service priority='10'> - <ProviderID>xri://!!1003!103</ProviderID> - <Type select='true'>http://openid.net/signon/1.0</Type> - <URI append='none' priority='1'>https://login.llli.org/server/</URI> - </Service> - <Service priority='1'> - <ProviderID>xri://!!1003!103</ProviderID> - <Type match='null' select='false'/> - <Type select='true'>xri://+i-service*(+forwarding)*($v*1.0)</Type> - <Path match='default'/> - <Path>(+index)</Path> - <URI append='qxri' priority='1'>http://linksafe-forward.ezibroker.net/forwarding/</URI> - </Service> - <Service priority='10'> - <ProviderID>xri://!!1003!103</ProviderID> - <Type select='true'>xri://$res*auth*($v*2.0)</Type> - <MediaType>application/xrds+xml;trust=none</MediaType> - <URI priority='10'>http://resolve.ezibroker.net/resolve/@llli/</URI> - </Service> - <Service priority='10'> - <ProviderID>xri://!!1003!103</ProviderID> - <Type select='true'>xri://+i-service*(+contact)*($v*1.0)</Type> - <Type match='null'/> - <Path select='true'>(+contact)</Path> - <Path match='null'/> - <URI append='authority' priority='1'>http://linksafe-contact.ezibroker.net/contact/</URI> - </Service> -</XRD> -"; - string llliAreaResponse = @"<?xml version='1.0' encoding='UTF-8'?> -<XRD xmlns='xri://$xrd*($v*2.0)'> - <Query>*area</Query> - <Status cid='verified' code='100'>SUCCESS</Status> - <ServerStatus code='100'>SUCCESS</ServerStatus> - <Expires>2008-07-15T01:21:07.000Z</Expires> - <ProviderID>xri://!!1003</ProviderID> - <LocalID>0000.0000.3B9A.CA0C</LocalID> - <CanonicalID>@!72CD.A072.157E.A9C6!0000.0000.3B9A.CA0C</CanonicalID> - <Service> - <ProviderID>xri://!!1003!103</ProviderID> - <Type select='true'>http://openid.net/signon/1.0</Type> - <URI append='none' priority='1'>https://login.llli.org/server/</URI> - </Service> - <Service> - <ProviderID>xri://!!1003!103</ProviderID> - <Type select='true'>xri://+i-service*(+contact)*($v*1.0)</Type> - <Type match='null'/> - <Path select='true'>(+contact)</Path> - <Path match='null'/> - <URI append='authority' priority='1'>http://linksafe-contact.ezibroker.net/contact/</URI> - </Service> - <Service priority='1'> - <ProviderID>xri://!!1003!103</ProviderID> - <Type select='true'>xri://+i-service*(+forwarding)*($v*1.0)</Type> - <Type match='null' select='false'/> - <Path>(+index)</Path> - <Path match='default'/> - <URI append='qxri' priority='1'>http://linksafe-forward.ezibroker.net/forwarding/</URI> - </Service> - <Service> - <ProviderID>xri://!!1003!103</ProviderID> - <Type select='true'>xri://$res*auth*($v*2.0)</Type> - <MediaType>application/xrds+xml;trust=none</MediaType> - <URI>http://resolve.ezibroker.net/resolve/@llli*area/</URI> - </Service> -</XRD>"; - string llliAreaCanadaUnattachedResponse = @"<?xml version='1.0' encoding='UTF-8'?> -<XRD xmlns='xri://$xrd*($v*2.0)'> - <Query>*canada.unattached</Query> - <Status cid='verified' code='100'>SUCCESS</Status> - <ServerStatus code='100'>SUCCESS</ServerStatus> - <Expires>2008-07-15T01:21:08.000Z</Expires> - <ProviderID>xri://!!1003</ProviderID> - <LocalID>0000.0000.3B9A.CA41</LocalID> - <CanonicalID>@!72CD.A072.157E.A9C6!0000.0000.3B9A.CA0C!0000.0000.3B9A.CA41</CanonicalID> - <Service> - <ProviderID>xri://!!1003!103</ProviderID> - <Type select='true'>http://openid.net/signon/1.0</Type> - <URI append='none' priority='1'>https://login.llli.org/server/</URI> - </Service> - <Service> - <ProviderID>xri://!!1003!103</ProviderID> - <Type select='true'>xri://+i-service*(+contact)*($v*1.0)</Type> - <Type match='null'/> - <Path select='true'>(+contact)</Path> - <Path match='null'/> - <URI append='authority' priority='1'>http://linksafe-contact.ezibroker.net/contact/</URI> - </Service> - <Service priority='1'> - <ProviderID>xri://!!1003!103</ProviderID> - <Type select='true'>xri://+i-service*(+forwarding)*($v*1.0)</Type> - <Type match='null' select='false'/> - <Path>(+index)</Path> - <Path match='default'/> - <URI append='qxri' priority='1'>http://linksafe-forward.ezibroker.net/forwarding/</URI> - </Service> - <Service> - <ProviderID>xri://!!1003!103</ProviderID> - <Type select='true'>xri://$res*auth*($v*2.0)</Type> - <MediaType>application/xrds+xml;trust=none</MediaType> - <URI>http://resolve.ezibroker.net/resolve/@llli*area*canada.unattached/</URI> - </Service> -</XRD>"; - string llliAreaCanadaUnattachedAdaResponse = @"<?xml version='1.0' encoding='UTF-8'?> -<XRD xmlns='xri://$xrd*($v*2.0)'> - <Query>*ada</Query> - <Status cid='verified' code='100'>SUCCESS</Status> - <ServerStatus code='100'>SUCCESS</ServerStatus> - <Expires>2008-07-15T01:21:10.000Z</Expires> - <ProviderID>xri://!!1003</ProviderID> - <LocalID>0000.0000.3B9A.CA01</LocalID> - <CanonicalID>@!72CD.A072.157E.A9C6!0000.0000.3B9A.CA0C!0000.0000.3B9A.CA41!0000.0000.3B9A.CA01</CanonicalID> - <Service> - <ProviderID>xri://!!1003!103</ProviderID> - <Type select='true'>http://openid.net/signon/1.0</Type> - <URI append='none' priority='1'>https://login.llli.org/server/</URI> - </Service> - <Service> - <ProviderID>xri://!!1003!103</ProviderID> - <Type select='true'>xri://+i-service*(+contact)*($v*1.0)</Type> - <Type match='null'/> - <Path select='true'>(+contact)</Path> - <Path match='null'/> - <URI append='authority' priority='1'>http://linksafe-contact.ezibroker.net/contact/</URI> - </Service> - <Service priority='1'> - <ProviderID>xri://!!1003!103</ProviderID> - <Type select='true'>xri://+i-service*(+forwarding)*($v*1.0)</Type> - <Type match='null' select='false'/> - <Path>(+index)</Path> - <Path match='default'/> - <URI append='qxri' priority='1'>http://linksafe-forward.ezibroker.net/forwarding/</URI> - </Service> -</XRD>"; - string webResponse = @"<?xml version='1.0' encoding='UTF-8'?> -<XRD version='2.0' xmlns='xri://$xrd*($v*2.0)'> - <Query>*Web</Query> - <Status ceid='off' cid='verified' code='100'/> - <Expires>2008-07-14T02:21:12.000Z</Expires> - <ProviderID>xri://=</ProviderID> - <LocalID>!91f2.8153.f600.ae24</LocalID> - <CanonicalID>=!91F2.8153.F600.AE24</CanonicalID> - <Service priority='10'> - <Type select='true'>xri://+i-service*(+locator)*($v*1.0)</Type> - <Path select='true'>(+locator)</Path> - <MediaType match='default' select='false'/> - <URI append='qxri'>http://locator.fullxri.com/locator/</URI> - </Service> - <Service priority='10'> - <ProviderID>xri://=web</ProviderID> - <Type select='true'>xri://$res*auth*($v*2.0)</Type> - <Type select='true'>xri://$res*auth*($v*2.0)</Type> - <MediaType select='true'>application/xrds+xml</MediaType> - <URI append='qxri' priority='1'>https://resolve.freexri.com/ns/=web/</URI> - <URI append='qxri' priority='2'>http://resolve.freexri.com/ns/=web/</URI> - </Service> - <Service priority='10'> - <Type select='true'>http://openid.net/signon/1.0</Type> - <Type select='true'>http://specs.openid.net/auth/2.0/signon</Type> - <Path select='true'>(+login)</Path> - <Path match='default' select='false'/> - <MediaType match='default' select='false'/> - <URI append='none' priority='2'>http://authn.fullxri.com/authentication/</URI> - <URI append='none' priority='1'>https://authn.fullxri.com/authentication/</URI> - </Service> - <Service priority='10'> - <Type select='true'>xri://+i-service*(+contact)*($v*1.0)</Type> - <Type match='null' select='false'/> - <Path select='true'>(+contact)</Path> - <Path match='null' select='false'/> - <MediaType match='default' select='false'/> - <URI append='qxri'>http://contact.fullxri.com/contact/</URI> - </Service> - <KeyInfo xmlns='http://www.w3.org/2000/09/xmldsig#'> - <X509Data> - <X509Certificate> -MIIExzCCA6+gAwIBAgIJAM+MlFr0Sth6MA0GCSqGSIb3DQEBBQUAMIGdMR8wHQYD -VQQDExZTdXBlcnZpbGxhaW46IFRoZSBSb290MQswCQYDVQQGEwJVUzERMA8GA1UE -CBMITmV3IFlvcmsxDzANBgNVBAcTBkdvdGhhbTEgMB4GA1UEChMXU3VwZXJ2aWxs -YWluIFVuaXZlcnNpdHkxJzAlBgkqhkiG9w0BCQEWGHBlbmd1aW5Ac3VwZXJ2aWxs -YWluLmVkdTAeFw0wNjA4MTcxOTU5NTNaFw0xMTA4MTYxOTU5NTNaMIGdMR8wHQYD -VQQDExZTdXBlcnZpbGxhaW46IFRoZSBSb290MQswCQYDVQQGEwJVUzERMA8GA1UE -CBMITmV3IFlvcmsxDzANBgNVBAcTBkdvdGhhbTEgMB4GA1UEChMXU3VwZXJ2aWxs -YWluIFVuaXZlcnNpdHkxJzAlBgkqhkiG9w0BCQEWGHBlbmd1aW5Ac3VwZXJ2aWxs -YWluLmVkdTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL6uFqas4dK6 -A2wTZL0viRQNJrPyFnFBDSZGib/2ijhgzed/vvmZIBM9sFpwahcuR5hvyKUe37/c -/RSZXoNDi/eiNOx4qb0l9UB6bd8qvc4V1PnLE7L+ZYcmwrvTKm4x8qXMgEv1wca2 -FPsreHNPdLiTUZ8v0tDTWi3Mgi7y47VTzJaTkcfmO1nL6xAtln5sLdH0PbMM3LAp -T1d3nwI3VdbhqqZ+6+OKEuC8gk5iH4lfrbr6C9bYS6vzIKrotHpZ3N2aIC3NMjJD -PMw/mfCuADfRNlHXgZW+0zyUkwGTMDea8qgsoAMWJGdeTIw8I1I3RhnbgLzdsNQl -b/1ZXx1uJRUCAwEAAaOCAQYwggECMB0GA1UdDgQWBBQe+xSjYTrlfraJARjMxscb -j36jvDCB0gYDVR0jBIHKMIHHgBQe+xSjYTrlfraJARjMxscbj36jvKGBo6SBoDCB -nTEfMB0GA1UEAxMWU3VwZXJ2aWxsYWluOiBUaGUgUm9vdDELMAkGA1UEBhMCVVMx -ETAPBgNVBAgTCE5ldyBZb3JrMQ8wDQYDVQQHEwZHb3RoYW0xIDAeBgNVBAoTF1N1 -cGVydmlsbGFpbiBVbml2ZXJzaXR5MScwJQYJKoZIhvcNAQkBFhhwZW5ndWluQHN1 -cGVydmlsbGFpbi5lZHWCCQDPjJRa9ErYejAMBgNVHRMEBTADAQH/MA0GCSqGSIb3 -DQEBBQUAA4IBAQC4SPBDGYAxfbXd8N5OvG0drM7a5hjXfcCZpiILlPSRpxp79yh7 -I5vVWxBxUfolwbei7PTBVy7CE27SUbSICeqWjcDCfjNjiZk6mLS80rm/TdLrHSyM -+Ujlw9MGcBGaLI+sdziDUMtTQDpeAyQTaGVbh1mx5874Hlo1VXqGYNo0RwR+iLfs -x48VuO6GbWVyxtktkE2ypz1KLWiyI056YynydRvuBCBHeRqGUixPlH9CrmeSCP2S -sfbiKnMOGXjIYbvbsTAMdW2iqg6IWa/fgxhvZoAXChM9bkhisJQc0qD0J5TJQwgr -uEyb50RJ7DWmXctSC0b3eymZ2lSXxAWNOsNy - </X509Certificate> - </X509Data> - </KeyInfo> -</XRD>"; - this.MockResponder.RegisterMockXrdsResponses(new Dictionary<string, string> { - { "https://xri.net/@llli?_xrd_r=application/xrd%2Bxml;sep=false", llliResponse }, - { "https://xri.net/@llli*area?_xrd_r=application/xrd%2Bxml;sep=false", llliAreaResponse }, - { "https://xri.net/@llli*area*canada.unattached?_xrd_r=application/xrd%2Bxml;sep=false", llliAreaCanadaUnattachedResponse }, - { "https://xri.net/@llli*area*canada.unattached*ada?_xrd_r=application/xrd%2Bxml;sep=false", llliAreaCanadaUnattachedAdaResponse }, - { "https://xri.net/=Web?_xrd_r=application/xrd%2Bxml;sep=false", webResponse }, - }); - this.VerifyCanonicalId("@llli", "@!72CD.A072.157E.A9C6"); - this.VerifyCanonicalId("@llli*area", "@!72CD.A072.157E.A9C6!0000.0000.3B9A.CA0C"); - this.VerifyCanonicalId("@llli*area*canada.unattached", "@!72CD.A072.157E.A9C6!0000.0000.3B9A.CA0C!0000.0000.3B9A.CA41"); - this.VerifyCanonicalId("@llli*area*canada.unattached*ada", "@!72CD.A072.157E.A9C6!0000.0000.3B9A.CA0C!0000.0000.3B9A.CA41!0000.0000.3B9A.CA01"); - this.VerifyCanonicalId("=Web", "=!91F2.8153.F600.AE24"); - } - - [TestMethod] - public void DiscoveryCommunityInameDelegateWithoutCanonicalID() { - this.MockResponder.RegisterMockXrdsResponses(new Dictionary<string, string> { - { "https://xri.net/=Web*andrew.arnott?_xrd_r=application/xrd%2Bxml;sep=false", @"<?xml version='1.0' encoding='UTF-8'?> -<XRD xmlns='xri://$xrd*($v*2.0)'> - <Query>*andrew.arnott</Query> - <Status cid='absent' code='100'>Success</Status> - <ServerStatus code='100'>Success</ServerStatus> - <Expires>2008-07-14T03:30:59.722Z</Expires> - <ProviderID>=!91F2.8153.F600.AE24</ProviderID> - <Service> - <Type select='true'>http://openid.net/signon/1.0</Type> - <Path select='true'>(+login)</Path> - <Path match='default'/> - <MediaType match='default'/> - <URI append='none' priority='2'>http://www.myopenid.com/server</URI> - <openid:Delegate xmlns:openid='http://openid.net/xmlns/1.0'>http://blog.nerdbank.net</openid:Delegate> - </Service> - <Service> - <ProviderID>@!7F6F.F50.A4E4.1133</ProviderID> - <Type select='true'>xri://+i-service*(+contact)*($v*1.0)</Type> - <Type match='null'/> - <Path select='true'>(+contact)</Path> - <Path match='null'/> - <MediaType match='default'/> - <URI append='qxri'>http://contact.freexri.com/contact/</URI> - </Service> - <Service> - <ProviderID>@!7F6F.F50.A4E4.1133</ProviderID> - <Type select='true'>xri://+i-service*(+forwarding)*($v*1.0)</Type> - <Path select='true'>(+index)</Path> - <Path match='default'/> - <MediaType match='default'/> - <URI append='qxri'>http://forwarding.freexri.com/forwarding/</URI> - </Service> - <Service> - <ProviderID>@!7F6F.F50.A4E4.1133</ProviderID> - <Type select='true'>http://openid.net/signon/1.0</Type> - <Path select='true'>(+login)</Path> - <Path match='default'/> - <MediaType match='default'/> - <URI append='none' priority='2'>http://authn.freexri.com/authentication/</URI> - <URI append='none' priority='1'>https://authn.freexri.com/authentication/</URI> - </Service> - <ServedBy>OpenXRI</ServedBy> -</XRD>" }, - { "https://xri.net/@id*andrewarnott?_xrd_r=application/xrd%2Bxml;sep=false", @"<?xml version='1.0' encoding='UTF-8'?> -<XRD xmlns='xri://$xrd*($v*2.0)'> - <Query>*andrewarnott</Query> - <Status cid='absent' code='100'>Success</Status> - <ServerStatus code='100'>Success</ServerStatus> - <Expires>2008-07-14T03:31:00.466Z</Expires> - <ProviderID>@!B1E8.C27B.E41C.25C3</ProviderID> - <Service> - <Type select='true'>http://openid.net/signon/1.0</Type> - <Path select='true'>(+login)</Path> - <Path match='default'/> - <MediaType match='default'/> - <URI append='none' priority='2'>http://www.myopenid.com/server</URI> - <openid:Delegate xmlns:openid='http://openid.net/xmlns/1.0'>http://blog.nerdbank.net</openid:Delegate> - </Service> - <Service> - <ProviderID>@!7F6F.F50.A4E4.1133</ProviderID> - <Type select='true'>xri://+i-service*(+contact)*($v*1.0)</Type> - <Type match='null'/> - <Path select='true'>(+contact)</Path> - <Path match='null'/> - <MediaType match='default'/> - <URI append='qxri'>http://contact.freexri.com/contact/</URI> - </Service> - <Service> - <ProviderID>@!7F6F.F50.A4E4.1133</ProviderID> - <Type select='true'>xri://+i-service*(+forwarding)*($v*1.0)</Type> - <Path select='true'>(+index)</Path> - <Path match='default'/> - <MediaType match='default'/> - <URI append='qxri'>http://forwarding.freexri.com/forwarding/</URI> - </Service> - <ServedBy>OpenXRI</ServedBy> -</XRD>" }, - }); - // Consistent with spec section 7.3.2.3, we do not permit - // delegation on XRI discovery when there is no CanonicalID present. - this.VerifyCanonicalId("=Web*andrew.arnott", null); - this.VerifyCanonicalId("@id*andrewarnott", null); - } - [TestMethod, Ignore] // XRI parsing and normalization is not implemented (yet). public void NormalizeCase() { Identifier id = "=!9B72.7dd1.50a9.5ccd"; Assert.AreEqual("=!9B72.7DD1.50A9.5CCD", id.ToString()); } - - private ServiceEndpoint VerifyCanonicalId(Identifier iname, string expectedClaimedIdentifier) { - ServiceEndpoint se = iname.Discover(this.RequestHandler).FirstOrDefault(); - if (expectedClaimedIdentifier != null) { - Assert.IsNotNull(se); - Assert.AreEqual(expectedClaimedIdentifier, se.ClaimedIdentifier.ToString(), "i-name {0} discovery resulted in unexpected CanonicalId", iname); - Assert.IsTrue(se.ProviderSupportedServiceTypeUris.Count > 0); - } else { - Assert.IsNull(se); - } - return se; - } } } |