1
0
mirror of https://github.com/bitwarden/server.git synced 2025-06-30 07:36:14 -05:00

[PM-11405] Account Management: Prevent a verified user from changing their email address (#4875)

* Add check for managed user before purging account

* Rename IOrganizationRepository.GetByClaimedUserDomainAsync to GetByVerifiedUserEmailDomainAsync and refactor to return a list. Remove ManagedByOrganizationId from ProfileResponseMode. Add ManagesActiveUser to ProfileOrganizationResponseModel

* Rename the property ManagesActiveUser to UserIsManagedByOrganization

* Remove whole class #nullable enable and add it to specific places

* [PM-11405] Account Deprovisioning: Prevent a verified user from changing their email address

* Remove unnecessary .ToList()

* Refactor IUserService methods GetOrganizationsManagingUserAsync and IsManagedByAnyOrganizationAsync to not return nullable objects. Update ProfileOrganizationResponseModel.UserIsManagedByOrganization to not be nullable

* Update error message when unable to purge vault for managed account

* Update error message when unable to change email for managed account

* Update expected error messages on unit tests

* Add TestFeatureService to Api.IntegrationTest.Helpers and use it on ApiApplicationFactory to be able to enable specific features for each test

* Add CreateVerifiedDomainAsync method to OrganizationTestHelpers

* Add tests to AccountsControllerTest to prevent changing email for managed accounts

* Remove setting the feature flag value in ApiApplicationFactory and set it on AccountsControllerTest

* Remove TestFeatureService class from Api.IntegrationTest.Helpers
This commit is contained in:
Rui Tomé
2024-10-28 16:12:13 +00:00
committed by GitHub
parent cc6e41b42a
commit c126fee296
4 changed files with 182 additions and 1 deletions

View File

@ -7,6 +7,7 @@ using Bit.Api.Auth.Models.Request.WebAuthn;
using Bit.Api.Auth.Validators;
using Bit.Api.Tools.Models.Request;
using Bit.Api.Vault.Models.Request;
using Bit.Core;
using Bit.Core.AdminConsole.Repositories;
using Bit.Core.AdminConsole.Services;
using Bit.Core.Auth.Entities;
@ -143,6 +144,21 @@ public class AccountsControllerTests : IDisposable
await _userService.Received(1).InitiateEmailChangeAsync(user, newEmail);
}
[Fact]
public async Task PostEmailToken_WithAccountDeprovisioningEnabled_WhenUserIsNotManagedByAnOrganization_ShouldInitiateEmailChange()
{
var user = GenerateExampleUser();
ConfigureUserServiceToReturnValidPrincipalFor(user);
ConfigureUserServiceToAcceptPasswordFor(user);
_featureService.IsEnabled(FeatureFlagKeys.AccountDeprovisioning).Returns(true);
_userService.IsManagedByAnyOrganizationAsync(user.Id).Returns(false);
var newEmail = "example@user.com";
await _sut.PostEmailToken(new EmailTokenRequestModel { NewEmail = newEmail });
await _userService.Received(1).InitiateEmailChangeAsync(user, newEmail);
}
[Fact]
public async Task PostEmailToken_WhenNotAuthorized_ShouldThrowUnauthorizedAccessException()
{
@ -165,6 +181,22 @@ public class AccountsControllerTests : IDisposable
);
}
[Fact]
public async Task PostEmailToken_WithAccountDeprovisioningEnabled_WhenUserIsManagedByAnOrganization_ShouldThrowBadRequestException()
{
var user = GenerateExampleUser();
ConfigureUserServiceToReturnValidPrincipalFor(user);
ConfigureUserServiceToAcceptPasswordFor(user);
_featureService.IsEnabled(FeatureFlagKeys.AccountDeprovisioning).Returns(true);
_userService.IsManagedByAnyOrganizationAsync(user.Id).Returns(true);
var result = await Assert.ThrowsAsync<BadRequestException>(
() => _sut.PostEmailToken(new EmailTokenRequestModel())
);
Assert.Equal("Cannot change emails for accounts owned by an organization. Contact your organization administrator for additional details.", result.Message);
}
[Fact]
public async Task PostEmail_ShouldChangeUserEmail()
{
@ -178,6 +210,21 @@ public class AccountsControllerTests : IDisposable
await _userService.Received(1).ChangeEmailAsync(user, default, default, default, default, default);
}
[Fact]
public async Task PostEmail_WithAccountDeprovisioningEnabled_WhenUserIsNotManagedByAnOrganization_ShouldChangeUserEmail()
{
var user = GenerateExampleUser();
ConfigureUserServiceToReturnValidPrincipalFor(user);
_userService.ChangeEmailAsync(user, default, default, default, default, default)
.Returns(Task.FromResult(IdentityResult.Success));
_featureService.IsEnabled(FeatureFlagKeys.AccountDeprovisioning).Returns(true);
_userService.IsManagedByAnyOrganizationAsync(user.Id).Returns(false);
await _sut.PostEmail(new EmailRequestModel());
await _userService.Received(1).ChangeEmailAsync(user, default, default, default, default, default);
}
[Fact]
public async Task PostEmail_WhenNotAuthorized_ShouldThrownUnauthorizedAccessException()
{
@ -201,6 +248,21 @@ public class AccountsControllerTests : IDisposable
);
}
[Fact]
public async Task PostEmail_WithAccountDeprovisioningEnabled_WhenUserIsManagedByAnOrganization_ShouldThrowBadRequestException()
{
var user = GenerateExampleUser();
ConfigureUserServiceToReturnValidPrincipalFor(user);
_featureService.IsEnabled(FeatureFlagKeys.AccountDeprovisioning).Returns(true);
_userService.IsManagedByAnyOrganizationAsync(user.Id).Returns(true);
var result = await Assert.ThrowsAsync<BadRequestException>(
() => _sut.PostEmail(new EmailRequestModel())
);
Assert.Equal("Cannot change emails for accounts owned by an organization. Contact your organization administrator for additional details.", result.Message);
}
[Fact]
public async Task PostVerifyEmail_ShouldSendEmailVerification()
{