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 DotNetOpenAuth
.Messaging
;
10 using DotNetOpenAuth
.Messaging
.Bindings
;
11 using DotNetOpenAuth
.OpenId
;
12 using DotNetOpenAuth
.OpenId
.Messages
;
13 using DotNetOpenAuth
.OpenId
.Provider
;
14 using DotNetOpenAuth
.OpenId
.RelyingParty
;
15 using DotNetOpenAuth
.Test
.Mocks
;
16 using Microsoft
.VisualStudio
.TestTools
.UnitTesting
;
19 public class AuthenticationTests
: OpenIdTestBase
{
21 public override void SetUp() {
26 public void SharedAssociationPositive() {
27 this.ParameterizedPositiveAuthenticationTest(true, true, false);
31 /// Verifies that a shared association protects against tampering.
34 public void SharedAssociationTampered() {
35 this.ParameterizedPositiveAuthenticationTest(true, true, true);
39 public void SharedAssociationNegative() {
40 this.ParameterizedPositiveAuthenticationTest(true, false, false);
44 public void PrivateAssociationPositive() {
45 this.ParameterizedPositiveAuthenticationTest(false, true, false);
49 /// Verifies that a private association protects against tampering.
52 public void PrivateAssociationTampered() {
53 this.ParameterizedPositiveAuthenticationTest(false, true, true);
57 public void NoAssociationNegative() {
58 this.ParameterizedPositiveAuthenticationTest(false, false, false);
61 private void ParameterizedPositiveAuthenticationTest(bool sharedAssociation
, bool positive
, bool tamper
) {
62 foreach (Protocol protocol
in Protocol
.AllPracticalVersions
) {
63 this.ParameterizedPositiveAuthenticationTest(protocol
, sharedAssociation
, positive
, tamper
);
67 private void ParameterizedPositiveAuthenticationTest(Protocol protocol
, bool sharedAssociation
, bool positive
, bool tamper
) {
68 ErrorUtilities
.VerifyArgument(positive
|| !tamper
, "Cannot tamper with a negative response.");
69 Uri userSetupUrl
= protocol
.Version
.Major
< 2 ? new Uri("http://usersetupurl") : null;
70 ProviderSecuritySettings securitySettings
= new ProviderSecuritySettings();
71 Association association
= sharedAssociation
? HmacShaAssociation
.Create(protocol
, protocol
.Args
.SignatureAlgorithm
.Best
, AssociationRelyingPartyType
.Smart
, securitySettings
) : null;
72 var coordinator
= new OpenIdCoordinator(
74 var request
= new CheckIdRequest(protocol
.Version
, ProviderUri
, AuthenticationRequestMode
.Immediate
);
76 if (association
!= null) {
77 rp
.AssociationStore
.StoreAssociation(ProviderUri
, association
);
78 request
.AssociationHandle
= association
.Handle
;
81 request
.ClaimedIdentifier
= "http://claimedid";
82 request
.LocalIdentifier
= "http://localid";
83 request
.ReturnTo
= RPUri
;
84 rp
.Channel
.Send(request
);
88 rp
.Channel
.ReadFromRequest
<PositiveAssertionResponse
>();
89 Assert
.Fail("Expected exception {0} not thrown.", typeof(InvalidSignatureException
).Name
);
90 } catch (InvalidSignatureException
) {
91 TestLogger
.InfoFormat("Caught expected {0} exception after tampering with signed data.", typeof(InvalidSignatureException
).Name
);
94 var response
= rp
.Channel
.ReadFromRequest
<PositiveAssertionResponse
>();
95 Assert
.IsNotNull(response
);
96 Assert
.AreEqual(request
.ClaimedIdentifier
, response
.ClaimedIdentifier
);
97 Assert
.AreEqual(request
.LocalIdentifier
, response
.LocalIdentifier
);
98 Assert
.AreEqual(request
.ReturnTo
, response
.ReturnTo
);
100 // Attempt to replay the message and verify that it fails.
101 // Because in various scenarios and protocol versions different components
102 // notice the replay, we can get one of two exceptions thrown.
103 // When the OP notices the replay we get a generic InvalidSignatureException.
104 // When the RP notices the replay we get a specific ReplayMessageException.
105 Type expectedExceptionType
= sharedAssociation
|| protocol
.Version
.Major
< 2 ? typeof(ReplayedMessageException
) : typeof(InvalidSignatureException
);
107 CoordinatingChannel channel
= (CoordinatingChannel
)rp
.Channel
;
108 channel
.Replay(response
);
109 Assert
.Fail("Expected exception {0} was not thrown.", expectedExceptionType
.Name
);
110 } catch (ProtocolException ex
) {
111 Assert
.IsInstanceOfType(ex
, expectedExceptionType
);
115 var response
= rp
.Channel
.ReadFromRequest
<NegativeAssertionResponse
>();
116 Assert
.IsNotNull(response
);
117 Assert
.AreEqual(userSetupUrl
, response
.UserSetupUrl
);
121 if (association
!= null) {
122 op
.AssociationStore
.StoreAssociation(AssociationRelyingPartyType
.Smart
, association
);
125 var request
= op
.Channel
.ReadFromRequest
<CheckIdRequest
>();
126 Assert
.IsNotNull(request
);
127 IProtocolMessage response
;
129 response
= new PositiveAssertionResponse(request
);
131 response
= new NegativeAssertionResponse(request
) { UserSetupUrl = userSetupUrl }
;
133 op
.Channel
.Send(response
);
135 if (positive
&& !sharedAssociation
) {
136 var checkauthRequest
= op
.Channel
.ReadFromRequest
<CheckAuthenticationRequest
>();
137 var checkauthResponse
= new CheckAuthenticationResponse(checkauthRequest
);
138 checkauthResponse
.IsValid
= checkauthRequest
.IsValid
;
139 op
.Channel
.Send(checkauthResponse
);
142 // Respond to the replay attack.
143 checkauthRequest
= op
.Channel
.ReadFromRequest
<CheckAuthenticationRequest
>();
144 checkauthResponse
= new CheckAuthenticationResponse(checkauthRequest
);
145 checkauthResponse
.IsValid
= checkauthRequest
.IsValid
;
146 op
.Channel
.Send(checkauthResponse
);
151 coordinator
.IncomingMessageFilter
= message
=> {
152 var assertion
= message
as PositiveAssertionResponse
;
153 if (assertion
!= null) {
154 // Alter the Local Identifier between the Provider and the Relying Party.
155 // If the signature binding element does its job, this should cause the RP
157 assertion
.LocalIdentifier
= "http://victim";