1
0
mirror of https://github.com/bitwarden/server.git synced 2025-07-14 22:27:32 -05:00

Move to api project, create new context class

This commit is contained in:
Thomas Rittson
2025-03-27 10:20:19 +10:00
parent b840e2e318
commit 3d83e4b5a7
14 changed files with 93 additions and 49 deletions

View File

@ -1,16 +0,0 @@
#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

@ -1,15 +0,0 @@
#nullable enable
using Bit.Core.AdminConsole.OrganizationFeatures.Shared.Authorization;
using Bit.Core.Context;
namespace Bit.Core.AdminConsole.OrganizationFeatures;
/// <summary>
/// Requires that the user is a member of the organization or a provider for the organization.
/// </summary>
public class MemberOrProviderRequirement : IOrganizationRequirement
{
public async Task<bool> AuthorizeAsync(Guid organizationId, CurrentContextOrganization? organizationClaims, ICurrentContext currentContext)
=> organizationClaims is not null || await currentContext.ProviderUserForOrgAsync(organizationId);
}

View File

@ -1,21 +0,0 @@
#nullable enable
using Microsoft.AspNetCore.Authorization;
namespace Bit.Core.AdminConsole.OrganizationFeatures.Shared.Authorization;
/// <summary>
/// An attribute which requires authorization using the specified requirement.
/// This uses the standard ASP.NET authorization middleware.
/// </summary>
/// <typeparam name="T">The IAuthorizationRequirement that will be used to authorize the user.</typeparam>
public class AuthorizeAttribute<T>
: AuthorizeAttribute, IAuthorizationRequirementData
where T : IAuthorizationRequirement, new()
{
public IEnumerable<IAuthorizationRequirement> GetRequirements()
{
var requirement = new T();
yield return requirement;
}
}

View File

@ -1,18 +0,0 @@
#nullable enable
using Bit.Core.Context;
using Microsoft.AspNetCore.Authorization;
namespace Bit.Core.AdminConsole.OrganizationFeatures.Shared.Authorization;
/// <summary>
/// A requirement that implements this interface will be handled by <see cref="OrganizationRequirementHandler"/>,
/// which calls AuthorizeAsync with the organization details from the route.
/// This is used for simple role-based checks.
/// This may only be used on endpoints with {orgId} in their path.
/// </summary>
public interface IOrganizationRequirement : IAuthorizationRequirement
{
// TODO: avoid injecting all of ICurrentContext?
public Task<bool> AuthorizeAsync(Guid organizationId, CurrentContextOrganization? organizationClaims, ICurrentContext currentContext);
}

View File

@ -1,36 +0,0 @@
#nullable enable
using Bit.Core.Context;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
namespace Bit.Core.AdminConsole.OrganizationFeatures.Shared.Authorization;
/// <summary>
/// Handles any requirement that implements <see cref="IOrganizationRequirement"/>.
/// Retrieves the Organization ID from the route and then passes it to the requirement's AuthorizeAsync callback to
/// determine whether the action is authorized.
/// </summary>
/// <param name="currentContext"></param>
/// <param name="httpContextAccessor"></param>
public class OrganizationRequirementHandler(ICurrentContext currentContext, IHttpContextAccessor httpContextAccessor)
: AuthorizationHandler<IOrganizationRequirement>
{
protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context, IOrganizationRequirement requirement)
{
var organizationId = httpContextAccessor.GetOrganizationId();
if (organizationId is null)
{
throw new Exception("No organizationId found in route. IOrganizationRequirement cannot be used on this endpoint.");
}
var organization = currentContext.GetOrganization(organizationId.Value);
var authorized = await requirement.AuthorizeAsync(organizationId.Value, organization, currentContext);
if (authorized)
{
context.Succeed(requirement);
}
}
}

View File

@ -1,25 +0,0 @@
#nullable enable
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Routing;
namespace Bit.Core.AdminConsole.OrganizationFeatures.Shared.Authorization;
public static class OrganizationRequirementHelpers
{
public static Guid? GetOrganizationId(this IHttpContextAccessor httpContextAccessor)
{
if (httpContextAccessor.HttpContext is null)
{
return null;
}
httpContextAccessor.HttpContext.GetRouteData().Values.TryGetValue("orgId", out var orgIdParam);
if (!Guid.TryParse(orgIdParam?.ToString(), out var orgId))
{
return null;
}
return orgId;
}
}