//----------------------------------------------------------------------- // // Copyright (c) Andrew Arnott. All rights reserved. // //----------------------------------------------------------------------- namespace DotNetOpenAuth.Test.OpenId { using System; using System.Collections.Generic; using System.Linq; using DotNetOpenAuth.OpenId; using DotNetOpenAuth.OpenId.RelyingParty; using Microsoft.VisualStudio.TestTools.UnitTesting; [TestClass] public class XriIdentifierTests : OpenIdTestBase { private string goodXri = "=Andrew*Arnott"; private string badXri = "some\\wacky%^&*()non-XRI"; [TestInitialize] public override void SetUp() { base.SetUp(); } [TestMethod, ExpectedException(typeof(ArgumentException))] public void CtorNull() { new XriIdentifier(null); } [TestMethod, ExpectedException(typeof(ArgumentException))] public void CtorBlank() { new XriIdentifier(string.Empty); } [TestMethod, ExpectedException(typeof(FormatException))] public void CtorBadXri() { new XriIdentifier(this.badXri); } [TestMethod] public void CtorGoodXri() { var xri = new XriIdentifier(this.goodXri); Assert.AreEqual(this.goodXri, xri.OriginalXri); Assert.AreEqual(this.goodXri, xri.CanonicalXri); // assumes 'goodXri' is canonical already Assert.IsFalse(xri.IsDiscoverySecureEndToEnd); } [TestMethod] public void CtorGoodXriSecure() { var xri = new XriIdentifier(this.goodXri, true); Assert.AreEqual(this.goodXri, xri.OriginalXri); Assert.AreEqual(this.goodXri, xri.CanonicalXri); // assumes 'goodXri' is canonical already Assert.IsTrue(xri.IsDiscoverySecureEndToEnd); } [TestMethod] public void IsValid() { Assert.IsTrue(XriIdentifier.IsValidXri(this.goodXri)); Assert.IsFalse(XriIdentifier.IsValidXri(this.badXri)); } /// /// Verifies 2.0 spec section 7.2#1 /// [TestMethod] public void StripXriScheme() { var xri = new XriIdentifier("xri://" + this.goodXri); Assert.AreEqual("xri://" + this.goodXri, xri.OriginalXri); Assert.AreEqual(this.goodXri, xri.CanonicalXri); } [TestMethod] public void TrimFragment() { Identifier xri = new XriIdentifier(this.goodXri); Assert.AreSame(xri, xri.TrimFragment()); } [TestMethod] public void ToStringTest() { Assert.AreEqual(this.goodXri, new XriIdentifier(this.goodXri).ToString()); } [TestMethod] public void EqualsTest() { Assert.AreEqual(new XriIdentifier(this.goodXri), new XriIdentifier(this.goodXri)); Assert.AreNotEqual(new XriIdentifier(this.goodXri), new XriIdentifier(this.goodXri + "a")); Assert.AreNotEqual(null, new XriIdentifier(this.goodXri)); Assert.AreEqual(this.goodXri, new XriIdentifier(this.goodXri)); } [TestMethod] public void Discover() { string xrds = @" *Arnott 2008-07-14T02:03:24.000Z xri://= !9b72.7dd1.50a9.5ccd =!9B72.7DD1.50A9.5CCD xri://!!1008 xri://+i-service*(+contact)*($v*1.0) (+contact) http://1id.com/contact/ xri://!!1008 xri://+i-service*(+forwarding)*($v*1.0) http://1id.com/ xri://!!1008 http://openid.net/signon/1.0 http://1id.com/sso "; Dictionary mocks = new Dictionary { { "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 = @" *llli 2008-07-14T02:21:06.000Z xri://@ !72cd.a072.157e.a9c6 @!72CD.A072.157E.A9C6 xri://!!1003!103 http://openid.net/signon/1.0 https://login.llli.org/server/ xri://!!1003!103 xri://+i-service*(+forwarding)*($v*1.0) (+index) http://linksafe-forward.ezibroker.net/forwarding/ xri://!!1003!103 xri://$res*auth*($v*2.0) application/xrds+xml;trust=none http://resolve.ezibroker.net/resolve/@llli/ xri://!!1003!103 xri://+i-service*(+contact)*($v*1.0) (+contact) http://linksafe-contact.ezibroker.net/contact/ "; string llliAreaResponse = @" *area SUCCESS SUCCESS 2008-07-15T01:21:07.000Z xri://!!1003 0000.0000.3B9A.CA0C @!72CD.A072.157E.A9C6!0000.0000.3B9A.CA0C xri://!!1003!103 http://openid.net/signon/1.0 https://login.llli.org/server/ xri://!!1003!103 xri://+i-service*(+contact)*($v*1.0) (+contact) http://linksafe-contact.ezibroker.net/contact/ xri://!!1003!103 xri://+i-service*(+forwarding)*($v*1.0) (+index) http://linksafe-forward.ezibroker.net/forwarding/ xri://!!1003!103 xri://$res*auth*($v*2.0) application/xrds+xml;trust=none http://resolve.ezibroker.net/resolve/@llli*area/ "; string llliAreaCanadaUnattachedResponse = @" *canada.unattached SUCCESS SUCCESS 2008-07-15T01:21:08.000Z xri://!!1003 0000.0000.3B9A.CA41 @!72CD.A072.157E.A9C6!0000.0000.3B9A.CA0C!0000.0000.3B9A.CA41 xri://!!1003!103 http://openid.net/signon/1.0 https://login.llli.org/server/ xri://!!1003!103 xri://+i-service*(+contact)*($v*1.0) (+contact) http://linksafe-contact.ezibroker.net/contact/ xri://!!1003!103 xri://+i-service*(+forwarding)*($v*1.0) (+index) http://linksafe-forward.ezibroker.net/forwarding/ xri://!!1003!103 xri://$res*auth*($v*2.0) application/xrds+xml;trust=none http://resolve.ezibroker.net/resolve/@llli*area*canada.unattached/ "; string llliAreaCanadaUnattachedAdaResponse = @" *ada SUCCESS SUCCESS 2008-07-15T01:21:10.000Z xri://!!1003 0000.0000.3B9A.CA01 @!72CD.A072.157E.A9C6!0000.0000.3B9A.CA0C!0000.0000.3B9A.CA41!0000.0000.3B9A.CA01 xri://!!1003!103 http://openid.net/signon/1.0 https://login.llli.org/server/ xri://!!1003!103 xri://+i-service*(+contact)*($v*1.0) (+contact) http://linksafe-contact.ezibroker.net/contact/ xri://!!1003!103 xri://+i-service*(+forwarding)*($v*1.0) (+index) http://linksafe-forward.ezibroker.net/forwarding/ "; string webResponse = @" *Web 2008-07-14T02:21:12.000Z xri://= !91f2.8153.f600.ae24 =!91F2.8153.F600.AE24 xri://+i-service*(+locator)*($v*1.0) (+locator) http://locator.fullxri.com/locator/ xri://=web xri://$res*auth*($v*2.0) xri://$res*auth*($v*2.0) application/xrds+xml https://resolve.freexri.com/ns/=web/ http://resolve.freexri.com/ns/=web/ http://openid.net/signon/1.0 http://specs.openid.net/auth/2.0/signon (+login) http://authn.fullxri.com/authentication/ https://authn.fullxri.com/authentication/ xri://+i-service*(+contact)*($v*1.0) (+contact) http://contact.fullxri.com/contact/ 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 "; this.MockResponder.RegisterMockXrdsResponses(new Dictionary { { "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 { { "https://xri.net/=Web*andrew.arnott?_xrd_r=application/xrd%2Bxml;sep=false", @" *andrew.arnott Success Success 2008-07-14T03:30:59.722Z =!91F2.8153.F600.AE24 http://openid.net/signon/1.0 (+login) http://www.myopenid.com/server http://blog.nerdbank.net @!7F6F.F50.A4E4.1133 xri://+i-service*(+contact)*($v*1.0) (+contact) http://contact.freexri.com/contact/ @!7F6F.F50.A4E4.1133 xri://+i-service*(+forwarding)*($v*1.0) (+index) http://forwarding.freexri.com/forwarding/ @!7F6F.F50.A4E4.1133 http://openid.net/signon/1.0 (+login) http://authn.freexri.com/authentication/ https://authn.freexri.com/authentication/ OpenXRI " }, { "https://xri.net/@id*andrewarnott?_xrd_r=application/xrd%2Bxml;sep=false", @" *andrewarnott Success Success 2008-07-14T03:31:00.466Z @!B1E8.C27B.E41C.25C3 http://openid.net/signon/1.0 (+login) http://www.myopenid.com/server http://blog.nerdbank.net @!7F6F.F50.A4E4.1133 xri://+i-service*(+contact)*($v*1.0) (+contact) http://contact.freexri.com/contact/ @!7F6F.F50.A4E4.1133 xri://+i-service*(+forwarding)*($v*1.0) (+index) http://forwarding.freexri.com/forwarding/ OpenXRI " }, }); // 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; } } }