mirror of
https://github.com/bitwarden/server.git
synced 2025-04-05 21:18:13 -05:00
First pass using policy based auth
This commit is contained in:
parent
948d8f707d
commit
1c697544b8
@ -145,14 +145,15 @@ public class OrganizationUsersController : Controller
|
|||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("")]
|
[HttpGet("")]
|
||||||
|
[Authorize(Policy = "owner")]
|
||||||
public async Task<ListResponseModel<OrganizationUserUserDetailsResponseModel>> Get(Guid orgId, bool includeGroups = false, bool includeCollections = false)
|
public async Task<ListResponseModel<OrganizationUserUserDetailsResponseModel>> Get(Guid orgId, bool includeGroups = false, bool includeCollections = false)
|
||||||
{
|
{
|
||||||
var authorized = (await _authorizationService.AuthorizeAsync(
|
// var authorized = (await _authorizationService.AuthorizeAsync(
|
||||||
User, new OrganizationScope(orgId), OrganizationUserUserDetailsOperations.ReadAll)).Succeeded;
|
// User, new OrganizationScope(orgId), OrganizationUserUserDetailsOperations.ReadAll)).Succeeded;
|
||||||
if (!authorized)
|
// if (!authorized)
|
||||||
{
|
// {
|
||||||
throw new NotFoundException();
|
// throw new NotFoundException();
|
||||||
}
|
// }
|
||||||
|
|
||||||
var organizationUsers = await _organizationUserUserDetailsQuery.GetOrganizationUserUserDetails(
|
var organizationUsers = await _organizationUserUserDetailsQuery.GetOrganizationUserUserDetails(
|
||||||
new OrganizationUserUserDetailsQueryRequest
|
new OrganizationUserUserDetailsQueryRequest
|
||||||
|
@ -27,8 +27,10 @@ using Bit.Core.OrganizationFeatures.OrganizationSubscriptions;
|
|||||||
using Bit.Core.Tools.Entities;
|
using Bit.Core.Tools.Entities;
|
||||||
using Bit.Core.Vault.Entities;
|
using Bit.Core.Vault.Entities;
|
||||||
using Bit.Api.Auth.Models.Request.WebAuthn;
|
using Bit.Api.Auth.Models.Request.WebAuthn;
|
||||||
|
using Bit.Core.AdminConsole.OrganizationFeatures;
|
||||||
using Bit.Core.Auth.Models.Data;
|
using Bit.Core.Auth.Models.Data;
|
||||||
using Bit.Core.Auth.Identity.TokenProviders;
|
using Bit.Core.Auth.Identity.TokenProviders;
|
||||||
|
using Bit.Core.Enums;
|
||||||
using Bit.Core.Tools.ImportFeatures;
|
using Bit.Core.Tools.ImportFeatures;
|
||||||
using Bit.Core.Tools.ReportFeatures;
|
using Bit.Core.Tools.ReportFeatures;
|
||||||
|
|
||||||
@ -143,6 +145,18 @@ public class Startup
|
|||||||
(c.Value.Contains(ApiScopes.Api) || c.Value.Contains(ApiScopes.ApiSecrets))
|
(c.Value.Contains(ApiScopes.Api) || c.Value.Contains(ApiScopes.ApiSecrets))
|
||||||
));
|
));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Simplest implementation: check for role
|
||||||
|
// Issues:
|
||||||
|
// - unable to specify custom permissions
|
||||||
|
// - multiple policies are treated as AND rather than OR
|
||||||
|
// - does not allow for more complex conditional logic - e.g. providers can affect whether owners can view billing
|
||||||
|
// Alternative: describe broad action/capability, e.g. ManageUsers, ManageGroups, ViewBilling, similar to CurrentContext today
|
||||||
|
// the handler is then implemented per domain to define who can do those things
|
||||||
|
config.AddPolicy("owner", policy
|
||||||
|
=> policy.AddRequirements(new RoleRequirement(OrganizationUserType.Owner)));
|
||||||
|
config.AddPolicy("admin", policy
|
||||||
|
=> policy.AddRequirements(new RoleRequirement(OrganizationUserType.Admin)));
|
||||||
});
|
});
|
||||||
|
|
||||||
services.AddScoped<AuthenticatorTokenProvider>();
|
services.AddScoped<AuthenticatorTokenProvider>();
|
||||||
@ -255,11 +269,12 @@ public class Startup
|
|||||||
|
|
||||||
// Add authentication and authorization to the request pipeline.
|
// Add authentication and authorization to the request pipeline.
|
||||||
app.UseAuthentication();
|
app.UseAuthentication();
|
||||||
app.UseAuthorization();
|
|
||||||
|
|
||||||
// Add current context
|
// Add current context - before authz
|
||||||
app.UseMiddleware<CurrentContextMiddleware>();
|
app.UseMiddleware<CurrentContextMiddleware>();
|
||||||
|
|
||||||
|
app.UseAuthorization();
|
||||||
|
|
||||||
// Add endpoints to the request pipeline.
|
// Add endpoints to the request pipeline.
|
||||||
app.UseEndpoints(endpoints =>
|
app.UseEndpoints(endpoints =>
|
||||||
{
|
{
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
using Bit.Api.Tools.Authorization;
|
using Bit.Api.Tools.Authorization;
|
||||||
using Bit.Api.Vault.AuthorizationHandlers.Collections;
|
using Bit.Api.Vault.AuthorizationHandlers.Collections;
|
||||||
|
using Bit.Core.AdminConsole.OrganizationFeatures;
|
||||||
using Bit.Core.AdminConsole.OrganizationFeatures.Groups.Authorization;
|
using Bit.Core.AdminConsole.OrganizationFeatures.Groups.Authorization;
|
||||||
using Bit.Core.IdentityServer;
|
using Bit.Core.IdentityServer;
|
||||||
using Bit.Core.Settings;
|
using Bit.Core.Settings;
|
||||||
@ -105,5 +106,7 @@ public static class ServiceCollectionExtensions
|
|||||||
services.AddScoped<IAuthorizationHandler, VaultExportAuthorizationHandler>();
|
services.AddScoped<IAuthorizationHandler, VaultExportAuthorizationHandler>();
|
||||||
services.AddScoped<IAuthorizationHandler, SecurityTaskAuthorizationHandler>();
|
services.AddScoped<IAuthorizationHandler, SecurityTaskAuthorizationHandler>();
|
||||||
services.AddScoped<IAuthorizationHandler, SecurityTaskOrganizationAuthorizationHandler>();
|
services.AddScoped<IAuthorizationHandler, SecurityTaskOrganizationAuthorizationHandler>();
|
||||||
|
|
||||||
|
services.AddScoped<IAuthorizationHandler, RoleAuthorizationHandler>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,36 @@
|
|||||||
|
using Bit.Core.Context;
|
||||||
|
using Bit.Core.Enums;
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using Microsoft.AspNetCore.Routing;
|
||||||
|
|
||||||
|
namespace Bit.Core.AdminConsole.OrganizationFeatures;
|
||||||
|
|
||||||
|
public record RoleRequirement(OrganizationUserType Role) : IAuthorizationRequirement;
|
||||||
|
|
||||||
|
public class RoleAuthorizationHandler(ICurrentContext currentContext, IHttpContextAccessor httpContextAccessor) : AuthorizationHandler<RoleRequirement>
|
||||||
|
{
|
||||||
|
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, RoleRequirement requirement)
|
||||||
|
{
|
||||||
|
if (httpContextAccessor.HttpContext is null)
|
||||||
|
{
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
httpContextAccessor.HttpContext.GetRouteData().Values.TryGetValue("orgId", out var orgIdParam);
|
||||||
|
if (!Guid.TryParse(orgIdParam?.ToString(), out var orgId))
|
||||||
|
{
|
||||||
|
// No orgId supplied, unable to authorize
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This could be an extension method on ClaimsPrincipal
|
||||||
|
var orgClaims = currentContext.GetOrganization(orgId);
|
||||||
|
if (orgClaims?.Type == requirement.Role)
|
||||||
|
{
|
||||||
|
context.Succeed(requirement);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user