1
0
mirror of https://github.com/bitwarden/server.git synced 2025-04-05 05:00:19 -05:00

Embed logic in requirement

This commit is contained in:
Thomas Rittson 2025-03-21 15:03:31 +10:00
parent 4dfc99dd85
commit b779dfec28
No known key found for this signature in database
GPG Key ID: CDDDA03861C35E27
7 changed files with 43 additions and 48 deletions

View File

@ -1,7 +1,7 @@
using Bit.Api.Tools.Authorization;
using Bit.Api.Vault.AuthorizationHandlers.Collections;
using Bit.Core.AdminConsole.OrganizationFeatures;
using Bit.Core.AdminConsole.OrganizationFeatures.Groups.Authorization;
using Bit.Core.AdminConsole.OrganizationFeatures.Shared.Authorization;
using Bit.Core.IdentityServer;
using Bit.Core.Settings;
using Bit.Core.Utilities;
@ -107,6 +107,6 @@ public static class ServiceCollectionExtensions
services.AddScoped<IAuthorizationHandler, SecurityTaskAuthorizationHandler>();
services.AddScoped<IAuthorizationHandler, SecurityTaskOrganizationAuthorizationHandler>();
services.AddScoped<IAuthorizationHandler, ManageUserRequirementHandler>();
services.AddScoped<IAuthorizationHandler, OrganizationRequirementHandler>();
}
}

View File

@ -1,21 +0,0 @@
#nullable enable
using Bit.Core.AdminConsole.OrganizationFeatures.Shared.Authorization;
using Bit.Core.Context;
using Bit.Core.Enums;
using Microsoft.AspNetCore.Http;
namespace Bit.Core.AdminConsole.OrganizationFeatures;
public class ManageUsersRequirement : IOrganizationRequirement;
public class ManageUserRequirementHandler(ICurrentContext currentContext, IHttpContextAccessor httpContextAccessor)
: OrganizationRequirementHandler<ManageUsersRequirement>(currentContext, httpContextAccessor)
{
private readonly ICurrentContext _currentContext = currentContext;
protected override async Task<bool> Authorize(Guid organizationId, CurrentContextOrganization? organizationClaims)
=> organizationClaims is { Type: OrganizationUserType.Owner or OrganizationUserType.Admin } or
{ Permissions.ManageUsers: true }
|| await _currentContext.ProviderUserForOrgAsync(organizationId);
}

View File

@ -0,0 +1,16 @@
#nullable enable
using Bit.Core.AdminConsole.OrganizationFeatures.Shared.Authorization;
using Bit.Core.Context;
using Bit.Core.Enums;
namespace Bit.Core.AdminConsole.OrganizationFeatures;
public class ManageUsersRequirement : IOrganizationRequirement
{
public async Task<bool> AuthorizeAsync(Guid organizationId, CurrentContextOrganization? organizationClaims, ICurrentContext currentContext)
=> organizationClaims is
{ Type: OrganizationUserType.Owner or OrganizationUserType.Admin } or
{ Permissions.ManageUsers: true }
|| await currentContext.ProviderUserForOrgAsync(organizationId);
}

View File

@ -0,0 +1,12 @@
#nullable enable
using Bit.Core.AdminConsole.OrganizationFeatures.Shared.Authorization;
using Bit.Core.Context;
namespace Bit.Core.AdminConsole.OrganizationFeatures;
public class OrganizationMemberRequirement : IOrganizationRequirement
{
public Task<bool> AuthorizeAsync(Guid organizationId, CurrentContextOrganization? organizationClaims, ICurrentContext currentContext)
=> Task.FromResult(organizationClaims is not null);
}

View File

@ -1,16 +0,0 @@
#nullable enable
using Bit.Core.AdminConsole.OrganizationFeatures.Shared.Authorization;
using Bit.Core.Context;
using Microsoft.AspNetCore.Http;
namespace Bit.Core.AdminConsole.OrganizationFeatures;
public class OrganizationMemberRequirement : IOrganizationRequirement;
public class OrganizationMemberRequirementHandler(ICurrentContext currentContext, IHttpContextAccessor httpContextAccessor)
: OrganizationRequirementHandler<OrganizationMemberRequirement>(currentContext, httpContextAccessor)
{
protected override Task<bool> Authorize(Guid organizationId, CurrentContextOrganization? organizationClaims)
=> Task.FromResult(organizationClaims is not null);
}

View File

@ -1,8 +1,15 @@
using Microsoft.AspNetCore.Authorization;
#nullable enable
using Bit.Core.Context;
using Microsoft.AspNetCore.Authorization;
namespace Bit.Core.AdminConsole.OrganizationFeatures.Shared.Authorization;
public interface IOrganizationRequirement : IAuthorizationRequirement;
public interface IOrganizationRequirement : IAuthorizationRequirement
{
// TODO: avoid injecting all of ICurrentContext?
public Task<bool> AuthorizeAsync(Guid organizationId, CurrentContextOrganization? organizationClaims, ICurrentContext currentContext);
}
public class OrganizationAuthorizeAttribute<T>
: AuthorizeAttribute, IAuthorizationRequirementData

View File

@ -6,13 +6,10 @@ using Microsoft.AspNetCore.Http;
namespace Bit.Core.AdminConsole.OrganizationFeatures.Shared.Authorization;
public abstract class OrganizationRequirementHandler<T>(ICurrentContext currentContext, IHttpContextAccessor httpContextAccessor)
: AuthorizationHandler<T>
where T : IAuthorizationRequirement
public class OrganizationRequirementHandler(ICurrentContext currentContext, IHttpContextAccessor httpContextAccessor)
: AuthorizationHandler<IOrganizationRequirement>
{
protected abstract Task<bool> Authorize(Guid organizationId, CurrentContextOrganization? organizationClaims);
protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context, T requirement)
protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context, IOrganizationRequirement requirement)
{
var organizationId = httpContextAccessor.GetOrganizationId();
if (organizationId is null)
@ -22,7 +19,7 @@ public abstract class OrganizationRequirementHandler<T>(ICurrentContext currentC
var organization = currentContext.GetOrganization(organizationId.Value);
var authorized = await Authorize(organizationId.Value, organization);
var authorized = await requirement.AuthorizeAsync(organizationId.Value, organization, currentContext);
if (authorized)
{