diff options
author | Andrew Arnott <andrewarnott@gmail.com> | 2009-12-15 22:17:20 -0800 |
---|---|---|
committer | Andrew Arnott <andrewarnott@gmail.com> | 2009-12-15 22:17:20 -0800 |
commit | e12782c1a6727390b2107ff2e39d4ac6173d86fc (patch) | |
tree | 3be0ccda0a9425927263f5b6b9616ef8ba11ac08 /src/DotNetOpenId.Test | |
parent | 078b1f350eb40ceee7423c25b1d833dd1f242da4 (diff) | |
parent | a545f7be2693596fa14540c359e43150a6a7cf88 (diff) | |
download | DotNetOpenAuth-origin/mono.zip DotNetOpenAuth-origin/mono.tar.gz DotNetOpenAuth-origin/mono.tar.bz2 |
Merge branch 'v2.5' into monoorigin/mono
Conflicts:
src/DotNetOpenId/Properties/AssemblyInfo.cs
src/DotNetOpenId/RelyingParty/AuthenticationResponse.cs
Diffstat (limited to 'src/DotNetOpenId.Test')
63 files changed, 2972 insertions, 569 deletions
diff --git a/src/DotNetOpenId.Test/AssociationTestSuite.cs b/src/DotNetOpenId.Test/AssociationTestSuite.cs index 327d174..3333f3a 100644 --- a/src/DotNetOpenId.Test/AssociationTestSuite.cs +++ b/src/DotNetOpenId.Test/AssociationTestSuite.cs @@ -1,15 +1,15 @@ using System;
using System.Collections.Generic;
-using System.Text;
+using System.Security.Cryptography;
using NUnit.Framework;
-namespace DotNetOpenId.Test
-{
+namespace DotNetOpenId.Test {
[TestFixture]
public class AssociationTestSuite {
static readonly TimeSpan deltaDateTime = TimeSpan.FromSeconds(2);
- byte[] sha1Secret = new byte[CryptUtil.Sha1.HashSize / 8];
- byte[] sha1Secret2 = new byte[CryptUtil.Sha1.HashSize / 8];
+ static HashAlgorithm sha1 = DiffieHellmanUtil.Lookup(Protocol.Default, Protocol.Default.Args.SessionType.DH_SHA1);
+ byte[] sha1Secret = new byte[sha1.HashSize / 8];
+ byte[] sha1Secret2 = new byte[sha1.HashSize / 8];
public AssociationTestSuite() {
// just a little something to make it at all interesting.
@@ -24,7 +24,8 @@ namespace DotNetOpenId.Test public void Properties() {
string handle = "somehandle";
TimeSpan lifetime = TimeSpan.FromMinutes(2);
- Association assoc = new HmacSha1Association(handle, sha1Secret, lifetime);
+ Association assoc = HmacShaAssociation.Create(Protocol.Default, Protocol.Default.Args.SignatureAlgorithm.HMAC_SHA1,
+ handle, sha1Secret, lifetime);
Assert.IsFalse(assoc.IsExpired);
Assert.IsTrue(Math.Abs((DateTime.Now - assoc.Issued.ToLocalTime()).TotalSeconds) < deltaDateTime.TotalSeconds);
Assert.IsTrue(Math.Abs((DateTime.Now.ToLocalTime() + lifetime - assoc.Expires.ToLocalTime()).TotalSeconds) < deltaDateTime.TotalSeconds);
@@ -36,8 +37,10 @@ namespace DotNetOpenId.Test [Test]
public void Sign() {
- Association assoc1 = new HmacSha1Association("h1", sha1Secret, TimeSpan.FromMinutes(2));
- Association assoc2 = new HmacSha1Association("h2", sha1Secret2, TimeSpan.FromMinutes(2));
+ Association assoc1 = HmacShaAssociation.Create(Protocol.Default, Protocol.Default.Args.SignatureAlgorithm.HMAC_SHA1,
+ "h1", sha1Secret, TimeSpan.FromMinutes(2));
+ Association assoc2 = HmacShaAssociation.Create(Protocol.Default, Protocol.Default.Args.SignatureAlgorithm.HMAC_SHA1,
+ "h2", sha1Secret2, TimeSpan.FromMinutes(2));
var dict = new Dictionary<string, string>();
dict.Add("a", "b");
@@ -77,7 +80,8 @@ namespace DotNetOpenId.Test [Test]
public void SignSome() {
- Association assoc = new HmacSha1Association("h1", sha1Secret, TimeSpan.FromMinutes(2));
+ Association assoc = HmacShaAssociation.Create(Protocol.Default, Protocol.Default.Args.SignatureAlgorithm.HMAC_SHA1,
+ "h1", sha1Secret, TimeSpan.FromMinutes(2));
const string prefix = "q.";
var dict = new Dictionary<string, string>();
@@ -85,7 +89,7 @@ namespace DotNetOpenId.Test dict.Add("q.c", "d");
dict.Add("q.e", "f");
- var signKeys = new List<string> {"a", "c"}; // don't sign e
+ var signKeys = new List<string> { "a", "c" }; // don't sign e
byte[] sig1 = assoc.Sign(dict, signKeys, prefix);
diff --git a/src/DotNetOpenId.Test/AssociationsTest.cs b/src/DotNetOpenId.Test/AssociationsTest.cs index 7f4ec26..01dad58 100644 --- a/src/DotNetOpenId.Test/AssociationsTest.cs +++ b/src/DotNetOpenId.Test/AssociationsTest.cs @@ -1,13 +1,12 @@ using System;
-using System.Collections.Generic;
-using System.Text;
+using System.Security.Cryptography;
using NUnit.Framework;
-using System.Threading;
namespace DotNetOpenId.Test {
[TestFixture]
public class AssociationsTest {
- byte[] sha1Secret = new byte[CryptUtil.Sha1.HashSize / 8];
+ static HashAlgorithm sha1 = DiffieHellmanUtil.Lookup(Protocol.Default, Protocol.Default.Args.SessionType.DH_SHA1);
+ byte[] sha1Secret = new byte[sha1.HashSize / 8];
Associations assocs;
[SetUp]
@@ -27,7 +26,8 @@ namespace DotNetOpenId.Test { [Test]
public void HandleLifecycle() {
- Association a = new HmacSha1Association("somehandle", sha1Secret, TimeSpan.FromDays(1));
+ Association a = HmacShaAssociation.Create(Protocol.Default, Protocol.Default.Args.SignatureAlgorithm.HMAC_SHA1,
+ "somehandle", sha1Secret, TimeSpan.FromDays(1));
assocs.Set(a);
Assert.AreSame(a, assocs.Get(a.Handle));
Assert.IsTrue(assocs.Remove(a.Handle));
@@ -37,8 +37,10 @@ namespace DotNetOpenId.Test { [Test]
public void Best() {
- Association a = new HmacSha1Association("h1", sha1Secret, TimeSpan.FromHours(1));
- Association b = new HmacSha1Association("h2", sha1Secret, TimeSpan.FromHours(1));
+ Association a = HmacShaAssociation.Create(Protocol.Default, Protocol.Default.Args.SignatureAlgorithm.HMAC_SHA1,
+ "h1", sha1Secret, TimeSpan.FromHours(1));
+ Association b = HmacShaAssociation.Create(Protocol.Default, Protocol.Default.Args.SignatureAlgorithm.HMAC_SHA1,
+ "h2", sha1Secret, TimeSpan.FromHours(1));
assocs.Set(a);
assocs.Set(b);
diff --git a/src/DotNetOpenId.Test/DiffieHellmanTestSuite.cs b/src/DotNetOpenId.Test/DiffieHellmanUtilTests.cs index 52d9b4c..9b2fba9 100644 --- a/src/DotNetOpenId.Test/DiffieHellmanTestSuite.cs +++ b/src/DotNetOpenId.Test/DiffieHellmanUtilTests.cs @@ -8,8 +8,8 @@ using NUnit.Framework; namespace DotNetOpenId.Test {
public static class DHTestUtil {
public static string Test1() {
- DiffieHellman dh1 = CryptUtil.CreateDiffieHellman();
- DiffieHellman dh2 = CryptUtil.CreateDiffieHellman();
+ DiffieHellman dh1 = DiffieHellmanUtil.CreateDiffieHellman();
+ DiffieHellman dh2 = DiffieHellmanUtil.CreateDiffieHellman();
string secret1 = Convert.ToBase64String(dh1.DecryptKeyExchange(dh2.CreateKeyExchange()));
string secret2 = Convert.ToBase64String(dh2.DecryptKeyExchange(dh1.CreateKeyExchange()));
@@ -21,7 +21,7 @@ namespace DotNetOpenId.Test { }
[TestFixture]
- public class DiffieHellmanTestSuite {
+ public class DiffieHellmanUtilTests {
[Test]
public void Test() {
@@ -40,14 +40,14 @@ namespace DotNetOpenId.Test { while ((line = sr.ReadLine()) != null) {
string[] parts = line.Trim().Split(' ');
byte[] x = Convert.FromBase64String(parts[0]);
- DiffieHellmanManaged dh = new DiffieHellmanManaged(CryptUtil.DEFAULT_MOD, CryptUtil.DEFAULT_GEN, x);
+ DiffieHellmanManaged dh = new DiffieHellmanManaged(DiffieHellmanUtil.DEFAULT_MOD, DiffieHellmanUtil.DEFAULT_GEN, x);
byte[] pub = dh.CreateKeyExchange();
byte[] y = Convert.FromBase64String(parts[1]);
if (y[0] == 0 && y[1] <= 127)
y.CopyTo(y, 1);
- Assert.AreEqual(y, Convert.FromBase64String(CryptUtil.UnsignedToBase64(pub)), line);
+ Assert.AreEqual(y, Convert.FromBase64String(DiffieHellmanUtil.UnsignedToBase64(pub)), line);
}
} finally {
sr.Close();
diff --git a/src/DotNetOpenId.Test/Discovery/htmldiscovery/html1020.html b/src/DotNetOpenId.Test/Discovery/htmldiscovery/html1020.html new file mode 100644 index 0000000..7c6c15e --- /dev/null +++ b/src/DotNetOpenId.Test/Discovery/htmldiscovery/html1020.html @@ -0,0 +1,12 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+ <title>Untitled Page</title>
+ <link rel="openid.server" href="http://e/f" />
+ <link rel="openid.delegate" href="http://g/h" />
+ <link rel="openid2.provider" href="http://a/b" />
+ <link rel="openid2.local_id" href="http://c/d" />
+</head>
+<body>
+</body>
+</html>
diff --git a/src/DotNetOpenId.Test/Discovery/htmldiscovery/html10both.html b/src/DotNetOpenId.Test/Discovery/htmldiscovery/html10both.html new file mode 100644 index 0000000..e97803e --- /dev/null +++ b/src/DotNetOpenId.Test/Discovery/htmldiscovery/html10both.html @@ -0,0 +1,10 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+ <title>Untitled Page</title>
+ <link rel="openid.server" href="http://a/b" />
+ <link rel="openid.delegate" href="http://c/d" />
+</head>
+<body>
+</body>
+</html>
diff --git a/src/DotNetOpenId.Test/Discovery/htmldiscovery/html10del.html b/src/DotNetOpenId.Test/Discovery/htmldiscovery/html10del.html new file mode 100644 index 0000000..ddf121a --- /dev/null +++ b/src/DotNetOpenId.Test/Discovery/htmldiscovery/html10del.html @@ -0,0 +1,9 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+ <title>Untitled Page</title>
+ <link rel="openid.delegate" href="http://c/d" />
+</head>
+<body>
+</body>
+</html>
diff --git a/src/DotNetOpenId.Test/Discovery/htmldiscovery/html10prov.html b/src/DotNetOpenId.Test/Discovery/htmldiscovery/html10prov.html new file mode 100644 index 0000000..1b198f9 --- /dev/null +++ b/src/DotNetOpenId.Test/Discovery/htmldiscovery/html10prov.html @@ -0,0 +1,9 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+ <title>Untitled Page</title>
+ <link rel="openid.server" href="http://a/b" />
+</head>
+<body>
+</body>
+</html>
diff --git a/src/DotNetOpenId.Test/Discovery/htmldiscovery/html2010.html b/src/DotNetOpenId.Test/Discovery/htmldiscovery/html2010.html new file mode 100644 index 0000000..9fa3738 --- /dev/null +++ b/src/DotNetOpenId.Test/Discovery/htmldiscovery/html2010.html @@ -0,0 +1,12 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+ <title>Untitled Page</title>
+ <link rel="openid2.provider" href="http://a/b" />
+ <link rel="openid2.local_id" href="http://c/d" />
+ <link rel="openid.server" href="http://e/f" />
+ <link rel="openid.delegate" href="http://g/h" />
+</head>
+<body>
+</body>
+</html>
diff --git a/src/DotNetOpenId.Test/Discovery/htmldiscovery/html2010combinedA.html b/src/DotNetOpenId.Test/Discovery/htmldiscovery/html2010combinedA.html new file mode 100644 index 0000000..c057b67 --- /dev/null +++ b/src/DotNetOpenId.Test/Discovery/htmldiscovery/html2010combinedA.html @@ -0,0 +1,10 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+ <title>Untitled Page</title>
+ <link rel="openid2.provider B openid.server" href="http://a/b" />
+ <link rel="openid2.local_id B openid.delegate" href="http://c/d" />
+</head>
+<body>
+</body>
+</html>
diff --git a/src/DotNetOpenId.Test/Discovery/htmldiscovery/html2010combinedB.html b/src/DotNetOpenId.Test/Discovery/htmldiscovery/html2010combinedB.html new file mode 100644 index 0000000..3a86d4c --- /dev/null +++ b/src/DotNetOpenId.Test/Discovery/htmldiscovery/html2010combinedB.html @@ -0,0 +1,10 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+ <title>Untitled Page</title>
+ <link rel="A openid2.provider openid.server" href="http://a/b" />
+ <link rel="A openid2.local_id openid.delegate" href="http://c/d" />
+</head>
+<body>
+</body>
+</html>
diff --git a/src/DotNetOpenId.Test/Discovery/htmldiscovery/html2010combinedC.html b/src/DotNetOpenId.Test/Discovery/htmldiscovery/html2010combinedC.html new file mode 100644 index 0000000..13a3185 --- /dev/null +++ b/src/DotNetOpenId.Test/Discovery/htmldiscovery/html2010combinedC.html @@ -0,0 +1,10 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+ <title>Untitled Page</title>
+ <link rel="openid.server B openid2.provider" href="http://a/b" />
+ <link rel="openid.delegate B openid2.local_id" href="http://c/d" />
+</head>
+<body>
+</body>
+</html>
diff --git a/src/DotNetOpenId.Test/Discovery/htmldiscovery/html20both.html b/src/DotNetOpenId.Test/Discovery/htmldiscovery/html20both.html new file mode 100644 index 0000000..f41e66a --- /dev/null +++ b/src/DotNetOpenId.Test/Discovery/htmldiscovery/html20both.html @@ -0,0 +1,10 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+ <title>Untitled Page</title>
+ <link rel="openid2.provider" href="http://a/b" />
+ <link rel="openid2.local_id" href="http://c/d" />
+</head>
+<body>
+</body>
+</html>
diff --git a/src/DotNetOpenId.Test/Discovery/htmldiscovery/html20del.html b/src/DotNetOpenId.Test/Discovery/htmldiscovery/html20del.html new file mode 100644 index 0000000..20852c0 --- /dev/null +++ b/src/DotNetOpenId.Test/Discovery/htmldiscovery/html20del.html @@ -0,0 +1,9 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+ <title>Untitled Page</title>
+ <link rel="openid2.local_id" href="http://c/d" />
+</head>
+<body>
+</body>
+</html>
diff --git a/src/DotNetOpenId.Test/Discovery/htmldiscovery/html20prov.html b/src/DotNetOpenId.Test/Discovery/htmldiscovery/html20prov.html new file mode 100644 index 0000000..f0e673e --- /dev/null +++ b/src/DotNetOpenId.Test/Discovery/htmldiscovery/html20prov.html @@ -0,0 +1,9 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+ <title>Untitled Page</title>
+ <link rel="openid2.provider" href="http://a/b" />
+</head>
+<body>
+</body>
+</html>
diff --git a/src/DotNetOpenId.Test/Discovery/htmldiscovery/html20relative.html b/src/DotNetOpenId.Test/Discovery/htmldiscovery/html20relative.html new file mode 100644 index 0000000..b13520c --- /dev/null +++ b/src/DotNetOpenId.Test/Discovery/htmldiscovery/html20relative.html @@ -0,0 +1,9 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+ <title>Untitled Page</title>
+ <link rel="openid2.provider" href="../a/b" />
+</head>
+<body>
+</body>
+</html>
diff --git a/src/DotNetOpenId.Test/Discovery/xrdsdiscovery/XrdsReferencedInHead.html b/src/DotNetOpenId.Test/Discovery/xrdsdiscovery/XrdsReferencedInHead.html new file mode 100644 index 0000000..615038c --- /dev/null +++ b/src/DotNetOpenId.Test/Discovery/xrdsdiscovery/XrdsReferencedInHead.html @@ -0,0 +1,12 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head runat="server">
+ <title>Untitled Page</title>
+ <meta http-equiv="X-XRDS-Location" content="http://localhost/xrds1020.xml"/>
+</head>
+<body>
+ <form id="form1" runat="server">
+ </form>
+</body>
+</html>
diff --git a/src/DotNetOpenId.Test/Discovery/xrdsdiscovery/XrdsReferencedInHttpHeader.html b/src/DotNetOpenId.Test/Discovery/xrdsdiscovery/XrdsReferencedInHttpHeader.html new file mode 100644 index 0000000..f0842db --- /dev/null +++ b/src/DotNetOpenId.Test/Discovery/xrdsdiscovery/XrdsReferencedInHttpHeader.html @@ -0,0 +1,9 @@ +<html xmlns="http://www.w3.org/1999/xhtml">
+<head runat="server">
+ <title>Untitled Page</title>
+</head>
+<body>
+ <form id="form1" runat="server">
+ </form>
+</body>
+</html>
diff --git a/src/DotNetOpenId.Test/Discovery/xrdsdiscovery/xrds-irrelevant.xml b/src/DotNetOpenId.Test/Discovery/xrdsdiscovery/xrds-irrelevant.xml new file mode 100644 index 0000000..5116c0b --- /dev/null +++ b/src/DotNetOpenId.Test/Discovery/xrdsdiscovery/xrds-irrelevant.xml @@ -0,0 +1,12 @@ +<?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>junk</Type> + <URI>http://a/b</URI> + </Service> + </XRD> +</xrds:XRDS> diff --git a/src/DotNetOpenId.Test/Discovery/xrdsdiscovery/xrds10.xml b/src/DotNetOpenId.Test/Discovery/xrdsdiscovery/xrds10.xml new file mode 100644 index 0000000..7280e9f --- /dev/null +++ b/src/DotNetOpenId.Test/Discovery/xrdsdiscovery/xrds10.xml @@ -0,0 +1,22 @@ +<?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://openid.net/signon/1.0</Type>
+ <!-- this next sreg one is deliberately an unofficial (but supported) sreg/1.0 typeUri, so we test it. -->
+ <Type>http://openid.net/sreg/1.0</Type>
+ <URI>http://a/b</URI>
+ <openid:Delegate></openid:Delegate> <!-- this is empty, but present, deliberately -->
+ </Service>
+ <!-- This next one is invalid since it doesn't have a URI value,
+ but it's here to verify it doesn't break the above valid services. -->
+ <Service priority="20">
+ <Type>http://openid.net/signon/1.0</Type>
+ <URI></URI>
+ <openid:Delegate></openid:Delegate>
+ </Service>
+ </XRD>
+</xrds:XRDS>
diff --git a/src/DotNetOpenId.Test/Discovery/xrdsdiscovery/xrds1020.xml b/src/DotNetOpenId.Test/Discovery/xrdsdiscovery/xrds1020.xml new file mode 100644 index 0000000..1b56f0f --- /dev/null +++ b/src/DotNetOpenId.Test/Discovery/xrdsdiscovery/xrds1020.xml @@ -0,0 +1,18 @@ +<?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://openid.net/signon/1.0</Type> + <Type>http://openid.net/extensions/sreg/1.1</Type> + <URI>http://a/b</URI> + </Service> + <Service priority="20"> + <Type>http://specs.openid.net/auth/2.0/signon</Type> + <Type>http://openid.net/extensions/sreg/1.1</Type> + <URI>http://c/d</URI> + </Service> + </XRD> +</xrds:XRDS> diff --git a/src/DotNetOpenId.Test/Discovery/xrdsdiscovery/xrds11.xml b/src/DotNetOpenId.Test/Discovery/xrdsdiscovery/xrds11.xml new file mode 100644 index 0000000..2d6a7aa --- /dev/null +++ b/src/DotNetOpenId.Test/Discovery/xrdsdiscovery/xrds11.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://openid.net/signon/1.1</Type> + <Type>http://openid.net/extensions/sreg/1.1</Type> + <URI>http://a/b</URI> + </Service> + </XRD> +</xrds:XRDS> diff --git a/src/DotNetOpenId.Test/Discovery/xrdsdiscovery/xrds20.xml b/src/DotNetOpenId.Test/Discovery/xrdsdiscovery/xrds20.xml new file mode 100644 index 0000000..870b540 --- /dev/null +++ b/src/DotNetOpenId.Test/Discovery/xrdsdiscovery/xrds20.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://openid.net/extensions/sreg/1.1</Type> + <URI>http://a/b</URI> + </Service> + </XRD> +</xrds:XRDS> diff --git a/src/DotNetOpenId.Test/Discovery/xrdsdiscovery/xrds2010a.xml b/src/DotNetOpenId.Test/Discovery/xrdsdiscovery/xrds2010a.xml new file mode 100644 index 0000000..4f72ac2 --- /dev/null +++ b/src/DotNetOpenId.Test/Discovery/xrdsdiscovery/xrds2010a.xml @@ -0,0 +1,18 @@ +<?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://openid.net/extensions/sreg/1.1</Type> + <URI>http://a/b</URI> + </Service> + <Service priority="20"> + <Type>http://openid.net/signon/1.0</Type> + <Type>http://openid.net/extensions/sreg/1.1</Type> + <URI>http://c/d</URI> + </Service> + </XRD> +</xrds:XRDS> diff --git a/src/DotNetOpenId.Test/Discovery/xrdsdiscovery/xrds2010b.xml b/src/DotNetOpenId.Test/Discovery/xrdsdiscovery/xrds2010b.xml new file mode 100644 index 0000000..8ad468f --- /dev/null +++ b/src/DotNetOpenId.Test/Discovery/xrdsdiscovery/xrds2010b.xml @@ -0,0 +1,18 @@ +<?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="20"> + <Type>http://openid.net/signon/1.0</Type> + <Type>http://openid.net/extensions/sreg/1.1</Type> + <URI>http://c/d</URI> + </Service> + <Service priority="10"> + <Type>http://specs.openid.net/auth/2.0/signon</Type> + <Type>http://openid.net/extensions/sreg/1.1</Type> + <URI>http://a/b</URI> + </Service> + </XRD> +</xrds:XRDS> diff --git a/src/DotNetOpenId.Test/DotNetOpenId.Test.csproj b/src/DotNetOpenId.Test/DotNetOpenId.Test.csproj index 4b59f51..851b7e2 100644 --- a/src/DotNetOpenId.Test/DotNetOpenId.Test.csproj +++ b/src/DotNetOpenId.Test/DotNetOpenId.Test.csproj @@ -2,7 +2,7 @@ <PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
- <ProductVersion>9.0.21022</ProductVersion>
+ <ProductVersion>9.0.30729</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{CDEE655B-3902-420E-ADED-F4B6F666FB03}</ProjectGuid>
<OutputType>Library</OutputType>
@@ -33,7 +33,12 @@ <WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
+ <Reference Include="log4net, Version=1.2.10.0, Culture=neutral, PublicKeyToken=1b44e1d426115821, processorArchitecture=MSIL">
+ <SpecificVersion>False</SpecificVersion>
+ <HintPath>..\..\lib\log4net.dll</HintPath>
+ </Reference>
<Reference Include="nunit.framework, Version=2.2.9.0, Culture=neutral, PublicKeyToken=96d09a1eb7f44a77, processorArchitecture=MSIL">
+ <HintPath>../../tools/NUnit/bin/nunit.framework.dll</HintPath>
<SpecificVersion>False</SpecificVersion>
</Reference>
<Reference Include="System" />
@@ -47,6 +52,8 @@ <ItemGroup>
<Compile Include="AssociationsTest.cs" />
<Compile Include="AssociationTestSuite.cs" />
+ <Compile Include="Mocks\DirectMessageSniffWrapper.cs" />
+ <Compile Include="Mocks\DirectMessageTestRedirector.cs" />
<Compile Include="ExtensionsArgumentsManagerTests.cs" />
<Compile Include="Extensions\AttributeExchangeFetchRequestTests.cs" />
<Compile Include="Extensions\AttributeExchangeFetchResponseTests.cs" />
@@ -58,31 +65,36 @@ <Compile Include="Extensions\PolicyRequestTests.cs" />
<Compile Include="Extensions\PolicyResponseTests.cs" />
<Compile Include="Extensions\SimpleRegistrationTests.cs" />
- <Compile Include="Hosting\EncodingInterceptor.cs" />
<Compile Include="IdentifierTests.cs" />
+ <Compile Include="Mocks\MockHttpRequest.cs" />
+ <Compile Include="Mocks\MockIdentifier.cs" />
<Compile Include="NonceTest.cs" />
<Compile Include="PiecewiseJointTesting.cs" />
<Compile Include="Provider\IAuthenticationRequestTest.cs" />
+ <Compile Include="RelyingParty\AuthenticationRequestTests.cs" />
<Compile Include="RelyingParty\AuthenticationResponseTests.cs" />
- <Compile Include="RelyingParty\OpenIdMobileTextBoxTest.cs" />
+ <Compile Include="RelyingParty\IProviderEndpointTests.cs" />
+ <Compile Include="UI\OpenIdMobileTextBoxTest.cs" />
<Compile Include="RelyingParty\OpenIdRelyingPartyTest.cs" />
- <Compile Include="RelyingParty\OpenIdTextBoxTest.cs" />
- <Compile Include="DiffieHellmanTestSuite.cs" />
+ <Compile Include="UI\OpenIdTextBoxTest.cs" />
+ <Compile Include="DiffieHellmanUtilTests.cs" />
<Compile Include="EndToEndTesting.cs" />
<Compile Include="KeyValueFormEncodingTests.cs" />
<Compile Include="RelyingParty\ServiceEndpointTests.cs" />
- <Compile Include="TestSupportSanityTest.cs" />
+ <Compile Include="UI\TestSupportSanityTest.cs" />
<Compile Include="Hosting\AspNetHost.cs" />
<Compile Include="Hosting\HttpHost.cs" />
<Compile Include="TestSupport.cs" />
<Compile Include="Hosting\TestingWorkerRequest.cs" />
- <Compile Include="ProfileFieldValuesTests.cs" />
+ <Compile Include="Extensions\ClaimsResponseTests.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
- <Compile Include="Provider\IdentityEndpointTest.cs" />
+ <Compile Include="UI\IdentityEndpointTest.cs" />
<Compile Include="Provider\OpenIdProviderTest.cs" />
- <Compile Include="Provider\ProviderEndpointTest.cs" />
+ <Compile Include="UI\ProviderEndpointTest.cs" />
<Compile Include="RelyingParty\TokenTest.cs" />
<Compile Include="RealmTestSuite.cs" />
+ <Compile Include="UI\UITestSupport.cs" />
+ <Compile Include="UI\WebControlTesting.cs" />
<Compile Include="UntrustedWebRequestTests.cs" />
<Compile Include="UriIdentifierTests.cs" />
<Compile Include="UriUtilTest.cs" />
@@ -91,6 +103,28 @@ </ItemGroup>
<ItemGroup>
<Content Include="dhpriv.txt" />
+ <EmbeddedResource Include="Logging.config" />
+ <EmbeddedResource Include="Discovery\htmldiscovery\html1020.html" />
+ <EmbeddedResource Include="Discovery\htmldiscovery\html10both.html" />
+ <EmbeddedResource Include="Discovery\htmldiscovery\html10del.html" />
+ <EmbeddedResource Include="Discovery\htmldiscovery\html10prov.html" />
+ <EmbeddedResource Include="Discovery\htmldiscovery\html2010.html" />
+ <EmbeddedResource Include="Discovery\htmldiscovery\html2010combinedA.html" />
+ <EmbeddedResource Include="Discovery\htmldiscovery\html2010combinedB.html" />
+ <EmbeddedResource Include="Discovery\htmldiscovery\html2010combinedC.html" />
+ <EmbeddedResource Include="Discovery\htmldiscovery\html20both.html" />
+ <EmbeddedResource Include="Discovery\htmldiscovery\html20del.html" />
+ <EmbeddedResource Include="Discovery\htmldiscovery\html20prov.html" />
+ <EmbeddedResource Include="Discovery\htmldiscovery\html20relative.html" />
+ <EmbeddedResource Include="Discovery\xrdsdiscovery\xrds-irrelevant.xml" />
+ <EmbeddedResource Include="Discovery\xrdsdiscovery\xrds10.xml" />
+ <EmbeddedResource Include="Discovery\xrdsdiscovery\xrds1020.xml" />
+ <EmbeddedResource Include="Discovery\xrdsdiscovery\xrds11.xml" />
+ <EmbeddedResource Include="Discovery\xrdsdiscovery\xrds20.xml" />
+ <EmbeddedResource Include="Discovery\xrdsdiscovery\xrds2010a.xml" />
+ <EmbeddedResource Include="Discovery\xrdsdiscovery\xrds2010b.xml" />
+ <EmbeddedResource Include="Discovery\xrdsdiscovery\XrdsReferencedInHead.html" />
+ <EmbeddedResource Include="Discovery\xrdsdiscovery\XrdsReferencedInHttpHeader.html" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\DotNetOpenId\DotNetOpenId.csproj">
@@ -99,11 +133,5 @@ </ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
- <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
- Other similar extension points exist, see Microsoft.Common.targets.
- <Target Name="BeforeBuild">
- </Target>
- <Target Name="AfterBuild">
- </Target>
- -->
+ <Import Project="..\..\tools\DotNetOpenId.Versioning.targets" />
</Project>
\ No newline at end of file diff --git a/src/DotNetOpenId.Test/EndToEndTesting.cs b/src/DotNetOpenId.Test/EndToEndTesting.cs index de1ed2a..f5a5291 100644 --- a/src/DotNetOpenId.Test/EndToEndTesting.cs +++ b/src/DotNetOpenId.Test/EndToEndTesting.cs @@ -1,272 +1,200 @@ using System;
-using System.Collections.Generic;
-using System.Text;
-using NUnit.Framework;
-using DotNetOpenId.RelyingParty;
using System.Collections.Specialized;
-using System.Web;
-using System.Net;
using System.Diagnostics;
using System.IO;
+using System.Net;
using System.Text.RegularExpressions;
+using DotNetOpenId.RelyingParty;
+using DotNetOpenId.Test.Mocks;
+using NUnit.Framework;
namespace DotNetOpenId.Test {
[TestFixture]
public class EndToEndTesting {
- IRelyingPartyApplicationStore appStore;
[SetUp]
public void Setup() {
- appStore = new ApplicationMemoryStore();
if (!UntrustedWebRequest.WhitelistHosts.Contains("localhost"))
UntrustedWebRequest.WhitelistHosts.Add("localhost");
}
- void parameterizedTest(UriIdentifier identityUrl,
- AuthenticationRequestMode requestMode, AuthenticationStatus expectedResult,
- bool tryReplayAttack, bool provideStore) {
- parameterizedProgrammaticTest(identityUrl, requestMode, expectedResult, tryReplayAttack, provideStore);
- parameterizedWebClientTest(identityUrl, requestMode, expectedResult, tryReplayAttack, provideStore);
+ [TearDown]
+ public void TearDown() {
+ MockHttpRequest.Reset();
}
- void parameterizedProgrammaticTest(UriIdentifier identityUrl,
- AuthenticationRequestMode requestMode, AuthenticationStatus expectedResult,
- bool tryReplayAttack, bool provideStore) {
- var store = provideStore ? appStore : null;
-
- Uri redirectToProviderUrl;
- var returnTo = TestSupport.GetFullUrl(TestSupport.ConsumerPage);
- var realm = new Realm(TestSupport.GetFullUrl(TestSupport.ConsumerPage).AbsoluteUri);
- var consumer = new OpenIdRelyingParty(store, null, null);
- Assert.IsNull(consumer.Response);
- var request = consumer.CreateRequest(identityUrl, realm, returnTo);
- Protocol protocol = Protocol.Lookup(request.ProviderVersion);
-
- // Test properties and defaults
- Assert.AreEqual(AuthenticationRequestMode.Setup, request.Mode);
- Assert.AreEqual(returnTo, request.ReturnToUrl);
- Assert.AreEqual(realm, request.Realm);
+ void parameterizedTest(TestSupport.Scenarios scenario, ProtocolVersion version,
+ AuthenticationRequestMode requestMode, AuthenticationStatus expectedResult) {
+
+ bool useSsl = true;
+ Identifier claimedId = TestSupport.GetMockIdentifier(scenario, version, useSsl);
+ parameterizedProgrammaticTest(scenario, version, claimedId, requestMode, expectedResult, true, useSsl);
+ parameterizedProgrammaticTest(scenario, version, claimedId, requestMode, expectedResult, false, useSsl);
+
+ useSsl = false;
+ claimedId = TestSupport.GetMockIdentifier(scenario, version, useSsl);
+ parameterizedProgrammaticTest(scenario, version, claimedId, requestMode, expectedResult, true, useSsl);
+ parameterizedProgrammaticTest(scenario, version, claimedId, requestMode, expectedResult, false, useSsl);
+ }
+ void parameterizedOPIdentifierTest(TestSupport.Scenarios scenario,
+ AuthenticationRequestMode requestMode, AuthenticationStatus expectedResult) {
+ ProtocolVersion version = ProtocolVersion.V20; // only this version supports directed identity
+ UriIdentifier claimedIdentifier = TestSupport.GetDirectedIdentityUrl(TestSupport.Scenarios.ApproveOnSetup, version);
+ Identifier opIdentifier = TestSupport.GetMockOPIdentifier(TestSupport.Scenarios.ApproveOnSetup, claimedIdentifier);
+ parameterizedProgrammaticOPIdentifierTest(opIdentifier, version, claimedIdentifier, requestMode, expectedResult, true);
+ parameterizedProgrammaticOPIdentifierTest(opIdentifier, version, claimedIdentifier, requestMode, expectedResult, false);
+ }
+ void parameterizedProgrammaticTest(TestSupport.Scenarios scenario, ProtocolVersion version,
+ Identifier claimedUrl, AuthenticationRequestMode requestMode,
+ AuthenticationStatus expectedResult, bool provideStore, bool useSsl) {
+ var request = TestSupport.CreateRelyingPartyRequest(!provideStore, scenario, version, useSsl);
request.Mode = requestMode;
- // Verify the redirect URL
- Assert.IsNotNull(request.RedirectingResponse);
- var consumerToProviderQuery = HttpUtility.ParseQueryString(request.RedirectingResponse.ExtractUrl().Query);
- Assert.IsTrue(consumerToProviderQuery[protocol.openid.return_to].StartsWith(returnTo.AbsoluteUri, StringComparison.Ordinal));
- Assert.AreEqual(realm.ToString(), consumerToProviderQuery[protocol.openid.Realm]);
- redirectToProviderUrl = request.RedirectingResponse.ExtractUrl();
-
- HttpWebRequest providerRequest = (HttpWebRequest)WebRequest.Create(redirectToProviderUrl);
- providerRequest.AllowAutoRedirect = false;
- Uri redirectUrl;
- try {
- using (HttpWebResponse providerResponse = (HttpWebResponse)providerRequest.GetResponse()) {
- Assert.AreEqual(HttpStatusCode.Redirect, providerResponse.StatusCode);
- redirectUrl = new Uri(providerResponse.Headers[HttpResponseHeader.Location]);
- }
- } catch (WebException ex) {
- Trace.WriteLine(ex);
- if (ex.Response != null) {
- using (StreamReader sr = new StreamReader(ex.Response.GetResponseStream())) {
- Trace.WriteLine(sr.ReadToEnd());
- }
- }
- throw;
- }
- consumer = new OpenIdRelyingParty(store, redirectUrl, HttpUtility.ParseQueryString(redirectUrl.Query));
- Assert.AreEqual(expectedResult, consumer.Response.Status);
- Assert.AreEqual(identityUrl, consumer.Response.ClaimedIdentifier);
-
- // Try replay attack
- if (tryReplayAttack) {
- // This simulates a network sniffing user who caught the
- // authenticating query en route to either the user agent or
- // the consumer, and tries the same query to the consumer in an
- // attempt to spoof the identity of the authenticating user.
- try {
- var replayAttackConsumer = new OpenIdRelyingParty(store, redirectUrl, HttpUtility.ParseQueryString(redirectUrl.Query));
- Assert.AreNotEqual(AuthenticationStatus.Authenticated, replayAttackConsumer.Response.Status, "Replay attack");
- } catch (OpenIdException) { // nonce already used
- // another way to pass
- }
- }
+ var rpResponse = TestSupport.CreateRelyingPartyResponseThroughProvider(request,
+ opReq => opReq.IsAuthenticated = expectedResult == AuthenticationStatus.Authenticated);
+ Assert.AreEqual(expectedResult, rpResponse.Status);
+ Assert.AreEqual(claimedUrl, rpResponse.ClaimedIdentifier);
}
- void parameterizedWebClientTest(UriIdentifier identityUrl,
- AuthenticationRequestMode requestMode, AuthenticationStatus expectedResult,
- bool tryReplayAttack, bool provideStore) {
- var store = provideStore ? appStore : null;
+ void parameterizedProgrammaticOPIdentifierTest(Identifier opIdentifier, ProtocolVersion version,
+ Identifier claimedUrl, AuthenticationRequestMode requestMode,
+ AuthenticationStatus expectedResult, bool provideStore) {
- Uri redirectToProviderUrl;
- HttpWebRequest rpRequest = (HttpWebRequest)WebRequest.Create(TestSupport.GetFullUrl(TestSupport.ConsumerPage));
- NameValueCollection query = new NameValueCollection();
- using (HttpWebResponse response = (HttpWebResponse)rpRequest.GetResponse()) {
- using (StreamReader sr = new StreamReader(response.GetResponseStream())) {
- Regex regex = new Regex(@"\<input\b.*\bname=""(\w+)"".*\bvalue=""([^""]+)""", RegexOptions.IgnoreCase);
- while (!sr.EndOfStream) {
- string line = sr.ReadLine();
- Match m = regex.Match(line);
- if (m.Success) {
- query[m.Groups[1].Value] = m.Groups[2].Value;
- }
- }
- }
- }
- query["OpenIdTextBox1$wrappedTextBox"] = identityUrl;
- rpRequest = (HttpWebRequest)WebRequest.Create(TestSupport.GetFullUrl(TestSupport.ConsumerPage));
- rpRequest.Method = "POST";
- rpRequest.AllowAutoRedirect = false;
- string queryString = UriUtil.CreateQueryString(query);
- rpRequest.ContentLength = queryString.Length;
- rpRequest.ContentType = "application/x-www-form-urlencoded";
- using (StreamWriter sw = new StreamWriter(rpRequest.GetRequestStream())) {
- sw.Write(queryString);
- }
- using (HttpWebResponse response = (HttpWebResponse)rpRequest.GetResponse()) {
- using (StreamReader sr = new StreamReader(response.GetResponseStream())) {
- string doc = sr.ReadToEnd();
- Debug.WriteLine(doc);
- }
- redirectToProviderUrl = new Uri(response.Headers[HttpResponseHeader.Location]);
- }
+ var rp = TestSupport.CreateRelyingParty(provideStore ? TestSupport.RelyingPartyStore : null, null, null);
- HttpWebRequest providerRequest = (HttpWebRequest)WebRequest.Create(redirectToProviderUrl);
- providerRequest.AllowAutoRedirect = false;
- Uri redirectUrl;
- try {
- using (HttpWebResponse providerResponse = (HttpWebResponse)providerRequest.GetResponse()) {
- Assert.AreEqual(HttpStatusCode.Redirect, providerResponse.StatusCode);
- redirectUrl = new Uri(providerResponse.Headers[HttpResponseHeader.Location]);
- }
- } catch (WebException ex) {
- Trace.WriteLine(ex);
- if (ex.Response != null) {
- using (StreamReader sr = new StreamReader(ex.Response.GetResponseStream())) {
- Trace.WriteLine(sr.ReadToEnd());
- }
- }
- throw;
- }
- rpRequest = (HttpWebRequest)WebRequest.Create(redirectUrl);
- rpRequest.AllowAutoRedirect = false;
- using (HttpWebResponse response = (HttpWebResponse)rpRequest.GetResponse()) {
- Assert.AreEqual(HttpStatusCode.Redirect, response.StatusCode); // redirect on login
- }
+ var returnTo = TestSupport.GetFullUrl(TestSupport.ConsumerPage);
+ var realm = new Realm(TestSupport.GetFullUrl(TestSupport.ConsumerPage).AbsoluteUri);
+ var request = rp.CreateRequest(opIdentifier, realm, returnTo);
+ request.Mode = requestMode;
- // Try replay attack
- if (tryReplayAttack) {
- // This simulates a network sniffing user who caught the
- // authenticating query en route to either the user agent or
- // the consumer, and tries the same query to the consumer in an
- // attempt to spoof the identity of the authenticating user.
- rpRequest = (HttpWebRequest)WebRequest.Create(redirectUrl);
- rpRequest.AllowAutoRedirect = false;
- using (HttpWebResponse response = (HttpWebResponse)rpRequest.GetResponse()) {
- Assert.AreEqual(HttpStatusCode.OK, response.StatusCode); // error message
- }
+ var rpResponse = TestSupport.CreateRelyingPartyResponseThroughProvider(request,
+ opReq => {
+ opReq.IsAuthenticated = expectedResult == AuthenticationStatus.Authenticated;
+ if (opReq.IsAuthenticated.Value) {
+ opReq.ClaimedIdentifier = claimedUrl;
+ }
+ });
+ Assert.AreEqual(expectedResult, rpResponse.Status);
+ if (rpResponse.Status == AuthenticationStatus.Authenticated) {
+ Assert.AreEqual(claimedUrl, rpResponse.ClaimedIdentifier);
+ } else if (rpResponse.Status == AuthenticationStatus.SetupRequired) {
+ Assert.IsNull(rpResponse.ClaimedIdentifier);
+ Assert.IsNull(rpResponse.FriendlyIdentifierForDisplay);
+ Assert.IsNull(rpResponse.Exception);
+ Assert.IsInstanceOfType(typeof(ISetupRequiredAuthenticationResponse), rpResponse);
+ Assert.AreEqual(opIdentifier.ToString(), ((ISetupRequiredAuthenticationResponse)rpResponse).ClaimedOrProviderIdentifier.ToString());
}
}
[Test]
public void Pass_Setup_AutoApproval_11() {
parameterizedTest(
- TestSupport.GetIdentityUrl(TestSupport.Scenarios.AutoApproval, ProtocolVersion.V11),
+ TestSupport.Scenarios.AutoApproval, ProtocolVersion.V11,
AuthenticationRequestMode.Setup,
- AuthenticationStatus.Authenticated,
- true,
- true
+ AuthenticationStatus.Authenticated
);
}
[Test]
public void Pass_Setup_AutoApproval_20() {
parameterizedTest(
- TestSupport.GetIdentityUrl(TestSupport.Scenarios.AutoApproval, ProtocolVersion.V20),
+ TestSupport.Scenarios.AutoApproval, ProtocolVersion.V20,
AuthenticationRequestMode.Setup,
- AuthenticationStatus.Authenticated,
- true,
- true
+ AuthenticationStatus.Authenticated
);
}
[Test]
public void Pass_Immediate_AutoApproval_11() {
parameterizedTest(
- TestSupport.GetIdentityUrl(TestSupport.Scenarios.AutoApproval, ProtocolVersion.V11),
+ TestSupport.Scenarios.AutoApproval, ProtocolVersion.V11,
AuthenticationRequestMode.Immediate,
- AuthenticationStatus.Authenticated,
- true,
- true
+ AuthenticationStatus.Authenticated
);
}
[Test]
public void Pass_Immediate_AutoApproval_20() {
parameterizedTest(
- TestSupport.GetIdentityUrl(TestSupport.Scenarios.AutoApproval, ProtocolVersion.V20),
+ TestSupport.Scenarios.AutoApproval, ProtocolVersion.V20,
AuthenticationRequestMode.Immediate,
- AuthenticationStatus.Authenticated,
- true,
- true
+ AuthenticationStatus.Authenticated
);
}
[Test]
public void Fail_Immediate_ApproveOnSetup_11() {
parameterizedTest(
- TestSupport.GetIdentityUrl(TestSupport.Scenarios.ApproveOnSetup, ProtocolVersion.V11),
+ TestSupport.Scenarios.ApproveOnSetup, ProtocolVersion.V11,
AuthenticationRequestMode.Immediate,
- AuthenticationStatus.SetupRequired,
- false,
- true
+ AuthenticationStatus.SetupRequired
);
}
[Test]
public void Fail_Immediate_ApproveOnSetup_20() {
parameterizedTest(
- TestSupport.GetIdentityUrl(TestSupport.Scenarios.ApproveOnSetup, ProtocolVersion.V20),
+ TestSupport.Scenarios.ApproveOnSetup, ProtocolVersion.V20,
AuthenticationRequestMode.Immediate,
- AuthenticationStatus.SetupRequired,
- false,
- true
+ AuthenticationStatus.SetupRequired
);
}
[Test]
public void Pass_Setup_ApproveOnSetup_11() {
parameterizedTest(
- TestSupport.GetIdentityUrl(TestSupport.Scenarios.ApproveOnSetup, ProtocolVersion.V11),
+ TestSupport.Scenarios.ApproveOnSetup, ProtocolVersion.V11,
AuthenticationRequestMode.Setup,
- AuthenticationStatus.Authenticated,
- true,
- true
+ AuthenticationStatus.Authenticated
);
}
[Test]
public void Pass_Setup_ApproveOnSetup_20() {
parameterizedTest(
- TestSupport.GetIdentityUrl(TestSupport.Scenarios.ApproveOnSetup, ProtocolVersion.V20),
+ TestSupport.Scenarios.ApproveOnSetup, ProtocolVersion.V20,
AuthenticationRequestMode.Setup,
- AuthenticationStatus.Authenticated,
- true,
- true
+ AuthenticationStatus.Authenticated
);
}
[Test]
- public void Pass_NoStore_AutoApproval_11() {
- parameterizedTest(
- TestSupport.GetIdentityUrl(TestSupport.Scenarios.ApproveOnSetup, ProtocolVersion.V11),
+ public void Pass_Immediate_AutoApproval_DirectedIdentity_20() {
+ parameterizedOPIdentifierTest(
+ TestSupport.Scenarios.AutoApproval,
+ AuthenticationRequestMode.Immediate,
+ AuthenticationStatus.Authenticated);
+ }
+
+ [Test]
+ public void Pass_Setup_ApproveOnSetup_DirectedIdentity_20() {
+ parameterizedOPIdentifierTest(
+ TestSupport.Scenarios.ApproveOnSetup,
AuthenticationRequestMode.Setup,
- AuthenticationStatus.Authenticated,
- true,
- false
- );
+ AuthenticationStatus.Authenticated);
}
+
[Test]
- public void Pass_NoStore_AutoApproval_20() {
- parameterizedTest(
- TestSupport.GetIdentityUrl(TestSupport.Scenarios.ApproveOnSetup, ProtocolVersion.V20),
+ public void Fail_Immediate_ApproveOnSetup_DirectedIdentity_20() {
+ parameterizedOPIdentifierTest(
+ TestSupport.Scenarios.ApproveOnSetup,
+ AuthenticationRequestMode.Immediate,
+ AuthenticationStatus.SetupRequired);
+ }
+
+ [Test]
+ public void ProviderAddedFragmentRemainsInClaimedIdentifier() {
+ Identifier userSuppliedIdentifier = TestSupport.GetMockIdentifier(TestSupport.Scenarios.AutoApprovalAddFragment, ProtocolVersion.V20);
+ UriBuilder claimedIdentifier = new UriBuilder(userSuppliedIdentifier);
+ claimedIdentifier.Fragment = "frag";
+ parameterizedProgrammaticTest(
+ TestSupport.Scenarios.AutoApprovalAddFragment, ProtocolVersion.V20,
+ claimedIdentifier.Uri,
AuthenticationRequestMode.Setup,
AuthenticationStatus.Authenticated,
true,
- false
- );
+ false);
+ }
+
+ [Test]
+ public void SampleScriptedTest() {
+ var rpReq = TestSupport.CreateRelyingPartyRequest(false, TestSupport.Scenarios.AutoApproval, ProtocolVersion.V20, false);
+ var rpResp = TestSupport.CreateRelyingPartyResponseThroughProvider(rpReq, opReq => opReq.IsAuthenticated = true);
+ Assert.AreEqual(AuthenticationStatus.Authenticated, rpResp.Status);
}
}
}
diff --git a/src/DotNetOpenId.Test/Extensions/AttributeExchangeTests.cs b/src/DotNetOpenId.Test/Extensions/AttributeExchangeTests.cs index 62efbc2..892d974 100644 --- a/src/DotNetOpenId.Test/Extensions/AttributeExchangeTests.cs +++ b/src/DotNetOpenId.Test/Extensions/AttributeExchangeTests.cs @@ -17,10 +17,10 @@ namespace DotNetOpenId.Test.Extensions { [Test]
public void None() {
var fetchResponse = ParameterizedTest<FetchResponse>(
- TestSupport.GetIdentityUrl(TestSupport.Scenarios.ExtensionFullCooperation, Version), null);
+ TestSupport.Scenarios.ExtensionFullCooperation, Version, null);
Assert.IsNull(fetchResponse);
var storeResponse = ParameterizedTest<StoreResponse>(
- TestSupport.GetIdentityUrl(TestSupport.Scenarios.ExtensionFullCooperation, Version), null);
+ TestSupport.Scenarios.ExtensionFullCooperation, Version, null);
Assert.IsNull(storeResponse);
}
@@ -30,7 +30,7 @@ namespace DotNetOpenId.Test.Extensions { request.AddAttribute(new AttributeRequest(nicknameTypeUri));
request.AddAttribute(new AttributeRequest(emailTypeUri, false, int.MaxValue));
var response = ParameterizedTest<FetchResponse>(
- TestSupport.GetIdentityUrl(TestSupport.Scenarios.ExtensionFullCooperation, Version), request);
+ TestSupport.Scenarios.ExtensionFullCooperation, Version, request);
Assert.IsNotNull(response);
var att = response.GetAttribute(nicknameTypeUri);
Assert.IsNotNull(att);
@@ -50,7 +50,7 @@ namespace DotNetOpenId.Test.Extensions { var request = new FetchRequest();
request.AddAttribute(new AttributeRequest { TypeUri = emailTypeUri, Count = 1 });
var response = ParameterizedTest<FetchResponse>(
- TestSupport.GetIdentityUrl(TestSupport.Scenarios.ExtensionFullCooperation, Version), request);
+ TestSupport.Scenarios.ExtensionFullCooperation, Version, request);
Assert.IsNotNull(response);
var att = response.GetAttribute(emailTypeUri);
Assert.IsNotNull(att);
@@ -69,7 +69,7 @@ namespace DotNetOpenId.Test.Extensions { request.AddAttribute(newAttribute);
var response = ParameterizedTest<StoreResponse>(
- TestSupport.GetIdentityUrl(TestSupport.Scenarios.ExtensionFullCooperation, Version), request);
+ TestSupport.Scenarios.ExtensionFullCooperation, Version, request);
Assert.IsNotNull(response);
Assert.IsTrue(response.Succeeded);
Assert.IsNull(response.FailureReason);
@@ -77,7 +77,7 @@ namespace DotNetOpenId.Test.Extensions { var fetchRequest = new FetchRequest();
fetchRequest.AddAttribute(new AttributeRequest { TypeUri = incrementingAttribute });
var fetchResponse = ParameterizedTest<FetchResponse>(
- TestSupport.GetIdentityUrl(TestSupport.Scenarios.ExtensionFullCooperation, Version), fetchRequest);
+ TestSupport.Scenarios.ExtensionFullCooperation, Version, fetchRequest);
Assert.IsNotNull(fetchResponse);
var att = fetchResponse.GetAttribute(incrementingAttribute);
Assert.IsNotNull(att);
@@ -92,11 +92,7 @@ namespace DotNetOpenId.Test.Extensions { /// </summary>
[Test, ExpectedException(typeof(OpenIdException))]
public void FetchAndStore() {
- var identityUrl = TestSupport.GetIdentityUrl(TestSupport.Scenarios.ExtensionFullCooperation, Version);
- var returnTo = TestSupport.GetFullUrl(TestSupport.ConsumerPage);
- var realm = new Realm(TestSupport.GetFullUrl(TestSupport.ConsumerPage).AbsoluteUri);
- var consumer = new OpenIdRelyingParty(AppStore, null, null);
- var request = consumer.CreateRequest(identityUrl, realm, returnTo);
+ var request = TestSupport.CreateRelyingPartyRequest(false, TestSupport.Scenarios.ExtensionFullCooperation, Version, false);
request.AddExtension(new FetchRequest());
request.AddExtension(new StoreRequest());
}
diff --git a/src/DotNetOpenId.Test/ProfileFieldValuesTests.cs b/src/DotNetOpenId.Test/Extensions/ClaimsResponseTests.cs index 51f6eca..afc2e03 100644 --- a/src/DotNetOpenId.Test/ProfileFieldValuesTests.cs +++ b/src/DotNetOpenId.Test/Extensions/ClaimsResponseTests.cs @@ -16,11 +16,11 @@ using NUnit.Framework; using DotNetOpenId.Extensions.SimpleRegistration;
using DotNetOpenId.Extensions;
-namespace DotNetOpenId.Test {
+namespace DotNetOpenId.Test.Extensions {
[TestFixture]
- public class ProfileFieldValuesTests {
+ public class ClaimsResponseTests {
ClaimsResponse getFilledData() {
- return new ClaimsResponse() {
+ return new ClaimsResponse(Constants.sreg_ns) {
BirthDate = new DateTime(2005, 2, 3),
Culture = new System.Globalization.CultureInfo("en-US"),
Email = "a@b.com",
@@ -33,6 +33,13 @@ namespace DotNetOpenId.Test { }
[Test]
+ public void EmptyMailAddress() {
+ ClaimsResponse response = new ClaimsResponse(Constants.sreg_ns);
+ response.Email = "";
+ Assert.IsNull(response.MailAddress);
+ }
+
+ [Test]
public void BinarySerialization() {
ClaimsResponse fields = getFilledData();
MemoryStream ms = new MemoryStream();
@@ -104,6 +111,26 @@ namespace DotNetOpenId.Test { Assert.AreNotEqual(fields1, fields2);
}
+ void parameterizedPreserveVersionFromRequest(string versionTypeUri) {
+ Dictionary<string, string> fields = new Dictionary<string, string>{
+ {"optional", "nickname"},
+ };
+ var req = new ClaimsRequest();
+ Assert.IsTrue(((IExtensionRequest)req).Deserialize(fields, null, versionTypeUri));
+ Assert.AreEqual(DemandLevel.Request, req.Nickname);
+ ClaimsResponse resp = req.CreateResponse();
+ Assert.AreEqual(versionTypeUri, ((IExtensionResponse)resp).TypeUri);
+ }
+
+ [Test]
+ public void PreserveVersionFromRequest() {
+ // some unofficial type URIs...
+ parameterizedPreserveVersionFromRequest("http://openid.net/sreg/1.0");
+ parameterizedPreserveVersionFromRequest("http://openid.net/sreg/1.1");
+ // and the official one.
+ parameterizedPreserveVersionFromRequest("http://openid.net/extensions/sreg/1.1");
+ }
+
//[Test]
public void AddToResponse() {
// TODO
diff --git a/src/DotNetOpenId.Test/Extensions/ExtensionTestBase.cs b/src/DotNetOpenId.Test/Extensions/ExtensionTestBase.cs index 825ef58..5958f0e 100644 --- a/src/DotNetOpenId.Test/Extensions/ExtensionTestBase.cs +++ b/src/DotNetOpenId.Test/Extensions/ExtensionTestBase.cs @@ -1,56 +1,128 @@ using System;
using System.Collections.Generic;
-using System.Linq;
-using System.Text;
+using DotNetOpenId.Extensions;
+using DotNetOpenId.Extensions.AttributeExchange;
+using DotNetOpenId.Extensions.ProviderAuthenticationPolicy;
+using DotNetOpenId.Extensions.SimpleRegistration;
using DotNetOpenId.RelyingParty;
using NUnit.Framework;
-using System.Net;
-using DotNetOpenId.Extensions;
-using System.IO;
-using System.Diagnostics;
-using System.Web;
+using OPRequest = DotNetOpenId.Provider.IAuthenticationRequest;
+using SregDemandLevel = DotNetOpenId.Extensions.SimpleRegistration.DemandLevel;
+using PapeConstants = DotNetOpenId.Extensions.ProviderAuthenticationPolicy.Constants;
namespace DotNetOpenId.Test.Extensions {
public class ExtensionTestBase {
- protected IRelyingPartyApplicationStore AppStore;
protected const ProtocolVersion Version = ProtocolVersion.V20;
+ Dictionary<string, AttributeValues> storedAttributes;
[SetUp]
public virtual void Setup() {
- AppStore = new ApplicationMemoryStore();
+ storedAttributes = new Dictionary<string, AttributeValues>();
+ }
+
+ [TearDown]
+ public virtual void TearDown() {
+ Mocks.MockHttpRequest.Reset();
}
- protected T ParameterizedTest<T>(Identifier identityUrl, IExtensionRequest extension)
+ protected T ParameterizedTest<T>(TestSupport.Scenarios scenario, ProtocolVersion version, IExtensionRequest extension)
where T : IExtensionResponse, new() {
- Debug.Assert(identityUrl != null);
- var returnTo = TestSupport.GetFullUrl(TestSupport.ConsumerPage);
- var realm = new Realm(TestSupport.GetFullUrl(TestSupport.ConsumerPage).AbsoluteUri);
- var consumer = new OpenIdRelyingParty(AppStore, null, null);
- var request = consumer.CreateRequest(identityUrl, realm, returnTo);
+ var rpRequest = TestSupport.CreateRelyingPartyRequest(false, scenario, version, false);
if (extension != null)
- request.AddExtension(extension);
-
- HttpWebRequest providerRequest = (HttpWebRequest)WebRequest.Create(request.RedirectingResponse.ExtractUrl());
- providerRequest.AllowAutoRedirect = false;
- Uri redirectUrl;
- try {
- using (HttpWebResponse providerResponse = (HttpWebResponse)providerRequest.GetResponse()) {
- Assert.AreEqual(HttpStatusCode.Redirect, providerResponse.StatusCode);
- redirectUrl = new Uri(providerResponse.Headers[HttpResponseHeader.Location]);
- }
- } catch (WebException ex) {
- Trace.WriteLine(ex);
- if (ex.Response != null) {
- using (StreamReader sr = new StreamReader(ex.Response.GetResponseStream())) {
- Trace.WriteLine(sr.ReadToEnd());
+ rpRequest.AddExtension(extension);
+
+ var response = TestSupport.CreateRelyingPartyResponseThroughProvider(rpRequest, request => {
+ TestSupport.SetAuthenticationFromScenario(scenario, request);
+ ExtensionsResponder(request);
+ });
+ Assert.AreEqual(AuthenticationStatus.Authenticated, response.Status);
+ return response.GetExtension<T>();
+ }
+
+ const string nicknameTypeUri = WellKnownAttributes.Name.Alias;
+ const string emailTypeUri = WellKnownAttributes.Contact.Email;
+
+ private void ExtensionsResponder(OPRequest request) {
+ var sregRequest = request.GetExtension<ClaimsRequest>();
+ var sregResponse = sregRequest != null ? sregRequest.CreateResponse() : null;
+ var aeFetchRequest = request.GetExtension<FetchRequest>();
+ var aeFetchResponse = new FetchResponse();
+ var aeStoreRequest = request.GetExtension<StoreRequest>();
+ var aeStoreResponse = new StoreResponse();
+ var papeRequest = request.GetExtension<PolicyRequest>();
+ var papeResponse = new PolicyResponse();
+
+ TestSupport.Scenarios scenario = (TestSupport.Scenarios)Enum.Parse(typeof(TestSupport.Scenarios),
+ new Uri(request.LocalIdentifier).AbsolutePath.TrimStart('/'));
+ switch (scenario) {
+ case TestSupport.Scenarios.ExtensionFullCooperation:
+ if (sregRequest != null) {
+ if (sregRequest.FullName != SregDemandLevel.NoRequest)
+ sregResponse.FullName = "Andrew Arnott";
+ if (sregRequest.Email != SregDemandLevel.NoRequest)
+ sregResponse.Email = "andrewarnott@gmail.com";
+ }
+ if (aeFetchRequest != null) {
+ var att = aeFetchRequest.GetAttribute(nicknameTypeUri);
+ if (att != null)
+ aeFetchResponse.AddAttribute(att.Respond("Andrew"));
+ att = aeFetchRequest.GetAttribute(emailTypeUri);
+ if (att != null) {
+ string[] emails = new[] { "a@a.com", "b@b.com" };
+ string[] subset = new string[Math.Min(emails.Length, att.Count)];
+ Array.Copy(emails, subset, subset.Length);
+ aeFetchResponse.AddAttribute(att.Respond(subset));
+ }
+ foreach (var att2 in aeFetchRequest.Attributes) {
+ if (storedAttributes.ContainsKey(att2.TypeUri))
+ aeFetchResponse.AddAttribute(storedAttributes[att2.TypeUri]);
+ }
+ }
+ if (papeRequest != null) {
+ if (papeRequest.MaximumAuthenticationAge.HasValue) {
+ papeResponse.AuthenticationTimeUtc = DateTime.UtcNow - (papeRequest.MaximumAuthenticationAge.Value - TimeSpan.FromSeconds(30));
+ }
+ if (papeRequest.PreferredAuthLevelTypes.Contains(PapeConstants.AuthenticationLevels.NistTypeUri)) {
+ papeResponse.NistAssuranceLevel = NistAssuranceLevel.Level1;
+ }
}
+ break;
+ case TestSupport.Scenarios.ExtensionPartialCooperation:
+ if (sregRequest != null) {
+ if (sregRequest.FullName == SregDemandLevel.Require)
+ sregResponse.FullName = "Andrew Arnott";
+ if (sregRequest.Email == SregDemandLevel.Require)
+ sregResponse.Email = "andrewarnott@gmail.com";
+ }
+ if (aeFetchRequest != null) {
+ var att = aeFetchRequest.GetAttribute(nicknameTypeUri);
+ if (att != null && att.IsRequired)
+ aeFetchResponse.AddAttribute(att.Respond("Andrew"));
+ att = aeFetchRequest.GetAttribute(emailTypeUri);
+ if (att != null && att.IsRequired) {
+ string[] emails = new[] { "a@a.com", "b@b.com" };
+ string[] subset = new string[Math.Min(emails.Length, att.Count)];
+ Array.Copy(emails, subset, subset.Length);
+ aeFetchResponse.AddAttribute(att.Respond(subset));
+ }
+ foreach (var att2 in aeFetchRequest.Attributes) {
+ if (att2.IsRequired && storedAttributes.ContainsKey(att2.TypeUri))
+ aeFetchResponse.AddAttribute(storedAttributes[att2.TypeUri]);
+ }
+ }
+ break;
+ }
+ if (aeStoreRequest != null) {
+ foreach (var att in aeStoreRequest.Attributes) {
+ storedAttributes[att.TypeUri] = att;
}
- throw;
+ aeStoreResponse.Succeeded = true;
}
- consumer = new OpenIdRelyingParty(AppStore, redirectUrl, HttpUtility.ParseQueryString(redirectUrl.Query));
- Assert.AreEqual(AuthenticationStatus.Authenticated, consumer.Response.Status);
- Assert.AreEqual(identityUrl, consumer.Response.ClaimedIdentifier);
- return consumer.Response.GetExtension<T>();
+
+ if (sregRequest != null) request.AddResponseExtension(sregResponse);
+ if (aeFetchRequest != null) request.AddResponseExtension(aeFetchResponse);
+ if (aeStoreRequest != null) request.AddResponseExtension(aeStoreResponse);
+ if (papeRequest != null) request.AddResponseExtension(papeResponse);
}
}
}
diff --git a/src/DotNetOpenId.Test/Extensions/PapeTests.cs b/src/DotNetOpenId.Test/Extensions/PapeTests.cs index f8acb79..6fb693d 100644 --- a/src/DotNetOpenId.Test/Extensions/PapeTests.cs +++ b/src/DotNetOpenId.Test/Extensions/PapeTests.cs @@ -11,7 +11,7 @@ namespace DotNetOpenId.Test.Extensions { [Test]
public void None() {
var response = ParameterizedTest<PolicyResponse>(
- TestSupport.GetIdentityUrl(TestSupport.Scenarios.ExtensionFullCooperation, Version), null);
+ TestSupport.Scenarios.ExtensionFullCooperation, Version, null);
Assert.IsNull(response);
}
@@ -19,11 +19,15 @@ namespace DotNetOpenId.Test.Extensions { public void Full() {
var request = new PolicyRequest();
request.MaximumAuthenticationAge = TimeSpan.FromMinutes(10);
+ request.PreferredAuthLevelTypes.Add(Constants.AuthenticationLevels.NistTypeUri);
var response = ParameterizedTest<PolicyResponse>(
- TestSupport.GetIdentityUrl(TestSupport.Scenarios.ExtensionFullCooperation, Version), request);
+ TestSupport.Scenarios.ExtensionFullCooperation, Version, request);
Assert.IsNotNull(response);
Assert.IsNotNull(response.AuthenticationTimeUtc);
Assert.IsTrue(response.AuthenticationTimeUtc.Value > DateTime.UtcNow - request.MaximumAuthenticationAge);
+ Assert.IsTrue(response.AssuranceLevels.ContainsKey(Constants.AuthenticationLevels.NistTypeUri));
+ Assert.AreEqual("1", response.AssuranceLevels[Constants.AuthenticationLevels.NistTypeUri]);
+ Assert.AreEqual(NistAssuranceLevel.Level1, response.NistAssuranceLevel);
}
}
}
diff --git a/src/DotNetOpenId.Test/Extensions/PolicyRequestTests.cs b/src/DotNetOpenId.Test/Extensions/PolicyRequestTests.cs index 5a46327..40155db 100644 --- a/src/DotNetOpenId.Test/Extensions/PolicyRequestTests.cs +++ b/src/DotNetOpenId.Test/Extensions/PolicyRequestTests.cs @@ -5,6 +5,7 @@ using System.Text; using NUnit.Framework;
using DotNetOpenId.Extensions.ProviderAuthenticationPolicy;
using DotNetOpenId.Extensions;
+using System.Globalization;
namespace DotNetOpenId.Test.Extensions {
[TestFixture]
@@ -50,6 +51,14 @@ namespace DotNetOpenId.Test.Extensions { }
[Test]
+ public void AddAuthLevelTypes() {
+ PolicyRequest req = new PolicyRequest();
+ req.PreferredAuthLevelTypes.Add(Constants.AuthenticationLevels.NistTypeUri);
+ Assert.AreEqual(1, req.PreferredAuthLevelTypes.Count);
+ Assert.IsTrue(req.PreferredAuthLevelTypes.Contains(Constants.AuthenticationLevels.NistTypeUri));
+ }
+
+ [Test]
public void EqualsTest() {
PolicyRequest req = new PolicyRequest();
PolicyRequest req2 = new PolicyRequest();
@@ -77,18 +86,27 @@ namespace DotNetOpenId.Test.Extensions { Assert.AreNotEqual(req, req2);
req2.MaximumAuthenticationAge = req.MaximumAuthenticationAge;
Assert.AreEqual(req, req2);
+
+ // Test PreferredAuthLevelTypes comparison.
+ req.PreferredAuthLevelTypes.Add("authlevel1");
+ Assert.AreNotEqual(req, req2);
+ req2.PreferredAuthLevelTypes.Add("authlevel2");
+ Assert.AreNotEqual(req, req2);
+ req.PreferredAuthLevelTypes.Add("authlevel2");
+ req2.PreferredAuthLevelTypes.Add("authlevel1");
+ Assert.AreEqual(req, req2);
}
[Test]
public void DeserializeNull() {
PolicyRequest req = new PolicyRequest();
- Assert.IsFalse(((IExtensionRequest)req).Deserialize(null, null));
+ Assert.IsFalse(((IExtensionRequest)req).Deserialize(null, null, Constants.TypeUri));
}
[Test]
public void DeserializeEmpty() {
PolicyRequest req = new PolicyRequest();
- Assert.IsFalse(((IExtensionRequest)req).Deserialize(new Dictionary<string, string>(), null));
+ Assert.IsFalse(((IExtensionRequest)req).Deserialize(new Dictionary<string, string>(), null, Constants.TypeUri));
}
[Test]
@@ -99,35 +117,78 @@ namespace DotNetOpenId.Test.Extensions { // Most basic test
PolicyRequest req = new PolicyRequest(), req2 = new PolicyRequest();
var fields = ((IExtensionRequest)req).Serialize(null);
- Assert.IsTrue(((IExtensionRequest)req2).Deserialize(fields, null));
+ Assert.IsTrue(((IExtensionRequest)req2).Deserialize(fields, null, Constants.TypeUri));
Assert.AreEqual(req, req2);
// Test with all fields set
req2 = new PolicyRequest();
req.PreferredPolicies.Add(AuthenticationPolicies.MultiFactor);
+ req.PreferredAuthLevelTypes.Add(Constants.AuthenticationLevels.NistTypeUri);
req.MaximumAuthenticationAge = TimeSpan.FromHours(1);
fields = ((IExtensionRequest)req).Serialize(null);
- Assert.IsTrue(((IExtensionRequest)req2).Deserialize(fields, null));
+ Assert.IsTrue(((IExtensionRequest)req2).Deserialize(fields, null, Constants.TypeUri));
Assert.AreEqual(req, req2);
- // Test with an extra policy
+ // Test with an extra policy and auth level
req2 = new PolicyRequest();
req.PreferredPolicies.Add(AuthenticationPolicies.PhishingResistant);
+ req.PreferredAuthLevelTypes.Add("customAuthLevel");
fields = ((IExtensionRequest)req).Serialize(null);
- Assert.IsTrue(((IExtensionRequest)req2).Deserialize(fields, null));
+ Assert.IsTrue(((IExtensionRequest)req2).Deserialize(fields, null, Constants.TypeUri));
Assert.AreEqual(req, req2);
// Test with a policy added twice. We should see it intelligently leave one of
// the doubled policies out.
req2 = new PolicyRequest();
req.PreferredPolicies.Add(AuthenticationPolicies.PhishingResistant);
+ req.PreferredAuthLevelTypes.Add(Constants.AuthenticationLevels.NistTypeUri);
fields = ((IExtensionRequest)req).Serialize(null);
- Assert.IsTrue(((IExtensionRequest)req2).Deserialize(fields, null));
+ Assert.IsTrue(((IExtensionRequest)req2).Deserialize(fields, null, Constants.TypeUri));
Assert.AreNotEqual(req, req2);
// Now go ahead and add the doubled one so we can do our equality test.
req2.PreferredPolicies.Add(AuthenticationPolicies.PhishingResistant);
+ req2.PreferredAuthLevelTypes.Add(Constants.AuthenticationLevels.NistTypeUri);
Assert.AreEqual(req, req2);
+ }
+ [Test]
+ public void Serialize() {
+ PolicyRequest req = new PolicyRequest();
+ var fields = ((IExtensionRequest)req).Serialize(null);
+ Assert.AreEqual(1, fields.Count);
+ Assert.IsTrue(fields.ContainsKey("preferred_auth_policies"));
+ Assert.IsEmpty(fields["preferred_auth_policies"]);
+
+ req.MaximumAuthenticationAge = TimeSpan.FromHours(1);
+ fields = ((IExtensionRequest)req).Serialize(null);
+ Assert.AreEqual(2, fields.Count);
+ Assert.IsTrue(fields.ContainsKey("max_auth_age"));
+ Assert.AreEqual(TimeSpan.FromHours(1).TotalSeconds.ToString(CultureInfo.InvariantCulture), fields["max_auth_age"]);
+
+ req.PreferredPolicies.Add("http://pol1/");
+ fields = ((IExtensionRequest)req).Serialize(null);
+ Assert.AreEqual("http://pol1/", fields["preferred_auth_policies"]);
+
+ req.PreferredPolicies.Add("http://pol2/");
+ fields = ((IExtensionRequest)req).Serialize(null);
+ Assert.AreEqual("http://pol1/ http://pol2/", fields["preferred_auth_policies"]);
+
+ req.PreferredAuthLevelTypes.Add("http://authtype1/");
+ fields = ((IExtensionRequest)req).Serialize(null);
+ Assert.AreEqual(4, fields.Count);
+ Assert.IsTrue(fields.ContainsKey("auth_level.ns.alias1"));
+ Assert.AreEqual("http://authtype1/", fields["auth_level.ns.alias1"]);
+ Assert.IsTrue(fields.ContainsKey("preferred_auth_level_types"));
+ Assert.AreEqual("alias1", fields["preferred_auth_level_types"]);
+
+ req.PreferredAuthLevelTypes.Add(Constants.AuthenticationLevels.NistTypeUri);
+ fields = ((IExtensionRequest)req).Serialize(null);
+ Assert.AreEqual(5, fields.Count);
+ Assert.IsTrue(fields.ContainsKey("auth_level.ns.alias2"));
+ Assert.AreEqual("http://authtype1/", fields["auth_level.ns.alias2"]);
+ Assert.IsTrue(fields.ContainsKey("auth_level.ns.nist"));
+ Assert.AreEqual(Constants.AuthenticationLevels.NistTypeUri, fields["auth_level.ns.nist"]);
+ Assert.AreEqual("alias2 nist", fields["preferred_auth_level_types"]);
}
}
}
diff --git a/src/DotNetOpenId.Test/Extensions/PolicyResponseTests.cs b/src/DotNetOpenId.Test/Extensions/PolicyResponseTests.cs index 6aefaaa..7fe240b 100644 --- a/src/DotNetOpenId.Test/Extensions/PolicyResponseTests.cs +++ b/src/DotNetOpenId.Test/Extensions/PolicyResponseTests.cs @@ -88,6 +88,19 @@ namespace DotNetOpenId.Test.Extensions { }
[Test]
+ public void AssuranceLevels() {
+ PolicyResponse resp = new PolicyResponse();
+ Assert.AreEqual(0, resp.AssuranceLevels.Count);
+ resp.NistAssuranceLevel = NistAssuranceLevel.Level2;
+ Assert.AreEqual(1, resp.AssuranceLevels.Count);
+ Assert.AreEqual("2", resp.AssuranceLevels[Constants.AuthenticationLevels.NistTypeUri]);
+ resp.AssuranceLevels[Constants.AuthenticationLevels.NistTypeUri] = "3";
+ Assert.AreEqual(NistAssuranceLevel.Level3, resp.NistAssuranceLevel);
+ resp.AssuranceLevels.Clear();
+ Assert.IsNull(resp.NistAssuranceLevel);
+ }
+
+ [Test]
public void EqualsTest() {
PolicyResponse resp = new PolicyResponse();
PolicyResponse resp2 = new PolicyResponse();
@@ -129,18 +142,30 @@ namespace DotNetOpenId.Test.Extensions { Assert.AreNotEqual(resp, resp2);
resp2.NistAssuranceLevel = NistAssuranceLevel.Level2;
Assert.AreEqual(resp, resp2);
+
+ // Test AssuranceLevels comparison.
+ resp.AssuranceLevels.Add("custom", "b");
+ Assert.AreNotEqual(resp, resp2);
+ resp2.AssuranceLevels.Add("custom", "2");
+ Assert.AreNotEqual(resp, resp2);
+ resp2.AssuranceLevels["custom"] = "b";
+ Assert.AreEqual(resp, resp2);
+ resp.AssuranceLevels[Constants.AuthenticationLevels.NistTypeUri] = "1";
+ Assert.AreNotEqual(resp, resp2);
+ resp2.AssuranceLevels[Constants.AuthenticationLevels.NistTypeUri] = "1";
+ Assert.AreEqual(resp, resp2);
}
[Test]
public void DeserializeNull() {
PolicyResponse resp = new PolicyResponse();
- Assert.IsFalse(((IExtensionResponse)resp).Deserialize(null, null));
+ Assert.IsFalse(((IExtensionResponse)resp).Deserialize(null, null, Constants.TypeUri));
}
[Test]
public void DeserializeEmpty() {
PolicyResponse resp = new PolicyResponse();
- Assert.IsFalse(((IExtensionResponse)resp).Deserialize(new Dictionary<string,string>(), null));
+ Assert.IsFalse(((IExtensionResponse)resp).Deserialize(new Dictionary<string, string>(), null, Constants.TypeUri));
}
[Test]
@@ -151,7 +176,7 @@ namespace DotNetOpenId.Test.Extensions { // Most basic test
PolicyResponse resp = new PolicyResponse(), resp2 = new PolicyResponse();
var fields = ((IExtensionResponse)resp).Serialize(null);
- Assert.IsTrue(((IExtensionResponse)resp2).Deserialize(fields, null));
+ Assert.IsTrue(((IExtensionResponse)resp2).Deserialize(fields, null, Constants.TypeUri));
Assert.AreEqual(resp, resp2);
// Test with all fields set
@@ -160,14 +185,15 @@ namespace DotNetOpenId.Test.Extensions { resp.AuthenticationTimeUtc = someUtcTime;
resp.NistAssuranceLevel = NistAssuranceLevel.Level2;
fields = ((IExtensionResponse)resp).Serialize(null);
- Assert.IsTrue(((IExtensionResponse)resp2).Deserialize(fields, null));
+ Assert.IsTrue(((IExtensionResponse)resp2).Deserialize(fields, null, Constants.TypeUri));
Assert.AreEqual(resp, resp2);
// Test with an extra policy
resp2 = new PolicyResponse();
resp.ActualPolicies.Add(AuthenticationPolicies.PhishingResistant);
+ resp.AssuranceLevels.Add("customlevel", "ABC");
fields = ((IExtensionResponse)resp).Serialize(null);
- Assert.IsTrue(((IExtensionResponse)resp2).Deserialize(fields, null));
+ Assert.IsTrue(((IExtensionResponse)resp2).Deserialize(fields, null, Constants.TypeUri));
Assert.AreEqual(resp, resp2);
// Test with a policy added twice. We should see it intelligently leave one of
@@ -175,11 +201,58 @@ namespace DotNetOpenId.Test.Extensions { resp2 = new PolicyResponse();
resp.ActualPolicies.Add(AuthenticationPolicies.PhishingResistant);
fields = ((IExtensionResponse)resp).Serialize(null);
- Assert.IsTrue(((IExtensionResponse)resp2).Deserialize(fields, null));
+ Assert.IsTrue(((IExtensionResponse)resp2).Deserialize(fields, null, Constants.TypeUri));
Assert.AreNotEqual(resp, resp2);
// Now go ahead and add the doubled one so we can do our equality test.
resp2.ActualPolicies.Add(AuthenticationPolicies.PhishingResistant);
Assert.AreEqual(resp, resp2);
}
+
+ [Test]
+ public void Serialize() {
+ PolicyResponse resp = new PolicyResponse(), resp2 = new PolicyResponse();
+ var fields = ((IExtensionResponse)resp).Serialize(null);
+ Assert.AreEqual(1, fields.Count);
+ Assert.IsTrue(fields.ContainsKey("auth_policies"));
+ Assert.AreEqual(AuthenticationPolicies.None, fields["auth_policies"]);
+
+ resp.ActualPolicies.Add(AuthenticationPolicies.PhishingResistant);
+ fields = ((IExtensionResponse)resp).Serialize(null);
+ Assert.AreEqual(1, fields.Count);
+ Assert.AreEqual(AuthenticationPolicies.PhishingResistant, fields["auth_policies"]);
+
+ resp.ActualPolicies.Add(AuthenticationPolicies.PhysicalMultiFactor);
+ fields = ((IExtensionResponse)resp).Serialize(null);
+ Assert.AreEqual(1, fields.Count);
+ Assert.AreEqual(
+ AuthenticationPolicies.PhishingResistant + " " + AuthenticationPolicies.PhysicalMultiFactor,
+ fields["auth_policies"]);
+
+ resp.AuthenticationTimeUtc = DateTime.UtcNow;
+ fields = ((IExtensionResponse)resp).Serialize(null);
+ Assert.AreEqual(2, fields.Count);
+ Assert.IsTrue(fields.ContainsKey("auth_time"));
+
+ resp.NistAssuranceLevel = NistAssuranceLevel.Level3;
+ fields = ((IExtensionResponse)resp).Serialize(null);
+ Assert.AreEqual(4, fields.Count);
+ Assert.IsTrue(fields.ContainsKey("auth_level.ns.nist"));
+ Assert.AreEqual(Constants.AuthenticationLevels.NistTypeUri, fields["auth_level.ns.nist"]);
+ Assert.IsTrue(fields.ContainsKey("auth_level.nist"));
+ Assert.AreEqual("3", fields["auth_level.nist"]);
+
+ resp.AssuranceLevels.Add("custom", "CU");
+ fields = ((IExtensionResponse)resp).Serialize(null);
+ Assert.AreEqual(6, fields.Count);
+ Assert.IsTrue(fields.ContainsKey("auth_level.ns.alias2"));
+ Assert.AreEqual("custom", fields["auth_level.ns.alias2"]);
+ Assert.IsTrue(fields.ContainsKey("auth_level.alias2"));
+ Assert.AreEqual("CU", fields["auth_level.alias2"]);
+ // and make sure the NIST is still there.
+ Assert.IsTrue(fields.ContainsKey("auth_level.ns.nist"));
+ Assert.AreEqual(Constants.AuthenticationLevels.NistTypeUri, fields["auth_level.ns.nist"]);
+ Assert.IsTrue(fields.ContainsKey("auth_level.nist"));
+ Assert.AreEqual("3", fields["auth_level.nist"]);
+ }
}
}
diff --git a/src/DotNetOpenId.Test/Extensions/SimpleRegistrationTests.cs b/src/DotNetOpenId.Test/Extensions/SimpleRegistrationTests.cs index 69942a5..9437f27 100644 --- a/src/DotNetOpenId.Test/Extensions/SimpleRegistrationTests.cs +++ b/src/DotNetOpenId.Test/Extensions/SimpleRegistrationTests.cs @@ -11,7 +11,7 @@ namespace DotNetOpenId.Test.Extensions { [Test]
public void None() {
var response = ParameterizedTest<ClaimsResponse>(
- TestSupport.GetIdentityUrl(TestSupport.Scenarios.ExtensionFullCooperation, Version), null);
+ TestSupport.Scenarios.ExtensionFullCooperation, Version, null);
Assert.IsNull(response);
}
@@ -21,7 +21,7 @@ namespace DotNetOpenId.Test.Extensions { request.FullName = DemandLevel.Request;
request.Email = DemandLevel.Require;
var response = ParameterizedTest<ClaimsResponse>(
- TestSupport.GetIdentityUrl(TestSupport.Scenarios.ExtensionFullCooperation, Version), request);
+ TestSupport.Scenarios.ExtensionFullCooperation, Version, request);
Assert.AreEqual("Andrew Arnott", response.FullName);
Assert.AreEqual("andrewarnott@gmail.com", response.Email);
}
@@ -31,7 +31,7 @@ namespace DotNetOpenId.Test.Extensions { request.FullName = DemandLevel.Request;
request.Email = DemandLevel.Require;
var response = ParameterizedTest<ClaimsResponse>(
- TestSupport.GetIdentityUrl(TestSupport.Scenarios.ExtensionPartialCooperation, Version), request);
+ TestSupport.Scenarios.ExtensionPartialCooperation, Version, request);
Assert.IsNull(response.FullName);
Assert.AreEqual("andrewarnott@gmail.com", response.Email);
}
diff --git a/src/DotNetOpenId.Test/Hosting/AspNetHost.cs b/src/DotNetOpenId.Test/Hosting/AspNetHost.cs index 844c040..47480f2 100644 --- a/src/DotNetOpenId.Test/Hosting/AspNetHost.cs +++ b/src/DotNetOpenId.Test/Hosting/AspNetHost.cs @@ -21,13 +21,9 @@ namespace DotNetOpenId.Test.Hosting { httpHost = HttpHost.CreateHost(this);
if (!UntrustedWebRequest.WhitelistHosts.Contains("localhost"))
UntrustedWebRequest.WhitelistHosts.Add("localhost");
- DotNetOpenId.Provider.SigningMessageEncoder.Signing += (s, e) => {
- if (MessageInterceptor != null) MessageInterceptor.OnSigningMessage(e.Message);
- };
}
public Uri BaseUri { get { return httpHost.BaseUri; } }
- public EncodingInterceptor MessageInterceptor { get; set; }
public static AspNetHost CreateHost(string webDirectory) {
AspNetHost host = (AspNetHost)ApplicationHost.
@@ -48,8 +44,13 @@ namespace DotNetOpenId.Test.Hosting { }
public void ProcessRequest(HttpListenerContext context) {
- using (TextWriter tw = new StreamWriter(context.Response.OutputStream)) {
- HttpRuntime.ProcessRequest(new TestingWorkerRequest(context, tw));
+ try {
+ using (TextWriter tw = new StreamWriter(context.Response.OutputStream)) {
+ HttpRuntime.ProcessRequest(new TestingWorkerRequest(context, tw));
+ }
+ } catch (Exception ex) {
+ TestSupport.Logger.Error("Exception in AspNetHost", ex);
+ throw;
}
}
diff --git a/src/DotNetOpenId.Test/Hosting/EncodingInterceptor.cs b/src/DotNetOpenId.Test/Hosting/EncodingInterceptor.cs deleted file mode 100644 index 0759ba2..0000000 --- a/src/DotNetOpenId.Test/Hosting/EncodingInterceptor.cs +++ /dev/null @@ -1,30 +0,0 @@ -using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using DotNetOpenId.Provider;
-using System.Diagnostics;
-
-namespace DotNetOpenId.Test.Hosting {
- /// <remarks>
- /// This should be instantiated in the test app domain,
- /// and passed to the ASP.NET host app domain.
- /// </remarks>
- public class EncodingInterceptor : MarshalByRefObject {
- /// <summary>
- /// Forwards a call from the ASP.NET host on to any interested test.
- /// </summary>
- /// <param name="message"></param>
- internal void OnSigningMessage(IEncodable message) {
- if (SigningMessage != null) {
- try {
- SigningMessage(message);
- } catch (Exception e) {
- Trace.TraceWarning("Unhandled exception in cross app-domain event handler: {0}", e);
- }
- }
- }
- internal delegate void InterceptorHandler(IEncodable message);
- internal InterceptorHandler SigningMessage;
- }
-}
diff --git a/src/DotNetOpenId.Test/Hosting/HttpHost.cs b/src/DotNetOpenId.Test/Hosting/HttpHost.cs index 44a7363..dc69848 100644 --- a/src/DotNetOpenId.Test/Hosting/HttpHost.cs +++ b/src/DotNetOpenId.Test/Hosting/HttpHost.cs @@ -67,9 +67,18 @@ namespace DotNetOpenId.Test.Hosting { using (StreamWriter sw = new StreamWriter(request.GetRequestStream()))
sw.Write(body);
}
- using (WebResponse response = request.GetResponse()) {
- using (StreamReader sr = new StreamReader(response.GetResponseStream()))
- return sr.ReadToEnd();
+ try {
+ using (WebResponse response = request.GetResponse()) {
+ using (StreamReader sr = new StreamReader(response.GetResponseStream()))
+ return sr.ReadToEnd();
+ }
+ } catch (WebException ex) {
+ TestSupport.Logger.Error("Exception in HttpHost", ex);
+ using (StreamReader sr = new StreamReader(ex.Response.GetResponseStream())) {
+ string streamContent = sr.ReadToEnd();
+ TestSupport.Logger.ErrorFormat("Error content stream follows: {0}", streamContent);
+ }
+ throw;
}
}
diff --git a/src/DotNetOpenId.Test/IdentifierTests.cs b/src/DotNetOpenId.Test/IdentifierTests.cs index 0f13ae2..562ed90 100644 --- a/src/DotNetOpenId.Test/IdentifierTests.cs +++ b/src/DotNetOpenId.Test/IdentifierTests.cs @@ -51,9 +51,6 @@ namespace DotNetOpenId.Test { id = Identifier.Parse(uriNoScheme);
Assert.IsInstanceOfType(typeof(UriIdentifier), id);
Assert.AreEqual(uri, ((UriIdentifier)id).Uri.AbsoluteUri);
- // verify that fragments are stripped
- id = Identifier.Parse(uri + "#fragment");
- Assert.AreEqual(uri, ((UriIdentifier)id).Uri.AbsoluteUri);
}
[Test, ExpectedException(typeof(ArgumentNullException))]
diff --git a/src/DotNetOpenId.Test/Logging.config b/src/DotNetOpenId.Test/Logging.config new file mode 100644 index 0000000..184568b --- /dev/null +++ b/src/DotNetOpenId.Test/Logging.config @@ -0,0 +1,33 @@ +<?xml version="1.0" encoding="utf-8" ?>
+<log4net>
+ <appender name="RollingFileAppender" type="log4net.Appender.RollingFileAppender">
+ <file value="Testing.log" />
+ <appendToFile value="true" />
+ <rollingStyle value="Size" />
+ <maxSizeRollBackups value="10" />
+ <maximumFileSize value="1024KB" />
+ <staticLogFileName value="true" />
+ <layout type="log4net.Layout.PatternLayout">
+ <conversionPattern value="%date [%thread] %-5level %logger - %message%newline" />
+ </layout>
+ </appender>
+ <appender name="TraceAppender" type="log4net.Appender.TraceAppender">
+ <immediateFlush value="true" />
+ <layout type="log4net.Layout.PatternLayout">
+ <conversionPattern value="%-5level - %message%newline" />
+ </layout>
+ </appender>
+ <!-- Setup the root category, add the appenders and set the default level -->
+ <root>
+ <level value="Warn" />
+ <!--<appender-ref ref="RollingFileAppender" />-->
+ <appender-ref ref="TraceAppender" />
+ </root>
+ <!-- Specify the level for some specific categories -->
+ <logger name="DotNetOpenId">
+ <level value="Off" />
+ </logger>
+ <logger name="DotNetOpenId.Test">
+ <level value="Info" />
+ </logger>
+</log4net>
diff --git a/src/DotNetOpenId.Test/Mocks/DirectMessageSniffWrapper.cs b/src/DotNetOpenId.Test/Mocks/DirectMessageSniffWrapper.cs new file mode 100644 index 0000000..1bcbfb9 --- /dev/null +++ b/src/DotNetOpenId.Test/Mocks/DirectMessageSniffWrapper.cs @@ -0,0 +1,41 @@ +using System;
+using System.Collections.Generic;
+using DotNetOpenId.RelyingParty;
+
+namespace DotNetOpenId.Test.Mocks {
+ class DirectMessageSniffWrapper : IDirectMessageChannel {
+ IDirectMessageChannel channel;
+
+ internal DirectMessageSniffWrapper(IDirectMessageChannel channel) {
+ this.channel = channel;
+ }
+
+ internal event Action<ServiceEndpoint, IDictionary<string, string>> Sending;
+ internal event Action<ServiceEndpoint, IDictionary<string, string>> Receiving;
+
+ protected virtual void OnSending(ServiceEndpoint provider, IDictionary<string, string> fields) {
+ var sending = Sending;
+ if (sending != null) {
+ sending(provider, fields);
+ }
+ }
+
+ protected virtual void OnReceiving(ServiceEndpoint provider, IDictionary<string, string> fields) {
+ var receiving = Receiving;
+ if (receiving != null) {
+ receiving(provider, fields);
+ }
+ }
+
+ #region IDirectMessageChannel Members
+
+ public IDictionary<string, string> SendDirectMessageAndGetResponse(ServiceEndpoint provider, IDictionary<string, string> fields) {
+ OnSending(provider, fields);
+ var results = channel.SendDirectMessageAndGetResponse(provider, fields);
+ OnReceiving(provider, results);
+ return results;
+ }
+
+ #endregion
+ }
+}
diff --git a/src/DotNetOpenId.Test/Mocks/DirectMessageTestRedirector.cs b/src/DotNetOpenId.Test/Mocks/DirectMessageTestRedirector.cs new file mode 100644 index 0000000..c63e2de --- /dev/null +++ b/src/DotNetOpenId.Test/Mocks/DirectMessageTestRedirector.cs @@ -0,0 +1,31 @@ +using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using DotNetOpenId.Provider;
+using DotNetOpenId.RelyingParty;
+using IProviderAssociationStore = DotNetOpenId.IAssociationStore<DotNetOpenId.AssociationRelyingPartyType>;
+
+namespace DotNetOpenId.Test.Mocks {
+ class DirectMessageTestRedirector : IDirectMessageChannel {
+
+ IProviderAssociationStore providerStore;
+
+ public DirectMessageTestRedirector(IProviderAssociationStore providerStore) {
+ if (providerStore == null) throw new ArgumentNullException("providerStore");
+ this.providerStore = providerStore;
+ }
+
+ #region IDirectMessageChannel Members
+
+ public IDictionary<string, string> SendDirectMessageAndGetResponse(ServiceEndpoint providerEndpoint, IDictionary<string, string> fields) {
+ OpenIdProvider provider = new OpenIdProvider(providerStore, providerEndpoint.ProviderEndpoint,
+ providerEndpoint.ProviderEndpoint, fields.ToNameValueCollection());
+ Debug.Assert(provider.Request.IsResponseReady, "Direct messages should always have an immediately available response.");
+ Response webResponse = (Response)provider.Request.Response;
+ EncodableResponse opAuthResponse = (EncodableResponse)webResponse.EncodableMessage;
+ return opAuthResponse.EncodedFields;
+ }
+
+ #endregion
+ }
+}
diff --git a/src/DotNetOpenId.Test/Mocks/MockHttpRequest.cs b/src/DotNetOpenId.Test/Mocks/MockHttpRequest.cs new file mode 100644 index 0000000..1a0547c --- /dev/null +++ b/src/DotNetOpenId.Test/Mocks/MockHttpRequest.cs @@ -0,0 +1,175 @@ +using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.IO;
+using System.Net;
+using DotNetOpenId.RelyingParty;
+using DotNetOpenId.Yadis;
+using NUnit.Framework;
+using System.Diagnostics;
+using System.Web;
+using System.Text;
+
+namespace DotNetOpenId.Test.Mocks {
+ class MockHttpRequest {
+ static Dictionary<Uri, UntrustedWebResponse> registeredMockResponses = new Dictionary<Uri, UntrustedWebResponse>();
+
+ static UntrustedWebResponse MockRequestResponse(Uri uri, byte[] body, string[] acceptTypes) {
+ UntrustedWebResponse response;
+ if (registeredMockResponses.TryGetValue(uri, out response)) {
+ // reset response stream position so this response can be reused on a subsequent request.
+ response.ResponseStream.Seek(0, SeekOrigin.Begin);
+ return response;
+ } else {
+ //Assert.Fail("Unexpected HTTP request: {0}", uri);
+ return new UntrustedWebResponse(uri, uri, new WebHeaderCollection(), HttpStatusCode.NotFound,
+ "text/html", null, new MemoryStream());
+ }
+ }
+
+ /// <summary>
+ /// Clears all all mock HTTP responses and deactivates HTTP mocking.
+ /// </summary>
+ internal static void Reset() {
+ UntrustedWebRequest.MockRequests = null;
+ registeredMockResponses.Clear();
+ }
+
+ internal static void RegisterMockResponse(UntrustedWebResponse response) {
+ if (response == null) throw new ArgumentNullException("response");
+ UntrustedWebRequest.MockRequests = MockRequestResponse;
+ if (registeredMockResponses.ContainsKey(response.RequestUri)) {
+ TestSupport.Logger.WarnFormat("Mock HTTP response already registered for {0}.", response.RequestUri);
+ } else {
+ registeredMockResponses.Add(response.RequestUri, response);
+ }
+ }
+
+ internal static void RegisterMockResponse(Uri requestUri, string contentType, string responseBody) {
+ RegisterMockResponse(requestUri, requestUri, contentType, responseBody);
+ }
+
+ internal static void RegisterMockResponse(Uri requestUri, Uri responseUri, string contentType, string responseBody) {
+ RegisterMockResponse(requestUri, responseUri, contentType, new WebHeaderCollection(), responseBody);
+ }
+
+ internal static void RegisterMockResponse(Uri requestUri, Uri responseUri, string contentType, WebHeaderCollection headers, string responseBody) {
+ if (requestUri == null) throw new ArgumentNullException("requestUri");
+ if (responseUri == null) throw new ArgumentNullException("responseUri");
+ if (String.IsNullOrEmpty(contentType)) throw new ArgumentNullException("contentType");
+
+ // Set up the redirect if appropriate
+ if (requestUri != responseUri) {
+ RegisterMockRedirect(requestUri, responseUri);
+ }
+
+ string contentEncoding = null;
+ MemoryStream stream = new MemoryStream();
+ StreamWriter sw = new StreamWriter(stream);
+ sw.Write(responseBody);
+ sw.Flush();
+ stream.Seek(0, SeekOrigin.Begin);
+ RegisterMockResponse(new UntrustedWebResponse(responseUri, responseUri, headers ?? new WebHeaderCollection(),
+ HttpStatusCode.OK, contentType, contentEncoding, stream));
+ }
+
+ internal static void RegisterMockXrdsResponses(IDictionary<string, string> requestUriAndResponseBody) {
+ foreach (var pair in requestUriAndResponseBody) {
+ RegisterMockResponse(new Uri(pair.Key), "text/xml; saml=false; https=false; charset=UTF-8", pair.Value);
+ }
+ }
+
+ internal static void RegisterMockXrdsResponse(ServiceEndpoint endpoint) {
+ if (endpoint == null) throw new ArgumentNullException("endpoint");
+
+ string identityUri;
+ if (endpoint.ClaimedIdentifier == endpoint.Protocol.ClaimedIdentifierForOPIdentifier) {
+ identityUri = endpoint.UserSuppliedIdentifier;
+ } else {
+ identityUri = endpoint.UserSuppliedIdentifier ?? endpoint.ClaimedIdentifier;
+ }
+ RegisterMockXrdsResponse(new Uri(identityUri), new ServiceEndpoint[] { endpoint });
+ }
+
+ internal static void RegisterMockXrdsResponse(Uri respondingUri, IEnumerable<ServiceEndpoint> endpoints) {
+ if (endpoints == null) throw new ArgumentNullException("endpoints");
+
+ StringBuilder xrds = new StringBuilder();
+ xrds.AppendLine(@"<xrds:XRDS xmlns:xrds='xri://$xrds' xmlns:openid='http://openid.net/xmlns/1.0' xmlns='xri://$xrd*($v*2.0)'>
+ <XRD>");
+ foreach (var endpoint in endpoints) {
+ string template = @"
+ <Service priority='10'>
+ <Type>{0}</Type>
+ <URI>{1}</URI>
+ <LocalID>{2}</LocalID>
+ <openid:Delegate xmlns:openid='http://openid.net/xmlns/1.0'>{2}</openid:Delegate>
+ </Service>";
+ string serviceTypeUri;
+ if (endpoint.ClaimedIdentifier == endpoint.Protocol.ClaimedIdentifierForOPIdentifier) {
+ serviceTypeUri = endpoint.Protocol.OPIdentifierServiceTypeURI;
+ } else {
+ serviceTypeUri = endpoint.Protocol.ClaimedIdentifierServiceTypeURI;
+ }
+ string xrd = string.Format(CultureInfo.InvariantCulture, template,
+ HttpUtility.HtmlEncode(serviceTypeUri),
+ HttpUtility.HtmlEncode(endpoint.ProviderEndpoint.AbsoluteUri),
+ HttpUtility.HtmlEncode(endpoint.ProviderLocalIdentifier)
+ );
+ xrds.Append(xrd);
+ }
+ xrds.Append(@"
+ </XRD>
+</xrds:XRDS>");
+
+ RegisterMockResponse(respondingUri, ContentTypes.Xrds, xrds.ToString());
+ }
+ internal static void RegisterMockXrdsResponse(UriIdentifier directedIdentityAssignedIdentifier, ServiceEndpoint providerEndpoint) {
+ ServiceEndpoint identityEndpoint = ServiceEndpoint.CreateForClaimedIdentifier(
+ directedIdentityAssignedIdentifier,
+ directedIdentityAssignedIdentifier,
+ providerEndpoint.ProviderEndpoint,
+ new string[] { providerEndpoint.Protocol.ClaimedIdentifierServiceTypeURI },
+ 10,
+ 10
+ );
+ RegisterMockXrdsResponse(identityEndpoint);
+ }
+ internal static Identifier RegisterMockXrdsResponse(string embeddedResourcePath) {
+ UriIdentifier id = TestSupport.GetFullUrl(embeddedResourcePath);
+ RegisterMockResponse(id, "application/xrds+xml", TestSupport.LoadEmbeddedFile(embeddedResourcePath));
+ return id;
+ }
+ internal static void RegisterMockRPDiscovery() {
+ Uri rpRealmUri = TestSupport.Realm.UriWithWildcardChangedToWww;
+
+ string template = @"<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>{0}</Type>
+ <URI>{1}</URI>
+ </Service>
+ </XRD>
+</xrds:XRDS>";
+ string xrds = string.Format(CultureInfo.InvariantCulture, template,
+ HttpUtility.HtmlEncode(Protocol.v20.RPReturnToTypeURI),
+ HttpUtility.HtmlEncode(rpRealmUri.AbsoluteUri)
+ );
+
+ RegisterMockResponse(rpRealmUri, ContentTypes.Xrds, xrds);
+ }
+
+ internal static void DeleteResponse(Uri requestUri) {
+ registeredMockResponses.Remove(requestUri);
+ }
+
+ internal static void RegisterMockRedirect(Uri origin, Uri redirectLocation) {
+ var redirectionHeaders = new WebHeaderCollection {
+ { HttpResponseHeader.Location, redirectLocation.AbsoluteUri },
+ };
+ UntrustedWebResponse response = new UntrustedWebResponse(origin, origin,
+ redirectionHeaders, HttpStatusCode.Redirect, null, null, new MemoryStream());
+ RegisterMockResponse(response);
+ }
+ }
+}
diff --git a/src/DotNetOpenId.Test/Mocks/MockIdentifier.cs b/src/DotNetOpenId.Test/Mocks/MockIdentifier.cs new file mode 100644 index 0000000..7ab2d74 --- /dev/null +++ b/src/DotNetOpenId.Test/Mocks/MockIdentifier.cs @@ -0,0 +1,58 @@ +using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using DotNetOpenId.RelyingParty;
+
+namespace DotNetOpenId.Test.Mocks {
+ /// <summary>
+ /// Performs similar to an ordinary <see cref="Identifier"/>, but when called upon
+ /// to perform discovery, it returns a preset list of sevice endpoints to avoid
+ /// having a dependency on a hosted web site to actually perform discovery on.
+ /// </summary>
+ class MockIdentifier : Identifier {
+ IEnumerable<ServiceEndpoint> endpoints;
+ Identifier wrappedIdentifier;
+
+ public MockIdentifier(Identifier wrappedIdentifier, IEnumerable<ServiceEndpoint> endpoints)
+ : base(false) {
+ if (wrappedIdentifier == null) throw new ArgumentNullException("wrappedIdentifier");
+ if (endpoints == null) throw new ArgumentNullException("endpoints");
+ this.wrappedIdentifier = wrappedIdentifier;
+ this.endpoints = endpoints;
+
+ // Register a mock HTTP response to enable discovery of this identifier within the RP
+ // without having to host an ASP.NET site within the test.
+ MockHttpRequest.RegisterMockXrdsResponse(new Uri(wrappedIdentifier.ToString()), endpoints);
+ }
+
+ internal override IEnumerable<ServiceEndpoint> Discover() {
+ return endpoints;
+ }
+
+ internal override Identifier TrimFragment() {
+ return this;
+ }
+
+ internal override bool TryRequireSsl(out Identifier secureIdentifier) {
+ // We take special care to make our wrapped identifier secure, but still
+ // return a mocked (secure) identifier.
+ Identifier secureWrappedIdentifier;
+ bool result = wrappedIdentifier.TryRequireSsl(out secureWrappedIdentifier);
+ secureIdentifier = new MockIdentifier(secureWrappedIdentifier, endpoints);
+ return result;
+ }
+
+ public override string ToString() {
+ return wrappedIdentifier.ToString();
+ }
+
+ public override bool Equals(object obj) {
+ return wrappedIdentifier.Equals(obj);
+ }
+
+ public override int GetHashCode() {
+ return wrappedIdentifier.GetHashCode();
+ }
+ }
+}
diff --git a/src/DotNetOpenId.Test/Properties/AssemblyInfo.cs b/src/DotNetOpenId.Test/Properties/AssemblyInfo.cs index 8a9801d..c4aef77 100644 --- a/src/DotNetOpenId.Test/Properties/AssemblyInfo.cs +++ b/src/DotNetOpenId.Test/Properties/AssemblyInfo.cs @@ -10,7 +10,7 @@ using System.Runtime.InteropServices; [assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("DotNetOpenId.Test")]
-[assembly: AssemblyCopyright("Copyright © 2007")]
+[assembly: AssemblyCopyright("Copyright © 2008")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
@@ -21,15 +21,3 @@ using System.Runtime.InteropServices; // The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("085104fb-07dc-4f3b-ad5e-cb266acb11b6")]
-
-// Version information for an assembly consists of the following four values:
-//
-// Major Version
-// Minor Version
-// Build Number
-// Revision
-//
-// You can specify all the values or you can default the Revision and Build Numbers
-// by using the '*' as shown below:
-[assembly: AssemblyVersion("2.3.0.0")]
-[assembly: AssemblyFileVersion("2.3.0.0")]
diff --git a/src/DotNetOpenId.Test/Provider/IAuthenticationRequestTest.cs b/src/DotNetOpenId.Test/Provider/IAuthenticationRequestTest.cs index 3ea7d9c..87521e1 100644 --- a/src/DotNetOpenId.Test/Provider/IAuthenticationRequestTest.cs +++ b/src/DotNetOpenId.Test/Provider/IAuthenticationRequestTest.cs @@ -15,22 +15,25 @@ namespace DotNetOpenId.Test.Provider { UntrustedWebRequest.WhitelistHosts.Add("localhost");
}
- [Test, ExpectedException(typeof(WebException), UserMessage = "OP should throw WebException when return URL is unverifiable.")]
- public void UnverifiableReturnUrl() {
- Uri returnTo;
- Realm realm;
- getUnverifiableRP(out returnTo, out realm);
- var consumer = new OpenIdRelyingParty(new ApplicationMemoryStore(), null, null);
- var request = consumer.CreateRequest(TestSupport.GetIdentityUrl(TestSupport.Scenarios.AutoApproval, ProtocolVersion.V20), realm, returnTo);
- WebRequest.Create(request.RedirectingResponse.ExtractUrl()).GetResponse(); // the OP should return 500, causing exception here.
+ [TearDown]
+ public void TearDown() {
+ Mocks.MockHttpRequest.Reset();
}
- static void getUnverifiableRP(out Uri returnTo, out Realm realm) {
- var disableDiscovery = new Dictionary<string, string> {
- {"AllowRPDiscovery", "false"},
- };
- returnTo = TestSupport.GetFullUrl(TestSupport.ConsumerPage, disableDiscovery);
- realm = new Realm(returnTo);
+ [Test]
+ public void UnverifiableReturnUrl() {
+ var request = TestSupport.CreateRelyingPartyRequest(true, TestSupport.Scenarios.AutoApproval, ProtocolVersion.V20, false);
+
+ // Clear out the RP discovery information registered by TestSupport
+ Mocks.MockHttpRequest.DeleteResponse(TestSupport.Realm.UriWithWildcardChangedToWww);
+
+ bool reachedOP = false;
+ var response = TestSupport.CreateRelyingPartyResponseThroughProvider(request, req => {
+ Assert.IsFalse(req.IsReturnUrlDiscoverable);
+ reachedOP = true;
+ req.IsAuthenticated = false;
+ });
+ Assert.IsTrue(reachedOP);
}
}
}
diff --git a/src/DotNetOpenId.Test/Provider/OpenIdProviderTest.cs b/src/DotNetOpenId.Test/Provider/OpenIdProviderTest.cs index 9f5c2e9..ff51461 100644 --- a/src/DotNetOpenId.Test/Provider/OpenIdProviderTest.cs +++ b/src/DotNetOpenId.Test/Provider/OpenIdProviderTest.cs @@ -1,13 +1,9 @@ using System;
-using System.Collections.Generic;
-using System.Text;
-using NUnit.Framework;
-using System.IO;
-using System.Diagnostics;
-using DotNetOpenId.Test.Hosting;
-using System.Text.RegularExpressions;
-using DotNetOpenId.Provider;
using System.Collections.Specialized;
+using DotNetOpenId.Provider;
+using DotNetOpenId.RelyingParty;
+using DotNetOpenId.Test.Mocks;
+using NUnit.Framework;
using ProviderMemoryStore = DotNetOpenId.AssociationMemoryStore<DotNetOpenId.AssociationRelyingPartyType>;
namespace DotNetOpenId.Test.Provider {
@@ -16,6 +12,17 @@ namespace DotNetOpenId.Test.Provider { readonly Uri providerEndpoint = new Uri("http://someendpoint");
readonly Uri emptyRequestUrl = new Uri("http://someendpoint/request");
+ [SetUp]
+ public void Setup() {
+ if (!UntrustedWebRequest.WhitelistHosts.Contains("localhost"))
+ UntrustedWebRequest.WhitelistHosts.Add("localhost");
+ }
+
+ [TearDown]
+ public void TearDown() {
+ MockHttpRequest.Reset();
+ }
+
/// <summary>
/// Verifies that without an ASP.NET context, the default constructor fails.
/// </summary>
@@ -26,31 +33,31 @@ namespace DotNetOpenId.Test.Provider { [Test]
public void CtorNonDefault() {
- OpenIdProvider op = new OpenIdProvider(new ProviderMemoryStore(),
+ OpenIdProvider op = new OpenIdProvider(new ProviderMemoryStore(),
providerEndpoint, emptyRequestUrl, new NameValueCollection());
}
[Test, ExpectedException(typeof(ArgumentNullException))]
public void CtorNullStore() {
- OpenIdProvider op = new OpenIdProvider(null, providerEndpoint,
+ OpenIdProvider op = new OpenIdProvider(null, providerEndpoint,
emptyRequestUrl, new NameValueCollection());
}
[Test, ExpectedException(typeof(ArgumentNullException))]
public void CtorNullEndpoint() {
- OpenIdProvider op = new OpenIdProvider(new ProviderMemoryStore(),
+ OpenIdProvider op = new OpenIdProvider(new ProviderMemoryStore(),
null, emptyRequestUrl, new NameValueCollection());
}
[Test, ExpectedException(typeof(ArgumentNullException))]
public void CtorNullRequestUrl() {
- OpenIdProvider op = new OpenIdProvider(new ProviderMemoryStore(),
+ OpenIdProvider op = new OpenIdProvider(new ProviderMemoryStore(),
providerEndpoint, null, new NameValueCollection());
}
[Test, ExpectedException(typeof(ArgumentNullException))]
public void CtorNullQuery() {
- OpenIdProvider op = new OpenIdProvider(new ProviderMemoryStore(),
+ OpenIdProvider op = new OpenIdProvider(new ProviderMemoryStore(),
providerEndpoint, emptyRequestUrl, null);
}
@@ -60,5 +67,60 @@ namespace DotNetOpenId.Test.Provider { providerEndpoint, emptyRequestUrl, new NameValueCollection());
Assert.IsNull(op.Request);
}
+
+ [Test]
+ public void BasicUnsolicitedAssertion() {
+ Mocks.MockHttpRequest.RegisterMockRPDiscovery();
+ TestSupport.Scenarios scenario = TestSupport.Scenarios.AutoApproval;
+ Identifier claimedId = TestSupport.GetMockIdentifier(scenario, ProtocolVersion.V20);
+ Identifier localId = TestSupport.GetDelegateUrl(scenario);
+
+ OpenIdProvider op = TestSupport.CreateProvider(null);
+ IResponse assertion = op.PrepareUnsolicitedAssertion(TestSupport.Realm, claimedId, localId);
+ var rpResponse = TestSupport.CreateRelyingPartyResponse(TestSupport.RelyingPartyStore, assertion);
+ Assert.AreEqual(AuthenticationStatus.Authenticated, rpResponse.Status);
+ Assert.AreEqual(claimedId, rpResponse.ClaimedIdentifier);
+ }
+
+ [Test]
+ public void UnsolicitedAssertionWithBadCapitalization() {
+ Mocks.MockHttpRequest.RegisterMockRPDiscovery();
+ TestSupport.Scenarios scenario = TestSupport.Scenarios.AutoApproval;
+ Identifier claimedId = TestSupport.GetMockIdentifier(scenario, ProtocolVersion.V20);
+ claimedId = claimedId.ToString().ToUpper(); // make all caps, which is not right
+ Identifier localId = TestSupport.GetDelegateUrl(scenario);
+
+ OpenIdProvider op = TestSupport.CreateProvider(null);
+ IResponse assertion = op.PrepareUnsolicitedAssertion(TestSupport.Realm, claimedId, localId);
+ var rpResponse = TestSupport.CreateRelyingPartyResponse(TestSupport.RelyingPartyStore, assertion);
+ Assert.AreEqual(AuthenticationStatus.Failed, rpResponse.Status);
+ }
+
+ /// <summary>
+ /// Verifies that OP will properly report RP versions in requests.
+ /// </summary>
+ [Test]
+ public void RelyingPartyVersion() {
+ Protocol simulatedVersion = Protocol.v11;
+ UriIdentifier id = TestSupport.GetIdentityUrl(TestSupport.Scenarios.AutoApproval, simulatedVersion.ProtocolVersion);
+
+ // make up some OpenID 1.x looking message...
+ NameValueCollection rp10Request = new NameValueCollection();
+ rp10Request[simulatedVersion.openid.mode] = simulatedVersion.Args.Mode.checkid_immediate;
+ rp10Request[simulatedVersion.openid.identity] = id;
+ rp10Request[simulatedVersion.openid.return_to] = TestSupport.ReturnTo.AbsoluteUri;
+ rp10Request[simulatedVersion.openid.Realm] = TestSupport.Realm;
+
+ OpenIdProvider op = TestSupport.CreateProvider(rp10Request);
+ Assert.AreEqual(simulatedVersion.ProtocolVersion,
+ ((DotNetOpenId.Provider.IAuthenticationRequest)op.Request).RelyingPartyVersion);
+
+ // Verify V2.0 reporting.
+ var rp20Request = TestSupport.CreateRelyingPartyRequest(true, TestSupport.Scenarios.AutoApproval, ProtocolVersion.V20, false);
+ TestSupport.CreateRelyingPartyResponseThroughProvider(rp20Request, opReq => {
+ Assert.AreEqual(ProtocolVersion.V20, opReq.RelyingPartyVersion);
+ opReq.IsAuthenticated = true;
+ });
+ }
}
}
diff --git a/src/DotNetOpenId.Test/RelyingParty/AuthenticationRequestTests.cs b/src/DotNetOpenId.Test/RelyingParty/AuthenticationRequestTests.cs new file mode 100644 index 0000000..a1655ad --- /dev/null +++ b/src/DotNetOpenId.Test/RelyingParty/AuthenticationRequestTests.cs @@ -0,0 +1,53 @@ +using System;
+using System.Collections.Generic;
+using System.Collections.Specialized;
+using System.Net;
+using System.Web;
+using DotNetOpenId.RelyingParty;
+using DotNetOpenId.Test.Mocks;
+using NUnit.Framework;
+
+namespace DotNetOpenId.Test.RelyingParty {
+ [TestFixture]
+ public class AuthenticationRequestTests {
+ Realm realm = new Realm(TestSupport.GetFullUrl(TestSupport.ConsumerPage).AbsoluteUri);
+ Uri returnTo = TestSupport.GetFullUrl(TestSupport.ConsumerPage);
+
+ [SetUp]
+ public void SetUp() {
+ if (!UntrustedWebRequest.WhitelistHosts.Contains("localhost"))
+ UntrustedWebRequest.WhitelistHosts.Add("localhost");
+ }
+
+ [TearDown]
+ public void TearDown() {
+ MockHttpRequest.Reset();
+ }
+
+ [Test]
+ public void Provider() {
+ OpenIdRelyingParty rp = new OpenIdRelyingParty(null, null, null);
+ Identifier id = TestSupport.GetMockIdentifier(TestSupport.Scenarios.AutoApproval, ProtocolVersion.V20);
+ IAuthenticationRequest request = rp.CreateRequest(id, realm, returnTo);
+ Assert.IsNotNull(request.Provider);
+ }
+
+ [Test]
+ public void AddCallbackArgumentReplacesExistingArguments() {
+ OpenIdRelyingParty rp = new OpenIdRelyingParty(null, null, null);
+ Identifier id = TestSupport.GetMockIdentifier(TestSupport.Scenarios.AutoApproval, ProtocolVersion.V20);
+
+ UriBuilder returnToWithParameter = new UriBuilder(returnTo);
+ UriUtil.AppendQueryArgs(returnToWithParameter, new Dictionary<string, string> { { "p1", "v1"} });
+
+ IAuthenticationRequest request = rp.CreateRequest(id, realm, returnToWithParameter.Uri);
+ request.AddCallbackArguments("p1", "v2");
+
+ Uri redirectUri = new Uri(request.RedirectingResponse.Headers[HttpResponseHeader.Location]);
+ NameValueCollection redirectArgs = HttpUtility.ParseQueryString(redirectUri.Query);
+ Uri returnToUri = new Uri(redirectArgs[Protocol.Default.openid.return_to]);
+ NameValueCollection returnToArgs = HttpUtility.ParseQueryString(returnToUri.Query);
+ Assert.AreEqual("v2", returnToArgs["p1"]);
+ }
+ }
+}
diff --git a/src/DotNetOpenId.Test/RelyingParty/AuthenticationResponseTests.cs b/src/DotNetOpenId.Test/RelyingParty/AuthenticationResponseTests.cs index 7dcb792..532b379 100644 --- a/src/DotNetOpenId.Test/RelyingParty/AuthenticationResponseTests.cs +++ b/src/DotNetOpenId.Test/RelyingParty/AuthenticationResponseTests.cs @@ -1,14 +1,10 @@ using System;
using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using NUnit.Framework;
-using DotNetOpenId.RelyingParty;
-using System.Net;
-using System.Diagnostics;
-using System.IO;
-using System.Web;
using System.Collections.Specialized;
+using System.Web;
+using DotNetOpenId.RelyingParty;
+using DotNetOpenId.Test.Mocks;
+using NUnit.Framework;
namespace DotNetOpenId.Test.RelyingParty {
[TestFixture]
@@ -16,7 +12,6 @@ namespace DotNetOpenId.Test.RelyingParty { Realm realm = new Realm(TestSupport.GetFullUrl(TestSupport.ConsumerPage).AbsoluteUri);
Uri returnTo;
const string returnToRemovableParameter = "a";
- ApplicationMemoryStore store;
public AuthenticationResponseTests() {
UriBuilder builder = new UriBuilder(TestSupport.GetFullUrl(TestSupport.ConsumerPage));
@@ -28,38 +23,23 @@ namespace DotNetOpenId.Test.RelyingParty { [SetUp]
public void SetUp() {
- store = new ApplicationMemoryStore();
if (!UntrustedWebRequest.WhitelistHosts.Contains("localhost"))
UntrustedWebRequest.WhitelistHosts.Add("localhost");
}
+ [TearDown]
+ public void TearDown() {
+ MockHttpRequest.Reset();
+ }
+
Uri getPositiveAssertion(ProtocolVersion version) {
- try {
- OpenIdRelyingParty rp = new OpenIdRelyingParty(store, null, null);
- Identifier id = TestSupport.GetIdentityUrl(TestSupport.Scenarios.AutoApproval, version);
- var request = rp.CreateRequest(id, realm, returnTo);
- HttpWebRequest providerRequest = (HttpWebRequest)WebRequest.Create(request.RedirectingResponse.ExtractUrl());
- providerRequest.AllowAutoRedirect = false;
- Uri redirectUrl;
- try {
- using (HttpWebResponse providerResponse = (HttpWebResponse)providerRequest.GetResponse()) {
- Assert.AreEqual(HttpStatusCode.Redirect, providerResponse.StatusCode);
- redirectUrl = new Uri(providerResponse.Headers[HttpResponseHeader.Location]);
- }
- } catch (WebException ex) {
- Trace.WriteLine(ex);
- if (ex.Response != null) {
- using (StreamReader sr = new StreamReader(ex.Response.GetResponseStream())) {
- Trace.WriteLine(sr.ReadToEnd());
- }
- }
- throw;
- }
- return redirectUrl;
- } catch (OpenIdException ex) {
- Assert.Ignore("Test failed to verify good or bad behavior on account of failing to set itself up: {0}", ex);
- return null; // Assert.Ignore will throw an exception anyway
- }
+ OpenIdRelyingParty rp = TestSupport.CreateRelyingParty(null);
+ Identifier id = TestSupport.GetMockIdentifier(TestSupport.Scenarios.AutoApproval, version);
+ var request = rp.CreateRequest(id, realm, returnTo);
+ var provider = TestSupport.CreateProviderForRequest(request);
+ var opRequest = provider.Request as DotNetOpenId.Provider.IAuthenticationRequest;
+ opRequest.IsAuthenticated = true;
+ return opRequest.Response.ExtractUrl();
}
void removeQueryParameter(ref Uri uri, string parameterToRemove) {
UriBuilder builder = new UriBuilder(uri);
@@ -92,7 +72,7 @@ namespace DotNetOpenId.Test.RelyingParty { void resign(ref Uri uri) {
UriBuilder builder = new UriBuilder(uri);
NameValueCollection nvc = HttpUtility.ParseQueryString(builder.Query);
- TestSupport.Resign(nvc, store);
+ TestSupport.Resign(nvc, TestSupport.RelyingPartyStore);
builder.Query = UriUtil.CreateQueryString(nvc);
uri = builder.Uri;
}
@@ -106,7 +86,7 @@ namespace DotNetOpenId.Test.RelyingParty { // which should cause a failure because the return_to argument
// says that parameter is supposed to be there.
removeQueryParameter(ref assertion, returnToRemovableParameter);
- var response = new OpenIdRelyingParty(store, assertion, HttpUtility.ParseQueryString(assertion.Query)).Response;
+ var response = TestSupport.CreateRelyingParty(TestSupport.RelyingPartyStore, assertion, HttpUtility.ParseQueryString(assertion.Query)).Response;
Assert.AreEqual(AuthenticationStatus.Failed, response.Status);
Assert.IsNotNull(response.Exception);
}
@@ -140,10 +120,44 @@ namespace DotNetOpenId.Test.RelyingParty { resign(ref assertion); // resign changed URL to simulate a contrived OP for breaking into RPs.
// (triggers exception) "... you're in trouble up to your ears."
- var response = new OpenIdRelyingParty(store, assertion, HttpUtility.ParseQueryString(assertion.Query)).Response;
+ var response = TestSupport.CreateRelyingParty(TestSupport.RelyingPartyStore, assertion, HttpUtility.ParseQueryString(assertion.Query)).Response;
Assert.AreEqual(AuthenticationStatus.Failed, response.Status);
Assert.IsNotNull(response.Exception);
}
+ [Test]
+ public void ClaimedIdentifierChangesAtProviderUnexpectedly() {
+ OpenIdRelyingParty rp = TestSupport.CreateRelyingParty(null);
+ MockIdentifier id = TestSupport.GetMockIdentifier(TestSupport.Scenarios.ApproveOnSetup, ProtocolVersion.V20);
+ id = FixLocalIdToMatchClaimedId(id); // don't make it look like a delegated auth
+ Identifier newClaimedId = TestSupport.GetMockIdentifier(TestSupport.Scenarios.AutoApproval, ProtocolVersion.V20);
+ Identifier newLocalId = TestSupport.GetDelegateUrl(TestSupport.Scenarios.AutoApproval);
+ MockHttpRequest.RegisterMockXrdsResponse(new Uri(newClaimedId), newClaimedId.Discover());
+ var request = rp.CreateRequest(id, realm, returnTo);
+ var provider = TestSupport.CreateProviderForRequest(request);
+ var opRequest = provider.Request as DotNetOpenId.Provider.IAuthenticationRequest;
+ opRequest.IsAuthenticated = true;
+ opRequest.ClaimedIdentifier = newClaimedId;
+ opRequest.LocalIdentifier = newLocalId;
+ var assertion = opRequest.Response.ExtractUrl();
+ var response = TestSupport.CreateRelyingParty(TestSupport.RelyingPartyStore, assertion, HttpUtility.ParseQueryString(assertion.Query)).Response;
+ Assert.AreEqual(AuthenticationStatus.Authenticated, response.Status);
+ }
+
+ private MockIdentifier FixLocalIdToMatchClaimedId(MockIdentifier identifier) {
+ var newEndpoints = new List<ServiceEndpoint>();
+ foreach (ServiceEndpoint se in identifier.Discover()) {
+ newEndpoints.Add(ServiceEndpoint.CreateForClaimedIdentifier(
+ se.ClaimedIdentifier,
+ se.ClaimedIdentifier,
+ se.ProviderEndpoint,
+ se.ProviderSupportedServiceTypeUris,
+ null,
+ null));
+ }
+
+ MockIdentifier altered = new MockIdentifier(identifier, newEndpoints);
+ return altered;
+ }
}
}
diff --git a/src/DotNetOpenId.Test/RelyingParty/IProviderEndpointTests.cs b/src/DotNetOpenId.Test/RelyingParty/IProviderEndpointTests.cs new file mode 100644 index 0000000..8830691 --- /dev/null +++ b/src/DotNetOpenId.Test/RelyingParty/IProviderEndpointTests.cs @@ -0,0 +1,55 @@ +using System;
+using DotNetOpenId.Extensions.AttributeExchange;
+using DotNetOpenId.Extensions.SimpleRegistration;
+using DotNetOpenId.RelyingParty;
+using NUnit.Framework;
+using DotNetOpenId.Test.Mocks;
+
+namespace DotNetOpenId.Test.RelyingParty {
+ [TestFixture]
+ public class IProviderEndpointTests {
+ IRelyingPartyApplicationStore store;
+ Realm realm = new Realm(TestSupport.GetFullUrl(TestSupport.ConsumerPage).AbsoluteUri);
+ Uri returnTo = TestSupport.GetFullUrl(TestSupport.ConsumerPage);
+
+ [SetUp]
+ public void SetUp() {
+ store = new ApplicationMemoryStore();
+ if (!UntrustedWebRequest.WhitelistHosts.Contains("localhost"))
+ UntrustedWebRequest.WhitelistHosts.Add("localhost");
+ }
+
+ [TearDown]
+ public void TearDown() {
+ Mocks.MockHttpRequest.Reset();
+ }
+
+ [Test]
+ public void IsExtensionSupportedTest() {
+ OpenIdRelyingParty rp = TestSupport.CreateRelyingParty(null);
+ Identifier id = MockHttpRequest.RegisterMockXrdsResponse("/Discovery/xrdsdiscovery/xrds20.xml");
+ IAuthenticationRequest request = rp.CreateRequest(id, TestSupport.Realm, TestSupport.ReturnTo);
+ IProviderEndpoint provider = request.Provider;
+ Assert.IsTrue(provider.IsExtensionSupported<ClaimsRequest>());
+ Assert.IsTrue(provider.IsExtensionSupported(typeof(ClaimsRequest)));
+ Assert.IsFalse(provider.IsExtensionSupported<FetchRequest>());
+ Assert.IsFalse(provider.IsExtensionSupported(typeof(FetchRequest)));
+
+ // Test the AdditionalTypeUris list by pulling from an XRDS page with one of the
+ // TypeURIs that only shows up in that list.
+ id = MockHttpRequest.RegisterMockXrdsResponse("/Discovery/xrdsdiscovery/xrds10.xml");
+ request = rp.CreateRequest(id, realm, returnTo);
+ Assert.IsTrue(provider.IsExtensionSupported<ClaimsRequest>());
+ Assert.IsTrue(provider.IsExtensionSupported(typeof(ClaimsRequest)));
+ }
+
+ [Test]
+ public void UriTest() {
+ OpenIdRelyingParty rp = TestSupport.CreateRelyingParty(null);
+ Identifier id = MockHttpRequest.RegisterMockXrdsResponse("/Discovery/xrdsdiscovery/xrds20.xml");
+ IAuthenticationRequest request = rp.CreateRequest(id, TestSupport.Realm, TestSupport.ReturnTo);
+ IProviderEndpoint provider = request.Provider;
+ Assert.AreEqual(new Uri("http://a/b"), provider.Uri);
+ }
+ }
+}
diff --git a/src/DotNetOpenId.Test/RelyingParty/OpenIdRelyingPartyTest.cs b/src/DotNetOpenId.Test/RelyingParty/OpenIdRelyingPartyTest.cs index ddef8a3..cf9a795 100644 --- a/src/DotNetOpenId.Test/RelyingParty/OpenIdRelyingPartyTest.cs +++ b/src/DotNetOpenId.Test/RelyingParty/OpenIdRelyingPartyTest.cs @@ -1,14 +1,15 @@ using System;
+using System.Collections.Generic;
+using System.Collections.Specialized;
+using System.Web;
using DotNetOpenId.RelyingParty;
+using DotNetOpenId.Test.Mocks;
using NUnit.Framework;
-using ProviderMemoryStore = DotNetOpenId.AssociationMemoryStore<DotNetOpenId.AssociationRelyingPartyType>;
-using System.Web;
-using System.Collections.Specialized;
+using OpenIdProvider = DotNetOpenId.Provider.OpenIdProvider;
namespace DotNetOpenId.Test.RelyingParty {
[TestFixture]
public class OpenIdRelyingPartyTest {
- IRelyingPartyApplicationStore store;
UriIdentifier simpleOpenId = new UriIdentifier("http://nonexistant.openid.com");
readonly Realm realm = new Realm(TestSupport.GetFullUrl(TestSupport.ConsumerPage).AbsoluteUri);
readonly Uri returnTo = TestSupport.GetFullUrl(TestSupport.ConsumerPage);
@@ -16,11 +17,15 @@ namespace DotNetOpenId.Test.RelyingParty { [SetUp]
public void Setup() {
- store = new ApplicationMemoryStore();
if (!UntrustedWebRequest.WhitelistHosts.Contains("localhost"))
UntrustedWebRequest.WhitelistHosts.Add("localhost");
}
+ [TearDown]
+ public void TearDown() {
+ MockHttpRequest.Reset();
+ }
+
[Test]
[ExpectedException(typeof(InvalidOperationException))]
public void DefaultCtorWithoutContext() {
@@ -29,7 +34,7 @@ namespace DotNetOpenId.Test.RelyingParty { [Test]
public void CtorWithNullRequestUri() {
- new OpenIdRelyingParty(store, null, null);
+ new OpenIdRelyingParty(new ApplicationMemoryStore(), null, null);
}
[Test]
@@ -40,50 +45,82 @@ namespace DotNetOpenId.Test.RelyingParty { [Test]
[ExpectedException(typeof(InvalidOperationException))]
public void CreateRequestWithoutContext1() {
- var consumer = new OpenIdRelyingParty(store, simpleNonOpenIdRequest, new NameValueCollection());
+ var consumer = new OpenIdRelyingParty(new ApplicationMemoryStore(), simpleNonOpenIdRequest, new NameValueCollection());
consumer.CreateRequest(simpleOpenId);
}
[Test]
[ExpectedException(typeof(InvalidOperationException))]
public void CreateRequestWithoutContext2() {
- var consumer = new OpenIdRelyingParty(store, simpleNonOpenIdRequest, new NameValueCollection());
+ var consumer = new OpenIdRelyingParty(new ApplicationMemoryStore(), simpleNonOpenIdRequest, new NameValueCollection());
consumer.CreateRequest(simpleOpenId, realm);
}
+ [Test, ExpectedException(typeof(ArgumentNullException))]
+ public void CreateRequestNullIdentifier() {
+ var consumer = TestSupport.CreateRelyingParty(null);
+ consumer.CreateRequest(null, realm, returnTo);
+ }
+
+ [Test, ExpectedException(typeof(ArgumentNullException))]
+ public void CreateRequestNullRealm() {
+ var consumer = TestSupport.CreateRelyingParty(null);
+ consumer.CreateRequest("=someEndpoint", null, returnTo);
+ }
+
+ [Test, ExpectedException(typeof(ArgumentNullException))]
+ public void CreateRequestNullReturnTo() {
+ var consumer = TestSupport.CreateRelyingParty(null);
+ consumer.CreateRequest("=someEndpoint", realm, null);
+ }
+
+ [Test]
+ public void CreateRequestStripsFragment() {
+ var consumer = TestSupport.CreateRelyingParty(null);
+ UriBuilder userSuppliedIdentifier = new UriBuilder((Uri)TestSupport.GetIdentityUrl(TestSupport.Scenarios.AutoApproval, ProtocolVersion.V20));
+ userSuppliedIdentifier.Fragment = "c";
+ Identifier mockIdentifer = new MockIdentifier(userSuppliedIdentifier.Uri,
+ TestSupport.GetMockIdentifier(TestSupport.Scenarios.AutoApproval, ProtocolVersion.V20).Discover());
+ Assert.IsTrue(mockIdentifer.ToString().EndsWith("#c"), "Test broken");
+ IAuthenticationRequest request = consumer.CreateRequest(mockIdentifer, TestSupport.Realm, TestSupport.ReturnTo);
+ Assert.AreEqual(0, new Uri(request.ClaimedIdentifier).Fragment.Length);
+ }
+
[Test]
public void AssociationCreationWithStore() {
- var providerStore = new ProviderMemoryStore();
+ TestSupport.ResetStores(); // get rid of existing associations so a new one is created
- OpenIdRelyingParty rp = new OpenIdRelyingParty(new ApplicationMemoryStore(), null, null);
- var idUrl = TestSupport.GetIdentityUrl(TestSupport.Scenarios.AutoApproval, ProtocolVersion.V20);
+ OpenIdRelyingParty rp = TestSupport.CreateRelyingParty(null);
+ var directMessageSniffer = new DirectMessageSniffWrapper(rp.DirectMessageChannel);
+ rp.DirectMessageChannel = directMessageSniffer;
+ var idUrl = TestSupport.GetMockIdentifier(TestSupport.Scenarios.AutoApproval, ProtocolVersion.V20);
DotNetOpenId.RelyingParty.IAuthenticationRequest req;
bool associationMade = false;
- TestSupport.Interceptor.SigningMessage = m => {
- if (m.EncodedFields.ContainsKey("assoc_handle") && m.EncodedFields.ContainsKey("session_type"))
+ directMessageSniffer.Receiving += (provider, fields) => {
+ if (fields.ContainsKey("assoc_handle") && fields.ContainsKey("session_type"))
associationMade = true;
};
req = rp.CreateRequest(idUrl, realm, returnTo);
- TestSupport.Interceptor.SigningMessage = null;
Assert.IsTrue(associationMade);
}
[Test]
public void NoAssociationRequestWithoutStore() {
- var providerStore = new ProviderMemoryStore();
+ TestSupport.ResetStores(); // get rid of existing associations so a new one is created
- OpenIdRelyingParty rp = new OpenIdRelyingParty(null, null, null);
- var idUrl = TestSupport.GetIdentityUrl(TestSupport.Scenarios.AutoApproval, ProtocolVersion.V20);
+ OpenIdRelyingParty rp = TestSupport.CreateRelyingParty(null, null);
+ var directMessageSniffer = new DirectMessageSniffWrapper(rp.DirectMessageChannel);
+ rp.DirectMessageChannel = directMessageSniffer;
+ var idUrl = TestSupport.GetMockIdentifier(TestSupport.Scenarios.AutoApproval, ProtocolVersion.V20);
DotNetOpenId.RelyingParty.IAuthenticationRequest req;
bool associationMade = false;
- TestSupport.Interceptor.SigningMessage = m => {
- if (m.EncodedFields.ContainsKey("assoc_handle") && m.EncodedFields.ContainsKey("session_type"))
+ directMessageSniffer.Receiving += (provider, fields) => {
+ if (fields.ContainsKey("assoc_handle") && fields.ContainsKey("session_type"))
associationMade = true;
};
req = rp.CreateRequest(idUrl, realm, returnTo);
- TestSupport.Interceptor.SigningMessage = null;
Assert.IsFalse(associationMade);
}
@@ -113,10 +150,8 @@ namespace DotNetOpenId.Test.RelyingParty { }
private static void testExplicitPortOnRealmAndReturnTo(Uri returnTo, Realm realm) {
- var identityUrl = TestSupport.GetIdentityUrl(TestSupport.Scenarios.AutoApproval, ProtocolVersion.V20);
- var consumer = new OpenIdRelyingParty(null, null, null);
- var request = consumer.CreateRequest(identityUrl, realm, returnTo);
- Protocol protocol = Protocol.Lookup(request.ProviderVersion);
+ var request = TestSupport.CreateRelyingPartyRequest(true, TestSupport.Scenarios.AutoApproval, ProtocolVersion.V20, false);
+ Protocol protocol = Protocol.Lookup(request.Provider.Version);
var nvc = HttpUtility.ParseQueryString(request.RedirectingResponse.ExtractUrl().Query);
string realmString = nvc[protocol.openid.Realm];
string returnToString = nvc[protocol.openid.return_to];
@@ -132,15 +167,279 @@ namespace DotNetOpenId.Test.RelyingParty { [Test]
public void ReturnToUrlEncodingTest() {
- Uri origin = TestSupport.GetFullUrl(TestSupport.ConsumerPage);
- var identityUrl = TestSupport.GetIdentityUrl(TestSupport.Scenarios.AutoApproval, ProtocolVersion.V20);
- var consumer = new OpenIdRelyingParty(null, null, null);
- var request = consumer.CreateRequest(identityUrl, origin, origin);
- Protocol protocol = Protocol.Lookup(request.ProviderVersion);
+ var request = TestSupport.CreateRelyingPartyRequest(true, TestSupport.Scenarios.AutoApproval, ProtocolVersion.V20, false);
+ Protocol protocol = Protocol.Lookup(request.Provider.Version);
request.AddCallbackArguments("a+b", "c+d");
var requestArgs = HttpUtility.ParseQueryString(request.RedirectingResponse.ExtractUrl().Query);
var returnToArgs = HttpUtility.ParseQueryString(requestArgs[protocol.openid.return_to]);
Assert.AreEqual("c+d", returnToArgs["a+b"]);
}
+
+ static ServiceEndpoint getServiceEndpoint(int? servicePriority, int? uriPriority) {
+ Protocol protocol = Protocol.v20;
+ ServiceEndpoint ep = ServiceEndpoint.CreateForClaimedIdentifier(
+ TestSupport.GetIdentityUrl(TestSupport.Scenarios.AutoApproval, ProtocolVersion.V20),
+ TestSupport.GetDelegateUrl(TestSupport.Scenarios.AutoApproval),
+ TestSupport.GetFullUrl(TestSupport.ProviderPage),
+ new[] { protocol.ClaimedIdentifierServiceTypeURI },
+ servicePriority,
+ uriPriority
+ );
+ return ep;
+ }
+
+ [Test]
+ public void DefaultEndpointOrder() {
+ var consumer = new OpenIdRelyingParty(null, null, null);
+ Assert.AreSame(OpenIdRelyingParty.DefaultEndpointOrder, consumer.EndpointOrder);
+ var defaultEndpointOrder = OpenIdRelyingParty.DefaultEndpointOrder;
+ // Test service priority ordering
+ Assert.AreEqual(-1, defaultEndpointOrder(getServiceEndpoint(10, null), getServiceEndpoint(20, null)));
+ Assert.AreEqual(1, defaultEndpointOrder(getServiceEndpoint(20, null), getServiceEndpoint(10, null)));
+ Assert.AreEqual(0, defaultEndpointOrder(getServiceEndpoint(10, null), getServiceEndpoint(10, null)));
+ Assert.AreEqual(-1, defaultEndpointOrder(getServiceEndpoint(20, null), getServiceEndpoint(null, null)));
+ Assert.AreEqual(1, defaultEndpointOrder(getServiceEndpoint(null, null), getServiceEndpoint(10, null)));
+ Assert.AreEqual(0, defaultEndpointOrder(getServiceEndpoint(null, null), getServiceEndpoint(null, null)));
+ // Test secondary type uri ordering
+ Assert.AreEqual(-1, defaultEndpointOrder(getServiceEndpoint(10, 10), getServiceEndpoint(10, 20)));
+ Assert.AreEqual(1, defaultEndpointOrder(getServiceEndpoint(10, 20), getServiceEndpoint(10, 10)));
+ Assert.AreEqual(0, defaultEndpointOrder(getServiceEndpoint(10, 5), getServiceEndpoint(10, 5)));
+ // test that it is secondary...
+ Assert.AreEqual(1, defaultEndpointOrder(getServiceEndpoint(20, 10), getServiceEndpoint(10, 20)));
+ Assert.AreEqual(-1, defaultEndpointOrder(getServiceEndpoint(null, 10), getServiceEndpoint(null, 20)));
+ Assert.AreEqual(1, defaultEndpointOrder(getServiceEndpoint(null, 20), getServiceEndpoint(null, 10)));
+ Assert.AreEqual(0, defaultEndpointOrder(getServiceEndpoint(null, 10), getServiceEndpoint(null, 10)));
+ }
+
+ [Test]
+ public void DefaultFilter() {
+ var consumer = new OpenIdRelyingParty(null, null, null);
+ Assert.IsNull(consumer.EndpointFilter);
+ }
+
+ [Test]
+ public void MultipleServiceEndpoints() {
+ string xrds = @"<?xml version='1.0' encoding='UTF-8'?>
+<XRD xmlns='xri://$xrd*($v*2.0)'>
+ <Query>=MultipleEndpoint</Query>
+ <Status cid='verified' code='100' />
+ <ProviderID>=!91F2.8153.F600.AE24</ProviderID>
+ <CanonicalID>=!91F2.8153.F600.AE24</CanonicalID>
+ <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 priority='20'>
+ <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/auth10/</URI>
+ <URI append='none' priority='1'>https://authn.freexri.com/auth10/</URI>
+ </Service>
+ <Service priority='10'>
+ <ProviderID>@!7F6F.F50.A4E4.1133</ProviderID>
+ <Type select='true'>http://specs.openid.net/auth/2.0/signon</Type>
+ <Path select='true'>(+login)</Path>
+ <Path match='default'/>
+ <MediaType match='default'/>
+ <URI append='none' priority='2'>http://authn.freexri.com/auth20/</URI>
+ <URI append='none' priority='1'>https://authn.freexri.com/auth20/</URI>
+ </Service>
+ <ServedBy>OpenXRI</ServedBy>
+</XRD>";
+ MockHttpRequest.RegisterMockXrdsResponses(new Dictionary<string, string> {
+ {"https://xri.net/=MultipleEndpoint?_xrd_r=application/xrd%2Bxml;sep=false", xrds},
+ });
+ OpenIdRelyingParty rp = new OpenIdRelyingParty(null, null, null);
+ Realm realm = new Realm("http://somerealm");
+ Uri return_to = new Uri("http://somerealm/return_to");
+ IAuthenticationRequest request = rp.CreateRequest("=MultipleEndpoint", realm, return_to);
+ Assert.AreEqual("https://authn.freexri.com/auth20/", request.Provider.Uri.AbsoluteUri);
+ rp.EndpointOrder = (se1, se2) => -se1.ServicePriority.Value.CompareTo(se2.ServicePriority.Value);
+ request = rp.CreateRequest("=MultipleEndpoint", realm, return_to);
+ Assert.AreEqual("https://authn.freexri.com/auth10/", request.Provider.Uri.AbsoluteUri);
+
+ // Now test the filter. Auth20 would come out on top, if we didn't select it out with the filter.
+ rp.EndpointOrder = OpenIdRelyingParty.DefaultEndpointOrder;
+ rp.EndpointFilter = (se) => se.Uri.AbsoluteUri == "https://authn.freexri.com/auth10/";
+ request = rp.CreateRequest("=MultipleEndpoint", realm, return_to);
+ Assert.AreEqual("https://authn.freexri.com/auth10/", request.Provider.Uri.AbsoluteUri);
+ }
+
+ private string stripScheme(string identifier) {
+ return identifier.Substring(identifier.IndexOf("://") + 3);
+ }
+
+ [Test]
+ public void RequireSslPrependsHttpsScheme() {
+ MockHttpRequest.Reset();
+ OpenIdRelyingParty rp = TestSupport.CreateRelyingParty(null);
+ rp.Settings.RequireSsl = true;
+ Identifier mockId = TestSupport.GetMockIdentifier(TestSupport.Scenarios.AutoApproval, ProtocolVersion.V20, true);
+ string noSchemeId = stripScheme(mockId);
+ var request = rp.CreateRequest(noSchemeId, TestSupport.Realm, TestSupport.ReturnTo);
+ Assert.IsTrue(request.ClaimedIdentifier.ToString().StartsWith("https://", StringComparison.OrdinalIgnoreCase));
+ }
+
+ [Test]
+ public void DirectedIdentityWithRequireSslSucceeds() {
+ Uri claimedId = TestSupport.GetFullUrl("/secureClaimedId", null, true);
+ Identifier opIdentifier = TestSupport.GetMockOPIdentifier(TestSupport.Scenarios.AutoApproval, claimedId, true, true);
+ var rp = TestSupport.CreateRelyingParty(null);
+ rp.Settings.RequireSsl = true;
+ var rpRequest = rp.CreateRequest(opIdentifier, TestSupport.Realm, TestSupport.ReturnTo);
+ var rpResponse = TestSupport.CreateRelyingPartyResponseThroughProvider(rpRequest, opRequest => {
+ opRequest.IsAuthenticated = true;
+ opRequest.ClaimedIdentifier = claimedId;
+ });
+ Assert.AreEqual(AuthenticationStatus.Authenticated, rpResponse.Status);
+ }
+
+ [Test]
+ public void DirectedIdentityWithRequireSslFailsWithoutSecureIdentity() {
+ Uri claimedId = TestSupport.GetFullUrl("/insecureClaimedId", null, false);
+ Identifier opIdentifier = TestSupport.GetMockOPIdentifier(TestSupport.Scenarios.AutoApproval, claimedId, true, true);
+ var rp = TestSupport.CreateRelyingParty(null);
+ rp.Settings.RequireSsl = true;
+ var rpRequest = rp.CreateRequest(opIdentifier, TestSupport.Realm, TestSupport.ReturnTo);
+ var rpResponse = TestSupport.CreateRelyingPartyResponseThroughProvider(rpRequest, opRequest => {
+ opRequest.IsAuthenticated = true;
+ opRequest.ClaimedIdentifier = claimedId;
+ });
+ Assert.AreEqual(AuthenticationStatus.Failed, rpResponse.Status);
+ }
+
+ [Test]
+ public void DirectedIdentityWithRequireSslFailsWithoutSecureProviderEndpoint() {
+ Uri claimedId = TestSupport.GetFullUrl("/secureClaimedId", null, true);
+ // We want to generate an OP Identifier that itself is secure, but whose
+ // XRDS doc describes an insecure provider endpoint.
+ Identifier opIdentifier = TestSupport.GetMockOPIdentifier(TestSupport.Scenarios.AutoApproval, claimedId, true, false);
+ var rp = TestSupport.CreateRelyingParty(null);
+ rp.Settings.RequireSsl = true;
+ var rpRequest = rp.CreateRequest(opIdentifier, TestSupport.Realm, TestSupport.ReturnTo);
+ var rpResponse = TestSupport.CreateRelyingPartyResponseThroughProvider(rpRequest, opRequest => {
+ opRequest.IsAuthenticated = true;
+ opRequest.ClaimedIdentifier = claimedId;
+ });
+ Assert.AreEqual(AuthenticationStatus.Failed, rpResponse.Status);
+ }
+
+ [Test]
+ public void UnsolicitedAssertionWithRequireSsl() {
+ MockHttpRequest.Reset();
+ Mocks.MockHttpRequest.RegisterMockRPDiscovery();
+ TestSupport.Scenarios scenario = TestSupport.Scenarios.AutoApproval;
+ Identifier claimedId = TestSupport.GetMockIdentifier(scenario, ProtocolVersion.V20, true);
+ Identifier localId = TestSupport.GetDelegateUrl(scenario, true);
+
+ OpenIdProvider op = TestSupport.CreateProvider(null, true);
+ IResponse assertion = op.PrepareUnsolicitedAssertion(TestSupport.Realm, claimedId, localId);
+
+ var opAuthWebResponse = (Response)assertion;
+ var opAuthResponse = (DotNetOpenId.Provider.EncodableResponse)opAuthWebResponse.EncodableMessage;
+ var rp = TestSupport.CreateRelyingParty(TestSupport.RelyingPartyStore, opAuthResponse.RedirectUrl,
+ opAuthResponse.EncodedFields.ToNameValueCollection());
+ rp.Settings.RequireSsl = true;
+
+ Assert.AreEqual(AuthenticationStatus.Authenticated, rp.Response.Status);
+ Assert.AreEqual(claimedId, rp.Response.ClaimedIdentifier);
+ }
+
+ [Test]
+ public void UnsolicitedAssertionWithRequireSslWithoutSecureIdentityUrl() {
+ MockHttpRequest.Reset();
+ Mocks.MockHttpRequest.RegisterMockRPDiscovery();
+ TestSupport.Scenarios scenario = TestSupport.Scenarios.AutoApproval;
+ Identifier claimedId = TestSupport.GetMockIdentifier(scenario, ProtocolVersion.V20);
+ Identifier localId = TestSupport.GetDelegateUrl(scenario);
+
+ OpenIdProvider op = TestSupport.CreateProvider(null);
+ IResponse assertion = op.PrepareUnsolicitedAssertion(TestSupport.Realm, claimedId, localId);
+
+ var opAuthWebResponse = (Response)assertion;
+ var opAuthResponse = (DotNetOpenId.Provider.EncodableResponse)opAuthWebResponse.EncodableMessage;
+ var rp = TestSupport.CreateRelyingParty(TestSupport.RelyingPartyStore, opAuthResponse.RedirectUrl,
+ opAuthResponse.EncodedFields.ToNameValueCollection());
+ rp.Settings.RequireSsl = true;
+
+ Assert.AreEqual(AuthenticationStatus.Failed, rp.Response.Status);
+ Assert.IsNull(rp.Response.ClaimedIdentifier);
+ }
+
+ [Test]
+ public void UnsolicitedAssertionWithRequireSslWithSecureIdentityButInsecureProviderEndpoint() {
+ MockHttpRequest.Reset();
+ Mocks.MockHttpRequest.RegisterMockRPDiscovery();
+ TestSupport.Scenarios scenario = TestSupport.Scenarios.AutoApproval;
+ ProtocolVersion version = ProtocolVersion.V20;
+ ServiceEndpoint providerEndpoint = TestSupport.GetServiceEndpoint(scenario, version, 10, false);
+ Identifier claimedId = new MockIdentifier(TestSupport.GetIdentityUrl(scenario, version, true),
+ new ServiceEndpoint[] { providerEndpoint });
+ Identifier localId = TestSupport.GetDelegateUrl(scenario, true);
+
+ OpenIdProvider op = TestSupport.CreateProvider(null, false);
+ IResponse assertion = op.PrepareUnsolicitedAssertion(TestSupport.Realm, claimedId, localId);
+
+ var opAuthWebResponse = (Response)assertion;
+ var opAuthResponse = (DotNetOpenId.Provider.EncodableResponse)opAuthWebResponse.EncodableMessage;
+ var rp = TestSupport.CreateRelyingParty(TestSupport.RelyingPartyStore, opAuthResponse.RedirectUrl,
+ opAuthResponse.EncodedFields.ToNameValueCollection());
+ rp.Settings.RequireSsl = true;
+
+ Assert.AreEqual(AuthenticationStatus.Failed, rp.Response.Status);
+ Assert.IsNull(rp.Response.ClaimedIdentifier);
+ }
+
+ /// <summary>
+ /// Verifies that an RP will not "discover" endpoints below OpenID 2.0 when appropriate.
+ /// </summary>
+ [Test, ExpectedException(typeof(OpenIdException))]
+ public void MinimumOPVersion20() {
+ MockIdentifier id = TestSupport.GetMockIdentifier(TestSupport.Scenarios.AutoApproval, ProtocolVersion.V11);
+
+ var rp = TestSupport.CreateRelyingParty(null);
+ rp.Settings.MinimumRequiredOpenIdVersion = ProtocolVersion.V20;
+ rp.CreateRequest(id, TestSupport.Realm, TestSupport.ReturnTo);
+ }
+
+ /// <summary>
+ /// Verifies that an RP configured to require 2.0 OPs will fail on communicating with 1.x OPs
+ /// that merely advertise 2.0 support but don't really have it.
+ /// </summary>
+ [Test]
+ public void MinimumOPVersion20WithDeceptiveEndpointRealizedAtAuthentication() {
+ // Create an identifier that claims to have a 2.0 OP endpoint.
+ MockIdentifier id = TestSupport.GetMockIdentifier(TestSupport.Scenarios.AutoApproval, ProtocolVersion.V20);
+
+ var rp = TestSupport.CreateRelyingParty(null, null);
+
+ IAuthenticationRequest req = rp.CreateRequest(id, TestSupport.Realm, TestSupport.ReturnTo);
+ IResponse providerResponse = TestSupport.CreateProviderResponseToRequest(req, opReq => {
+ opReq.IsAuthenticated = true;
+ });
+
+ var opAuthWebResponse = (Response)providerResponse;
+ var opAuthResponse = (DotNetOpenId.Provider.EncodableResponse)opAuthWebResponse.EncodableMessage;
+ var rp2 =TestSupport. CreateRelyingParty(null, opAuthResponse.RedirectUrl,
+ opAuthResponse.EncodedFields.ToNameValueCollection());
+ rp2.Settings.MinimumRequiredOpenIdVersion = ProtocolVersion.V20;
+ // Rig an intercept between the provider and RP to make our own Provider LOOK like a 1.x provider.
+ var sniffer = new DirectMessageSniffWrapper(rp2.DirectMessageChannel);
+ rp2.DirectMessageChannel = sniffer;
+ sniffer.Receiving += (endpoint, fields) => {
+ fields.Remove(Protocol.v20.openidnp.ns);
+ };
+ var resp = rp2.Response;
+
+ Assert.AreEqual(AuthenticationStatus.Failed, resp.Status, "Authentication should have failed since OP is really a 1.x OP masquerading as a 2.0 OP.");
+ }
}
}
diff --git a/src/DotNetOpenId.Test/RelyingParty/ServiceEndpointTests.cs b/src/DotNetOpenId.Test/RelyingParty/ServiceEndpointTests.cs index b85044b..d2677b8 100644 --- a/src/DotNetOpenId.Test/RelyingParty/ServiceEndpointTests.cs +++ b/src/DotNetOpenId.Test/RelyingParty/ServiceEndpointTests.cs @@ -1,32 +1,37 @@ using System;
using System.Collections.Generic;
-using System.Linq;
+using System.IO;
using System.Text;
-using NUnit.Framework;
using DotNetOpenId.RelyingParty;
-using System.IO;
+using NUnit.Framework;
+using System.Diagnostics;
namespace DotNetOpenId.Test.RelyingParty {
[TestFixture]
public class ServiceEndpointTests {
- Identifier claimedId = "http://claimedid.justatest.com";
+ UriIdentifier claimedId = new UriIdentifier("http://claimedid.justatest.com");
+ XriIdentifier claimedXri = new XriIdentifier("=!9B72.7DD1.50A9.5CCD");
+ XriIdentifier userSuppliedXri = new XriIdentifier("=Arnot");
Uri providerEndpoint = new Uri("http://someprovider.com");
Identifier localId = "http://localid.someprovider.com";
string[] v20TypeUris = { Protocol.v20.ClaimedIdentifierServiceTypeURI };
string[] v11TypeUris = { Protocol.v11.ClaimedIdentifierServiceTypeURI };
+ int servicePriority = 10;
+ int uriPriority = 10;
[Test]
public void Ctor() {
- ServiceEndpoint se = new ServiceEndpoint(claimedId, providerEndpoint, localId, v20TypeUris);
+ ServiceEndpoint se = ServiceEndpoint.CreateForClaimedIdentifier(claimedId, localId, providerEndpoint, v20TypeUris, servicePriority, uriPriority);
Assert.AreSame(claimedId, se.ClaimedIdentifier);
Assert.AreSame(providerEndpoint, se.ProviderEndpoint);
Assert.AreSame(localId, se.ProviderLocalIdentifier);
Assert.AreSame(v20TypeUris, se.ProviderSupportedServiceTypeUris);
+ Assert.AreEqual(servicePriority, ((IXrdsProviderEndpoint)se).ServicePriority);
}
[Test]
public void CtorImpliedLocalIdentifier() {
- ServiceEndpoint se = new ServiceEndpoint(claimedId, providerEndpoint, null, v20TypeUris);
+ ServiceEndpoint se = ServiceEndpoint.CreateForClaimedIdentifier(claimedId, null, providerEndpoint, v20TypeUris, servicePriority, uriPriority);
Assert.AreSame(claimedId, se.ClaimedIdentifier);
Assert.AreSame(providerEndpoint, se.ProviderEndpoint);
Assert.AreSame(claimedId, se.ProviderLocalIdentifier);
@@ -35,25 +40,26 @@ namespace DotNetOpenId.Test.RelyingParty { [Test]
public void ProtocolDetection() {
- ServiceEndpoint se = new ServiceEndpoint(claimedId, providerEndpoint, localId, v20TypeUris);
+ ServiceEndpoint se = ServiceEndpoint.CreateForClaimedIdentifier(claimedId, localId, providerEndpoint, v20TypeUris, servicePriority, uriPriority);
Assert.AreSame(Protocol.v20, se.Protocol);
- se = new ServiceEndpoint(claimedId, providerEndpoint, localId,
- new[] { Protocol.v20.OPIdentifierServiceTypeURI });
+ se = ServiceEndpoint.CreateForClaimedIdentifier(claimedId, localId, providerEndpoint,
+ new[] { Protocol.v20.OPIdentifierServiceTypeURI }, servicePriority, uriPriority);
Assert.AreSame(Protocol.v20, se.Protocol);
- se = new ServiceEndpoint(claimedId, providerEndpoint, localId, v11TypeUris);
+ se = ServiceEndpoint.CreateForClaimedIdentifier(claimedId, localId, providerEndpoint, v11TypeUris, servicePriority, uriPriority);
Assert.AreSame(Protocol.v11, se.Protocol);
}
[Test, ExpectedException(typeof(InvalidOperationException))]
public void ProtocolDetectionWithoutClues() {
- ServiceEndpoint se = new ServiceEndpoint(claimedId, providerEndpoint, localId,
- new[] { Protocol.v20.HtmlDiscoveryLocalIdKey }); // random type URI irrelevant to detection
+ ServiceEndpoint se = ServiceEndpoint.CreateForClaimedIdentifier(
+ claimedId, localId, providerEndpoint,
+ new[] { Protocol.v20.HtmlDiscoveryLocalIdKey }, servicePriority, uriPriority); // random type URI irrelevant to detection
Protocol p = se.Protocol;
}
[Test]
- public void Serialization() {
- ServiceEndpoint se = new ServiceEndpoint(claimedId, providerEndpoint, localId, v20TypeUris);
+ public void SerializationWithUri() {
+ ServiceEndpoint se = ServiceEndpoint.CreateForClaimedIdentifier(claimedId, localId, providerEndpoint, v20TypeUris, servicePriority, uriPriority);
StringBuilder sb = new StringBuilder();
using (StringWriter sw = new StringWriter(sb)) {
se.Serialize(sw);
@@ -62,25 +68,79 @@ namespace DotNetOpenId.Test.RelyingParty { 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);
+ }
+ }
+
+ [Test]
+ public void SerializationWithXri() {
+ ServiceEndpoint se = ServiceEndpoint.CreateForClaimedIdentifier(claimedXri, userSuppliedXri, localId, providerEndpoint, v20TypeUris, servicePriority, 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);
}
}
[Test]
public void EqualsTests() {
- ServiceEndpoint se = new ServiceEndpoint(claimedId, providerEndpoint, localId, v20TypeUris);
- ServiceEndpoint se2 = new ServiceEndpoint(claimedId, providerEndpoint, localId, v20TypeUris);
+ ServiceEndpoint se = ServiceEndpoint.CreateForClaimedIdentifier(claimedId, localId, providerEndpoint, v20TypeUris, servicePriority, uriPriority);
+ ServiceEndpoint se2 = ServiceEndpoint.CreateForClaimedIdentifier(claimedId, localId, providerEndpoint, v20TypeUris, (int?)null, (int?)null);
Assert.AreEqual(se2, se);
Assert.AreNotEqual(se, null);
Assert.AreNotEqual(null, se);
- ServiceEndpoint se3 = new ServiceEndpoint(claimedId + "a", providerEndpoint, localId, v20TypeUris);
+ ServiceEndpoint se3 = ServiceEndpoint.CreateForClaimedIdentifier(new UriIdentifier(claimedId + "a"), localId, providerEndpoint, v20TypeUris, servicePriority, uriPriority);
Assert.AreNotEqual(se, se3);
- se3 = new ServiceEndpoint(claimedId, new Uri(providerEndpoint.AbsoluteUri + "a"), localId, v20TypeUris);
+ se3 = ServiceEndpoint.CreateForClaimedIdentifier(claimedId, localId, new Uri(providerEndpoint.AbsoluteUri + "a"), v20TypeUris, servicePriority, uriPriority);
Assert.AreNotEqual(se, se3);
- se3 = new ServiceEndpoint(claimedId, providerEndpoint, localId + "a", v20TypeUris);
+ se3 = ServiceEndpoint.CreateForClaimedIdentifier(claimedId, localId + "a", providerEndpoint, v20TypeUris, servicePriority, uriPriority);
Assert.AreNotEqual(se, se3);
- se3 = new ServiceEndpoint(claimedId, providerEndpoint, localId, v11TypeUris);
+ se3 = ServiceEndpoint.CreateForClaimedIdentifier(claimedId, localId, providerEndpoint, v11TypeUris, servicePriority, 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));
+ }
+
+ [Test]
+ public void FriendlyIdentifierForDisplay() {
+ Uri providerEndpoint= new Uri("http://someprovider");
+ Identifier localId = "someuser";
+ string[] serviceTypeUris = new string[] {
+ Protocol.v20.ClaimedIdentifierServiceTypeURI,
+ };
+ ServiceEndpoint se;
+
+ // strip of protocol and fragment
+ se = ServiceEndpoint.CreateForClaimedIdentifier("http://someprovider.somedomain.com:79/someuser#frag",
+ localId, providerEndpoint, serviceTypeUris, null, null);
+ Assert.AreEqual("someprovider.somedomain.com:79/someuser", se.FriendlyIdentifierForDisplay);
+
+ // unescape characters
+ Uri foreignUri = new Uri("http://server崎/村");
+ se = ServiceEndpoint.CreateForClaimedIdentifier(foreignUri, localId, 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, 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, providerEndpoint, serviceTypeUris, null, null);
+ Assert.AreEqual("=!9B72.7DD1.50A9.5CCD", se.FriendlyIdentifierForDisplay);
}
}
}
diff --git a/src/DotNetOpenId.Test/RelyingParty/TokenTest.cs b/src/DotNetOpenId.Test/RelyingParty/TokenTest.cs index b83c47f..c57f68a 100644 --- a/src/DotNetOpenId.Test/RelyingParty/TokenTest.cs +++ b/src/DotNetOpenId.Test/RelyingParty/TokenTest.cs @@ -1,20 +1,18 @@ -using System;
-using System.Collections.Generic;
-using System.Text;
+using DotNetOpenId.RelyingParty;
using NUnit.Framework;
-using DotNetOpenId.RelyingParty;
-using System.Threading;
namespace DotNetOpenId.Test.RelyingParty {
[TestFixture]
public class TokenTest {
static ServiceEndpoint getServiceEndpoint(TestSupport.Scenarios scenario, ProtocolVersion version) {
Protocol protocol = Protocol.Lookup(version);
- ServiceEndpoint ep = new ServiceEndpoint(
+ ServiceEndpoint ep = ServiceEndpoint.CreateForClaimedIdentifier(
TestSupport.GetIdentityUrl(scenario, version),
- TestSupport.GetFullUrl(TestSupport.ProviderPage),
TestSupport.GetDelegateUrl(scenario),
- new[] { protocol.ClaimedIdentifierServiceTypeURI }
+ TestSupport.GetFullUrl(TestSupport.ProviderPage),
+ new[] { protocol.ClaimedIdentifierServiceTypeURI },
+ 10,
+ 10
);
return ep;
}
diff --git a/src/DotNetOpenId.Test/TestSupport.cs b/src/DotNetOpenId.Test/TestSupport.cs index be17494..66822eb 100644 --- a/src/DotNetOpenId.Test/TestSupport.cs +++ b/src/DotNetOpenId.Test/TestSupport.cs @@ -1,27 +1,39 @@ using System;
using System.Collections.Generic;
-using System.Text;
-using NUnit.Framework;
+using System.Collections.Specialized;
+using System.Diagnostics;
using System.IO;
-using System.Globalization;
-using DotNetOpenId.Test.Hosting;
+using System.Reflection;
+using System.Web;
using DotNetOpenId;
-using System.Net;
-using System.Collections.Specialized;
+using DotNetOpenId.Provider;
using DotNetOpenId.RelyingParty;
-using System.Diagnostics;
+using DotNetOpenId.Test.Mocks;
+using DotNetOpenId.Test.UI;
+using log4net;
+using NUnit.Framework;
+using IProviderAssociationStore = DotNetOpenId.IAssociationStore<DotNetOpenId.AssociationRelyingPartyType>;
+using ProviderMemoryStore = DotNetOpenId.AssociationMemoryStore<DotNetOpenId.AssociationRelyingPartyType>;
[SetUpFixture]
public class TestSupport {
public static readonly string TestWebDirectory = Path.GetFullPath(Path.Combine(Directory.GetCurrentDirectory(), @"..\..\src\DotNetOpenId.TestWeb"));
public const string HostTestPage = "HostTest.aspx";
const string identityPage = "IdentityEndpoint.aspx";
+ const string directedIdentityPage = "DirectedIdentityEndpoint.aspx";
public const string ProviderPage = "ProviderEndpoint.aspx";
+ public const string DirectedProviderEndpoint = "DirectedProviderEndpoint.aspx";
public const string MobileConsumerPage = "RelyingPartyMobile.aspx";
public const string ConsumerPage = "RelyingParty.aspx";
+ public const string OPDefaultPage = "OPDefault.aspx";
+ public static Uri ReturnTo { get { return TestSupport.GetFullUrl(TestSupport.ConsumerPage); } }
+ public static Realm Realm { get { return new Realm(TestSupport.GetFullUrl(TestSupport.ConsumerPage).AbsoluteUri); } }
+ public readonly static ILog Logger = LogManager.GetLogger("DotNetOpenId.Test");
+
public enum Scenarios {
// Authentication test scenarios
AutoApproval,
+ AutoApprovalAddFragment,
ApproveOnSetup,
AlwaysDeny,
@@ -35,39 +47,278 @@ public class TestSupport { /// </summary>
ExtensionPartialCooperation,
}
+ internal static UriIdentifier GetOPIdentityUrl(Scenarios scenario, bool useSsl) {
+ var args = new Dictionary<string, string> {
+ { "user", scenario.ToString() },
+ };
+ return new UriIdentifier(GetFullUrl("/" + OPDefaultPage, args, useSsl));
+ }
internal static UriIdentifier GetIdentityUrl(Scenarios scenario, ProtocolVersion providerVersion) {
- UriBuilder builder = new UriBuilder(Host.BaseUri);
- builder.Path = "/" + identityPage;
- builder.Query = "user=" + scenario + "&version=" + providerVersion;
- return new UriIdentifier(builder.Uri);
+ return GetIdentityUrl(scenario, providerVersion, false);
+ }
+ internal static UriIdentifier GetIdentityUrl(Scenarios scenario, ProtocolVersion providerVersion, bool useSsl) {
+ return new UriIdentifier(GetFullUrl("/" + identityPage, new Dictionary<string, string> {
+ { "user", scenario.ToString() },
+ { "version", providerVersion.ToString() },
+ }, useSsl));
+ }
+ internal static UriIdentifier GetDirectedIdentityUrl(Scenarios scenario, ProtocolVersion providerVersion) {
+ return GetDirectedIdentityUrl(scenario, providerVersion, false);
+ }
+ internal static UriIdentifier GetDirectedIdentityUrl(Scenarios scenario, ProtocolVersion providerVersion, bool useSsl) {
+ return new UriIdentifier(GetFullUrl("/" + directedIdentityPage, new Dictionary<string, string> {
+ { "user", scenario.ToString() },
+ { "version", providerVersion.ToString() },
+ }, useSsl));
}
public static Identifier GetDelegateUrl(Scenarios scenario) {
- return new UriIdentifier(new Uri(Host.BaseUri, "/" + scenario));
+ return GetDelegateUrl(scenario, false);
+ }
+ public static Identifier GetDelegateUrl(Scenarios scenario, bool useSsl) {
+ return new UriIdentifier(GetFullUrl("/" + scenario, null, useSsl));
+ }
+ internal static MockIdentifier GetMockIdentifier(Scenarios scenario, ProtocolVersion providerVersion) {
+ return GetMockIdentifier(scenario, providerVersion, false);
+ }
+ internal static MockIdentifier GetMockIdentifier(Scenarios scenario, ProtocolVersion providerVersion, bool useSsl) {
+ ServiceEndpoint se = GetServiceEndpoint(scenario, providerVersion, 10, useSsl);
+ return new MockIdentifier(GetIdentityUrl(scenario, providerVersion, useSsl), new ServiceEndpoint[] { se });
+ }
+ internal static ServiceEndpoint GetServiceEndpoint(Scenarios scenario, ProtocolVersion providerVersion, int servicePriority, bool useSsl) {
+ return ServiceEndpoint.CreateForClaimedIdentifier(
+ GetIdentityUrl(scenario, providerVersion, useSsl),
+ GetDelegateUrl(scenario, useSsl),
+ GetFullUrl("/" + ProviderPage, null, useSsl),
+ new string[] { Protocol.Lookup(providerVersion).ClaimedIdentifierServiceTypeURI },
+ servicePriority,
+ 10
+ );
+ }
+ internal static MockIdentifier GetMockOPIdentifier(Scenarios scenario, UriIdentifier expectedClaimedId) {
+ return GetMockOPIdentifier(scenario, expectedClaimedId, false, false);
+ }
+ internal static MockIdentifier GetMockOPIdentifier(Scenarios scenario, UriIdentifier expectedClaimedId, bool useSslOpIdentifier, bool useSslProviderEndpoint) {
+ var fields = new Dictionary<string, string> {
+ { "user", scenario.ToString() },
+ };
+ Uri opEndpoint = GetFullUrl(DirectedProviderEndpoint, fields, useSslProviderEndpoint);
+ Uri opIdentifier = GetOPIdentityUrl(scenario, useSslOpIdentifier);
+ ServiceEndpoint se = ServiceEndpoint.CreateForProviderIdentifier(
+ opIdentifier,
+ opEndpoint,
+ new string[] { Protocol.v20.OPIdentifierServiceTypeURI },
+ 10,
+ 10
+ );
+
+ // Register the Claimed Identifier that directed identity will choose so that RP
+ // discovery on that identifier can be mocked up.
+ MockHttpRequest.RegisterMockXrdsResponse(expectedClaimedId, se);
+
+ return new MockIdentifier(opIdentifier, new ServiceEndpoint[] { se });
}
public static Uri GetFullUrl(string url) {
- return GetFullUrl(url, null);
+ return GetFullUrl(url, null, false);
+ }
+ public static Uri GetFullUrl(string url, string key, object value) {
+ return GetFullUrl(url, new Dictionary<string, string> {
+ { key, value.ToString() },
+ }, false);
}
- public static Uri GetFullUrl(string url, IDictionary<string, string> args) {
- UriBuilder builder = new UriBuilder(new Uri(Host.BaseUri, url));
+ public static Uri GetFullUrl(string url, IDictionary<string, string> args, bool useSsl) {
+ Uri defaultUriBase = new Uri(useSsl ? "https://localhost/" : "http://localhost/");
+ Uri baseUri = UITestSupport.Host != null ? UITestSupport.Host.BaseUri : defaultUriBase;
+ UriBuilder builder = new UriBuilder(new Uri(baseUri, url));
UriUtil.AppendQueryArgs(builder, args);
return builder.Uri;
}
- internal static AspNetHost Host { get; private set; }
- internal static EncodingInterceptor Interceptor { get; private set; }
+ /// <summary>
+ /// Returns the content of a given embedded resource.
+ /// </summary>
+ /// <param name="path">The path of the file as it appears within the project,
+ /// where the leading / marks the root directory of the project.</param>
+ internal static string LoadEmbeddedFile(string path) {
+ if (!path.StartsWith("/")) path = "/" + path;
+ path = "DotNetOpenId.Test" + path.Replace('/', '.');
+ Stream resource = Assembly.GetExecutingAssembly().GetManifestResourceStream(path);
+ if (resource == null) throw new ArgumentException();
+ using (StreamReader sr = new StreamReader(resource)) {
+ return sr.ReadToEnd();
+ }
+ }
+
+ internal static IRelyingPartyApplicationStore RelyingPartyStore;
+ internal static IProviderAssociationStore ProviderStore;
+ /// <summary>
+ /// Generates a new, stateful <see cref="OpenIdRelyingParty"/> whose direct messages
+ /// will be automatically handled by an internal <see cref="OpenIdProvider"/>
+ /// that uses the shared <see cref="ProviderStore"/>.
+ /// </summary>
+ internal static OpenIdRelyingParty CreateRelyingParty(NameValueCollection fields) {
+ return CreateRelyingParty(RelyingPartyStore, null, fields);
+ }
+ internal static OpenIdRelyingParty CreateRelyingParty(IRelyingPartyApplicationStore store, NameValueCollection fields) {
+ return CreateRelyingParty(store, null, fields);
+ }
+ /// <summary>
+ /// Generates a new <see cref="OpenIdRelyingParty"/> whose direct messages
+ /// will be automatically handled by an internal <see cref="OpenIdProvider"/>
+ /// that uses the shared <see cref="ProviderStore"/>.
+ /// </summary>
+ internal static OpenIdRelyingParty CreateRelyingParty(IRelyingPartyApplicationStore store, Uri requestUrl, NameValueCollection fields) {
+ var rp = new OpenIdRelyingParty(store, requestUrl ?? GetFullUrl(ConsumerPage), fields ?? new NameValueCollection());
+ if (fields == null || fields.Count == 0) {
+ Assert.IsNull(rp.Response);
+ }
+ rp.DirectMessageChannel = new DirectMessageTestRedirector(ProviderStore);
+ return rp;
+ }
+ internal static DotNetOpenId.RelyingParty.IAuthenticationRequest CreateRelyingPartyRequest(bool stateless, Scenarios scenario, ProtocolVersion version, bool useSsl) {
+ // Publish RP discovery information
+ MockHttpRequest.RegisterMockRPDiscovery();
+
+ var rp = TestSupport.CreateRelyingParty(stateless ? null : RelyingPartyStore, null);
+ var rpReq = rp.CreateRequest(TestSupport.GetMockIdentifier(scenario, version, useSsl), Realm, ReturnTo);
+
+ {
+ // Sidetrack: verify URLs and other default properties
+ Assert.AreEqual(AuthenticationRequestMode.Setup, rpReq.Mode);
+ Assert.AreEqual(Realm, rpReq.Realm);
+ Assert.AreEqual(ReturnTo, rpReq.ReturnToUrl);
+ }
+
+ return rpReq;
+ }
+ /// <summary>
+ /// Generates a new <see cref="OpenIdRelyingParty"/> ready to process a
+ /// response from an <see cref="OpenIdProvider"/>.
+ /// </summary>
+ internal static IAuthenticationResponse CreateRelyingPartyResponse(IRelyingPartyApplicationStore store, IResponse providerResponse) {
+ return CreateRelyingPartyResponse(store, providerResponse, false);
+ }
+ internal static IAuthenticationResponse CreateRelyingPartyResponse(IRelyingPartyApplicationStore store, IResponse providerResponse, bool requireSsl) {
+ if (providerResponse == null) throw new ArgumentNullException("providerResponse");
+
+ var opAuthWebResponse = (Response)providerResponse;
+ var opAuthResponse = (EncodableResponse)opAuthWebResponse.EncodableMessage;
+ var rp = CreateRelyingParty(store, opAuthResponse.RedirectUrl,
+ opAuthResponse.EncodedFields.ToNameValueCollection());
+ rp.Settings.RequireSsl = requireSsl;
+ // Get the response now, before trying the replay attack. The Response
+ // property is lazily-evaluated, so the replay attack can be evaluated first
+ // and pass, while this one that SUPPOSED to pass fails, if we don't force it now.
+ var response = rp.Response;
+
+ // Side-track to test for replay attack while we're at it.
+ // This simulates a network sniffing user who caught the
+ // authenticating query en route to either the user agent or
+ // the consumer, and tries the same query to the consumer in an
+ // attempt to spoof the identity of the authenticating user.
+ try {
+ Logger.Info("Attempting replay attack...");
+ var replayRP = CreateRelyingParty(store, opAuthResponse.RedirectUrl,
+ opAuthResponse.EncodedFields.ToNameValueCollection());
+ replayRP.Settings.RequireSsl = requireSsl;
+ Assert.AreNotEqual(AuthenticationStatus.Authenticated, replayRP.Response.Status, "Replay attack succeeded!");
+ } catch (OpenIdException) { // nonce already used
+ // another way to pass
+ }
+
+ // Return the result of the initial response (not the replay attack one).
+ return response;
+ }
+ /// <summary>
+ /// Generates a new <see cref="OpenIdProvider"/> that uses the shared
+ /// store in <see cref="ProviderStore"/>.
+ /// </summary>
+ internal static OpenIdProvider CreateProvider(NameValueCollection fields) {
+ return CreateProvider(fields, false);
+ }
+ internal static OpenIdProvider CreateProvider(NameValueCollection fields, bool useSsl) {
+ Protocol protocol = fields != null ? Protocol.Detect(fields.ToDictionary()) : Protocol.v20;
+ Uri opEndpoint = GetFullUrl(ProviderPage, null, useSsl);
+ var provider = new OpenIdProvider(ProviderStore, opEndpoint, opEndpoint, fields ?? new NameValueCollection());
+ return provider;
+ }
+ internal static OpenIdProvider CreateProviderForRequest(DotNetOpenId.RelyingParty.IAuthenticationRequest request) {
+ IResponse relyingPartyAuthenticationRequest = request.RedirectingResponse;
+ var rpWebMessageToOP = (Response)relyingPartyAuthenticationRequest;
+ var rpMessageToOP = (IndirectMessageRequest)rpWebMessageToOP.EncodableMessage;
+ var opEndpoint = (ServiceEndpoint)request.Provider;
+ var provider = new OpenIdProvider(ProviderStore, opEndpoint.ProviderEndpoint,
+ opEndpoint.ProviderEndpoint, rpMessageToOP.EncodedFields.ToNameValueCollection());
+ return provider;
+ }
+ internal static IResponse CreateProviderResponseToRequest(
+ DotNetOpenId.RelyingParty.IAuthenticationRequest request,
+ Action<DotNetOpenId.Provider.IAuthenticationRequest> prepareProviderResponse) {
+
+ {
+ // Sidetrack: Verify the return_to and realm URLs
+ var consumerToProviderQuery = HttpUtility.ParseQueryString(request.RedirectingResponse.ExtractUrl().Query);
+ Protocol protocol = Protocol.Detect(consumerToProviderQuery.ToDictionary());
+ Assert.IsTrue(consumerToProviderQuery[protocol.openid.return_to].StartsWith(request.ReturnToUrl.AbsoluteUri, StringComparison.Ordinal));
+ Assert.AreEqual(request.Realm.ToString(), consumerToProviderQuery[protocol.openid.Realm]);
+ }
+
+ var op = TestSupport.CreateProviderForRequest(request);
+ var opReq = (DotNetOpenId.Provider.IAuthenticationRequest)op.Request;
+ prepareProviderResponse(opReq);
+ Assert.IsTrue(opReq.IsResponseReady);
+ return opReq.Response;
+ }
+ internal static IAuthenticationResponse CreateRelyingPartyResponseThroughProvider(
+ DotNetOpenId.RelyingParty.IAuthenticationRequest request,
+ Action<DotNetOpenId.Provider.IAuthenticationRequest> providerAction) {
+
+ var rpReq = (AuthenticationRequest)request;
+ var opResponse = CreateProviderResponseToRequest(rpReq, providerAction);
+ // Be careful to use whatever store the original RP was using.
+ var rp = CreateRelyingPartyResponse(rpReq.RelyingParty.Store, opResponse,
+ ((AuthenticationRequest)request).RelyingParty.Settings.RequireSsl);
+ Assert.IsNotNull(rp);
+ return rp;
+ }
[SetUp]
public void SetUp() {
- Host = AspNetHost.CreateHost(TestSupport.TestWebDirectory);
- Host.MessageInterceptor = Interceptor = new EncodingInterceptor();
+ log4net.Config.XmlConfigurator.Configure(Assembly.GetExecutingAssembly().GetManifestResourceStream("DotNetOpenId.Test.Logging.config"));
+
+ ResetStores();
}
[TearDown]
public void TearDown() {
- Host.MessageInterceptor = null;
- if (Host != null) {
- Host.CloseHttp();
- Host = null;
+ log4net.LogManager.Shutdown();
+ }
+
+ internal static void ResetStores() {
+ RelyingPartyStore = new ApplicationMemoryStore();
+ ProviderStore = new ProviderMemoryStore();
+ }
+
+ internal static void SetAuthenticationFromScenario(Scenarios scenario, DotNetOpenId.Provider.IAuthenticationRequest request) {
+ Assert.IsTrue(request.IsReturnUrlDiscoverable);
+ switch (scenario) {
+ case TestSupport.Scenarios.ExtensionFullCooperation:
+ case TestSupport.Scenarios.ExtensionPartialCooperation:
+ case TestSupport.Scenarios.AutoApproval:
+ // immediately approve
+ request.IsAuthenticated = true;
+ break;
+ case TestSupport.Scenarios.AutoApprovalAddFragment:
+ request.SetClaimedIdentifierFragment("frag");
+ request.IsAuthenticated = true;
+ break;
+ case TestSupport.Scenarios.ApproveOnSetup:
+ request.IsAuthenticated = !request.Immediate;
+ break;
+ case TestSupport.Scenarios.AlwaysDeny:
+ request.IsAuthenticated = false;
+ break;
+ default:
+ throw new InvalidOperationException("Unrecognized scenario");
}
}
@@ -76,7 +327,7 @@ public class TestSupport { /// to simulate a Provider that deliberately sent a bad message in an attempt
/// to thwart RP security.
/// </summary>
- internal static void Resign(NameValueCollection nvc, ApplicationMemoryStore store) {
+ internal static void Resign(NameValueCollection nvc, IRelyingPartyApplicationStore store) {
Debug.Assert(nvc != null);
Debug.Assert(store != null);
var dict = Util.NameValueCollectionToDictionary(nvc);
@@ -84,6 +335,7 @@ public class TestSupport { Uri providerEndpoint = new Uri(nvc[protocol.openid.op_endpoint]);
string assoc_handle = nvc[protocol.openid.assoc_handle];
Association assoc = store.GetAssociation(providerEndpoint, assoc_handle);
+ Debug.Assert(assoc != null, "Association not found in RP's store. Maybe you're communicating with a hosted OP instead of the TestSupport one?");
IList<string> signed = nvc[protocol.openid.signed].Split(',');
var subsetDictionary = new Dictionary<string, string>();
foreach (string signedKey in signed) {
@@ -92,6 +344,12 @@ public class TestSupport { }
nvc[protocol.openid.sig] = Convert.ToBase64String(assoc.Sign(subsetDictionary, signed));
}
+
+ public static IAssociationStore<AssociationRelyingPartyType> ProviderStoreContext {
+ get {
+ return DotNetOpenId.Provider.OpenIdProvider.HttpApplicationStore;
+ }
+ }
}
static class TestExtensions {
@@ -105,4 +363,20 @@ static class TestExtensions { UriUtil.AppendQueryArgs(builder, encodable.EncodedFields);
return builder.Uri;
}
+
+ public static NameValueCollection ToNameValueCollection(this IDictionary<string, string> dictionary) {
+ NameValueCollection nvc = new NameValueCollection(dictionary.Count);
+ foreach (var pair in dictionary) {
+ nvc.Add(pair.Key, pair.Value);
+ }
+ return nvc;
+ }
+ public static IDictionary<string, string> ToDictionary(this NameValueCollection nvc) {
+ if (nvc == null) return null;
+ Dictionary<string, string> dict = new Dictionary<string, string>(nvc.Count);
+ foreach (string key in nvc) {
+ dict[key] = nvc[key];
+ }
+ return dict;
+ }
}
diff --git a/src/DotNetOpenId.Test/Provider/IdentityEndpointTest.cs b/src/DotNetOpenId.Test/UI/IdentityEndpointTest.cs index 3fef4ec..89ec02a 100644 --- a/src/DotNetOpenId.Test/Provider/IdentityEndpointTest.cs +++ b/src/DotNetOpenId.Test/UI/IdentityEndpointTest.cs @@ -9,15 +9,15 @@ using System.Text.RegularExpressions; using System.Net;
using System.Globalization;
-namespace DotNetOpenId.Test.Provider {
+namespace DotNetOpenId.Test.UI {
[TestFixture]
public class IdentityEndpointTest {
void parameterizedIdentityEndpointPage(ProtocolVersion version) {
Protocol protocol = Protocol.Lookup(version);
TestSupport.Scenarios scenario = TestSupport.Scenarios.AutoApproval;
- UriIdentifier identityUrl = TestSupport.GetIdentityUrl(scenario, version);
- string html = TestSupport.Host.ProcessRequest(identityUrl.Uri.AbsoluteUri);
- Trace.TraceInformation("{0} response:{1}{2}", identityUrl, Environment.NewLine, html);
+ Identifier identityUrl = TestSupport.GetIdentityUrl(scenario, version);
+ string html = UITestSupport.Host.ProcessRequest(identityUrl);
+ TestSupport.Logger.InfoFormat("{0} response:{1}{2}", identityUrl, Environment.NewLine, html);
Assert.IsTrue(Regex.IsMatch(html, string.Format(CultureInfo.InvariantCulture,
@"\<link rel=""{1}"" href=""http://[^/]+/{0}""\>\</link\>",
Regex.Escape(TestSupport.ProviderPage),
diff --git a/src/DotNetOpenId.Test/RelyingParty/OpenIdMobileTextBoxTest.cs b/src/DotNetOpenId.Test/UI/OpenIdMobileTextBoxTest.cs index 0feea56..7ab78c6 100644 --- a/src/DotNetOpenId.Test/RelyingParty/OpenIdMobileTextBoxTest.cs +++ b/src/DotNetOpenId.Test/UI/OpenIdMobileTextBoxTest.cs @@ -4,12 +4,12 @@ using System.Linq; using System.Text;
using NUnit.Framework;
-namespace DotNetOpenId.Test.RelyingParty {
+namespace DotNetOpenId.Test.UI {
[TestFixture]
public class OpenIdMobileTextBoxTest {
[Test]
public void TextBoxAppears() {
- string html = TestSupport.Host.ProcessRequest(TestSupport.MobileConsumerPage);
+ string html = UITestSupport.Host.ProcessRequest(TestSupport.MobileConsumerPage);
Assert.IsTrue(html.Contains("<input "));
}
}
diff --git a/src/DotNetOpenId.Test/RelyingParty/OpenIdTextBoxTest.cs b/src/DotNetOpenId.Test/UI/OpenIdTextBoxTest.cs index 9176096..4012a05 100644 --- a/src/DotNetOpenId.Test/RelyingParty/OpenIdTextBoxTest.cs +++ b/src/DotNetOpenId.Test/UI/OpenIdTextBoxTest.cs @@ -5,12 +5,12 @@ using NUnit.Framework; using DotNetOpenId.Test.Hosting;
using System.Net;
-namespace DotNetOpenId.Test.RelyingParty {
+namespace DotNetOpenId.Test.UI {
[TestFixture]
public class OpenIdTextBoxTest {
[Test]
public void TextBoxAppears() {
- string html = TestSupport.Host.ProcessRequest(TestSupport.ConsumerPage);
+ string html = UITestSupport.Host.ProcessRequest(TestSupport.ConsumerPage);
Assert.IsTrue(html.Contains("<input "));
}
}
diff --git a/src/DotNetOpenId.Test/Provider/ProviderEndpointTest.cs b/src/DotNetOpenId.Test/UI/ProviderEndpointTest.cs index 7148f5b..6da933a 100644 --- a/src/DotNetOpenId.Test/Provider/ProviderEndpointTest.cs +++ b/src/DotNetOpenId.Test/UI/ProviderEndpointTest.cs @@ -6,7 +6,7 @@ using DotNetOpenId.Test.Hosting; using DotNetOpenId.Provider;
using System.Net;
-namespace DotNetOpenId.Test.Provider {
+namespace DotNetOpenId.Test.UI {
[TestFixture]
public class ProviderEndpointTest {
[Test]
diff --git a/src/DotNetOpenId.Test/TestSupportSanityTest.cs b/src/DotNetOpenId.Test/UI/TestSupportSanityTest.cs index df78dd5..e84625b 100644 --- a/src/DotNetOpenId.Test/TestSupportSanityTest.cs +++ b/src/DotNetOpenId.Test/UI/TestSupportSanityTest.cs @@ -8,14 +8,14 @@ using System.IO; using System.Diagnostics;
using System.Text.RegularExpressions;
-namespace DotNetOpenId.Test {
+namespace DotNetOpenId.Test.UI {
[TestFixture]
public class TestSupportSanityTest {
[Test]
public void TestHost() {
string query = "a=b&c=d";
string body = "aa=bb&cc=dd";
- string resultHtml = TestSupport.Host.ProcessRequest(TestSupport.HostTestPage + "?" + query, body);
+ string resultHtml = UITestSupport.Host.ProcessRequest(TestSupport.HostTestPage + "?" + query, body);
Assert.IsFalse(string.IsNullOrEmpty(resultHtml));
Debug.WriteLine(resultHtml);
@@ -25,7 +25,7 @@ namespace DotNetOpenId.Test { [Test]
public void TestProviderPage() {
- string html = TestSupport.Host.ProcessRequest(TestSupport.ProviderPage);
+ string html = UITestSupport.Host.ProcessRequest(TestSupport.ProviderPage);
Assert.IsFalse(string.IsNullOrEmpty(html));
}
}
diff --git a/src/DotNetOpenId.Test/UI/UITestSupport.cs b/src/DotNetOpenId.Test/UI/UITestSupport.cs new file mode 100644 index 0000000..40d169a --- /dev/null +++ b/src/DotNetOpenId.Test/UI/UITestSupport.cs @@ -0,0 +1,26 @@ +using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using NUnit.Framework;
+using DotNetOpenId.Test.Hosting;
+
+namespace DotNetOpenId.Test.UI {
+ [SetUpFixture]
+ public class UITestSupport {
+ internal static AspNetHost Host { get; private set; }
+
+ [SetUp]
+ public void SetUp() {
+ Host = AspNetHost.CreateHost(TestSupport.TestWebDirectory);
+ }
+
+ [TearDown]
+ public void TearDown() {
+ if (Host != null) {
+ Host.CloseHttp();
+ Host = null;
+ }
+ }
+ }
+}
diff --git a/src/DotNetOpenId.Test/UI/WebControlTesting.cs b/src/DotNetOpenId.Test/UI/WebControlTesting.cs new file mode 100644 index 0000000..2ec010f --- /dev/null +++ b/src/DotNetOpenId.Test/UI/WebControlTesting.cs @@ -0,0 +1,103 @@ +using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using NUnit.Framework;
+using DotNetOpenId.RelyingParty;
+using System.Net;
+using System.Collections.Specialized;
+using System.IO;
+using System.Text.RegularExpressions;
+using System.Diagnostics;
+
+namespace DotNetOpenId.Test.UI {
+ [TestFixture]
+ public class WebControlTesting {
+ void parameterizedWebClientTest(Identifier identityUrl,
+ AuthenticationRequestMode requestMode, AuthenticationStatus expectedResult) {
+
+ Uri redirectToProviderUrl;
+ HttpWebRequest rpRequest = (HttpWebRequest)WebRequest.Create(TestSupport.GetFullUrl(TestSupport.ConsumerPage));
+ NameValueCollection query = new NameValueCollection();
+ using (HttpWebResponse response = (HttpWebResponse)rpRequest.GetResponse()) {
+ using (StreamReader sr = new StreamReader(response.GetResponseStream())) {
+ Regex regex = new Regex(@"\<input\b.*\bname=""(\w+)"".*\bvalue=""([^""]+)""", RegexOptions.IgnoreCase);
+ while (!sr.EndOfStream) {
+ string line = sr.ReadLine();
+ Match m = regex.Match(line);
+ if (m.Success) {
+ query[m.Groups[1].Value] = m.Groups[2].Value;
+ }
+ }
+ }
+ }
+ query["OpenIdTextBox1$wrappedTextBox"] = identityUrl;
+ rpRequest = (HttpWebRequest)WebRequest.Create(TestSupport.GetFullUrl(TestSupport.ConsumerPage));
+ rpRequest.Method = "POST";
+ rpRequest.AllowAutoRedirect = false;
+ string queryString = UriUtil.CreateQueryString(query);
+ rpRequest.ContentLength = queryString.Length;
+ rpRequest.ContentType = "application/x-www-form-urlencoded";
+ using (StreamWriter sw = new StreamWriter(rpRequest.GetRequestStream())) {
+ sw.Write(queryString);
+ }
+ using (HttpWebResponse response = (HttpWebResponse)rpRequest.GetResponse()) {
+ using (StreamReader sr = new StreamReader(response.GetResponseStream())) {
+ string doc = sr.ReadToEnd();
+ Debug.WriteLine(doc);
+ }
+ redirectToProviderUrl = new Uri(response.Headers[HttpResponseHeader.Location]);
+ }
+
+ HttpWebRequest providerRequest = (HttpWebRequest)WebRequest.Create(redirectToProviderUrl);
+ providerRequest.AllowAutoRedirect = false;
+ Uri redirectUrl;
+ try {
+ using (HttpWebResponse providerResponse = (HttpWebResponse)providerRequest.GetResponse()) {
+ Assert.AreEqual(HttpStatusCode.Redirect, providerResponse.StatusCode);
+ redirectUrl = new Uri(providerResponse.Headers[HttpResponseHeader.Location]);
+ }
+ } catch (WebException ex) {
+ TestSupport.Logger.Error("WebException", ex);
+ if (ex.Response != null) {
+ using (StreamReader sr = new StreamReader(ex.Response.GetResponseStream())) {
+ TestSupport.Logger.ErrorFormat("Response stream follows: {0}", sr.ReadToEnd());
+ }
+ }
+ throw;
+ }
+ rpRequest = (HttpWebRequest)WebRequest.Create(redirectUrl);
+ rpRequest.AllowAutoRedirect = false;
+ using (HttpWebResponse response = (HttpWebResponse)rpRequest.GetResponse()) {
+ Assert.AreEqual(HttpStatusCode.Redirect, response.StatusCode); // redirect on login
+ }
+
+ // Try replay attack
+ if (expectedResult == AuthenticationStatus.Authenticated) {
+ // This simulates a network sniffing user who caught the
+ // authenticating query en route to either the user agent or
+ // the consumer, and tries the same query to the consumer in an
+ // attempt to spoof the identity of the authenticating user.
+ rpRequest = (HttpWebRequest)WebRequest.Create(redirectUrl);
+ rpRequest.AllowAutoRedirect = false;
+ using (HttpWebResponse response = (HttpWebResponse)rpRequest.GetResponse()) {
+ Assert.AreEqual(HttpStatusCode.OK, response.StatusCode); // error message
+ }
+ }
+ }
+
+ [Test]
+ public void Pass_Setup_AutoApproval_20() {
+ Identifier userSuppliedIdentifier = TestSupport.GetMockIdentifier(TestSupport.Scenarios.AutoApproval, ProtocolVersion.V20);
+ Identifier claimedId = userSuppliedIdentifier;
+ parameterizedWebClientTest(userSuppliedIdentifier, AuthenticationRequestMode.Setup, AuthenticationStatus.Authenticated);
+ }
+
+ [Test]
+ public void Fail_Immediate_ApproveOnSetup_20() {
+ Identifier userSuppliedIdentifier = TestSupport.GetMockIdentifier(TestSupport.Scenarios.ApproveOnSetup, ProtocolVersion.V20);
+ Identifier claimedId = userSuppliedIdentifier;
+ parameterizedWebClientTest(userSuppliedIdentifier, AuthenticationRequestMode.Immediate, AuthenticationStatus.Authenticated);
+ }
+ }
+}
diff --git a/src/DotNetOpenId.Test/UntrustedWebRequestTests.cs b/src/DotNetOpenId.Test/UntrustedWebRequestTests.cs index c44354c..7bba993 100644 --- a/src/DotNetOpenId.Test/UntrustedWebRequestTests.cs +++ b/src/DotNetOpenId.Test/UntrustedWebRequestTests.cs @@ -1,10 +1,9 @@ using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using NUnit.Framework;
-using System.Text.RegularExpressions;
+using System.IO;
using System.Net;
+using System.Text.RegularExpressions;
+using DotNetOpenId.Test.Mocks;
+using NUnit.Framework;
namespace DotNetOpenId.Test {
[TestFixture]
@@ -25,7 +24,7 @@ namespace DotNetOpenId.Test { [Test]
public void DisallowUnsafeHosts() {
- string[] unsafeHosts = new [] {
+ string[] unsafeHosts = new[] {
// IPv4 loopback representations
"http://127.0.0.1",
"http://127.100.0.1",
@@ -89,5 +88,38 @@ namespace DotNetOpenId.Test { UntrustedWebRequest.BlacklistHostsRegex.Add(new Regex(@"\Wmicrosoft.com$"));
UntrustedWebRequest.Request(new Uri("http://WWW.MICROSOFT.COM"));
}
+
+ /// <summary>
+ /// Tests an implicit redirect where the HTTP server changes the responding URI without even
+ /// redirecting the client.
+ /// </summary>
+ [Test]
+ public void Redirects() {
+ UntrustedWebRequest.WhitelistHosts.Add("localhost");
+ UntrustedWebResponse resp = new UntrustedWebResponse(
+ new Uri("http://localhost/req"), new Uri("http://localhost/resp"),
+ new WebHeaderCollection(), HttpStatusCode.OK, "text/html", null, new MemoryStream());
+ MockHttpRequest.RegisterMockResponse(resp);
+ Assert.AreSame(resp, UntrustedWebRequest.Request(new Uri("http://localhost/req")));
+ }
+
+ /// <summary>
+ /// Tests that HTTP Location headers that only use a relative path get interpreted correctly.
+ /// </summary>
+ [Test]
+ public void RelativeRedirect() {
+ UntrustedWebRequest.WhitelistHosts.Add("localhost");
+ UntrustedWebResponse resp1 = new UntrustedWebResponse(
+ new Uri("http://localhost/dir/file1"), new Uri("http://localhost/dir/file1"),
+ new WebHeaderCollection {
+ { HttpResponseHeader.Location, "file2" },
+ }, HttpStatusCode.Redirect, "text/html", null, new MemoryStream());
+ MockHttpRequest.RegisterMockResponse(resp1);
+ UntrustedWebResponse resp2 = new UntrustedWebResponse(
+ new Uri("http://localhost/dir/file2"), new Uri("http://localhost/dir/file2"),
+ new WebHeaderCollection(), HttpStatusCode.OK, "text/html", null, new MemoryStream());
+ MockHttpRequest.RegisterMockResponse(resp2);
+ Assert.AreSame(resp2, UntrustedWebRequest.Request(new Uri("http://localhost/dir/file1")));
+ }
}
}
diff --git a/src/DotNetOpenId.Test/UriIdentifierTests.cs b/src/DotNetOpenId.Test/UriIdentifierTests.cs index 337ec23..830be3c 100644 --- a/src/DotNetOpenId.Test/UriIdentifierTests.cs +++ b/src/DotNetOpenId.Test/UriIdentifierTests.cs @@ -1,15 +1,18 @@ using System;
using System.Collections.Generic;
-using System.Text;
-using NUnit.Framework;
-using DotNetOpenId.RelyingParty;
+using System.Linq;
using System.Net;
+using System.Web;
using DotNetOpenId.Extensions.SimpleRegistration;
+using DotNetOpenId.RelyingParty;
+using DotNetOpenId.Test.Mocks;
+using NUnit.Framework;
namespace DotNetOpenId.Test {
[TestFixture]
public class UriIdentifierTests {
string goodUri = "http://blog.nerdbank.net/";
+ string relativeUri = "host/path";
string badUri = "som%-)830w8vf/?.<>,ewackedURI";
[SetUp]
@@ -18,6 +21,11 @@ namespace DotNetOpenId.Test { UntrustedWebRequest.WhitelistHosts.Add("localhost");
}
+ [TearDown]
+ public void TearDown() {
+ Mocks.MockHttpRequest.Reset();
+ }
+
[Test, ExpectedException(typeof(ArgumentNullException))]
public void CtorNullUri() {
new UriIdentifier((Uri)null);
@@ -42,12 +50,69 @@ namespace DotNetOpenId.Test { public void CtorGoodUri() {
var uri = new UriIdentifier(goodUri);
Assert.AreEqual(new Uri(goodUri), uri.Uri);
+ Assert.IsFalse(uri.SchemeImplicitlyPrepended);
+ Assert.IsFalse(uri.IsDiscoverySecureEndToEnd);
+ }
+
+ [Test]
+ public void CtorStringNoSchemeSecure() {
+ var uri = new UriIdentifier("host/path", true);
+ Assert.AreEqual("https://host/path", uri.Uri.AbsoluteUri);
+ Assert.IsTrue(uri.IsDiscoverySecureEndToEnd);
+ }
+
+ [Test]
+ public void CtorStringHttpsSchemeSecure() {
+ var uri = new UriIdentifier("https://host/path", true);
+ Assert.AreEqual("https://host/path", uri.Uri.AbsoluteUri);
+ Assert.IsTrue(uri.IsDiscoverySecureEndToEnd);
+ }
+
+ [Test, ExpectedException(typeof(ArgumentException))]
+ public void CtorStringHttpSchemeSecure() {
+ new UriIdentifier("http://host/path", true);
+ }
+
+ [Test]
+ public void CtorUriHttpsSchemeSecure() {
+ var uri = new UriIdentifier(new Uri("https://host/path"), true);
+ Assert.AreEqual("https://host/path", uri.Uri.AbsoluteUri);
+ Assert.IsTrue(uri.IsDiscoverySecureEndToEnd);
+ }
+
+ [Test, ExpectedException(typeof(ArgumentException))]
+ public void CtorUriHttpSchemeSecure() {
+ new UriIdentifier(new Uri("http://host/path"), true);
+ }
+
+ /// <summary>
+ /// Verifies that the fragment is not stripped from an Identifier.
+ /// </summary>
+ /// <remarks>
+ /// Although fragments should be stripped from user supplied identifiers,
+ /// they should NOT be stripped from claimed identifiers. So the UriIdentifier
+ /// class, which serves both identifier types, must not do the stripping.
+ /// </remarks>
+ [Test]
+ public void DoesNotStripFragment() {
+ Uri original = new Uri("http://a/b#c");
+ UriIdentifier identifier = new UriIdentifier(original);
+ Assert.AreEqual(original.Fragment, identifier.Uri.Fragment);
}
[Test]
public void IsValid() {
Assert.IsTrue(UriIdentifier.IsValidUri(goodUri));
Assert.IsFalse(UriIdentifier.IsValidUri(badUri));
+ Assert.IsTrue(UriIdentifier.IsValidUri(relativeUri), "URL lacking http:// prefix should have worked anyway.");
+ }
+
+ [Test]
+ public void TrimFragment() {
+ Identifier noFragment = UriIdentifier.Parse("http://a/b");
+ Identifier fragment = UriIdentifier.Parse("http://a/b#c");
+ Assert.AreSame(noFragment, noFragment.TrimFragment());
+ Assert.AreEqual(noFragment, fragment.TrimFragment());
}
[Test]
@@ -58,91 +123,305 @@ namespace DotNetOpenId.Test { [Test]
public void EqualsTest() {
Assert.AreEqual(new UriIdentifier(goodUri), new UriIdentifier(goodUri));
+ // This next test is an interesting side-effect of passing off to Uri.Equals. But it's probably ok.
+ Assert.AreEqual(new UriIdentifier(goodUri), new UriIdentifier(goodUri + "#frag"));
Assert.AreNotEqual(new UriIdentifier(goodUri), new UriIdentifier(goodUri + "a"));
Assert.AreNotEqual(null, new UriIdentifier(goodUri));
Assert.AreNotEqual(goodUri, new UriIdentifier(goodUri));
}
- void discover(string url, ProtocolVersion version, Identifier expectedLocalId, bool expectSreg, bool useRedirect) {
+ [Test]
+ public void UnicodeTest() {
+ string unicodeUrl = "http://nerdbank.org/opaffirmative/崎村.aspx";
+ Assert.IsTrue(UriIdentifier.IsValidUri(unicodeUrl));
+ Identifier id;
+ Assert.IsTrue(UriIdentifier.TryParse(unicodeUrl, out id));
+ Assert.AreEqual("/opaffirmative/%E5%B4%8E%E6%9D%91.aspx", ((UriIdentifier)id).Uri.AbsolutePath);
+ Assert.AreEqual(Uri.EscapeUriString(unicodeUrl), id.ToString());
+ }
+
+ void discover(string url, ProtocolVersion version, Identifier expectedLocalId, Uri providerEndpoint, bool expectSreg, bool useRedirect) {
+ discover(url, version, expectedLocalId, providerEndpoint, expectSreg, useRedirect, null);
+ }
+ void discover(string url, ProtocolVersion version, Identifier expectedLocalId, Uri providerEndpoint, bool expectSreg, bool useRedirect, WebHeaderCollection headers) {
Protocol protocol = Protocol.Lookup(version);
UriIdentifier claimedId = TestSupport.GetFullUrl(url);
UriIdentifier userSuppliedIdentifier = TestSupport.GetFullUrl(
- "htmldiscovery/redirect.aspx?target=" + url);
+ "Discovery/htmldiscovery/redirect.aspx?target=" + url);
if (expectedLocalId == null) expectedLocalId = claimedId;
Identifier idToDiscover = useRedirect ? userSuppliedIdentifier : claimedId;
- // confirm the page exists (validates the test)
- WebRequest.Create(idToDiscover).GetResponse().Close();
- ServiceEndpoint se = idToDiscover.Discover();
+
+ string contentType;
+ if (url.EndsWith("html")) {
+ contentType = "text/html";
+ } else if (url.EndsWith("xml")) {
+ contentType = "application/xrds+xml";
+ } else {
+ throw new InvalidOperationException();
+ }
+ MockHttpRequest.RegisterMockResponse(new Uri(idToDiscover), claimedId, contentType,
+ headers ?? new WebHeaderCollection(), TestSupport.LoadEmbeddedFile(url));
+
+ ServiceEndpoint expected = ServiceEndpoint.CreateForClaimedIdentifier(
+ claimedId,
+ expectedLocalId,
+ providerEndpoint,
+ new string[] { protocol.ClaimedIdentifierServiceTypeURI }, // this isn't checked by Equals
+ null,
+ null);
+
+ ServiceEndpoint se = idToDiscover.Discover().FirstOrDefault(ep => ep.Equals(expected));
Assert.IsNotNull(se, url + " failed to be discovered.");
- Assert.AreSame(protocol, se.Protocol);
- Assert.AreEqual(claimedId, se.ClaimedIdentifier);
- Assert.AreEqual(expectedLocalId, se.ProviderLocalIdentifier);
+
+ // Do extra checking of service type URIs, which aren't included in
+ // the ServiceEndpoint.Equals method.
Assert.AreEqual(expectSreg ? 2 : 1, se.ProviderSupportedServiceTypeUris.Length);
- Assert.IsTrue(Array.IndexOf(se.ProviderSupportedServiceTypeUris, protocol.ClaimedIdentifierServiceTypeURI)>=0);
- if (expectSreg)
- Assert.IsTrue(Array.IndexOf(se.ProviderSupportedServiceTypeUris, Constants.TypeUri) >= 0);
+ Assert.IsTrue(Array.IndexOf(se.ProviderSupportedServiceTypeUris, protocol.ClaimedIdentifierServiceTypeURI) >= 0);
+ Assert.AreEqual(expectSreg, se.IsExtensionSupported(new ClaimsRequest()));
+ }
+ void discoverXrds(string page, ProtocolVersion version, Identifier expectedLocalId, string providerEndpoint) {
+ discoverXrds(page, version, expectedLocalId, providerEndpoint, null);
}
- void discoverXrds(string page, ProtocolVersion version, Identifier expectedLocalId) {
- discover("/xrdsdiscovery/" + page + ".aspx", version, expectedLocalId, true, false);
- discover("/xrdsdiscovery/" + page + ".aspx", version, expectedLocalId, true, true);
+ void discoverXrds(string page, ProtocolVersion version, Identifier expectedLocalId, string providerEndpoint, WebHeaderCollection headers) {
+ if (!page.Contains(".")) page += ".xml";
+ discover("/Discovery/xrdsdiscovery/" + page, version, expectedLocalId, new Uri(providerEndpoint), true, false, headers);
+ discover("/Discovery/xrdsdiscovery/" + page, version, expectedLocalId, new Uri(providerEndpoint), true, true, headers);
}
- void discoverHtml(string page, ProtocolVersion version, Identifier expectedLocalId, bool useRedirect) {
- discover("/htmldiscovery/" + page, version, expectedLocalId, false, useRedirect);
+ void discoverHtml(string page, ProtocolVersion version, Identifier expectedLocalId, string providerEndpoint, bool useRedirect) {
+ discover("/Discovery/htmldiscovery/" + page, version, expectedLocalId, new Uri(providerEndpoint), false, useRedirect);
}
- void discoverHtml(string scenario, ProtocolVersion version, Identifier expectedLocalId) {
- string page = scenario + ".aspx";
- discoverHtml(page, version, expectedLocalId, false);
- discoverHtml(page, version, expectedLocalId, true);
+ void discoverHtml(string scenario, ProtocolVersion version, Identifier expectedLocalId, string providerEndpoint) {
+ string page = scenario + ".html";
+ discoverHtml(page, version, expectedLocalId, providerEndpoint, false);
+ discoverHtml(page, version, expectedLocalId, providerEndpoint, true);
}
void failDiscover(string url) {
UriIdentifier userSuppliedId = TestSupport.GetFullUrl(url);
- WebRequest.Create((Uri)userSuppliedId).GetResponse().Close(); // confirm the page exists ...
- Assert.IsNull(userSuppliedId.Discover()); // ... but that no endpoint info is discoverable
+
+ Mocks.MockHttpRequest.RegisterMockResponse(new Uri(userSuppliedId), userSuppliedId, "text/html",
+ TestSupport.LoadEmbeddedFile(url));
+
+ Assert.AreEqual(0, userSuppliedId.Discover().Count()); // ... but that no endpoint info is discoverable
}
void failDiscoverHtml(string scenario) {
- failDiscover("htmldiscovery/" + scenario + ".aspx");
+ failDiscover("/Discovery/htmldiscovery/" + scenario + ".html");
}
void failDiscoverXrds(string scenario) {
- failDiscover("xrdsdiscovery/" + scenario + ".aspx");
+ failDiscover("/Discovery/xrdsdiscovery/" + scenario + ".xml");
}
[Test]
public void HtmlDiscover_11() {
- discoverHtml("html10prov", ProtocolVersion.V11, null);
- discoverHtml("html10both", ProtocolVersion.V11, "http://c/d");
+ discoverHtml("html10prov", ProtocolVersion.V11, null, "http://a/b");
+ discoverHtml("html10both", ProtocolVersion.V11, "http://c/d", "http://a/b");
failDiscoverHtml("html10del");
+
+ // Verify that HTML discovery generates the 1.x endpoints when appropriate
+ discoverHtml("html2010", ProtocolVersion.V11, "http://g/h", "http://e/f");
+ discoverHtml("html1020", ProtocolVersion.V11, "http://g/h", "http://e/f");
+ discoverHtml("html2010combinedA", ProtocolVersion.V11, "http://c/d", "http://a/b");
+ discoverHtml("html2010combinedB", ProtocolVersion.V11, "http://c/d", "http://a/b");
+ discoverHtml("html2010combinedC", ProtocolVersion.V11, "http://c/d", "http://a/b");
}
[Test]
public void HtmlDiscover_20() {
- discoverHtml("html20prov", ProtocolVersion.V20, null);
- discoverHtml("html20both", ProtocolVersion.V20, "http://c/d");
+ discoverHtml("html20prov", ProtocolVersion.V20, null, "http://a/b");
+ discoverHtml("html20both", ProtocolVersion.V20, "http://c/d", "http://a/b");
failDiscoverHtml("html20del");
- discoverHtml("html2010", ProtocolVersion.V20, "http://c/d");
- discoverHtml("html1020", ProtocolVersion.V20, "http://c/d");
- discoverHtml("html2010combinedA", ProtocolVersion.V20, "http://c/d");
- discoverHtml("html2010combinedB", ProtocolVersion.V20, "http://c/d");
- discoverHtml("html2010combinedC", ProtocolVersion.V20, "http://c/d");
+ discoverHtml("html2010", ProtocolVersion.V20, "http://c/d", "http://a/b");
+ discoverHtml("html1020", ProtocolVersion.V20, "http://c/d", "http://a/b");
+ discoverHtml("html2010combinedA", ProtocolVersion.V20, "http://c/d", "http://a/b");
+ discoverHtml("html2010combinedB", ProtocolVersion.V20, "http://c/d", "http://a/b");
+ discoverHtml("html2010combinedC", ProtocolVersion.V20, "http://c/d", "http://a/b");
failDiscoverHtml("html20relative");
}
[Test]
public void XrdsDiscoveryFromHead() {
- discoverXrds("XrdsReferencedInHead", ProtocolVersion.V10, null);
+ Mocks.MockHttpRequest.RegisterMockResponse(new Uri("http://localhost/xrds1020.xml"),
+ "application/xrds+xml", TestSupport.LoadEmbeddedFile("/Discovery/xrdsdiscovery/xrds1020.xml"));
+ discoverXrds("XrdsReferencedInHead.html", ProtocolVersion.V10, null, "http://a/b");
}
[Test]
public void XrdsDiscoveryFromHttpHeader() {
- discoverXrds("XrdsReferencedInHttpHeader", ProtocolVersion.V10, null);
+ WebHeaderCollection headers = new WebHeaderCollection();
+ headers.Add("X-XRDS-Location", TestSupport.GetFullUrl("http://localhost/xrds1020.xml").AbsoluteUri);
+ Mocks.MockHttpRequest.RegisterMockResponse(new Uri("http://localhost/xrds1020.xml"),
+ "application/xrds+xml", TestSupport.LoadEmbeddedFile("/Discovery/xrdsdiscovery/xrds1020.xml"));
+ discoverXrds("XrdsReferencedInHttpHeader.html", ProtocolVersion.V10, null, "http://a/b", headers);
}
[Test]
public void XrdsDirectDiscovery_10() {
failDiscoverXrds("xrds-irrelevant");
- discoverXrds("xrds10", ProtocolVersion.V10, null);
- discoverXrds("xrds11", ProtocolVersion.V11, null);
- discoverXrds("xrds1020", ProtocolVersion.V10, null);
+ discoverXrds("xrds10", ProtocolVersion.V10, null, "http://a/b");
+ discoverXrds("xrds11", ProtocolVersion.V11, null, "http://a/b");
+ discoverXrds("xrds1020", ProtocolVersion.V10, null, "http://a/b");
}
[Test]
public void XrdsDirectDiscovery_20() {
- discoverXrds("xrds20", ProtocolVersion.V20, null);
- discoverXrds("xrds2010a", ProtocolVersion.V20, null);
- discoverXrds("xrds2010b", ProtocolVersion.V20, null);
+ discoverXrds("xrds20", ProtocolVersion.V20, null, "http://a/b");
+ discoverXrds("xrds2010a", ProtocolVersion.V20, null, "http://a/b");
+ discoverXrds("xrds2010b", ProtocolVersion.V20, null, "http://a/b");
+ }
+
+ [Test]
+ public void NormalizeCase() {
+ // only the host name can be normalized in casing safely.
+ Identifier id = "http://HOST:80/PaTH?KeY=VaLUE#fRag";
+ Assert.AreEqual("http://host/PaTH?KeY=VaLUE#fRag", id.ToString());
+ // make sure https is preserved, along with port 80, which is NON-default for https
+ id = "https://HOST:80/PaTH?KeY=VaLUE#fRag";
+ Assert.AreEqual("https://host:80/PaTH?KeY=VaLUE#fRag", id.ToString());
+ }
+
+ [Test]
+ public void HttpSchemePrepended() {
+ UriIdentifier id = new UriIdentifier("www.yahoo.com");
+ Assert.AreEqual("http://www.yahoo.com/", id.ToString());
+ Assert.IsTrue(id.SchemeImplicitlyPrepended);
+ }
+
+ //[Test, Ignore("The spec says http:// must be prepended in this case, but that just creates an invalid URI. Our UntrustedWebRequest will stop disallowed schemes.")]
+ public void CtorDisallowedScheme() {
+ UriIdentifier id = new UriIdentifier(new Uri("ftp://host/path"));
+ Assert.AreEqual("http://ftp://host/path", id.ToString());
+ Assert.IsTrue(id.SchemeImplicitlyPrepended);
+ }
+
+ [Test]
+ public void DiscoveryWithRedirects() {
+ MockHttpRequest.Reset();
+ Identifier claimedId = TestSupport.GetMockIdentifier(TestSupport.Scenarios.AutoApproval, ProtocolVersion.V20);
+
+ // Add a couple of chained redirect pages that lead to the claimedId.
+ Uri userSuppliedUri = TestSupport.GetFullUrl("/someSecurePage", null, true);
+ Uri insecureMidpointUri = TestSupport.GetFullUrl("/insecureStop");
+ MockHttpRequest.RegisterMockRedirect(userSuppliedUri, insecureMidpointUri);
+ MockHttpRequest.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().Count());
+ }
+
+ [Test]
+ public void TryRequireSslAdjustsIdentifier() {
+ Identifier secureId;
+ // Try Parse and ctor without explicit scheme
+ var id = Identifier.Parse("www.yahoo.com");
+ Assert.AreEqual("http://www.yahoo.com/", id.ToString());
+ Assert.IsTrue(id.TryRequireSsl(out secureId));
+ Assert.IsTrue(secureId.IsDiscoverySecureEndToEnd);
+ Assert.AreEqual("https://www.yahoo.com/", secureId.ToString());
+
+ id = new UriIdentifier("www.yahoo.com");
+ Assert.AreEqual("http://www.yahoo.com/", id.ToString());
+ Assert.IsTrue(id.TryRequireSsl(out secureId));
+ Assert.IsTrue(secureId.IsDiscoverySecureEndToEnd);
+ Assert.AreEqual("https://www.yahoo.com/", secureId.ToString());
+
+ // Try Parse and ctor with explicit http:// scheme
+ id = Identifier.Parse("http://www.yahoo.com");
+ 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().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().Count());
+ }
+
+ [Test]
+ public void DiscoverRequireSslWithSecureRedirects() {
+ MockHttpRequest.Reset();
+ Identifier claimedId = TestSupport.GetMockIdentifier(TestSupport.Scenarios.AutoApproval, ProtocolVersion.V20, true);
+
+ // Add a couple of chained redirect pages that lead to the claimedId.
+ // All redirects should be secure.
+ Uri userSuppliedUri = TestSupport.GetFullUrl("/someSecurePage", null, true);
+ Uri secureMidpointUri = TestSupport.GetFullUrl("/secureStop", null, true);
+ MockHttpRequest.RegisterMockRedirect(userSuppliedUri, secureMidpointUri);
+ MockHttpRequest.RegisterMockRedirect(secureMidpointUri, new Uri(claimedId.ToString()));
+
+ Identifier userSuppliedIdentifier = new UriIdentifier(userSuppliedUri, true);
+ Assert.AreEqual(1, userSuppliedIdentifier.Discover().Count());
+ }
+
+ [Test, ExpectedException(typeof(OpenIdException))]
+ public void DiscoverRequireSslWithInsecureRedirect() {
+ MockHttpRequest.Reset();
+ Identifier claimedId = TestSupport.GetMockIdentifier(TestSupport.Scenarios.AutoApproval, 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 = TestSupport.GetFullUrl("/someSecurePage", null, true);
+ Uri insecureMidpointUri = TestSupport.GetFullUrl("/insecureStop");
+ MockHttpRequest.RegisterMockRedirect(userSuppliedUri, insecureMidpointUri);
+ MockHttpRequest.RegisterMockRedirect(insecureMidpointUri, new Uri(claimedId.ToString()));
+
+ Identifier userSuppliedIdentifier = new UriIdentifier(userSuppliedUri, true);
+ userSuppliedIdentifier.Discover();
+ }
+
+ [Test]
+ public void DiscoveryRequireSslWithInsecureXrdsInSecureHtmlHead() {
+ var insecureXrdsSource = TestSupport.GetMockIdentifier(TestSupport.Scenarios.AutoApproval, ProtocolVersion.V20, false);
+ Uri secureClaimedUri = TestSupport.GetFullUrl("/secureId", null, true);
+
+ string html = string.Format("<html><head><meta http-equiv='X-XRDS-Location' content='{0}'/></head><body></body></html>",
+ insecureXrdsSource);
+ MockHttpRequest.RegisterMockResponse(secureClaimedUri, "text/html", html);
+
+ Identifier userSuppliedIdentifier = new UriIdentifier(secureClaimedUri, true);
+ Assert.AreEqual(0, userSuppliedIdentifier.Discover().Count());
+ }
+
+ [Test]
+ public void DiscoveryRequireSslWithInsecureXrdsInSecureHttpHeader() {
+ var insecureXrdsSource = TestSupport.GetMockIdentifier(TestSupport.Scenarios.AutoApproval, ProtocolVersion.V20, false);
+ Uri secureClaimedUri = TestSupport.GetFullUrl("/secureId", null, true);
+
+ string html = "<html><head></head><body></body></html>";
+ WebHeaderCollection headers = new WebHeaderCollection {
+ { "X-XRDS-Location", insecureXrdsSource }
+ };
+ MockHttpRequest.RegisterMockResponse(secureClaimedUri, secureClaimedUri, "text/html", headers, html);
+
+ Identifier userSuppliedIdentifier = new UriIdentifier(secureClaimedUri, true);
+ Assert.AreEqual(0, userSuppliedIdentifier.Discover().Count());
+ }
+
+ [Test]
+ public void DiscoveryRequireSslWithInsecureXrdsButSecureLinkTags() {
+ var insecureXrdsSource = TestSupport.GetMockIdentifier(TestSupport.Scenarios.AutoApproval, ProtocolVersion.V20, false);
+ Uri secureClaimedUri = TestSupport.GetFullUrl("/secureId", null, true);
+
+ Identifier localIdForLinkTag = TestSupport.GetDelegateUrl(TestSupport.Scenarios.AlwaysDeny, true);
+ 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(TestSupport.GetFullUrl("/" + TestSupport.ProviderPage, null, true).AbsoluteUri),
+ HttpUtility.HtmlEncode(localIdForLinkTag.ToString())
+ );
+ MockHttpRequest.RegisterMockResponse(secureClaimedUri, "text/html", html);
+
+ Identifier userSuppliedIdentifier = new UriIdentifier(secureClaimedUri, true);
+ Assert.AreEqual(localIdForLinkTag, userSuppliedIdentifier.Discover().Single().ProviderLocalIdentifier);
+ }
+
+ [Test]
+ public void DiscoveryRequiresSslIgnoresInsecureEndpointsInXrds() {
+ var insecureEndpoint = TestSupport.GetServiceEndpoint(TestSupport.Scenarios.AutoApproval, ProtocolVersion.V20, 10, false);
+ var secureEndpoint = TestSupport.GetServiceEndpoint(TestSupport.Scenarios.ApproveOnSetup, ProtocolVersion.V20, 20, true);
+ UriIdentifier secureClaimedId = new UriIdentifier(TestSupport.GetFullUrl("/claimedId", null, true), true);
+ MockHttpRequest.RegisterMockXrdsResponse(secureClaimedId, new ServiceEndpoint[] { insecureEndpoint, secureEndpoint });
+ Assert.AreEqual(secureEndpoint.ProviderLocalIdentifier, secureClaimedId.Discover().Single().ProviderLocalIdentifier);
}
}
}
diff --git a/src/DotNetOpenId.Test/UriUtilTest.cs b/src/DotNetOpenId.Test/UriUtilTest.cs index aac92e1..4e2793d 100644 --- a/src/DotNetOpenId.Test/UriUtilTest.cs +++ b/src/DotNetOpenId.Test/UriUtilTest.cs @@ -44,6 +44,16 @@ namespace DotNetOpenId.Test { Assert.AreEqual("http://baseline.org/page?a=b&c%2fd=e%2ff&g=h", uri.Uri.AbsoluteUri);
}
+ [Test, ExpectedException(typeof(ArgumentNullException))]
+ public void AppendQueryArgsNullUriBuilder() {
+ UriUtil.AppendQueryArgs(null, new Dictionary<string, string>());
+ }
+
+ [Test]
+ public void AppendQueryArgsNullDictionary() {
+ UriUtil.AppendQueryArgs(new UriBuilder(), null);
+ }
+
[Test]
public void UriBuilderToStringWithImpliedPorts() {
Assert.AreEqual("http://localhost/p?q#f",
diff --git a/src/DotNetOpenId.Test/XriIdentifierTests.cs b/src/DotNetOpenId.Test/XriIdentifierTests.cs index 6127c49..3255776 100644 --- a/src/DotNetOpenId.Test/XriIdentifierTests.cs +++ b/src/DotNetOpenId.Test/XriIdentifierTests.cs @@ -1,9 +1,9 @@ using System;
using System.Collections.Generic;
-using System.Text;
-using NUnit.Framework;
+using System.Linq;
using DotNetOpenId.RelyingParty;
-using System.Net;
+using DotNetOpenId.Test.Mocks;
+using NUnit.Framework;
namespace DotNetOpenId.Test {
[TestFixture]
@@ -11,6 +11,11 @@ namespace DotNetOpenId.Test { string goodXri = "=Andrew*Arnott";
string badXri = "some\\wacky%^&*()non-XRI";
+ [TearDown]
+ public void TearDown() {
+ MockHttpRequest.Reset();
+ }
+
[Test, ExpectedException(typeof(ArgumentNullException))]
public void CtorNull() {
new XriIdentifier(null);
@@ -31,6 +36,15 @@ namespace DotNetOpenId.Test { var xri = new XriIdentifier(goodXri);
Assert.AreEqual(goodXri, xri.OriginalXri);
Assert.AreEqual(goodXri, xri.CanonicalXri); // assumes 'goodXri' is canonical already
+ Assert.IsFalse(xri.IsDiscoverySecureEndToEnd);
+ }
+
+ [Test]
+ public void CtorGoodXriSecure() {
+ var xri = new XriIdentifier(goodXri, true);
+ Assert.AreEqual(goodXri, xri.OriginalXri);
+ Assert.AreEqual(goodXri, xri.CanonicalXri); // assumes 'goodXri' is canonical already
+ Assert.IsTrue(xri.IsDiscoverySecureEndToEnd);
}
[Test]
@@ -50,6 +64,12 @@ namespace DotNetOpenId.Test { }
[Test]
+ public void TrimFragment() {
+ Identifier xri = new XriIdentifier(goodXri);
+ Assert.AreSame(xri, xri.TrimFragment());
+ }
+
+ [Test]
public void ToStringTest() {
Assert.AreEqual(goodXri, new XriIdentifier(goodXri).ToString());
}
@@ -62,23 +82,386 @@ namespace DotNetOpenId.Test { Assert.AreNotEqual(goodXri, new XriIdentifier(goodXri));
}
+ private ServiceEndpoint verifyCanonicalId(Identifier iname, string expectedClaimedIdentifier) {
+ ServiceEndpoint se = iname.Discover().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.Length > 0);
+ } else {
+ Assert.IsNull(se);
+ }
+ return se;
+ }
+
[Test]
public void Discover() {
- // This test requires a network connection
- Identifier id = "=Arnott";
- ServiceEndpoint se = null;
- try {
- se = id.Discover();
- } catch (WebException ex) {
- if (ex.Message.Contains("remote name could not be resolved"))
- Assert.Ignore("This test requires a network connection.");
- }
- Assert.IsNotNull(se);
+ 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},
+ };
+ MockHttpRequest.RegisterMockXrdsResponses(mocks);
+
+ string expectedCanonicalId = "=!9B72.7DD1.50A9.5CCD";
+ ServiceEndpoint se = verifyCanonicalId("=Arnott", expectedCanonicalId);
Assert.AreEqual(Protocol.v10, se.Protocol);
- Assert.AreEqual("=!9B72.7DD1.50A9.5CCD", se.ClaimedIdentifier.ToString());
Assert.AreEqual("http://1id.com/sso", se.ProviderEndpoint.ToString());
- Assert.AreEqual("=!9B72.7DD1.50A9.5CCD", se.ProviderLocalIdentifier.ToString());
- Assert.AreEqual(1, se.ProviderSupportedServiceTypeUris.Length);
+ Assert.AreEqual(se.ClaimedIdentifier, se.ProviderLocalIdentifier);
+ Assert.AreEqual("=Arnott", se.FriendlyIdentifierForDisplay);
+ }
+
+ [Test]
+ 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>";
+ MockHttpRequest.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},
+ });
+ verifyCanonicalId("@llli", "@!72CD.A072.157E.A9C6");
+ verifyCanonicalId("@llli*area", "@!72CD.A072.157E.A9C6!0000.0000.3B9A.CA0C");
+ verifyCanonicalId("@llli*area*canada.unattached", "@!72CD.A072.157E.A9C6!0000.0000.3B9A.CA0C!0000.0000.3B9A.CA41");
+ verifyCanonicalId("@llli*area*canada.unattached*ada", "@!72CD.A072.157E.A9C6!0000.0000.3B9A.CA0C!0000.0000.3B9A.CA41!0000.0000.3B9A.CA01");
+ verifyCanonicalId("=Web", "=!91F2.8153.F600.AE24");
+ }
+
+ [Test]
+ public void DiscoveryCommunityInameDelegateWithoutCanonicalID() {
+ MockHttpRequest.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.
+ verifyCanonicalId("=Web*andrew.arnott", null);
+ verifyCanonicalId("@id*andrewarnott", null);
+ }
+
+ //[Test, 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());
}
}
}
|