feat(emergency-access) [PM-29584] Create Email for Emergency Access Removal (#6793)

* feat(emergency-access) [PM-29584]: Add email template.

* refactor(emergency-access) [PM-29584]: Move Emergency Access to Auth/UserFeatures.

* refactor(emergency-access) [PM-29584]: Move EmergencyAccess tests to UserFeatures space.

* feat(emergency-access) [PM-29584]: Add compiled EmergencyAccess templates.

* test(emergency-access) [PM-29584]: Add mailer-specific tests.

* refactor(emergency-access) [PM-29584]: Move mail to UserFeatures area.

* feat(emergency-access) [PM-29584]: Update link for help pages, not web vault.

* test(emergency-access) [PM-29584]: Update mail tests for new URL and single responsibility.

* refactor(emergency-access) [PM-29584]: Add comments for added test.
This commit is contained in:
Dave
2026-01-22 20:24:15 -05:00
committed by GitHub
parent 0cc72127d7
commit 93e2c971df
14 changed files with 802 additions and 100 deletions

View File

@@ -0,0 +1,153 @@
using Bit.Core.Auth.UserFeatures.EmergencyAccess.Mail;
using Bit.Core.Models.Mail;
using Bit.Core.Platform.Mail.Delivery;
using Bit.Core.Platform.Mail.Mailer;
using Bit.Test.Common.AutoFixture.Attributes;
using Microsoft.Extensions.Logging;
using NSubstitute;
using Xunit;
using GlobalSettings = Bit.Core.Settings.GlobalSettings;
namespace Bit.Core.Test.Auth.UserFeatures.EmergencyAccess;
[SutProviderCustomize]
public class EmergencyAccessMailTests
{
// Constant values for all Emergency Access emails
private const string _emergencyAccessHelpUrl = "https://bitwarden.com/help/emergency-access/";
private const string _emergencyAccessMailSubject = "Emergency contacts removed";
/// <summary>
/// Documents how to construct and send the emergency access removal email.
/// 1. Inject IMailer into their command/service
/// 2. Construct EmergencyAccessRemoveGranteesMail as shown below
/// 3. Call mailer.SendEmail(mail)
/// </summary>
[Theory, BitAutoData]
public async Task SendEmergencyAccessRemoveGranteesEmail_SingleGrantee_Success(
string grantorEmail,
string granteeName)
{
// Arrange
var logger = Substitute.For<ILogger<HandlebarMailRenderer>>();
var globalSettings = new GlobalSettings { SelfHosted = false };
var deliveryService = Substitute.For<IMailDeliveryService>();
var mailer = new Mailer(
new HandlebarMailRenderer(logger, globalSettings),
deliveryService);
var mail = new EmergencyAccessRemoveGranteesMail
{
ToEmails = [grantorEmail],
View = new EmergencyAccessRemoveGranteesMailView
{
RemovedGranteeNames = [granteeName]
}
};
MailMessage sentMessage = null;
await deliveryService.SendEmailAsync(Arg.Do<MailMessage>(message =>
sentMessage = message
));
// Act
await mailer.SendEmail(mail);
// Assert
Assert.NotNull(sentMessage);
Assert.Contains(grantorEmail, sentMessage.ToEmails);
// Verify the content contains the grantee name
Assert.Contains(granteeName, sentMessage.TextContent);
Assert.Contains(granteeName, sentMessage.HtmlContent);
}
/// <summary>
/// Documents handling multiple removed grantees in a single email.
/// </summary>
[Theory, BitAutoData]
public async Task SendEmergencyAccessRemoveGranteesEmail_MultipleGrantees_RendersAllNames(
string grantorEmail)
{
// Arrange
var logger = Substitute.For<ILogger<HandlebarMailRenderer>>();
var globalSettings = new GlobalSettings { SelfHosted = false };
var deliveryService = Substitute.For<IMailDeliveryService>();
var mailer = new Mailer(
new HandlebarMailRenderer(logger, globalSettings),
deliveryService);
var granteeNames = new[] { "Alice", "Bob", "Carol" };
var mail = new EmergencyAccessRemoveGranteesMail
{
ToEmails = [grantorEmail],
View = new EmergencyAccessRemoveGranteesMailView
{
RemovedGranteeNames = granteeNames
}
};
MailMessage sentMessage = null;
await deliveryService.SendEmailAsync(Arg.Do<MailMessage>(message =>
sentMessage = message
));
// Act
await mailer.SendEmail(mail);
// Assert - All grantee names should appear in the email
Assert.NotNull(sentMessage);
foreach (var granteeName in granteeNames)
{
Assert.Contains(granteeName, sentMessage.TextContent);
Assert.Contains(granteeName, sentMessage.HtmlContent);
}
}
/// <summary>
/// Validates the required GranteeNames for the email view model.
/// </summary>
[Theory, BitAutoData]
public void EmergencyAccessRemoveGranteesMailView_GranteeNames_AreRequired(
string grantorEmail)
{
// Arrange - Shows the minimum required to construct the email
var mail = new EmergencyAccessRemoveGranteesMail
{
ToEmails = [grantorEmail], // Required: who to send to
View = new EmergencyAccessRemoveGranteesMailView
{
// Required: at least one removed grantee name
RemovedGranteeNames = ["Example Grantee"]
}
};
// Assert
Assert.NotNull(mail);
Assert.NotNull(mail.View);
Assert.NotEmpty(mail.View.RemovedGranteeNames);
}
/// <summary>
/// Ensure consistency with help pages link and email subject.
/// </summary>
/// <param name="grantorEmail"></param>
/// <param name="granteeName"></param>
[Theory, BitAutoData]
public void EmergencyAccessRemoveGranteesMailView_SubjectAndHelpLink_MatchesExpectedValues(string grantorEmail, string granteeName)
{
// Arrange
var mail = new EmergencyAccessRemoveGranteesMail
{
ToEmails = [grantorEmail],
View = new EmergencyAccessRemoveGranteesMailView { RemovedGranteeNames = [granteeName] }
};
// Assert
Assert.NotNull(mail);
Assert.NotNull(mail.View);
Assert.Equal(_emergencyAccessMailSubject, mail.Subject);
Assert.Equal(_emergencyAccessHelpUrl, mail.View.EmergencyAccessHelpPageUrl);
}
}

View File

@@ -1,11 +1,10 @@
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.Interfaces;
using Bit.Core.AdminConsole.Repositories;
using Bit.Core.Auth.Entities;
using Bit.Core.Auth.Enums;
using Bit.Core.Auth.Models;
using Bit.Core.Auth.Models.Business.Tokenables;
using Bit.Core.Auth.Models.Data;
using Bit.Core.Auth.Services;
using Bit.Core.Auth.UserFeatures.EmergencyAccess;
using Bit.Core.Entities;
using Bit.Core.Enums;
using Bit.Core.Exceptions;
@@ -17,7 +16,7 @@ using Bit.Test.Common.AutoFixture.Attributes;
using NSubstitute;
using Xunit;
namespace Bit.Core.Test.Auth.Services;
namespace Bit.Core.Test.Auth.UserFeatures.EmergencyAccess;
[SutProviderCustomize]
public class EmergencyAccessServiceTests
@@ -68,13 +67,13 @@ public class EmergencyAccessServiceTests
Assert.Equal(EmergencyAccessStatusType.Invited, result.Status);
await sutProvider.GetDependency<IEmergencyAccessRepository>()
.Received(1)
.CreateAsync(Arg.Any<EmergencyAccess>());
.CreateAsync(Arg.Any<Core.Auth.Entities.EmergencyAccess>());
sutProvider.GetDependency<IDataProtectorTokenFactory<EmergencyAccessInviteTokenable>>()
.Received(1)
.Protect(Arg.Any<EmergencyAccessInviteTokenable>());
await sutProvider.GetDependency<IMailService>()
.Received(1)
.SendEmergencyAccessInviteEmailAsync(Arg.Any<EmergencyAccess>(), Arg.Any<string>(), Arg.Any<string>());
.SendEmergencyAccessInviteEmailAsync(Arg.Any<Core.Auth.Entities.EmergencyAccess>(), Arg.Any<string>(), Arg.Any<string>());
}
[Theory, BitAutoData]
@@ -98,7 +97,7 @@ public class EmergencyAccessServiceTests
User invitingUser,
Guid emergencyAccessId)
{
EmergencyAccess emergencyAccess = null;
Core.Auth.Entities.EmergencyAccess emergencyAccess = null;
sutProvider.GetDependency<IEmergencyAccessRepository>()
.GetByIdAsync(Arg.Any<Guid>())
@@ -119,7 +118,7 @@ public class EmergencyAccessServiceTests
User invitingUser,
Guid emergencyAccessId)
{
var emergencyAccess = new EmergencyAccess
var emergencyAccess = new Core.Auth.Entities.EmergencyAccess
{
Status = EmergencyAccessStatusType.Invited,
GrantorId = Guid.NewGuid(),
@@ -148,7 +147,7 @@ public class EmergencyAccessServiceTests
User invitingUser,
Guid emergencyAccessId)
{
var emergencyAccess = new EmergencyAccess
var emergencyAccess = new Core.Auth.Entities.EmergencyAccess
{
Status = statusType,
GrantorId = invitingUser.Id,
@@ -172,7 +171,7 @@ public class EmergencyAccessServiceTests
User invitingUser,
Guid emergencyAccessId)
{
var emergencyAccess = new EmergencyAccess
var emergencyAccess = new Core.Auth.Entities.EmergencyAccess
{
Status = EmergencyAccessStatusType.Invited,
GrantorId = invitingUser.Id,
@@ -194,7 +193,7 @@ public class EmergencyAccessServiceTests
public async Task AcceptUserAsync_EmergencyAccessNull_ThrowsBadRequest(
SutProvider<EmergencyAccessService> sutProvider, User acceptingUser, string token)
{
EmergencyAccess emergencyAccess = null;
Core.Auth.Entities.EmergencyAccess emergencyAccess = null;
sutProvider.GetDependency<IEmergencyAccessRepository>()
.GetByIdAsync(Arg.Any<Guid>())
.Returns(emergencyAccess);
@@ -209,7 +208,7 @@ public class EmergencyAccessServiceTests
public async Task AcceptUserAsync_CannotUnprotectToken_ThrowsBadRequest(
SutProvider<EmergencyAccessService> sutProvider,
User acceptingUser,
EmergencyAccess emergencyAccess,
Core.Auth.Entities.EmergencyAccess emergencyAccess,
string token)
{
sutProvider.GetDependency<IEmergencyAccessRepository>()
@@ -230,8 +229,8 @@ public class EmergencyAccessServiceTests
public async Task AcceptUserAsync_TokenDataInvalid_ThrowsBadRequest(
SutProvider<EmergencyAccessService> sutProvider,
User acceptingUser,
EmergencyAccess emergencyAccess,
EmergencyAccess wrongEmergencyAccess,
Core.Auth.Entities.EmergencyAccess emergencyAccess,
Core.Auth.Entities.EmergencyAccess wrongEmergencyAccess,
string token)
{
sutProvider.GetDependency<IEmergencyAccessRepository>()
@@ -257,7 +256,7 @@ public class EmergencyAccessServiceTests
public async Task AcceptUserAsync_AcceptedStatus_ThrowsBadRequest(
SutProvider<EmergencyAccessService> sutProvider,
User acceptingUser,
EmergencyAccess emergencyAccess,
Core.Auth.Entities.EmergencyAccess emergencyAccess,
string token)
{
emergencyAccess.Status = EmergencyAccessStatusType.Accepted;
@@ -284,7 +283,7 @@ public class EmergencyAccessServiceTests
public async Task AcceptUserAsync_NotInvitedStatus_ThrowsBadRequest(
SutProvider<EmergencyAccessService> sutProvider,
User acceptingUser,
EmergencyAccess emergencyAccess,
Core.Auth.Entities.EmergencyAccess emergencyAccess,
string token)
{
emergencyAccess.Status = EmergencyAccessStatusType.Confirmed;
@@ -311,7 +310,7 @@ public class EmergencyAccessServiceTests
public async Task AcceptUserAsync_EmergencyAccessEmailDoesNotMatch_ThrowsBadRequest(
SutProvider<EmergencyAccessService> sutProvider,
User acceptingUser,
EmergencyAccess emergencyAccess,
Core.Auth.Entities.EmergencyAccess emergencyAccess,
string token)
{
emergencyAccess.Status = EmergencyAccessStatusType.Invited;
@@ -339,7 +338,7 @@ public class EmergencyAccessServiceTests
SutProvider<EmergencyAccessService> sutProvider,
User acceptingUser,
User invitingUser,
EmergencyAccess emergencyAccess,
Core.Auth.Entities.EmergencyAccess emergencyAccess,
string token)
{
emergencyAccess.Status = EmergencyAccessStatusType.Invited;
@@ -364,7 +363,7 @@ public class EmergencyAccessServiceTests
await sutProvider.GetDependency<IEmergencyAccessRepository>()
.Received(1)
.ReplaceAsync(Arg.Is<EmergencyAccess>(x => x.Status == EmergencyAccessStatusType.Accepted));
.ReplaceAsync(Arg.Is<Core.Auth.Entities.EmergencyAccess>(x => x.Status == EmergencyAccessStatusType.Accepted));
await sutProvider.GetDependency<IMailService>()
.Received(1)
@@ -375,11 +374,11 @@ public class EmergencyAccessServiceTests
public async Task DeleteAsync_EmergencyAccessNull_ThrowsBadRequest(
SutProvider<EmergencyAccessService> sutProvider,
User invitingUser,
EmergencyAccess emergencyAccess)
Core.Auth.Entities.EmergencyAccess emergencyAccess)
{
sutProvider.GetDependency<IEmergencyAccessRepository>()
.GetByIdAsync(Arg.Any<Guid>())
.Returns((EmergencyAccess)null);
.Returns((Core.Auth.Entities.EmergencyAccess)null);
var exception = await Assert.ThrowsAsync<BadRequestException>(
() => sutProvider.Sut.DeleteAsync(emergencyAccess.Id, invitingUser.Id));
@@ -391,7 +390,7 @@ public class EmergencyAccessServiceTests
public async Task DeleteAsync_EmergencyAccessGrantorIdNotEqual_ThrowsBadRequest(
SutProvider<EmergencyAccessService> sutProvider,
User invitingUser,
EmergencyAccess emergencyAccess)
Core.Auth.Entities.EmergencyAccess emergencyAccess)
{
emergencyAccess.GrantorId = Guid.NewGuid();
sutProvider.GetDependency<IEmergencyAccessRepository>()
@@ -408,7 +407,7 @@ public class EmergencyAccessServiceTests
public async Task DeleteAsync_EmergencyAccessGranteeIdNotEqual_ThrowsBadRequest(
SutProvider<EmergencyAccessService> sutProvider,
User invitingUser,
EmergencyAccess emergencyAccess)
Core.Auth.Entities.EmergencyAccess emergencyAccess)
{
emergencyAccess.GranteeId = Guid.NewGuid();
sutProvider.GetDependency<IEmergencyAccessRepository>()
@@ -425,7 +424,7 @@ public class EmergencyAccessServiceTests
public async Task DeleteAsync_EmergencyAccessIsDeleted_Success(
SutProvider<EmergencyAccessService> sutProvider,
User user,
EmergencyAccess emergencyAccess)
Core.Auth.Entities.EmergencyAccess emergencyAccess)
{
emergencyAccess.GranteeId = user.Id;
emergencyAccess.GrantorId = user.Id;
@@ -443,7 +442,7 @@ public class EmergencyAccessServiceTests
[Theory, BitAutoData]
public async Task ConfirmUserAsync_EmergencyAccessNull_ThrowsBadRequest(
SutProvider<EmergencyAccessService> sutProvider,
EmergencyAccess emergencyAccess,
Core.Auth.Entities.EmergencyAccess emergencyAccess,
string key,
User grantorUser)
{
@@ -451,7 +450,7 @@ public class EmergencyAccessServiceTests
emergencyAccess.Status = EmergencyAccessStatusType.RecoveryInitiated;
sutProvider.GetDependency<IEmergencyAccessRepository>()
.GetByIdAsync(Arg.Any<Guid>())
.Returns((EmergencyAccess)null);
.Returns((Core.Auth.Entities.EmergencyAccess)null);
var exception = await Assert.ThrowsAsync<BadRequestException>(
() => sutProvider.Sut.ConfirmUserAsync(emergencyAccess.Id, key, grantorUser.Id));
@@ -463,7 +462,7 @@ public class EmergencyAccessServiceTests
[Theory, BitAutoData]
public async Task ConfirmUserAsync_EmergencyAccessStatusIsNotAccepted_ThrowsBadRequest(
SutProvider<EmergencyAccessService> sutProvider,
EmergencyAccess emergencyAccess,
Core.Auth.Entities.EmergencyAccess emergencyAccess,
string key,
User grantorUser)
{
@@ -484,7 +483,7 @@ public class EmergencyAccessServiceTests
[Theory, BitAutoData]
public async Task ConfirmUserAsync_EmergencyAccessGrantorIdNotEqualToConfirmingUserId_ThrowsBadRequest(
SutProvider<EmergencyAccessService> sutProvider,
EmergencyAccess emergencyAccess,
Core.Auth.Entities.EmergencyAccess emergencyAccess,
string key,
User grantorUser)
{
@@ -505,7 +504,7 @@ public class EmergencyAccessServiceTests
SutProvider<EmergencyAccessService> sutProvider, User confirmingUser, string key)
{
confirmingUser.UsesKeyConnector = true;
var emergencyAccess = new EmergencyAccess
var emergencyAccess = new Core.Auth.Entities.EmergencyAccess
{
Status = EmergencyAccessStatusType.Accepted,
GrantorId = confirmingUser.Id,
@@ -530,7 +529,7 @@ public class EmergencyAccessServiceTests
[Theory, BitAutoData]
public async Task ConfirmUserAsync_ConfirmsAndReplacesEmergencyAccess_Success(
SutProvider<EmergencyAccessService> sutProvider,
EmergencyAccess emergencyAccess,
Core.Auth.Entities.EmergencyAccess emergencyAccess,
string key,
User grantorUser,
User granteeUser)
@@ -553,7 +552,7 @@ public class EmergencyAccessServiceTests
await sutProvider.GetDependency<IEmergencyAccessRepository>()
.Received(1)
.ReplaceAsync(Arg.Is<EmergencyAccess>(x => x.Status == EmergencyAccessStatusType.Confirmed));
.ReplaceAsync(Arg.Is<Core.Auth.Entities.EmergencyAccess>(x => x.Status == EmergencyAccessStatusType.Confirmed));
await sutProvider.GetDependency<IMailService>()
.Received(1)
@@ -564,7 +563,7 @@ public class EmergencyAccessServiceTests
public async Task SaveAsync_PremiumCannotUpdate_ThrowsBadRequest(
SutProvider<EmergencyAccessService> sutProvider, User savingUser)
{
var emergencyAccess = new EmergencyAccess
var emergencyAccess = new Core.Auth.Entities.EmergencyAccess
{
Type = EmergencyAccessType.Takeover,
GrantorId = savingUser.Id,
@@ -586,7 +585,7 @@ public class EmergencyAccessServiceTests
SutProvider<EmergencyAccessService> sutProvider, User savingUser)
{
savingUser.Premium = true;
var emergencyAccess = new EmergencyAccess
var emergencyAccess = new Core.Auth.Entities.EmergencyAccess
{
Type = EmergencyAccessType.Takeover,
GrantorId = new Guid(),
@@ -611,7 +610,7 @@ public class EmergencyAccessServiceTests
SutProvider<EmergencyAccessService> sutProvider, User grantorUser)
{
grantorUser.UsesKeyConnector = true;
var emergencyAccess = new EmergencyAccess
var emergencyAccess = new Core.Auth.Entities.EmergencyAccess
{
Type = EmergencyAccessType.Takeover,
GrantorId = grantorUser.Id,
@@ -633,7 +632,7 @@ public class EmergencyAccessServiceTests
SutProvider<EmergencyAccessService> sutProvider, User grantorUser)
{
grantorUser.UsesKeyConnector = true;
var emergencyAccess = new EmergencyAccess
var emergencyAccess = new Core.Auth.Entities.EmergencyAccess
{
Type = EmergencyAccessType.View,
GrantorId = grantorUser.Id,
@@ -655,7 +654,7 @@ public class EmergencyAccessServiceTests
SutProvider<EmergencyAccessService> sutProvider, User grantorUser)
{
grantorUser.UsesKeyConnector = false;
var emergencyAccess = new EmergencyAccess
var emergencyAccess = new Core.Auth.Entities.EmergencyAccess
{
Type = EmergencyAccessType.Takeover,
GrantorId = grantorUser.Id,
@@ -678,7 +677,7 @@ public class EmergencyAccessServiceTests
{
sutProvider.GetDependency<IEmergencyAccessRepository>()
.GetByIdAsync(Arg.Any<Guid>())
.Returns((EmergencyAccess)null);
.Returns((Core.Auth.Entities.EmergencyAccess)null);
var exception = await Assert.ThrowsAsync<BadRequestException>(
() => sutProvider.Sut.InitiateAsync(new Guid(), initiatingUser));
@@ -692,7 +691,7 @@ public class EmergencyAccessServiceTests
[Theory, BitAutoData]
public async Task InitiateAsync_EmergencyAccessGranteeIdNotEqual_ThrowBadRequest(
SutProvider<EmergencyAccessService> sutProvider,
EmergencyAccess emergencyAccess,
Core.Auth.Entities.EmergencyAccess emergencyAccess,
User initiatingUser)
{
emergencyAccess.GranteeId = new Guid();
@@ -712,7 +711,7 @@ public class EmergencyAccessServiceTests
[Theory, BitAutoData]
public async Task InitiateAsync_EmergencyAccessStatusIsNotConfirmed_ThrowBadRequest(
SutProvider<EmergencyAccessService> sutProvider,
EmergencyAccess emergencyAccess,
Core.Auth.Entities.EmergencyAccess emergencyAccess,
User initiatingUser)
{
emergencyAccess.GranteeId = initiatingUser.Id;
@@ -735,7 +734,7 @@ public class EmergencyAccessServiceTests
SutProvider<EmergencyAccessService> sutProvider, User initiatingUser, User grantor)
{
grantor.UsesKeyConnector = true;
var emergencyAccess = new EmergencyAccess
var emergencyAccess = new Core.Auth.Entities.EmergencyAccess
{
Status = EmergencyAccessStatusType.Confirmed,
GranteeId = initiatingUser.Id,
@@ -764,7 +763,7 @@ public class EmergencyAccessServiceTests
SutProvider<EmergencyAccessService> sutProvider, User initiatingUser, User grantor)
{
grantor.UsesKeyConnector = true;
var emergencyAccess = new EmergencyAccess
var emergencyAccess = new Core.Auth.Entities.EmergencyAccess
{
Status = EmergencyAccessStatusType.Confirmed,
GranteeId = initiatingUser.Id,
@@ -783,14 +782,14 @@ public class EmergencyAccessServiceTests
await sutProvider.GetDependency<IEmergencyAccessRepository>()
.Received(1)
.ReplaceAsync(Arg.Is<EmergencyAccess>(x => x.Status == EmergencyAccessStatusType.RecoveryInitiated));
.ReplaceAsync(Arg.Is<Core.Auth.Entities.EmergencyAccess>(x => x.Status == EmergencyAccessStatusType.RecoveryInitiated));
}
[Theory, BitAutoData]
public async Task InitiateAsync_RequestIsCorrect_Success(
SutProvider<EmergencyAccessService> sutProvider, User initiatingUser, User grantor)
{
var emergencyAccess = new EmergencyAccess
var emergencyAccess = new Core.Auth.Entities.EmergencyAccess
{
Status = EmergencyAccessStatusType.Confirmed,
GranteeId = initiatingUser.Id,
@@ -809,7 +808,7 @@ public class EmergencyAccessServiceTests
await sutProvider.GetDependency<IEmergencyAccessRepository>()
.Received(1)
.ReplaceAsync(Arg.Is<EmergencyAccess>(x => x.Status == EmergencyAccessStatusType.RecoveryInitiated));
.ReplaceAsync(Arg.Is<Core.Auth.Entities.EmergencyAccess>(x => x.Status == EmergencyAccessStatusType.RecoveryInitiated));
}
[Theory, BitAutoData]
@@ -818,7 +817,7 @@ public class EmergencyAccessServiceTests
{
sutProvider.GetDependency<IEmergencyAccessRepository>()
.GetByIdAsync(Arg.Any<Guid>())
.Returns((EmergencyAccess)null);
.Returns((Core.Auth.Entities.EmergencyAccess)null);
var exception = await Assert.ThrowsAsync<BadRequestException>(
() => sutProvider.Sut.ApproveAsync(new Guid(), null));
@@ -829,7 +828,7 @@ public class EmergencyAccessServiceTests
[Theory, BitAutoData]
public async Task ApproveAsync_EmergencyAccessGrantorIdNotEquatToApproving_ThrowsBadRequest(
SutProvider<EmergencyAccessService> sutProvider,
EmergencyAccess emergencyAccess,
Core.Auth.Entities.EmergencyAccess emergencyAccess,
User grantorUser)
{
emergencyAccess.Status = EmergencyAccessStatusType.RecoveryInitiated;
@@ -851,7 +850,7 @@ public class EmergencyAccessServiceTests
public async Task ApproveAsync_EmergencyAccessStatusNotRecoveryInitiated_ThrowsBadRequest(
EmergencyAccessStatusType statusType,
SutProvider<EmergencyAccessService> sutProvider,
EmergencyAccess emergencyAccess,
Core.Auth.Entities.EmergencyAccess emergencyAccess,
User grantorUser)
{
emergencyAccess.GrantorId = grantorUser.Id;
@@ -869,7 +868,7 @@ public class EmergencyAccessServiceTests
[Theory, BitAutoData]
public async Task ApproveAsync_Success(
SutProvider<EmergencyAccessService> sutProvider,
EmergencyAccess emergencyAccess,
Core.Auth.Entities.EmergencyAccess emergencyAccess,
User grantorUser,
User granteeUser)
{
@@ -885,20 +884,20 @@ public class EmergencyAccessServiceTests
await sutProvider.Sut.ApproveAsync(emergencyAccess.Id, grantorUser);
await sutProvider.GetDependency<IEmergencyAccessRepository>()
.Received(1)
.ReplaceAsync(Arg.Is<EmergencyAccess>(x => x.Status == EmergencyAccessStatusType.RecoveryApproved));
.ReplaceAsync(Arg.Is<Core.Auth.Entities.EmergencyAccess>(x => x.Status == EmergencyAccessStatusType.RecoveryApproved));
}
[Theory, BitAutoData]
public async Task RejectAsync_EmergencyAccessIdNull_ThrowsBadRequest(
SutProvider<EmergencyAccessService> sutProvider,
EmergencyAccess emergencyAccess,
Core.Auth.Entities.EmergencyAccess emergencyAccess,
User GrantorUser)
{
emergencyAccess.GrantorId = GrantorUser.Id;
emergencyAccess.Status = EmergencyAccessStatusType.Accepted;
sutProvider.GetDependency<IEmergencyAccessRepository>()
.GetByIdAsync(Arg.Any<Guid>())
.Returns((EmergencyAccess)null);
.Returns((Core.Auth.Entities.EmergencyAccess)null);
var exception = await Assert.ThrowsAsync<BadRequestException>(
() => sutProvider.Sut.RejectAsync(emergencyAccess.Id, GrantorUser));
@@ -909,7 +908,7 @@ public class EmergencyAccessServiceTests
[Theory, BitAutoData]
public async Task RejectAsync_EmergencyAccessGrantorIdNotEqualToRequestUser_ThrowsBadRequest(
SutProvider<EmergencyAccessService> sutProvider,
EmergencyAccess emergencyAccess,
Core.Auth.Entities.EmergencyAccess emergencyAccess,
User GrantorUser)
{
emergencyAccess.Status = EmergencyAccessStatusType.Accepted;
@@ -930,7 +929,7 @@ public class EmergencyAccessServiceTests
public async Task RejectAsync_EmergencyAccessStatusNotValid_ThrowsBadRequest(
EmergencyAccessStatusType statusType,
SutProvider<EmergencyAccessService> sutProvider,
EmergencyAccess emergencyAccess,
Core.Auth.Entities.EmergencyAccess emergencyAccess,
User GrantorUser)
{
emergencyAccess.GrantorId = GrantorUser.Id;
@@ -951,7 +950,7 @@ public class EmergencyAccessServiceTests
public async Task RejectAsync_Success(
EmergencyAccessStatusType statusType,
SutProvider<EmergencyAccessService> sutProvider,
EmergencyAccess emergencyAccess,
Core.Auth.Entities.EmergencyAccess emergencyAccess,
User GrantorUser,
User GranteeUser)
{
@@ -968,7 +967,7 @@ public class EmergencyAccessServiceTests
await sutProvider.GetDependency<IEmergencyAccessRepository>()
.Received(1)
.ReplaceAsync(Arg.Is<EmergencyAccess>(x => x.Status == EmergencyAccessStatusType.Confirmed));
.ReplaceAsync(Arg.Is<Core.Auth.Entities.EmergencyAccess>(x => x.Status == EmergencyAccessStatusType.Confirmed));
}
[Theory, BitAutoData]
@@ -977,7 +976,7 @@ public class EmergencyAccessServiceTests
{
sutProvider.GetDependency<IEmergencyAccessRepository>()
.GetByIdAsync(Arg.Any<Guid>())
.Returns((EmergencyAccess)null);
.Returns((Core.Auth.Entities.EmergencyAccess)null);
var exception = await Assert.ThrowsAsync<BadRequestException>(
() => sutProvider.Sut.GetPoliciesAsync(default, default));
@@ -992,7 +991,7 @@ public class EmergencyAccessServiceTests
public async Task GetPoliciesAsync_RequestNotValidStatusType_ThrowsBadRequest(
EmergencyAccessStatusType statusType,
SutProvider<EmergencyAccessService> sutProvider,
EmergencyAccess emergencyAccess,
Core.Auth.Entities.EmergencyAccess emergencyAccess,
User granteeUser)
{
emergencyAccess.GranteeId = granteeUser.Id;
@@ -1010,7 +1009,7 @@ public class EmergencyAccessServiceTests
[Theory, BitAutoData]
public async Task GetPoliciesAsync_RequestNotValidType_ThrowsBadRequest(
SutProvider<EmergencyAccessService> sutProvider,
EmergencyAccess emergencyAccess,
Core.Auth.Entities.EmergencyAccess emergencyAccess,
User granteeUser)
{
emergencyAccess.GranteeId = granteeUser.Id;
@@ -1032,7 +1031,7 @@ public class EmergencyAccessServiceTests
public async Task GetPoliciesAsync_OrganizationUserTypeNotOwner_ReturnsNull(
OrganizationUserType userType,
SutProvider<EmergencyAccessService> sutProvider,
EmergencyAccess emergencyAccess,
Core.Auth.Entities.EmergencyAccess emergencyAccess,
User granteeUser,
User grantorUser,
OrganizationUser grantorOrganizationUser)
@@ -1062,7 +1061,7 @@ public class EmergencyAccessServiceTests
[Theory, BitAutoData]
public async Task GetPoliciesAsync_OrganizationUserEmpty_ReturnsNull(
SutProvider<EmergencyAccessService> sutProvider,
EmergencyAccess emergencyAccess,
Core.Auth.Entities.EmergencyAccess emergencyAccess,
User granteeUser,
User grantorUser)
{
@@ -1090,7 +1089,7 @@ public class EmergencyAccessServiceTests
[Theory, BitAutoData]
public async Task GetPoliciesAsync_ReturnsNotNull(
SutProvider<EmergencyAccessService> sutProvider,
EmergencyAccess emergencyAccess,
Core.Auth.Entities.EmergencyAccess emergencyAccess,
User granteeUser,
User grantorUser,
OrganizationUser grantorOrganizationUser)
@@ -1127,7 +1126,7 @@ public class EmergencyAccessServiceTests
{
sutProvider.GetDependency<IEmergencyAccessRepository>()
.GetByIdAsync(Arg.Any<Guid>())
.Returns((EmergencyAccess)null);
.Returns((Core.Auth.Entities.EmergencyAccess)null);
var exception = await Assert.ThrowsAsync<BadRequestException>(
() => sutProvider.Sut.TakeoverAsync(default, default));
@@ -1138,7 +1137,7 @@ public class EmergencyAccessServiceTests
[Theory, BitAutoData]
public async Task TakeoverAsync_RequestNotValid_GranteeNotEqualToRequestingUser_ThrowsBadRequest(
SutProvider<EmergencyAccessService> sutProvider,
EmergencyAccess emergencyAccess,
Core.Auth.Entities.EmergencyAccess emergencyAccess,
User granteeUser)
{
emergencyAccess.Status = EmergencyAccessStatusType.RecoveryApproved;
@@ -1161,7 +1160,7 @@ public class EmergencyAccessServiceTests
public async Task TakeoverAsync_RequestNotValid_StatusType_ThrowsBadRequest(
EmergencyAccessStatusType statusType,
SutProvider<EmergencyAccessService> sutProvider,
EmergencyAccess emergencyAccess,
Core.Auth.Entities.EmergencyAccess emergencyAccess,
User granteeUser)
{
emergencyAccess.GranteeId = granteeUser.Id;
@@ -1180,7 +1179,7 @@ public class EmergencyAccessServiceTests
[Theory, BitAutoData]
public async Task TakeoverAsync_RequestNotValid_TypeIsView_ThrowsBadRequest(
SutProvider<EmergencyAccessService> sutProvider,
EmergencyAccess emergencyAccess,
Core.Auth.Entities.EmergencyAccess emergencyAccess,
User granteeUser)
{
emergencyAccess.GranteeId = granteeUser.Id;
@@ -1203,7 +1202,7 @@ public class EmergencyAccessServiceTests
User grantor)
{
grantor.UsesKeyConnector = true;
var emergencyAccess = new EmergencyAccess
var emergencyAccess = new Core.Auth.Entities.EmergencyAccess
{
GrantorId = grantor.Id,
GranteeId = granteeUser.Id,
@@ -1232,7 +1231,7 @@ public class EmergencyAccessServiceTests
User grantor)
{
grantor.UsesKeyConnector = false;
var emergencyAccess = new EmergencyAccess
var emergencyAccess = new Core.Auth.Entities.EmergencyAccess
{
GrantorId = grantor.Id,
GranteeId = granteeUser.Id,
@@ -1260,7 +1259,7 @@ public class EmergencyAccessServiceTests
{
sutProvider.GetDependency<IEmergencyAccessRepository>()
.GetByIdAsync(Arg.Any<Guid>())
.Returns((EmergencyAccess)null);
.Returns((Core.Auth.Entities.EmergencyAccess)null);
var exception = await Assert.ThrowsAsync<BadRequestException>(
() => sutProvider.Sut.PasswordAsync(default, default, default, default));
@@ -1271,7 +1270,7 @@ public class EmergencyAccessServiceTests
[Theory, BitAutoData]
public async Task PasswordAsync_RequestNotValid_GranteeNotEqualToRequestingUser_ThrowsBadRequest(
SutProvider<EmergencyAccessService> sutProvider,
EmergencyAccess emergencyAccess,
Core.Auth.Entities.EmergencyAccess emergencyAccess,
User granteeUser)
{
emergencyAccess.Status = EmergencyAccessStatusType.RecoveryApproved;
@@ -1294,7 +1293,7 @@ public class EmergencyAccessServiceTests
public async Task PasswordAsync_RequestNotValid_StatusType_ThrowsBadRequest(
EmergencyAccessStatusType statusType,
SutProvider<EmergencyAccessService> sutProvider,
EmergencyAccess emergencyAccess,
Core.Auth.Entities.EmergencyAccess emergencyAccess,
User granteeUser)
{
emergencyAccess.GranteeId = granteeUser.Id;
@@ -1313,7 +1312,7 @@ public class EmergencyAccessServiceTests
[Theory, BitAutoData]
public async Task PasswordAsync_RequestNotValid_TypeIsView_ThrowsBadRequest(
SutProvider<EmergencyAccessService> sutProvider,
EmergencyAccess emergencyAccess,
Core.Auth.Entities.EmergencyAccess emergencyAccess,
User granteeUser)
{
emergencyAccess.GranteeId = granteeUser.Id;
@@ -1332,7 +1331,7 @@ public class EmergencyAccessServiceTests
[Theory, BitAutoData]
public async Task PasswordAsync_NonOrgUser_Success(
SutProvider<EmergencyAccessService> sutProvider,
EmergencyAccess emergencyAccess,
Core.Auth.Entities.EmergencyAccess emergencyAccess,
User granteeUser,
User grantorUser,
string key,
@@ -1367,7 +1366,7 @@ public class EmergencyAccessServiceTests
public async Task PasswordAsync_OrgUser_NotOrganizationOwner_RemovedFromOrganization_Success(
OrganizationUserType userType,
SutProvider<EmergencyAccessService> sutProvider,
EmergencyAccess emergencyAccess,
Core.Auth.Entities.EmergencyAccess emergencyAccess,
User granteeUser,
User grantorUser,
OrganizationUser organizationUser,
@@ -1408,7 +1407,7 @@ public class EmergencyAccessServiceTests
[Theory, BitAutoData]
public async Task PasswordAsync_OrgUser_IsOrganizationOwner_NotRemovedFromOrganization_Success(
SutProvider<EmergencyAccessService> sutProvider,
EmergencyAccess emergencyAccess,
Core.Auth.Entities.EmergencyAccess emergencyAccess,
User granteeUser,
User grantorUser,
OrganizationUser organizationUser,
@@ -1459,7 +1458,7 @@ public class EmergencyAccessServiceTests
Enabled = true
}
});
var emergencyAccess = new EmergencyAccess
var emergencyAccess = new Core.Auth.Entities.EmergencyAccess
{
GrantorId = grantor.Id,
GranteeId = requestingUser.Id,
@@ -1484,7 +1483,7 @@ public class EmergencyAccessServiceTests
[Theory, BitAutoData]
public async Task ViewAsync_EmergencyAccessTypeNotView_ThrowsBadRequest(
SutProvider<EmergencyAccessService> sutProvider,
EmergencyAccess emergencyAccess,
Core.Auth.Entities.EmergencyAccess emergencyAccess,
User granteeUser)
{
emergencyAccess.GranteeId = granteeUser.Id;
@@ -1500,7 +1499,7 @@ public class EmergencyAccessServiceTests
[Theory, BitAutoData]
public async Task GetAttachmentDownloadAsync_EmergencyAccessTypeNotView_ThrowsBadRequest(
SutProvider<EmergencyAccessService> sutProvider,
EmergencyAccess emergencyAccess,
Core.Auth.Entities.EmergencyAccess emergencyAccess,
User granteeUser)
{
emergencyAccess.GranteeId = granteeUser.Id;

View File

@@ -2,7 +2,6 @@
using Bit.Core.AdminConsole.Entities;
using Bit.Core.AdminConsole.Enums;
using Bit.Core.AdminConsole.Repositories;
using Bit.Core.Auth.Entities;
using Bit.Core.Auth.Enums;
using Bit.Core.Auth.Models;
using Bit.Core.Auth.Models.Business.Tokenables;
@@ -23,6 +22,7 @@ using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.WebUtilities;
using NSubstitute;
using Xunit;
using EmergencyAccessEntity = Bit.Core.Auth.Entities.EmergencyAccess;
namespace Bit.Core.Test.Auth.UserFeatures.Registration;
@@ -726,7 +726,7 @@ public class RegisterUserCommandTests
[BitAutoData]
public async Task RegisterUserViaAcceptEmergencyAccessInviteToken_Succeeds(
SutProvider<RegisterUserCommand> sutProvider, User user, string masterPasswordHash,
EmergencyAccess emergencyAccess, string acceptEmergencyAccessInviteToken, Guid acceptEmergencyAccessId)
EmergencyAccessEntity emergencyAccess, string acceptEmergencyAccessInviteToken, Guid acceptEmergencyAccessId)
{
// Arrange
user.Email = $"test+{Guid.NewGuid()}@example.com";
@@ -767,7 +767,7 @@ public class RegisterUserCommandTests
[Theory]
[BitAutoData]
public async Task RegisterUserViaAcceptEmergencyAccessInviteToken_InvalidToken_ThrowsBadRequestException(SutProvider<RegisterUserCommand> sutProvider, User user,
string masterPasswordHash, EmergencyAccess emergencyAccess, string acceptEmergencyAccessInviteToken, Guid acceptEmergencyAccessId)
string masterPasswordHash, EmergencyAccessEntity emergencyAccess, string acceptEmergencyAccessInviteToken, Guid acceptEmergencyAccessId)
{
// Arrange
user.Email = $"test+{Guid.NewGuid()}@example.com";
@@ -1112,7 +1112,7 @@ public class RegisterUserCommandTests
[BitAutoData]
public async Task RegisterUserViaAcceptEmergencyAccessInviteToken_BlockedDomain_ThrowsBadRequestException(
SutProvider<RegisterUserCommand> sutProvider, User user, string masterPasswordHash,
EmergencyAccess emergencyAccess, string acceptEmergencyAccessInviteToken, Guid acceptEmergencyAccessId)
EmergencyAccessEntity emergencyAccess, string acceptEmergencyAccessInviteToken, Guid acceptEmergencyAccessId)
{
// Arrange
user.Email = "user@blocked-domain.com";