1
0
mirror of https://github.com/bitwarden/server.git synced 2025-02-16 01:51:21 +01:00

WIP initial authz work

This commit is contained in:
Thomas Rittson 2024-11-18 16:36:50 +10:00
parent e16cad50b1
commit f661f9599b
No known key found for this signature in database
GPG Key ID: CDDDA03861C35E27
3 changed files with 149 additions and 0 deletions

View File

@ -0,0 +1,40 @@
using System.Security.Claims;
using Bit.Core.AdminConsole.OrganizationFeatures.Shared.Authorization;
using Bit.Core.Context;
using Bit.Core.Enums;
using Microsoft.AspNetCore.Authorization;
namespace Bit.Core.Tools.Authorization;
public class VaultExportAuthorizationHandler(ICurrentContext currentContext)
: AuthorizationHandler<VaultExportOperationRequirement, OrganizationScope>
{
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context,
VaultExportOperationRequirement requirement, OrganizationScope organizationScope)
{
var org = currentContext.GetOrganization(organizationScope);
var authorized = requirement switch
{
not null when requirement.Name == nameof(VaultExportOperations.ExportAll) =>
CanExportAll(org),
not null when requirement.Name == nameof(VaultExportOperations.ExportPartial) =>
CanExportPartial(org),
_ => false
};
if (requirement is not null && authorized)
{
context.Succeed(requirement);
}
return Task.FromResult(0);
}
private bool CanExportAll(CurrentContextOrganization organization) => organization is
{ Type: OrganizationUserType.Owner or OrganizationUserType.Admin } or
{ Type: OrganizationUserType.Custom, Permissions.AccessImportExport: true };
private bool CanExportPartial(CurrentContextOrganization organization) => organization is not null;
}

View File

@ -0,0 +1,21 @@
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Authorization.Infrastructure;
namespace Bit.Core.Tools.Authorization;
public class VaultExportOperationRequirement : OperationAuthorizationRequirement;
public static class VaultExportOperations
{
/// <summary>
/// Exporting the entire organization vault.
/// </summary>
public static readonly VaultExportOperationRequirement ExportAll =
new() { Name = nameof(ExportAll) };
/// <summary>
/// Exporting only the organization items that the user has Can Manage permissions for
/// </summary>
public static readonly VaultExportOperationRequirement ExportPartial =
new() { Name = nameof(ExportPartial) };
}

View File

@ -0,0 +1,88 @@
using System.Security.Claims;
using Bit.Core.AdminConsole.OrganizationFeatures.Shared.Authorization;
using Bit.Core.Context;
using Bit.Core.Enums;
using Bit.Core.Models.Data;
using Bit.Core.Tools.Authorization;
using Bit.Test.Common.AutoFixture;
using Bit.Test.Common.AutoFixture.Attributes;
using Microsoft.AspNetCore.Authorization;
using NSubstitute;
using Xunit;
namespace Bit.Api.Test.Tools.Authorization;
[SutProviderCustomize]
public class VaultExportAuthorizationHandlerTests
{
public static IEnumerable<object[]> CanExportEntireVault => new[]
{
new CurrentContextOrganization { Type = OrganizationUserType.Owner },
new CurrentContextOrganization { Type = OrganizationUserType.Admin },
new CurrentContextOrganization
{
Type = OrganizationUserType.Custom, Permissions = new Permissions { AccessImportExport = true }
}
}.Select(org => new []{org});
[Theory]
[BitMemberAutoData(nameof(CanExportEntireVault))]
public async Task ExportAll_PermittedRoles_Success(CurrentContextOrganization org, OrganizationScope orgScope, ClaimsPrincipal user,
SutProvider<VaultExportAuthorizationHandler> sutProvider)
{
org.Id = orgScope;
sutProvider.GetDependency<ICurrentContext>().GetOrganization(orgScope).Returns(org);
var authContext = new AuthorizationHandlerContext(new[] { VaultExportOperations.ExportAll }, user, orgScope);
await sutProvider.Sut.HandleAsync(authContext);
Assert.True(authContext.HasSucceeded);
}
public static IEnumerable<object[]> CannotExportEntireVault => new[]
{
new CurrentContextOrganization { Type = OrganizationUserType.User },
new CurrentContextOrganization
{
Type = OrganizationUserType.Custom, Permissions = FlipPermissions(new Permissions { AccessImportExport = true })
}
}.Select(org => new []{org});
[Theory]
[BitMemberAutoData(nameof(CannotExportEntireVault))]
public async Task ExportAll_NotPermitted_Failure(CurrentContextOrganization org, OrganizationScope orgScope, ClaimsPrincipal user,
SutProvider<VaultExportAuthorizationHandler> sutProvider)
{
org.Id = orgScope;
sutProvider.GetDependency<ICurrentContext>().GetOrganization(orgScope).Returns(org);
var authContext = new AuthorizationHandlerContext(new[] { VaultExportOperations.ExportAll }, user, orgScope);
await sutProvider.Sut.HandleAsync(authContext);
Assert.False(authContext.HasSucceeded);
}
private static Permissions FlipPermissions(Permissions permissions)
{
// Get all false boolean properties of input object
var inputsToFlip = permissions
.GetType()
.GetProperties()
.Where(p =>
p.PropertyType == typeof(bool) &&
(bool)p.GetValue(permissions, null)! == false)
.Select(p => p.Name);
var result = new Permissions();
// Set these to true on the result object
result
.GetType()
.GetProperties()
.Where(p => inputsToFlip.Contains(p.Name))
.ToList()
.ForEach(p => p.SetValue(result, true));
return result;
}
}