mirror of
https://github.com/bitwarden/server.git
synced 2025-04-05 21:18:13 -05:00
Consolidated account recovery into 1 handler. Both use the same method.
This commit is contained in:
parent
8aa8e0499c
commit
2c70b3a903
@ -7,9 +7,9 @@ using Bit.Core;
|
||||
using Bit.Core.AdminConsole.Enums;
|
||||
using Bit.Core.AdminConsole.Models.Data.Organizations.Policies;
|
||||
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.Authorization;
|
||||
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.Authorization.OrganizationUserAccountRecoveryDetails;
|
||||
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.Authorization.OrganizationUserDetails;
|
||||
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.Authorization.OrganizationUserGroups;
|
||||
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.Authorization.OrganizationUsersResetPasswordDetails;
|
||||
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.Interfaces;
|
||||
using Bit.Core.AdminConsole.OrganizationFeatures.Shared.Authorization;
|
||||
using Bit.Core.AdminConsole.Repositories;
|
||||
@ -214,7 +214,7 @@ public class OrganizationUsersController : Controller
|
||||
{
|
||||
var authResult = await _authorizationService.AuthorizeAsync(User,
|
||||
new OrganizationScope(orgId),
|
||||
[OrganizationUsersResetPasswordDetailsOperations.Read]);
|
||||
[OrganizationUsersAccountRecoveryDetailsOperations.Read]);
|
||||
|
||||
if (authResult.Succeeded is false)
|
||||
{
|
||||
@ -248,8 +248,11 @@ public class OrganizationUsersController : Controller
|
||||
[HttpPost("account-recovery-details")]
|
||||
public async Task<ListResponseModel<OrganizationUserResetPasswordDetailsResponseModel>> GetAccountRecoveryDetails(Guid orgId, [FromBody] OrganizationUserBulkRequestModel model)
|
||||
{
|
||||
// Make sure the calling user can reset passwords for this org
|
||||
if (!await _currentContext.ManageResetPassword(orgId))
|
||||
var authResult = await _authorizationService.AuthorizeAsync(User,
|
||||
new OrganizationScope(orgId),
|
||||
[OrganizationUsersAccountRecoveryDetailsOperations.ReadAll]);
|
||||
|
||||
if (authResult.Succeeded is false)
|
||||
{
|
||||
throw new NotFoundException();
|
||||
}
|
||||
|
@ -2,17 +2,19 @@
|
||||
using Bit.Core.Context;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
|
||||
namespace Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.Authorization.OrganizationUsersResetPasswordDetails;
|
||||
namespace Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.Authorization.
|
||||
OrganizationUserAccountRecoveryDetails;
|
||||
|
||||
public class OrganizationUserResetPasswordDetailsAuthorizationHandler(ICurrentContext currentContext)
|
||||
: AuthorizationHandler<OrganizationUsersResetPasswordDetailsOperationRequirement, OrganizationScope>
|
||||
public class OrganizationUserAccountRecoveryDetailsAuthorizationHandler(ICurrentContext currentContext)
|
||||
: AuthorizationHandler<OrganizationUsersAccountRecoveryDetailsOperationRequirement, OrganizationScope>
|
||||
{
|
||||
protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context,
|
||||
OrganizationUsersResetPasswordDetailsOperationRequirement requirement, OrganizationScope resource)
|
||||
OrganizationUsersAccountRecoveryDetailsOperationRequirement requirement, OrganizationScope resource)
|
||||
{
|
||||
var authorized = requirement switch
|
||||
{
|
||||
not null when requirement.Name == nameof(OrganizationUsersResetPasswordDetailsOperations.Read) =>
|
||||
not null when requirement.Name is nameof(OrganizationUsersAccountRecoveryDetailsOperations.Read) or
|
||||
nameof(OrganizationUsersAccountRecoveryDetailsOperations.ReadAll) =>
|
||||
await currentContext.ManageResetPassword(resource),
|
||||
_ => false
|
||||
};
|
@ -0,0 +1,11 @@
|
||||
using Microsoft.AspNetCore.Authorization.Infrastructure;
|
||||
|
||||
namespace Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.Authorization.OrganizationUserAccountRecoveryDetails;
|
||||
|
||||
public class OrganizationUsersAccountRecoveryDetailsOperationRequirement : OperationAuthorizationRequirement;
|
||||
|
||||
public static class OrganizationUsersAccountRecoveryDetailsOperations
|
||||
{
|
||||
public static readonly OrganizationUsersAccountRecoveryDetailsOperationRequirement Read = new() { Name = nameof(Read) };
|
||||
public static readonly OrganizationUsersAccountRecoveryDetailsOperationRequirement ReadAll = new() { Name = nameof(ReadAll) };
|
||||
}
|
@ -12,9 +12,9 @@ using Bit.Core.AdminConsole.OrganizationFeatures.Organizations;
|
||||
using Bit.Core.AdminConsole.OrganizationFeatures.Organizations.Interfaces;
|
||||
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers;
|
||||
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.Authorization;
|
||||
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.Authorization.OrganizationUserAccountRecoveryDetails;
|
||||
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.Authorization.OrganizationUserDetails;
|
||||
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.Authorization.OrganizationUserGroups;
|
||||
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.Authorization.OrganizationUsersResetPasswordDetails;
|
||||
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.Interfaces;
|
||||
using Bit.Core.Models.Business.Tokenables;
|
||||
using Bit.Core.OrganizationFeatures.OrganizationCollections;
|
||||
@ -174,7 +174,7 @@ public static class OrganizationServiceCollectionExtensions
|
||||
services.AddScoped<IAuthorizationHandler, OrganizationUserUserDetailsAuthorizationHandler>();
|
||||
services.AddScoped<IAuthorizationHandler, OrganizationUserDetailsAuthorizationHandler>();
|
||||
services.AddScoped<IAuthorizationHandler, OrganizationUserGroupsAuthorizationHandler>();
|
||||
services.AddScoped<IAuthorizationHandler, OrganizationUserResetPasswordDetailsAuthorizationHandler>();
|
||||
services.AddScoped<IAuthorizationHandler, OrganizationUserAccountRecoveryDetailsAuthorizationHandler>();
|
||||
|
||||
services.AddScoped<IHasConfirmedOwnersExceptQuery, HasConfirmedOwnersExceptQuery>();
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ using Bit.Core;
|
||||
using Bit.Core.AdminConsole.Entities;
|
||||
using Bit.Core.AdminConsole.Enums;
|
||||
using Bit.Core.AdminConsole.Models.Data.Organizations.Policies;
|
||||
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.Authorization.OrganizationUserAccountRecoveryDetails;
|
||||
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.Authorization.OrganizationUserDetails;
|
||||
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.Interfaces;
|
||||
using Bit.Core.AdminConsole.OrganizationFeatures.Shared.Authorization;
|
||||
@ -294,7 +295,13 @@ public class OrganizationUsersControllerTests
|
||||
ICollection<OrganizationUserResetPasswordDetails> resetPasswordDetails,
|
||||
SutProvider<OrganizationUsersController> sutProvider)
|
||||
{
|
||||
sutProvider.GetDependency<ICurrentContext>().ManageResetPassword(organizationId).Returns(true);
|
||||
sutProvider.GetDependency<IAuthorizationService>()
|
||||
.AuthorizeAsync(
|
||||
user: Arg.Any<ClaimsPrincipal>(),
|
||||
resource: Arg.Is<OrganizationScope>(x => x == organizationId),
|
||||
requirements: Arg.Is<IEnumerable<IAuthorizationRequirement>>(x =>
|
||||
x.Any(y => y == OrganizationUsersAccountRecoveryDetailsOperations.ReadAll)))
|
||||
.Returns(AuthorizationResult.Success());
|
||||
sutProvider.GetDependency<IOrganizationUserRepository>()
|
||||
.GetManyAccountRecoveryDetailsByOrganizationUserAsync(organizationId, bulkRequestModel.Ids)
|
||||
.Returns(resetPasswordDetails);
|
||||
@ -320,7 +327,13 @@ public class OrganizationUsersControllerTests
|
||||
OrganizationUserBulkRequestModel bulkRequestModel,
|
||||
SutProvider<OrganizationUsersController> sutProvider)
|
||||
{
|
||||
sutProvider.GetDependency<ICurrentContext>().ManageResetPassword(organizationId).Returns(false);
|
||||
sutProvider.GetDependency<IAuthorizationService>()
|
||||
.AuthorizeAsync(
|
||||
user: Arg.Any<ClaimsPrincipal>(),
|
||||
resource: Arg.Is<OrganizationScope>(x => x == organizationId),
|
||||
requirements: Arg.Is<IEnumerable<IAuthorizationRequirement>>(x =>
|
||||
x.Any(y => y == OrganizationUsersAccountRecoveryDetailsOperations.ReadAll)))
|
||||
.Returns(AuthorizationResult.Failed());
|
||||
|
||||
await Assert.ThrowsAsync<NotFoundException>(async () => await sutProvider.Sut.GetAccountRecoveryDetails(organizationId, bulkRequestModel));
|
||||
}
|
||||
|
@ -0,0 +1,87 @@
|
||||
using System.Security.Claims;
|
||||
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.Authorization.OrganizationUserAccountRecoveryDetails;
|
||||
using Bit.Core.AdminConsole.OrganizationFeatures.Shared.Authorization;
|
||||
using Bit.Core.Context;
|
||||
using Bit.Test.Common.AutoFixture;
|
||||
using Bit.Test.Common.AutoFixture.Attributes;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using NSubstitute;
|
||||
using Xunit;
|
||||
|
||||
namespace Bit.Core.Test.AdminConsole.Authorization;
|
||||
|
||||
[SutProviderCustomize]
|
||||
public class OrganizationUserAccountRecoveryDetailsAuthorizationHandlerTests
|
||||
{
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task ReadAll_UserCanManageResetPassword_ShouldReturnSuccess(
|
||||
CurrentContextOrganization contextOrganization,
|
||||
SutProvider<OrganizationUserAccountRecoveryDetailsAuthorizationHandler> sutProvider)
|
||||
{
|
||||
sutProvider.GetDependency<ICurrentContext>().ManageResetPassword(contextOrganization.Id).Returns(true);
|
||||
|
||||
var context = new AuthorizationHandlerContext(
|
||||
[OrganizationUsersAccountRecoveryDetailsOperations.ReadAll],
|
||||
new ClaimsPrincipal(),
|
||||
new OrganizationScope(contextOrganization.Id));
|
||||
|
||||
await sutProvider.Sut.HandleAsync(context);
|
||||
|
||||
Assert.True(context.HasSucceeded);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task ReadAll_UserCannotManageResetPassword_ShouldReturnFailure(
|
||||
CurrentContextOrganization contextOrganization,
|
||||
SutProvider<OrganizationUserAccountRecoveryDetailsAuthorizationHandler> sutProvider)
|
||||
{
|
||||
sutProvider.GetDependency<ICurrentContext>().ManageResetPassword(contextOrganization.Id).Returns(false);
|
||||
|
||||
var context = new AuthorizationHandlerContext(
|
||||
[OrganizationUsersAccountRecoveryDetailsOperations.ReadAll],
|
||||
new ClaimsPrincipal(),
|
||||
new OrganizationScope(contextOrganization.Id));
|
||||
|
||||
await sutProvider.Sut.HandleAsync(context);
|
||||
|
||||
Assert.True(context.HasFailed);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task Read_UserCanManageResetPassword_ShouldReturnSuccess(
|
||||
CurrentContextOrganization contextOrganization,
|
||||
SutProvider<OrganizationUserAccountRecoveryDetailsAuthorizationHandler> sutProvider)
|
||||
{
|
||||
sutProvider.GetDependency<ICurrentContext>().ManageResetPassword(contextOrganization.Id).Returns(true);
|
||||
|
||||
var context = new AuthorizationHandlerContext(
|
||||
[OrganizationUsersAccountRecoveryDetailsOperations.Read],
|
||||
new ClaimsPrincipal(),
|
||||
new OrganizationScope(contextOrganization.Id));
|
||||
|
||||
await sutProvider.Sut.HandleAsync(context);
|
||||
|
||||
Assert.True(context.HasSucceeded);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task Read_UserCannotManageResetPassword_ShouldReturnFailure(
|
||||
CurrentContextOrganization contextOrganization,
|
||||
SutProvider<OrganizationUserAccountRecoveryDetailsAuthorizationHandler> sutProvider)
|
||||
{
|
||||
sutProvider.GetDependency<ICurrentContext>().ManageResetPassword(contextOrganization.Id).Returns(false);
|
||||
|
||||
var context = new AuthorizationHandlerContext(
|
||||
[OrganizationUsersAccountRecoveryDetailsOperations.Read],
|
||||
new ClaimsPrincipal(),
|
||||
new OrganizationScope(contextOrganization.Id));
|
||||
|
||||
await sutProvider.Sut.HandleAsync(context);
|
||||
|
||||
Assert.True(context.HasFailed);
|
||||
}
|
||||
}
|
@ -1,51 +0,0 @@
|
||||
using System.Security.Claims;
|
||||
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.Authorization.OrganizationUsersResetPasswordDetails;
|
||||
using Bit.Core.AdminConsole.OrganizationFeatures.Shared.Authorization;
|
||||
using Bit.Core.Context;
|
||||
using Bit.Test.Common.AutoFixture;
|
||||
using Bit.Test.Common.AutoFixture.Attributes;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using NSubstitute;
|
||||
using Xunit;
|
||||
|
||||
namespace Bit.Core.Test.AdminConsole.Authorization;
|
||||
|
||||
[SutProviderCustomize]
|
||||
public class OrganizationUserResetPasswordDetailsAuthorizationHandlerTests
|
||||
{
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task Read_UserCanManageResetPassword_ShouldReturnSuccess(
|
||||
CurrentContextOrganization contextOrganization,
|
||||
SutProvider<OrganizationUserResetPasswordDetailsAuthorizationHandler> sutProvider)
|
||||
{
|
||||
sutProvider.GetDependency<ICurrentContext>().ManageResetPassword(contextOrganization.Id).Returns(true);
|
||||
|
||||
var context = new AuthorizationHandlerContext(
|
||||
[OrganizationUsersResetPasswordDetailsOperations.Read],
|
||||
new ClaimsPrincipal(),
|
||||
new OrganizationScope(contextOrganization.Id));
|
||||
|
||||
await sutProvider.Sut.HandleAsync(context);
|
||||
|
||||
Assert.True(context.HasSucceeded);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task Read_UserCannotManageResetPassword_ShouldReturnFailure(
|
||||
CurrentContextOrganization contextOrganization,
|
||||
SutProvider<OrganizationUserResetPasswordDetailsAuthorizationHandler> sutProvider)
|
||||
{
|
||||
sutProvider.GetDependency<ICurrentContext>().ManageResetPassword(contextOrganization.Id).Returns(false);
|
||||
|
||||
var context = new AuthorizationHandlerContext(
|
||||
[OrganizationUsersResetPasswordDetailsOperations.Read],
|
||||
new ClaimsPrincipal(),
|
||||
new OrganizationScope(contextOrganization.Id));
|
||||
|
||||
await sutProvider.Sut.HandleAsync(context);
|
||||
|
||||
Assert.True(context.HasFailed);
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user