Skip to content

Commit f58f500

Browse files
committed
more unit test coverage
1 parent d9bd084 commit f58f500

File tree

2 files changed

+425
-0
lines changed

2 files changed

+425
-0
lines changed
Lines changed: 215 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,215 @@
1+
using Bit.Core.AdminConsole.Entities;
2+
using Bit.Core.Auth.Models.Data;
3+
using Bit.Core.Auth.UserFeatures.TdeOnboardingPassword;
4+
using Bit.Core.Entities;
5+
using Bit.Core.Enums;
6+
using Bit.Core.Exceptions;
7+
using Bit.Core.KeyManagement.Models.Data;
8+
using Bit.Core.Repositories;
9+
using Bit.Core.Services;
10+
using Bit.Test.Common.AutoFixture;
11+
using Bit.Test.Common.AutoFixture.Attributes;
12+
using Microsoft.AspNetCore.Identity;
13+
using NSubstitute;
14+
using NSubstitute.ReturnsExtensions;
15+
using Xunit;
16+
17+
namespace Bit.Core.Test.Auth.UserFeatures.TdeOnboardingPassword;
18+
19+
[SutProviderCustomize]
20+
public class TdeOnboardingPasswordCommandTests
21+
{
22+
[Theory]
23+
[BitAutoData]
24+
public async Task OnboardMasterPassword_Success(SutProvider<TdeOnboardingPasswordCommand> sutProvider,
25+
User user, KdfSettings kdfSettings,
26+
Organization org, OrganizationUser orgUser, string serverSideHash, string masterPasswordHint)
27+
{
28+
// Arrange
29+
user.Key = null;
30+
user.PublicKey = "public-key";
31+
user.PrivateKey = "private-key";
32+
var model = CreateValidModel(user, kdfSettings, org.Identifier, masterPasswordHint);
33+
34+
sutProvider.GetDependency<IOrganizationRepository>()
35+
.GetByIdentifierAsync(org.Identifier)
36+
.Returns(org);
37+
38+
sutProvider.GetDependency<IOrganizationUserRepository>()
39+
.GetByOrganizationAsync(org.Id, user.Id)
40+
.Returns(orgUser);
41+
42+
sutProvider.GetDependency<IPasswordHasher<User>>()
43+
.HashPassword(user, model.MasterPasswordAuthentication.MasterPasswordAuthenticationHash)
44+
.Returns(serverSideHash);
45+
46+
// Mock SetMasterPassword to return a specific UpdateUserData delegate
47+
UpdateUserData mockUpdateUserData = (connection, transaction) => Task.CompletedTask;
48+
sutProvider.GetDependency<IUserRepository>()
49+
.SetMasterPassword(user.Id, model.MasterPasswordUnlock, serverSideHash, model.MasterPasswordHint)
50+
.Returns(mockUpdateUserData);
51+
52+
// Act
53+
await sutProvider.Sut.OnboardMasterPasswordAsync(user, model);
54+
55+
// Assert
56+
await sutProvider.GetDependency<IUserRepository>().Received(1)
57+
.UpdateUserDataAsync(Arg.Do<IEnumerable<UpdateUserData>>(actions =>
58+
{
59+
var actionsList = actions.ToList();
60+
Assert.Single(actionsList);
61+
Assert.Same(mockUpdateUserData, actionsList[0]);
62+
}));
63+
64+
await sutProvider.GetDependency<IEventService>().Received(1)
65+
.LogUserEventAsync(user.Id, EventType.User_ChangedPassword);
66+
}
67+
68+
[Theory]
69+
[BitAutoData]
70+
public async Task OnboardMasterPassword_UserAlreadyHasPassword_ThrowsBadRequestException(
71+
SutProvider<TdeOnboardingPasswordCommand> sutProvider,
72+
User user, KdfSettings kdfSettings, string orgSsoIdentifier, string masterPasswordHint)
73+
{
74+
// Arrange
75+
user.Key = "existing-key";
76+
var model = CreateValidModel(user, kdfSettings, orgSsoIdentifier, masterPasswordHint);
77+
78+
// Act & Assert
79+
var exception = await Assert.ThrowsAsync<BadRequestException>(
80+
async () => await sutProvider.Sut.OnboardMasterPasswordAsync(user, model));
81+
Assert.Equal("User already has a master password set.", exception.Message);
82+
}
83+
84+
[Theory]
85+
[BitAutoData([null, "private-key"])]
86+
[BitAutoData("public-key", null)]
87+
[BitAutoData([null, null])]
88+
public async Task OnboardMasterPassword_MissingAccountKeys_ThrowsBadRequestException(
89+
string? publicKey, string? privateKey,
90+
SutProvider<TdeOnboardingPasswordCommand> sutProvider,
91+
User user, KdfSettings kdfSettings, string orgSsoIdentifier, string masterPasswordHint)
92+
{
93+
// Arrange
94+
user.Key = null;
95+
user.PublicKey = publicKey;
96+
user.PrivateKey = privateKey;
97+
var model = CreateValidModel(user, kdfSettings, orgSsoIdentifier, masterPasswordHint);
98+
99+
// Act & Assert
100+
var exception = await Assert.ThrowsAsync<BadRequestException>(
101+
async () => await sutProvider.Sut.OnboardMasterPasswordAsync(user, model));
102+
Assert.Equal("TDE user account keys must be set before setting initial master password.", exception.Message);
103+
}
104+
105+
[Theory]
106+
[BitAutoData("wrong-salt", null)]
107+
[BitAutoData([null, "wrong-salt"])]
108+
[BitAutoData("wrong-salt", "different-wrong-salt")]
109+
public async Task OnboardMasterPassword_InvalidSalt_ThrowsBadRequestException(
110+
string? authSaltOverride, string? unlockSaltOverride,
111+
SutProvider<TdeOnboardingPasswordCommand> sutProvider,
112+
User user, KdfSettings kdfSettings, string orgSsoIdentifier, string masterPasswordHint)
113+
{
114+
// Arrange
115+
user.Key = null;
116+
user.PublicKey = "public-key";
117+
user.PrivateKey = "private-key";
118+
var correctSalt = user.GetMasterPasswordSalt();
119+
var model = new SetInitialMasterPasswordDataModel
120+
{
121+
MasterPasswordAuthentication = new MasterPasswordAuthenticationData
122+
{
123+
Salt = authSaltOverride ?? correctSalt,
124+
MasterPasswordAuthenticationHash = "hash",
125+
Kdf = kdfSettings
126+
},
127+
MasterPasswordUnlock = new MasterPasswordUnlockData
128+
{
129+
Salt = unlockSaltOverride ?? correctSalt,
130+
MasterKeyWrappedUserKey = "wrapped-key",
131+
Kdf = kdfSettings
132+
},
133+
AccountKeys = null,
134+
OrgSsoIdentifier = orgSsoIdentifier,
135+
MasterPasswordHint = masterPasswordHint
136+
};
137+
138+
// Act & Assert
139+
var exception = await Assert.ThrowsAsync<BadRequestException>(
140+
async () => await sutProvider.Sut.OnboardMasterPasswordAsync(user, model));
141+
Assert.Equal("Invalid master password salt.", exception.Message);
142+
}
143+
144+
[Theory]
145+
[BitAutoData]
146+
public async Task OnboardMasterPassword_InvalidOrgSsoIdentifier_ThrowsBadRequestException(
147+
SutProvider<TdeOnboardingPasswordCommand> sutProvider,
148+
User user, KdfSettings kdfSettings, string orgSsoIdentifier, string masterPasswordHint)
149+
{
150+
// Arrange
151+
user.Key = null;
152+
user.PublicKey = "public-key";
153+
user.PrivateKey = "private-key";
154+
var model = CreateValidModel(user, kdfSettings, orgSsoIdentifier, masterPasswordHint);
155+
156+
sutProvider.GetDependency<IOrganizationRepository>()
157+
.GetByIdentifierAsync(orgSsoIdentifier)
158+
.ReturnsNull();
159+
160+
// Act & Assert
161+
var exception = await Assert.ThrowsAsync<BadRequestException>(
162+
async () => await sutProvider.Sut.OnboardMasterPasswordAsync(user, model));
163+
Assert.Equal("Organization SSO identifier is invalid.", exception.Message);
164+
}
165+
166+
[Theory]
167+
[BitAutoData]
168+
public async Task OnboardMasterPassword_UserNotFoundInOrganization_ThrowsBadRequestException(
169+
SutProvider<TdeOnboardingPasswordCommand> sutProvider,
170+
User user, KdfSettings kdfSettings, Organization org, string masterPasswordHint)
171+
{
172+
// Arrange
173+
user.Key = null;
174+
user.PublicKey = "public-key";
175+
user.PrivateKey = "private-key";
176+
var model = CreateValidModel(user, kdfSettings, org.Identifier, masterPasswordHint);
177+
178+
sutProvider.GetDependency<IOrganizationRepository>()
179+
.GetByIdentifierAsync(org.Identifier)
180+
.Returns(org);
181+
182+
sutProvider.GetDependency<IOrganizationUserRepository>()
183+
.GetByOrganizationAsync(org.Id, user.Id)
184+
.ReturnsNull();
185+
186+
// Act & Assert
187+
var exception = await Assert.ThrowsAsync<BadRequestException>(
188+
async () => await sutProvider.Sut.OnboardMasterPasswordAsync(user, model));
189+
Assert.Equal("User not found within organization.", exception.Message);
190+
}
191+
192+
private static SetInitialMasterPasswordDataModel CreateValidModel(
193+
User user, KdfSettings kdfSettings, string orgSsoIdentifier, string? masterPasswordHint)
194+
{
195+
var salt = user.GetMasterPasswordSalt();
196+
return new SetInitialMasterPasswordDataModel
197+
{
198+
MasterPasswordAuthentication = new MasterPasswordAuthenticationData
199+
{
200+
Salt = salt,
201+
MasterPasswordAuthenticationHash = "hash",
202+
Kdf = kdfSettings
203+
},
204+
MasterPasswordUnlock = new MasterPasswordUnlockData
205+
{
206+
Salt = salt,
207+
MasterKeyWrappedUserKey = "wrapped-key",
208+
Kdf = kdfSettings
209+
},
210+
AccountKeys = null,
211+
OrgSsoIdentifier = orgSsoIdentifier,
212+
MasterPasswordHint = masterPasswordHint
213+
};
214+
}
215+
}

0 commit comments

Comments
 (0)