1
//-----------------------------------------------------------------------
2 // <copyright file="ExtensionsBindingElementTests.cs" company="Andrew Arnott">
3 // Copyright (c) Andrew Arnott. All rights reserved.
5 //-----------------------------------------------------------------------
7 namespace DotNetOpenAuth
.Test
.OpenId
.ChannelElements
{
9 using System
.Collections
.Generic
;
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
;
23 public class ExtensionsBindingElementTests
: OpenIdTestBase
{
24 private OpenIdExtensionFactory factory
;
25 private ExtensionsBindingElement rpElement
;
26 private IProtocolMessageWithExtensions request
;
29 public override void 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
);
39 public void RoundTripFullStackTest() {
40 IOpenIdMessageExtension request
= new MockOpenIdExtension("requestPart", "requestData");
41 IOpenIdMessageExtension response
= new MockOpenIdExtension("responsePart", "responseData");
42 ExtensionTestUtilities
.Roundtrip(
44 new IOpenIdMessageExtension
[] { request }
,
45 new IOpenIdMessageExtension
[] { response }
);
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);
59 /// Verifies that false is returned when a non-extendable message is sent.
62 public void PrepareMessageForSendingNonExtendableMessage() {
63 IProtocolMessage request
= new AssociateDiffieHellmanRequest(Protocol
.Default
.Version
, OpenIdTestBase
.OPUri
);
64 Assert
.IsFalse(this.rpElement
.PrepareMessageForSending(request
));
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"]);
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
);
90 /// Verifies that extension responses are included in the OP's signature.
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
));
112 /// Verifies that unsigned extension responses (where any or all fields are unsigned) are ignored.
115 public void UnsignedExtensionsAreIgnored() {
116 Protocol protocol
= Protocol
.Default
;
117 OpenIdCoordinator coordinator
= new OpenIdCoordinator(
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.");
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
137 /// Verifies that two extensions with the same TypeURI cannot be applied to the same message.
140 /// OpenID Authentication 2.0 section 12 states that
141 /// "A namespace MUST NOT be assigned more than one alias in the same message".
144 public void TwoExtensionsSameTypeUri() {
145 IOpenIdMessageExtension request1
= new MockOpenIdExtension("requestPart1", "requestData1");
146 IOpenIdMessageExtension request2
= new MockOpenIdExtension("requestPart2", "requestData2");
148 ExtensionTestUtilities
.Roundtrip(
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
)
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
);
173 /// Creates a response message with one extensions.
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"));