Refactored test helpers to remove TestSupport and move its functionality into OpenIdT...
[dotnetoauth.git] / src / DotNetOpenAuth.Test / OpenId / ChannelElements / ExtensionsBindingElementTests.cs
blob948cd1aebe95236fbf16447669136e3083f7da8d
1 //-----------------------------------------------------------------------
2 // <copyright file="ExtensionsBindingElementTests.cs" company="Andrew Arnott">
3 // Copyright (c) Andrew Arnott. All rights reserved.
4 // </copyright>
5 //-----------------------------------------------------------------------
7 namespace DotNetOpenAuth.Test.OpenId.ChannelElements {
8 using System;
9 using System.Collections.Generic;
10 using System.Linq;
11 using System.Text.RegularExpressions;
12 using DotNetOpenAuth.Messaging;
13 using DotNetOpenAuth.OpenId;
14 using DotNetOpenAuth.OpenId.ChannelElements;
15 using DotNetOpenAuth.OpenId.Extensions;
16 using DotNetOpenAuth.OpenId.Messages;
17 using DotNetOpenAuth.OpenId.RelyingParty;
18 using DotNetOpenAuth.Test.Mocks;
19 using DotNetOpenAuth.Test.OpenId.Extensions;
20 using Microsoft.VisualStudio.TestTools.UnitTesting;
22 [TestClass]
23 public class ExtensionsBindingElementTests : OpenIdTestBase {
24 private OpenIdExtensionFactory factory;
25 private ExtensionsBindingElement rpElement;
26 private IProtocolMessageWithExtensions request;
28 [TestInitialize]
29 public override void SetUp() {
30 base.SetUp();
32 this.factory = new OpenIdExtensionFactory();
33 this.factory.RegisterExtension(MockOpenIdExtension.Factory);
34 this.rpElement = new ExtensionsBindingElement(this.factory, new RelyingPartySecuritySettings());
35 this.request = new SignedResponseRequest(Protocol.Default.Version, OpenIdTestBase.OPUri, AuthenticationRequestMode.Immediate);
38 [TestMethod]
39 public void RoundTripFullStackTest() {
40 IOpenIdMessageExtension request = new MockOpenIdExtension("requestPart", "requestData");
41 IOpenIdMessageExtension response = new MockOpenIdExtension("responsePart", "responseData");
42 ExtensionTestUtilities.Roundtrip(
43 Protocol.Default,
44 new IOpenIdMessageExtension[] { request },
45 new IOpenIdMessageExtension[] { response });
48 [TestMethod]
49 public void ExtensionFactory() {
50 Assert.AreSame(this.factory, this.rpElement.ExtensionFactory);
53 [TestMethod, ExpectedException(typeof(ArgumentNullException))]
54 public void PrepareMessageForSendingNull() {
55 this.rpElement.PrepareMessageForSending(null);
58 /// <summary>
59 /// Verifies that false is returned when a non-extendable message is sent.
60 /// </summary>
61 [TestMethod]
62 public void PrepareMessageForSendingNonExtendableMessage() {
63 IProtocolMessage request = new AssociateDiffieHellmanRequest(Protocol.Default.Version, OpenIdTestBase.OPUri);
64 Assert.IsFalse(this.rpElement.PrepareMessageForSending(request));
67 [TestMethod]
68 public void PrepareMessageForSending() {
69 this.request.Extensions.Add(new MockOpenIdExtension("part", "extra"));
70 Assert.IsTrue(this.rpElement.PrepareMessageForSending(this.request));
72 string alias = GetAliases(this.request.ExtraData).Single();
73 Assert.AreEqual(MockOpenIdExtension.MockTypeUri, this.request.ExtraData["openid.ns." + alias]);
74 Assert.AreEqual("part", this.request.ExtraData["openid." + alias + ".Part"]);
75 Assert.AreEqual("extra", this.request.ExtraData["openid." + alias + ".data"]);
78 [TestMethod]
79 public void PrepareMessageForReceiving() {
80 this.request.ExtraData["openid.ns.mock"] = MockOpenIdExtension.MockTypeUri;
81 this.request.ExtraData["openid.mock.Part"] = "part";
82 this.request.ExtraData["openid.mock.data"] = "extra";
83 Assert.IsTrue(this.rpElement.PrepareMessageForReceiving(this.request));
84 MockOpenIdExtension ext = this.request.Extensions.OfType<MockOpenIdExtension>().Single();
85 Assert.AreEqual("part", ext.Part);
86 Assert.AreEqual("extra", ext.Data);
89 /// <summary>
90 /// Verifies that extension responses are included in the OP's signature.
91 /// </summary>
92 [TestMethod]
93 public void ExtensionResponsesAreSigned() {
94 Protocol protocol = Protocol.Default;
95 var op = this.CreateProvider();
96 IndirectSignedResponse response = this.CreateResponseWithExtensions(protocol);
97 op.Channel.PrepareResponse(response);
98 ITamperResistantOpenIdMessage signedResponse = (ITamperResistantOpenIdMessage)response;
99 string extensionAliasKey = signedResponse.ExtraData.Single(kv => kv.Value == MockOpenIdExtension.MockTypeUri).Key;
100 Assert.IsTrue(extensionAliasKey.StartsWith("openid.ns."));
101 string extensionAlias = extensionAliasKey.Substring("openid.ns.".Length);
103 // Make sure that the extension members and the alias=namespace declaration are all signed.
104 Assert.IsNotNull(signedResponse.SignedParameterOrder);
105 string[] signedParameters = signedResponse.SignedParameterOrder.Split(',');
106 Assert.IsTrue(signedParameters.Contains(extensionAlias + ".Part"));
107 Assert.IsTrue(signedParameters.Contains(extensionAlias + ".data"));
108 Assert.IsTrue(signedParameters.Contains("ns." + extensionAlias));
111 /// <summary>
112 /// Verifies that unsigned extension responses (where any or all fields are unsigned) are ignored.
113 /// </summary>
114 [TestMethod]
115 public void UnsignedExtensionsAreIgnored() {
116 Protocol protocol = Protocol.Default;
117 OpenIdCoordinator coordinator = new OpenIdCoordinator(
118 rp => {
119 RegisterMockExtension(rp.Channel);
120 var response = rp.Channel.ReadFromRequest<IndirectSignedResponse>();
121 Assert.AreEqual(1, response.Extensions.Count, "Signed extension should have been received.");
122 response = rp.Channel.ReadFromRequest<IndirectSignedResponse>();
123 Assert.AreEqual(0, response.Extensions.Count, "Unsigned extension should have been ignored.");
125 op => {
126 RegisterMockExtension(op.Channel);
127 op.Channel.Send(CreateResponseWithExtensions(protocol));
128 op.GetRequest().Response.Send(); // check_auth
129 op.SecuritySettings.SignOutgoingExtensions = false;
130 op.Channel.Send(CreateResponseWithExtensions(protocol));
131 op.GetRequest().Response.Send(); // check_auth
133 coordinator.Run();
136 /// <summary>
137 /// Verifies that two extensions with the same TypeURI cannot be applied to the same message.
138 /// </summary>
139 /// <remarks>
140 /// OpenID Authentication 2.0 section 12 states that
141 /// "A namespace MUST NOT be assigned more than one alias in the same message".
142 /// </remarks>
143 [TestMethod]
144 public void TwoExtensionsSameTypeUri() {
145 IOpenIdMessageExtension request1 = new MockOpenIdExtension("requestPart1", "requestData1");
146 IOpenIdMessageExtension request2 = new MockOpenIdExtension("requestPart2", "requestData2");
147 try {
148 ExtensionTestUtilities.Roundtrip(
149 Protocol.Default,
150 new IOpenIdMessageExtension[] { request1, request2 },
151 new IOpenIdMessageExtension[0]);
152 Assert.Fail("Expected ProtocolException not thrown.");
153 } catch (AssertFailedException ex) {
154 Assert.IsInstanceOfType(ex.InnerException, typeof(ProtocolException));
158 private static IEnumerable<string> GetAliases(IDictionary<string, string> extraData) {
159 Regex regex = new Regex(@"^openid\.ns\.(\w+)");
160 return from key in extraData.Keys
161 let m = regex.Match(key)
162 where m.Success
163 select m.Groups[1].Value;
166 private static void RegisterMockExtension(Channel channel) {
167 ErrorUtilities.VerifyArgumentNotNull(channel, "channel");
169 ((OpenIdExtensionFactory)channel.BindingElements.OfType<ExtensionsBindingElement>().Single().ExtensionFactory).RegisterExtension(MockOpenIdExtension.Factory);
172 /// <summary>
173 /// Creates a response message with one extensions.
174 /// </summary>
175 /// <param name="protocol">The protocol to construct the message with.</param>
176 /// <returns>The message ready to send from OP to RP.</returns>
177 private IndirectSignedResponse CreateResponseWithExtensions(Protocol protocol) {
178 ErrorUtilities.VerifyArgumentNotNull(protocol, "protocol");
180 IndirectSignedResponse response = new IndirectSignedResponse(protocol.Version, RPUri);
181 response.ProviderEndpoint = OPUri;
182 response.Extensions.Add(new MockOpenIdExtension("pv", "ev"));
183 return response;