1
//-----------------------------------------------------------------------
2 // <copyright file="AuthenticationTests.cs" company="Andrew Arnott">
3 // Copyright (c) Andrew Arnott. All rights reserved.
5 //-----------------------------------------------------------------------
7 namespace DotNetOpenAuth
.Test
.OpenId
{
9 using System
.Collections
.Generic
;
12 using DotNetOpenAuth
.Messaging
;
13 using DotNetOpenAuth
.Messaging
.Bindings
;
14 using DotNetOpenAuth
.OpenId
;
15 using DotNetOpenAuth
.OpenId
.ChannelElements
;
16 using DotNetOpenAuth
.OpenId
.Messages
;
17 using DotNetOpenAuth
.Test
.Mocks
;
18 using Microsoft
.VisualStudio
.TestTools
.UnitTesting
;
21 public class AuthenticationTests
: OpenIdTestBase
{
23 public override void SetUp() {
28 public void SharedAssociationPositive() {
29 this.ParameterizedPositiveAuthenticationTest(true, true, false);
33 /// Verifies that a shared association protects against tampering.
36 public void SharedAssociationTampered() {
37 this.ParameterizedPositiveAuthenticationTest(true, true, true);
41 public void SharedAssociationNegative() {
42 this.ParameterizedPositiveAuthenticationTest(true, false, false);
46 public void PrivateAssociationPositive() {
47 this.ParameterizedPositiveAuthenticationTest(false, true, false);
51 /// Verifies that a private association protects against tampering.
54 public void PrivateAssociationTampered() {
55 this.ParameterizedPositiveAuthenticationTest(false, true, true);
59 public void NoAssociationNegative() {
60 this.ParameterizedPositiveAuthenticationTest(false, false, false);
63 private void ParameterizedPositiveAuthenticationTest(bool sharedAssociation
, bool positive
, bool tamper
) {
64 foreach (Protocol protocol
in Protocol
.AllPracticalVersions
) {
65 this.ParameterizedPositiveAuthenticationTest(protocol
, sharedAssociation
, positive
, tamper
);
69 private void ParameterizedPositiveAuthenticationTest(Protocol protocol
, bool sharedAssociation
, bool positive
, bool tamper
) {
70 ErrorUtilities
.VerifyArgument(positive
|| !tamper
, "Cannot tamper with a negative response.");
71 Uri userSetupUrl
= protocol
.Version
.Major
< 2 ? new Uri("http://usersetupurl") : null;
72 Association association
= sharedAssociation
? HmacShaAssociation
.Create(protocol
, protocol
.Args
.SignatureAlgorithm
.Best
, AssociationRelyingPartyType
.Smart
) : null;
73 var coordinator
= new OpenIdCoordinator(
75 var request
= new CheckIdRequest(protocol
.Version
, ProviderUri
, true);
77 if (association
!= null) {
78 rp
.AssociationStore
.StoreAssociation(ProviderUri
, association
);
79 request
.AssociationHandle
= association
.Handle
;
82 request
.ClaimedIdentifier
= "http://claimedid";
83 request
.LocalIdentifier
= "http://localid";
84 request
.ReturnTo
= RPUri
;
85 rp
.Channel
.Send(request
);
89 rp
.Channel
.ReadFromRequest
<PositiveAssertionResponse
>();
90 Assert
.Fail("Expected exception {0} not thrown.", typeof(InvalidSignatureException
).Name
);
91 } catch (InvalidSignatureException
) {
92 TestLogger
.InfoFormat("Caught expected {0} exception after tampering with signed data.", typeof(InvalidSignatureException
).Name
);
95 var response
= rp
.Channel
.ReadFromRequest
<PositiveAssertionResponse
>();
96 Assert
.IsNotNull(response
);
97 Assert
.AreEqual(request
.ClaimedIdentifier
, response
.ClaimedIdentifier
);
98 Assert
.AreEqual(request
.LocalIdentifier
, response
.LocalIdentifier
);
99 Assert
.AreEqual(request
.ReturnTo
, response
.ReturnTo
);
101 // Attempt to replay the message and verify that it fails.
102 // Because in various scenarios and protocol versions different components
103 // notice the replay, we can get one of two exceptions thrown.
104 // When the OP notices the replay we get a generic InvalidSignatureException.
105 // When the RP notices the replay we get a specific ReplayMessageException.
106 Type expectedExceptionType
= sharedAssociation
|| protocol
.Version
.Major
< 2 ? typeof(ReplayedMessageException
) : typeof(InvalidSignatureException
);
108 CoordinatingChannel channel
= (CoordinatingChannel
)rp
.Channel
;
109 channel
.Replay(response
);
110 Assert
.Fail("Expected exception {0} was not thrown.", expectedExceptionType
.Name
);
111 } catch (ProtocolException ex
) {
112 Assert
.IsInstanceOfType(ex
, expectedExceptionType
);
116 var response
= rp
.Channel
.ReadFromRequest
<NegativeAssertionResponse
>();
117 Assert
.IsNotNull(response
);
118 Assert
.AreEqual(userSetupUrl
, response
.UserSetupUrl
);
122 if (association
!= null) {
123 op
.AssociationStore
.StoreAssociation(AssociationRelyingPartyType
.Smart
, association
);
126 var request
= op
.Channel
.ReadFromRequest
<CheckIdRequest
>();
127 Assert
.IsNotNull(request
);
128 IProtocolMessage response
;
130 response
= new PositiveAssertionResponse(request
);
132 response
= new NegativeAssertionResponse(request
) { UserSetupUrl = userSetupUrl }
;
134 op
.Channel
.Send(response
);
136 if (positive
&& !sharedAssociation
) {
137 var checkauthRequest
= op
.Channel
.ReadFromRequest
<CheckAuthenticationRequest
>();
138 var checkauthResponse
= new CheckAuthenticationResponse(checkauthRequest
);
139 checkauthResponse
.IsValid
= checkauthRequest
.IsValid
;
140 op
.Channel
.Send(checkauthResponse
);
143 // Respond to the replay attack.
144 checkauthRequest
= op
.Channel
.ReadFromRequest
<CheckAuthenticationRequest
>();
145 checkauthResponse
= new CheckAuthenticationResponse(checkauthRequest
);
146 checkauthResponse
.IsValid
= checkauthRequest
.IsValid
;
147 op
.Channel
.Send(checkauthResponse
);
152 coordinator
.IncomingMessageFilter
= message
=> {
153 var assertion
= message
as PositiveAssertionResponse
;
154 if (assertion
!= null) {
155 // Alter the Local Identifier between the Provider and the Relying Party.
156 // If the signature binding element does its job, this should cause the RP
158 assertion
.LocalIdentifier
= "http://victim";