Several hundred StyleCop fixes.
[dotnetoauth.git] / src / DotNetOpenAuth.Test / OpenId / UriIdentifierTests.cs
blob1dfb1739c22093a1674f1f4562ebfe7008634725
1 //-----------------------------------------------------------------------
2 // <copyright file="UriIdentifierTests.cs" company="Andrew Arnott">
3 // Copyright (c) Andrew Arnott. All rights reserved.
4 // </copyright>
5 //-----------------------------------------------------------------------
7 namespace DotNetOpenAuth.Test.OpenId {
8 using System;
9 using System.Linq;
10 using System.Net;
11 using System.Web;
12 using DotNetOpenAuth.Messaging;
13 using DotNetOpenAuth.OpenId;
14 using DotNetOpenAuth.OpenId.RelyingParty;
15 using Microsoft.VisualStudio.TestTools.UnitTesting;
17 [TestClass]
18 public class UriIdentifierTests : OpenIdTestBase {
19 private string goodUri = "http://blog.nerdbank.net/";
20 private string relativeUri = "host/path";
21 private string badUri = "som%-)830w8vf/?.<>,ewackedURI";
23 [TestInitialize]
24 public override void SetUp() {
25 base.SetUp();
28 [TestMethod, ExpectedException(typeof(ArgumentNullException))]
29 public void CtorNullUri() {
30 new UriIdentifier((Uri)null);
33 [TestMethod, ExpectedException(typeof(ArgumentNullException))]
34 public void CtorNullString() {
35 new UriIdentifier((string)null);
38 [TestMethod, ExpectedException(typeof(ArgumentException))]
39 public void CtorBlank() {
40 new UriIdentifier(string.Empty);
43 [TestMethod, ExpectedException(typeof(UriFormatException))]
44 public void CtorBadUri() {
45 new UriIdentifier(this.badUri);
48 [TestMethod]
49 public void CtorGoodUri() {
50 var uri = new UriIdentifier(this.goodUri);
51 Assert.AreEqual(new Uri(this.goodUri), uri.Uri);
52 Assert.IsFalse(uri.SchemeImplicitlyPrepended);
53 Assert.IsFalse(uri.IsDiscoverySecureEndToEnd);
56 [TestMethod]
57 public void CtorStringNoSchemeSecure() {
58 var uri = new UriIdentifier("host/path", true);
59 Assert.AreEqual("https://host/path", uri.Uri.AbsoluteUri);
60 Assert.IsTrue(uri.IsDiscoverySecureEndToEnd);
63 [TestMethod]
64 public void CtorStringHttpsSchemeSecure() {
65 var uri = new UriIdentifier("https://host/path", true);
66 Assert.AreEqual("https://host/path", uri.Uri.AbsoluteUri);
67 Assert.IsTrue(uri.IsDiscoverySecureEndToEnd);
70 [TestMethod, ExpectedException(typeof(ArgumentException))]
71 public void CtorStringHttpSchemeSecure() {
72 new UriIdentifier("http://host/path", true);
75 [TestMethod]
76 public void CtorUriHttpsSchemeSecure() {
77 var uri = new UriIdentifier(new Uri("https://host/path"), true);
78 Assert.AreEqual("https://host/path", uri.Uri.AbsoluteUri);
79 Assert.IsTrue(uri.IsDiscoverySecureEndToEnd);
82 [TestMethod, ExpectedException(typeof(ArgumentException))]
83 public void CtorUriHttpSchemeSecure() {
84 new UriIdentifier(new Uri("http://host/path"), true);
87 /// <summary>
88 /// Verifies that the fragment is not stripped from an Identifier.
89 /// </summary>
90 /// <remarks>
91 /// Although fragments should be stripped from user supplied identifiers,
92 /// they should NOT be stripped from claimed identifiers. So the UriIdentifier
93 /// class, which serves both identifier types, must not do the stripping.
94 /// </remarks>
95 [TestMethod]
96 public void DoesNotStripFragment() {
97 Uri original = new Uri("http://a/b#c");
98 UriIdentifier identifier = new UriIdentifier(original);
99 Assert.AreEqual(original.Fragment, identifier.Uri.Fragment);
102 [TestMethod]
103 public void IsValid() {
104 Assert.IsTrue(UriIdentifier.IsValidUri(this.goodUri));
105 Assert.IsFalse(UriIdentifier.IsValidUri(this.badUri));
106 Assert.IsTrue(UriIdentifier.IsValidUri(relativeUri), "URL lacking http:// prefix should have worked anyway.");
109 [TestMethod]
110 public void TrimFragment() {
111 Identifier noFragment = UriIdentifier.Parse("http://a/b");
112 Identifier fragment = UriIdentifier.Parse("http://a/b#c");
113 Assert.AreSame(noFragment, noFragment.TrimFragment());
114 Assert.AreEqual(noFragment, fragment.TrimFragment());
117 [TestMethod]
118 public void ToStringTest() {
119 Assert.AreEqual(this.goodUri, new UriIdentifier(this.goodUri).ToString());
122 [TestMethod]
123 public void EqualsTest() {
124 Assert.AreEqual(new UriIdentifier(this.goodUri), new UriIdentifier(this.goodUri));
125 // This next test is an interesting side-effect of passing off to Uri.Equals. But it's probably ok.
126 Assert.AreEqual(new UriIdentifier(this.goodUri), new UriIdentifier(this.goodUri + "#frag"));
127 Assert.AreNotEqual(new UriIdentifier(this.goodUri), new UriIdentifier(this.goodUri + "a"));
128 Assert.AreNotEqual(null, new UriIdentifier(this.goodUri));
129 Assert.AreEqual(this.goodUri, new UriIdentifier(this.goodUri));
132 [TestMethod]
133 public void UnicodeTest() {
134 string unicodeUrl = "http://nerdbank.org/opaffirmative/崎村.aspx";
135 Assert.IsTrue(UriIdentifier.IsValidUri(unicodeUrl));
136 Identifier id;
137 Assert.IsTrue(UriIdentifier.TryParse(unicodeUrl, out id));
138 Assert.AreEqual("/opaffirmative/%E5%B4%8E%E6%9D%91.aspx", ((UriIdentifier)id).Uri.AbsolutePath);
139 Assert.AreEqual(Uri.EscapeUriString(unicodeUrl), id.ToString());
142 [TestMethod]
143 public void HtmlDiscover_11() {
144 this.DiscoverHtml("html10prov", ProtocolVersion.V11, null);
145 this.DiscoverHtml("html10both", ProtocolVersion.V11, "http://c/d");
146 this.FailDiscoverHtml("html10del");
149 [TestMethod]
150 public void HtmlDiscover_20() {
151 this.DiscoverHtml("html20prov", ProtocolVersion.V20, null);
152 this.DiscoverHtml("html20both", ProtocolVersion.V20, "http://c/d");
153 this.FailDiscoverHtml("html20del");
154 this.DiscoverHtml("html2010", ProtocolVersion.V20, "http://c/d");
155 this.DiscoverHtml("html1020", ProtocolVersion.V20, "http://c/d");
156 this.DiscoverHtml("html2010combinedA", ProtocolVersion.V20, "http://c/d");
157 this.DiscoverHtml("html2010combinedB", ProtocolVersion.V20, "http://c/d");
158 this.DiscoverHtml("html2010combinedC", ProtocolVersion.V20, "http://c/d");
159 this.FailDiscoverHtml("html20relative");
162 [TestMethod]
163 public void XrdsDiscoveryFromHead() {
164 this.mockResponder.RegisterMockResponse(new Uri("http://localhost/xrds1020.xml"),
165 "application/xrds+xml", TestSupport.LoadEmbeddedFile("/Discovery/xrdsdiscovery/xrds1020.xml"));
166 this.DiscoverXrds("XrdsReferencedInHead.html", ProtocolVersion.V10, null);
169 [TestMethod]
170 public void XrdsDiscoveryFromHttpHeader() {
171 WebHeaderCollection headers = new WebHeaderCollection();
172 headers.Add("X-XRDS-Location", TestSupport.GetFullUrl("http://localhost/xrds1020.xml").AbsoluteUri);
173 this.mockResponder.RegisterMockResponse(new Uri("http://localhost/xrds1020.xml"), "application/xrds+xml", TestSupport.LoadEmbeddedFile("/Discovery/xrdsdiscovery/xrds1020.xml"));
174 this.DiscoverXrds("XrdsReferencedInHttpHeader.html", ProtocolVersion.V10, null, headers);
177 [TestMethod]
178 public void XrdsDirectDiscovery_10() {
179 this.FailDiscoverXrds("xrds-irrelevant");
180 this.DiscoverXrds("xrds10", ProtocolVersion.V10, null);
181 this.DiscoverXrds("xrds11", ProtocolVersion.V11, null);
182 this.DiscoverXrds("xrds1020", ProtocolVersion.V10, null);
185 [TestMethod]
186 public void XrdsDirectDiscovery_20() {
187 this.DiscoverXrds("xrds20", ProtocolVersion.V20, null);
188 this.DiscoverXrds("xrds2010a", ProtocolVersion.V20, null);
189 this.DiscoverXrds("xrds2010b", ProtocolVersion.V20, null);
192 [TestMethod]
193 public void NormalizeCase() {
194 // only the host name can be normalized in casing safely.
195 Identifier id = "http://HOST:80/PaTH?KeY=VaLUE#fRag";
196 Assert.AreEqual("http://host/PaTH?KeY=VaLUE#fRag", id.ToString());
197 // make sure https is preserved, along with port 80, which is NON-default for https
198 id = "https://HOST:80/PaTH?KeY=VaLUE#fRag";
199 Assert.AreEqual("https://host:80/PaTH?KeY=VaLUE#fRag", id.ToString());
202 [TestMethod]
203 public void HttpSchemePrepended() {
204 UriIdentifier id = new UriIdentifier("www.yahoo.com");
205 Assert.AreEqual("http://www.yahoo.com/", id.ToString());
206 Assert.IsTrue(id.SchemeImplicitlyPrepended);
209 ////[TestMethod, Ignore("The spec says http:// must be prepended in this case, but that just creates an invalid URI. Our UntrustedWebRequest will stop disallowed schemes.")]
210 public void CtorDisallowedScheme() {
211 UriIdentifier id = new UriIdentifier(new Uri("ftp://host/path"));
212 Assert.AreEqual("http://ftp://host/path", id.ToString());
213 Assert.IsTrue(id.SchemeImplicitlyPrepended);
216 [TestMethod]
217 public void DiscoveryWithRedirects() {
218 Identifier claimedId = TestSupport.GetMockIdentifier(TestSupport.Scenarios.AutoApproval, this.mockResponder, ProtocolVersion.V20);
220 // Add a couple of chained redirect pages that lead to the claimedId.
221 Uri userSuppliedUri = TestSupport.GetFullUrl("/someSecurePage", null, true);
222 Uri insecureMidpointUri = TestSupport.GetFullUrl("/insecureStop");
223 this.mockResponder.RegisterMockRedirect(userSuppliedUri, insecureMidpointUri);
224 this.mockResponder.RegisterMockRedirect(insecureMidpointUri, new Uri(claimedId.ToString()));
226 // don't require secure SSL discovery for this test.
227 Identifier userSuppliedIdentifier = new UriIdentifier(userSuppliedUri, false);
228 Assert.AreEqual(1, userSuppliedIdentifier.Discover(this.requestHandler).Count());
231 [TestMethod]
232 public void TryRequireSslAdjustsIdentifier() {
233 Identifier secureId;
234 // Try Parse and ctor without explicit scheme
235 var id = Identifier.Parse("www.yahoo.com");
236 Assert.AreEqual("http://www.yahoo.com/", id.ToString());
237 Assert.IsTrue(id.TryRequireSsl(out secureId));
238 Assert.IsTrue(secureId.IsDiscoverySecureEndToEnd);
239 Assert.AreEqual("https://www.yahoo.com/", secureId.ToString());
241 id = new UriIdentifier("www.yahoo.com");
242 Assert.AreEqual("http://www.yahoo.com/", id.ToString());
243 Assert.IsTrue(id.TryRequireSsl(out secureId));
244 Assert.IsTrue(secureId.IsDiscoverySecureEndToEnd);
245 Assert.AreEqual("https://www.yahoo.com/", secureId.ToString());
247 // Try Parse and ctor with explicit http:// scheme
248 id = Identifier.Parse("http://www.yahoo.com");
249 Assert.IsFalse(id.TryRequireSsl(out secureId));
250 Assert.IsFalse(secureId.IsDiscoverySecureEndToEnd);
251 Assert.AreEqual("http://www.yahoo.com/", secureId.ToString());
252 Assert.AreEqual(0, secureId.Discover(this.requestHandler).Count());
254 id = new UriIdentifier("http://www.yahoo.com");
255 Assert.IsFalse(id.TryRequireSsl(out secureId));
256 Assert.IsFalse(secureId.IsDiscoverySecureEndToEnd);
257 Assert.AreEqual("http://www.yahoo.com/", secureId.ToString());
258 Assert.AreEqual(0, secureId.Discover(this.requestHandler).Count());
261 [TestMethod]
262 public void DiscoverRequireSslWithSecureRedirects() {
263 Identifier claimedId = TestSupport.GetMockIdentifier(TestSupport.Scenarios.AutoApproval, this.mockResponder, ProtocolVersion.V20, true);
265 // Add a couple of chained redirect pages that lead to the claimedId.
266 // All redirects should be secure.
267 Uri userSuppliedUri = TestSupport.GetFullUrl("/someSecurePage", null, true);
268 Uri secureMidpointUri = TestSupport.GetFullUrl("/secureStop", null, true);
269 this.mockResponder.RegisterMockRedirect(userSuppliedUri, secureMidpointUri);
270 this.mockResponder.RegisterMockRedirect(secureMidpointUri, new Uri(claimedId.ToString()));
272 Identifier userSuppliedIdentifier = new UriIdentifier(userSuppliedUri, true);
273 Assert.AreEqual(1, userSuppliedIdentifier.Discover(this.requestHandler).Count());
276 [TestMethod, ExpectedException(typeof(ProtocolException))]
277 public void DiscoverRequireSslWithInsecureRedirect() {
278 Identifier claimedId = TestSupport.GetMockIdentifier(TestSupport.Scenarios.AutoApproval, this.mockResponder, ProtocolVersion.V20, true);
280 // Add a couple of chained redirect pages that lead to the claimedId.
281 // Include an insecure HTTP jump in those redirects to verify that
282 // the ultimate endpoint is never found as a result of high security profile.
283 Uri userSuppliedUri = TestSupport.GetFullUrl("/someSecurePage", null, true);
284 Uri insecureMidpointUri = TestSupport.GetFullUrl("/insecureStop");
285 this.mockResponder.RegisterMockRedirect(userSuppliedUri, insecureMidpointUri);
286 this.mockResponder.RegisterMockRedirect(insecureMidpointUri, new Uri(claimedId.ToString()));
288 Identifier userSuppliedIdentifier = new UriIdentifier(userSuppliedUri, true);
289 userSuppliedIdentifier.Discover(this.requestHandler);
292 [TestMethod]
293 public void DiscoveryRequireSslWithInsecureXrdsInSecureHtmlHead() {
294 var insecureXrdsSource = TestSupport.GetMockIdentifier(TestSupport.Scenarios.AutoApproval, this.mockResponder, ProtocolVersion.V20, false);
295 Uri secureClaimedUri = TestSupport.GetFullUrl("/secureId", null, true);
297 string html = string.Format("<html><head><meta http-equiv='X-XRDS-Location' content='{0}'/></head><body></body></html>", insecureXrdsSource);
298 this.mockResponder.RegisterMockResponse(secureClaimedUri, "text/html", html);
300 Identifier userSuppliedIdentifier = new UriIdentifier(secureClaimedUri, true);
301 Assert.AreEqual(0, userSuppliedIdentifier.Discover(this.requestHandler).Count());
304 [TestMethod]
305 public void DiscoveryRequireSslWithInsecureXrdsInSecureHttpHeader() {
306 var insecureXrdsSource = TestSupport.GetMockIdentifier(TestSupport.Scenarios.AutoApproval, this.mockResponder, ProtocolVersion.V20, false);
307 Uri secureClaimedUri = TestSupport.GetFullUrl("/secureId", null, true);
309 string html = "<html><head></head><body></body></html>";
310 WebHeaderCollection headers = new WebHeaderCollection {
311 { "X-XRDS-Location", insecureXrdsSource }
313 this.mockResponder.RegisterMockResponse(secureClaimedUri, secureClaimedUri, "text/html", headers, html);
315 Identifier userSuppliedIdentifier = new UriIdentifier(secureClaimedUri, true);
316 Assert.AreEqual(0, userSuppliedIdentifier.Discover(this.requestHandler).Count());
319 [TestMethod]
320 public void DiscoveryRequireSslWithInsecureXrdsButSecureLinkTags() {
321 var insecureXrdsSource = TestSupport.GetMockIdentifier(TestSupport.Scenarios.AutoApproval, this.mockResponder, ProtocolVersion.V20, false);
322 Uri secureClaimedUri = TestSupport.GetFullUrl("/secureId", null, true);
324 Identifier localIdForLinkTag = TestSupport.GetDelegateUrl(TestSupport.Scenarios.AlwaysDeny, true);
325 string html = string.Format(@"
326 <html><head>
327 <meta http-equiv='X-XRDS-Location' content='{0}'/> <!-- this one will be insecure and ignored -->
328 <link rel='openid2.provider' href='{1}' />
329 <link rel='openid2.local_id' href='{2}' />
330 </head><body></body></html>",
331 HttpUtility.HtmlEncode(insecureXrdsSource),
332 HttpUtility.HtmlEncode(TestSupport.GetFullUrl("/" + TestSupport.ProviderPage, null, true).AbsoluteUri),
333 HttpUtility.HtmlEncode(localIdForLinkTag.ToString()));
334 this.mockResponder.RegisterMockResponse(secureClaimedUri, "text/html", html);
336 Identifier userSuppliedIdentifier = new UriIdentifier(secureClaimedUri, true);
337 Assert.AreEqual(localIdForLinkTag, userSuppliedIdentifier.Discover(this.requestHandler).Single().ProviderLocalIdentifier);
340 [TestMethod]
341 public void DiscoveryRequiresSslIgnoresInsecureEndpointsInXrds() {
342 var insecureEndpoint = TestSupport.GetServiceEndpoint(TestSupport.Scenarios.AutoApproval, ProtocolVersion.V20, 10, false);
343 var secureEndpoint = TestSupport.GetServiceEndpoint(TestSupport.Scenarios.ApproveOnSetup, ProtocolVersion.V20, 20, true);
344 UriIdentifier secureClaimedId = new UriIdentifier(TestSupport.GetFullUrl("/claimedId", null, true), true);
345 this.mockResponder.RegisterMockXrdsResponse(secureClaimedId, new ServiceEndpoint[] { insecureEndpoint, secureEndpoint });
346 Assert.AreEqual(secureEndpoint.ProviderLocalIdentifier, secureClaimedId.Discover(this.requestHandler).Single().ProviderLocalIdentifier);
349 private void Discover(string url, ProtocolVersion version, Identifier expectedLocalId, bool expectSreg, bool useRedirect) {
350 this.Discover(url, version, expectedLocalId, expectSreg, useRedirect, null);
353 private void Discover(string url, ProtocolVersion version, Identifier expectedLocalId, bool expectSreg, bool useRedirect, WebHeaderCollection headers) {
354 Protocol protocol = Protocol.Lookup(version);
355 UriIdentifier claimedId = TestSupport.GetFullUrl(url);
356 UriIdentifier userSuppliedIdentifier = TestSupport.GetFullUrl(
357 "Discovery/htmldiscovery/redirect.aspx?target=" + url);
358 if (expectedLocalId == null) {
359 expectedLocalId = claimedId;
361 Identifier idToDiscover = useRedirect ? userSuppliedIdentifier : claimedId;
363 string contentType;
364 if (url.EndsWith("html")) {
365 contentType = "text/html";
366 } else if (url.EndsWith("xml")) {
367 contentType = "application/xrds+xml";
368 } else {
369 throw new InvalidOperationException();
371 this.mockResponder.RegisterMockResponse(new Uri(idToDiscover), claimedId, contentType, headers ?? new WebHeaderCollection(), TestSupport.LoadEmbeddedFile(url));
373 ServiceEndpoint se = idToDiscover.Discover(this.requestHandler).FirstOrDefault();
374 Assert.IsNotNull(se, url + " failed to be discovered.");
375 Assert.AreSame(protocol, se.Protocol);
376 Assert.AreEqual(claimedId, se.ClaimedIdentifier);
377 Assert.AreEqual(expectedLocalId, se.ProviderLocalIdentifier);
378 Assert.AreEqual(expectSreg ? 2 : 1, se.ProviderSupportedServiceTypeUris.Length);
379 Assert.IsTrue(Array.IndexOf(se.ProviderSupportedServiceTypeUris, protocol.ClaimedIdentifierServiceTypeURI) >= 0);
381 // TODO: re-enable this line once extensions support is added back in.
382 ////Assert.AreEqual(expectSreg, se.IsExtensionSupported(new ClaimsRequest()));
385 private void DiscoverXrds(string page, ProtocolVersion version, Identifier expectedLocalId) {
386 this.DiscoverXrds(page, version, expectedLocalId, null);
389 private void DiscoverXrds(string page, ProtocolVersion version, Identifier expectedLocalId, WebHeaderCollection headers) {
390 if (!page.Contains(".")) page += ".xml";
391 this.Discover("/Discovery/xrdsdiscovery/" + page, version, expectedLocalId, true, false, headers);
392 this.Discover("/Discovery/xrdsdiscovery/" + page, version, expectedLocalId, true, true, headers);
395 private void DiscoverHtml(string page, ProtocolVersion version, Identifier expectedLocalId, bool useRedirect) {
396 this.Discover("/Discovery/htmldiscovery/" + page, version, expectedLocalId, false, useRedirect);
399 private void DiscoverHtml(string scenario, ProtocolVersion version, Identifier expectedLocalId) {
400 string page = scenario + ".html";
401 this.DiscoverHtml(page, version, expectedLocalId, false);
402 this.DiscoverHtml(page, version, expectedLocalId, true);
405 private void FailDiscover(string url) {
406 UriIdentifier userSuppliedId = TestSupport.GetFullUrl(url);
408 this.mockResponder.RegisterMockResponse(new Uri(userSuppliedId), userSuppliedId, "text/html", TestSupport.LoadEmbeddedFile(url));
410 Assert.AreEqual(0, userSuppliedId.Discover(this.requestHandler).Count()); // ... but that no endpoint info is discoverable
413 private void FailDiscoverHtml(string scenario) {
414 this.FailDiscover("/Discovery/htmldiscovery/" + scenario + ".html");
417 private void FailDiscoverXrds(string scenario) {
418 this.FailDiscover("/Discovery/xrdsdiscovery/" + scenario + ".xml");