Skip to content

Commit f028da9

Browse files
test: unit test SendNeverAuthenticate method
1 parent aba190e commit f028da9

File tree

1 file changed

+280
-0
lines changed

1 file changed

+280
-0
lines changed
Lines changed: 280 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,280 @@
1+
using Bit.Core.Tools.Models.Data;
2+
using Bit.Identity.IdentityServer.RequestValidators.SendAccess;
3+
using Bit.Test.Common.AutoFixture;
4+
using Bit.Test.Common.AutoFixture.Attributes;
5+
using Duende.IdentityModel;
6+
using Duende.IdentityServer.Validation;
7+
using Xunit;
8+
9+
namespace Bit.Identity.Test.IdentityServer.SendAccess;
10+
11+
[SutProviderCustomize]
12+
public class SendNeverAuthenticateRequestValidatorTests
13+
{
14+
/// <summary>
15+
/// To support the static hashing function <see cref="EnumerationProtectionHelpers.GetIndexForSaltHash"/> theses GUIDs and Key must be hardcoded
16+
/// </summary>
17+
private static readonly string _testHashKey = "test-key-123456789012345678901234567890";
18+
// These Guids are static and ensure the correct index for each error type
19+
private static readonly Guid _invalidSendGuid = Guid.Parse("1b35fbf3-a14a-4d48-82b7-2adc34fdae6f");
20+
private static readonly Guid _emailSendGuid = Guid.Parse("bc8e2ef5-a0bd-44d2-bdb7-5902be6f5c41");
21+
private static readonly Guid _passwordSendGuid = Guid.Parse("da36fa27-f0e8-4701-a585-d3d8c2f67c4b");
22+
23+
private static readonly NeverAuthenticate _authMethod = new();
24+
25+
[Theory, BitAutoData]
26+
public async Task ValidateRequestAsync_GuidErrorSelected_ReturnsInvalidSendId(
27+
SutProvider<SendNeverAuthenticateRequestValidator> sutProvider,
28+
[AutoFixture.ValidatedTokenRequest] ValidatedTokenRequest tokenRequest)
29+
{
30+
// Arrange
31+
tokenRequest.Raw = SendAccessTestUtilities.CreateValidatedTokenRequest(_invalidSendGuid);
32+
var context = new ExtensionGrantValidationContext
33+
{
34+
Request = tokenRequest
35+
};
36+
37+
sutProvider.GetDependency<Core.Settings.GlobalSettings>().SendDefaultHashKey = _testHashKey;
38+
39+
// Act
40+
var result = await sutProvider.Sut.ValidateRequestAsync(context, _authMethod, _invalidSendGuid);
41+
42+
// Assert
43+
Assert.True(result.IsError);
44+
Assert.Equal(OidcConstants.TokenErrors.InvalidGrant, result.Error);
45+
Assert.Equal(SendAccessConstants.GrantValidatorResults.InvalidSendId, result.ErrorDescription);
46+
47+
var customResponse = result.CustomResponse as Dictionary<string, object>;
48+
Assert.NotNull(customResponse);
49+
Assert.Equal(
50+
SendAccessConstants.GrantValidatorResults.InvalidSendId, customResponse[SendAccessConstants.SendAccessError]);
51+
}
52+
53+
[Theory, BitAutoData]
54+
public async Task ValidateRequestAsync_EmailErrorSelected_HasEmail_ReturnsEmailInvalid(
55+
SutProvider<SendNeverAuthenticateRequestValidator> sutProvider,
56+
[AutoFixture.ValidatedTokenRequest] ValidatedTokenRequest tokenRequest,
57+
string email)
58+
{
59+
// Arrange
60+
tokenRequest.Raw = SendAccessTestUtilities.CreateValidatedTokenRequest(_emailSendGuid, sendEmail: email);
61+
var context = new ExtensionGrantValidationContext
62+
{
63+
Request = tokenRequest
64+
};
65+
sutProvider.GetDependency<Core.Settings.GlobalSettings>().SendDefaultHashKey = _testHashKey;
66+
67+
// Act
68+
var result = await sutProvider.Sut.ValidateRequestAsync(context, _authMethod, _emailSendGuid);
69+
70+
// Assert
71+
Assert.True(result.IsError);
72+
Assert.Equal(OidcConstants.TokenErrors.InvalidGrant, result.Error);
73+
Assert.Equal(SendAccessConstants.EmailOtpValidatorResults.EmailInvalid, result.ErrorDescription);
74+
75+
var customResponse = result.CustomResponse as Dictionary<string, object>;
76+
Assert.NotNull(customResponse);
77+
Assert.Equal(SendAccessConstants.EmailOtpValidatorResults.EmailInvalid, customResponse[SendAccessConstants.SendAccessError]);
78+
}
79+
80+
[Theory, BitAutoData]
81+
public async Task ValidateRequestAsync_EmailErrorSelected_NoEmail_ReturnsEmailRequired(
82+
SutProvider<SendNeverAuthenticateRequestValidator> sutProvider,
83+
[AutoFixture.ValidatedTokenRequest] ValidatedTokenRequest tokenRequest)
84+
{
85+
// Arrange
86+
tokenRequest.Raw = SendAccessTestUtilities.CreateValidatedTokenRequest(_emailSendGuid);
87+
var context = new ExtensionGrantValidationContext
88+
{
89+
Request = tokenRequest
90+
};
91+
sutProvider.GetDependency<Core.Settings.GlobalSettings>().SendDefaultHashKey = _testHashKey;
92+
93+
// Act
94+
var result = await sutProvider.Sut.ValidateRequestAsync(context, _authMethod, _emailSendGuid);
95+
96+
// Assert
97+
Assert.True(result.IsError);
98+
Assert.Equal(OidcConstants.TokenErrors.InvalidRequest, result.Error);
99+
Assert.Equal(SendAccessConstants.EmailOtpValidatorResults.EmailRequired, result.ErrorDescription);
100+
101+
var customResponse = result.CustomResponse as Dictionary<string, object>;
102+
Assert.NotNull(customResponse);
103+
Assert.Equal(SendAccessConstants.EmailOtpValidatorResults.EmailRequired, customResponse[SendAccessConstants.SendAccessError]);
104+
}
105+
106+
[Theory, BitAutoData]
107+
public async Task ValidateRequestAsync_PasswordErrorSelected_HasPassword_ReturnsPasswordDoesNotMatch(
108+
SutProvider<SendNeverAuthenticateRequestValidator> sutProvider,
109+
[AutoFixture.ValidatedTokenRequest] ValidatedTokenRequest tokenRequest,
110+
string password)
111+
{
112+
// Arrange
113+
tokenRequest.Raw = SendAccessTestUtilities.CreateValidatedTokenRequest(_passwordSendGuid, passwordHash: password);
114+
var context = new ExtensionGrantValidationContext
115+
{
116+
Request = tokenRequest
117+
};
118+
sutProvider.GetDependency<Core.Settings.GlobalSettings>().SendDefaultHashKey = _testHashKey;
119+
120+
// Act
121+
var result = await sutProvider.Sut.ValidateRequestAsync(context, _authMethod, _passwordSendGuid);
122+
123+
// Assert
124+
Assert.True(result.IsError);
125+
Assert.Equal(OidcConstants.TokenErrors.InvalidRequest, result.Error);
126+
Assert.Equal(SendAccessConstants.PasswordValidatorResults.RequestPasswordDoesNotMatch, result.ErrorDescription);
127+
128+
var customResponse = result.CustomResponse as Dictionary<string, object>;
129+
Assert.NotNull(customResponse);
130+
Assert.Equal(SendAccessConstants.PasswordValidatorResults.RequestPasswordDoesNotMatch, customResponse[SendAccessConstants.SendAccessError]);
131+
}
132+
133+
[Theory, BitAutoData]
134+
public async Task ValidateRequestAsync_PasswordErrorSelected_NoPassword_ReturnsPasswordRequired(
135+
SutProvider<SendNeverAuthenticateRequestValidator> sutProvider,
136+
[AutoFixture.ValidatedTokenRequest] ValidatedTokenRequest tokenRequest)
137+
{
138+
// Arrange
139+
140+
tokenRequest.Raw = SendAccessTestUtilities.CreateValidatedTokenRequest(_passwordSendGuid);
141+
var context = new ExtensionGrantValidationContext
142+
{
143+
Request = tokenRequest
144+
};
145+
sutProvider.GetDependency<Core.Settings.GlobalSettings>().SendDefaultHashKey = _testHashKey;
146+
147+
// Act
148+
var result = await sutProvider.Sut.ValidateRequestAsync(context, _authMethod, _passwordSendGuid);
149+
150+
// Assert
151+
Assert.True(result.IsError);
152+
Assert.Equal(OidcConstants.TokenErrors.InvalidGrant, result.Error);
153+
Assert.Equal(SendAccessConstants.PasswordValidatorResults.RequestPasswordIsRequired, result.ErrorDescription);
154+
155+
var customResponse = result.CustomResponse as Dictionary<string, object>;
156+
Assert.NotNull(customResponse);
157+
Assert.Equal(SendAccessConstants.PasswordValidatorResults.RequestPasswordIsRequired, customResponse[SendAccessConstants.SendAccessError]);
158+
}
159+
160+
[Theory, BitAutoData]
161+
public async Task ValidateRequestAsync_NullHashKey_UsesEmptyKey(
162+
SutProvider<SendNeverAuthenticateRequestValidator> sutProvider,
163+
[AutoFixture.ValidatedTokenRequest] ValidatedTokenRequest tokenRequest)
164+
{
165+
// Arrange
166+
tokenRequest.Raw = SendAccessTestUtilities.CreateValidatedTokenRequest(_invalidSendGuid);
167+
var context = new ExtensionGrantValidationContext { Request = tokenRequest };
168+
sutProvider.GetDependency<Core.Settings.GlobalSettings>().SendDefaultHashKey = null;
169+
170+
// Act
171+
var result = await sutProvider.Sut.ValidateRequestAsync(context, _authMethod, _invalidSendGuid);
172+
173+
// Assert
174+
Assert.True(result.IsError);
175+
Assert.Equal(OidcConstants.TokenErrors.InvalidGrant, result.Error);
176+
Assert.Contains(result.ErrorDescription, SendAccessConstants.GrantValidatorResults.InvalidSendId);
177+
}
178+
179+
[Theory, BitAutoData]
180+
public async Task ValidateRequestAsync_EmptyHashKey_UsesEmptyKey(
181+
SutProvider<SendNeverAuthenticateRequestValidator> sutProvider,
182+
[AutoFixture.ValidatedTokenRequest] ValidatedTokenRequest tokenRequest)
183+
{
184+
// Arrange
185+
tokenRequest.Raw = SendAccessTestUtilities.CreateValidatedTokenRequest(_invalidSendGuid);
186+
var context = new ExtensionGrantValidationContext
187+
{
188+
Request = tokenRequest
189+
};
190+
191+
sutProvider.GetDependency<Core.Settings.GlobalSettings>().SendDefaultHashKey = "";
192+
193+
// Act
194+
var result = await sutProvider.Sut.ValidateRequestAsync(context, _authMethod, _invalidSendGuid);
195+
196+
// Assert
197+
Assert.True(result.IsError);
198+
Assert.Equal(OidcConstants.TokenErrors.InvalidGrant, result.Error);
199+
Assert.Contains(result.ErrorDescription, SendAccessConstants.GrantValidatorResults.InvalidSendId);
200+
}
201+
202+
[Theory, BitAutoData]
203+
public async Task ValidateRequestAsync_ConsistentBehavior_SameSendIdSameResult(
204+
SutProvider<SendNeverAuthenticateRequestValidator> sutProvider,
205+
[AutoFixture.ValidatedTokenRequest] ValidatedTokenRequest tokenRequest,
206+
Guid sendId)
207+
{
208+
// Arrange
209+
tokenRequest.Raw = SendAccessTestUtilities.CreateValidatedTokenRequest(sendId);
210+
var context = new ExtensionGrantValidationContext
211+
{
212+
Request = tokenRequest
213+
};
214+
215+
sutProvider.GetDependency<Core.Settings.GlobalSettings>().SendDefaultHashKey = "consistent-test-key-123456789012345678901234567890";
216+
217+
// Act
218+
var result1 = await sutProvider.Sut.ValidateRequestAsync(context, _authMethod, sendId);
219+
var result2 = await sutProvider.Sut.ValidateRequestAsync(context, _authMethod, sendId);
220+
221+
// Assert
222+
Assert.Equal(result1.ErrorDescription, result2.ErrorDescription);
223+
Assert.Equal(result1.Error, result2.Error);
224+
225+
var customResponse1 = result1.CustomResponse as Dictionary<string, object>;
226+
var customResponse2 = result2.CustomResponse as Dictionary<string, object>;
227+
Assert.Equal(customResponse1[SendAccessConstants.SendAccessError], customResponse2[SendAccessConstants.SendAccessError]);
228+
}
229+
230+
[Theory, BitAutoData]
231+
public async Task ValidateRequestAsync_DifferentSendIds_CanReturnDifferentResults(
232+
SutProvider<SendNeverAuthenticateRequestValidator> sutProvider,
233+
[AutoFixture.ValidatedTokenRequest] ValidatedTokenRequest tokenRequest,
234+
Guid sendId1,
235+
Guid sendId2)
236+
{
237+
// Arrange
238+
tokenRequest.Raw = SendAccessTestUtilities.CreateValidatedTokenRequest(sendId1);
239+
var context = new ExtensionGrantValidationContext
240+
{
241+
Request = tokenRequest
242+
};
243+
244+
sutProvider.GetDependency<Core.Settings.GlobalSettings>().SendDefaultHashKey = "different-test-key-123456789012345678901234567890";
245+
246+
// Act
247+
var result1 = await sutProvider.Sut.ValidateRequestAsync(context, _authMethod, sendId1);
248+
var result2 = await sutProvider.Sut.ValidateRequestAsync(context, _authMethod, sendId2);
249+
250+
// Assert - Both should be errors
251+
Assert.True(result1.IsError);
252+
Assert.True(result2.IsError);
253+
254+
// Both should have valid error types
255+
var validErrors = new[]
256+
{
257+
SendAccessConstants.GrantValidatorResults.InvalidSendId,
258+
SendAccessConstants.EmailOtpValidatorResults.EmailRequired,
259+
SendAccessConstants.PasswordValidatorResults.RequestPasswordIsRequired
260+
};
261+
Assert.Contains(result1.ErrorDescription, validErrors);
262+
Assert.Contains(result2.ErrorDescription, validErrors);
263+
}
264+
265+
[Fact]
266+
public void Constructor_WithValidGlobalSettings_CreatesInstance()
267+
{
268+
// Arrange
269+
var globalSettings = new Core.Settings.GlobalSettings
270+
{
271+
SendDefaultHashKey = "test-key-123456789012345678901234567890"
272+
};
273+
274+
// Act
275+
var validator = new SendNeverAuthenticateRequestValidator(globalSettings);
276+
277+
// Assert
278+
Assert.NotNull(validator);
279+
}
280+
}

0 commit comments

Comments
 (0)