mirror of
https://github.com/bitwarden/server.git
synced 2025-04-15 01:58:14 -05:00
Moved authz code from GET organizations/orgId/users/id/groups to auth handler. Added tests.
This commit is contained in:
parent
589af12f8f
commit
058460cec7
@ -8,6 +8,7 @@ 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.OrganizationUserDetails;
|
||||
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.Authorization.OrganizationUserGroups;
|
||||
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.Interfaces;
|
||||
using Bit.Core.AdminConsole.OrganizationFeatures.Shared.Authorization;
|
||||
using Bit.Core.AdminConsole.Repositories;
|
||||
@ -186,11 +187,18 @@ public class OrganizationUsersController : Controller
|
||||
}
|
||||
|
||||
[HttpGet("{id}/groups")]
|
||||
public async Task<IEnumerable<string>> GetGroups(string orgId, string id)
|
||||
public async Task<IEnumerable<string>> GetGroups([FromRoute] Guid orgId, [FromRoute] Guid id)
|
||||
{
|
||||
var organizationUser = await _organizationUserRepository.GetByIdAsync(new Guid(id));
|
||||
if (organizationUser == null || (!await _currentContext.ManageGroups(organizationUser.OrganizationId) &&
|
||||
!await _currentContext.ManageUsers(organizationUser.OrganizationId)))
|
||||
var authorized = await _authorizationService.AuthorizeAsync(User, new OrganizationScope(orgId),
|
||||
[OrganizationUserGroupOperations.ReadAllIds]);
|
||||
|
||||
if (authorized.Succeeded is false)
|
||||
{
|
||||
throw new NotFoundException();
|
||||
}
|
||||
|
||||
var organizationUser = await _organizationUserRepository.GetByIdAsync(id);
|
||||
if (organizationUser == null)
|
||||
{
|
||||
throw new NotFoundException();
|
||||
}
|
||||
|
@ -0,0 +1,10 @@
|
||||
using Microsoft.AspNetCore.Authorization.Infrastructure;
|
||||
|
||||
namespace Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.Authorization.OrganizationUserGroups;
|
||||
|
||||
public class OrganizationUserGroupOperationRequirement : OperationAuthorizationRequirement;
|
||||
|
||||
public static class OrganizationUserGroupOperations
|
||||
{
|
||||
public static readonly OrganizationUserGroupOperationRequirement ReadAllIds = new() { Name = nameof(ReadAllIds) };
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
using Bit.Core.AdminConsole.OrganizationFeatures.Shared.Authorization;
|
||||
using Bit.Core.Context;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
|
||||
namespace Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.Authorization.OrganizationUserGroups;
|
||||
|
||||
public class OrganizationUserGroupsAuthorizationHandler(ICurrentContext currentContext)
|
||||
: AuthorizationHandler<OrganizationUserGroupOperationRequirement, OrganizationScope>
|
||||
{
|
||||
protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context,
|
||||
OrganizationUserGroupOperationRequirement requirement,
|
||||
OrganizationScope resource)
|
||||
{
|
||||
var authorized = requirement switch
|
||||
{
|
||||
not null when requirement.Name == nameof(OrganizationUserGroupOperations.ReadAllIds) =>
|
||||
await CanReadGroupIdsAsync(resource),
|
||||
_ => false
|
||||
};
|
||||
|
||||
if (authorized)
|
||||
{
|
||||
context.Succeed(requirement!);
|
||||
return;
|
||||
}
|
||||
|
||||
context.Fail();
|
||||
}
|
||||
|
||||
private async Task<bool> CanReadGroupIdsAsync(OrganizationScope organizationId) =>
|
||||
await currentContext.ManageUsers(organizationId) || await currentContext.ManageGroups(organizationId);
|
||||
}
|
@ -13,6 +13,7 @@ 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.OrganizationUserDetails;
|
||||
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.Authorization.OrganizationUserGroups;
|
||||
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.Interfaces;
|
||||
using Bit.Core.Models.Business.Tokenables;
|
||||
using Bit.Core.OrganizationFeatures.OrganizationCollections;
|
||||
@ -171,6 +172,8 @@ public static class OrganizationServiceCollectionExtensions
|
||||
services.AddScoped<IAuthorizationHandler, OrganizationUserUserMiniDetailsAuthorizationHandler>();
|
||||
services.AddScoped<IAuthorizationHandler, OrganizationUserUserDetailsAuthorizationHandler>();
|
||||
services.AddScoped<IAuthorizationHandler, OrganizationUserDetailsAuthorizationHandler>();
|
||||
services.AddScoped<IAuthorizationHandler, OrganizationUserGroupsAuthorizationHandler>();
|
||||
|
||||
services.AddScoped<IHasConfirmedOwnersExceptQuery, HasConfirmedOwnersExceptQuery>();
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,56 @@
|
||||
using System.Security.Claims;
|
||||
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.Authorization.OrganizationUserGroups;
|
||||
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 OrganizationUserGroupsAuthorizationHandlerTests
|
||||
{
|
||||
[Theory]
|
||||
[BitAutoData(true, false)]
|
||||
[BitAutoData(false, true)]
|
||||
[BitAutoData(true, true)]
|
||||
public async Task ReadAllIds_UserCanManageUsersOrGroups_ShouldReturnSuccess(
|
||||
bool canManageUsers,
|
||||
bool canManageGroups,
|
||||
CurrentContextOrganization contextOrganization,
|
||||
SutProvider<OrganizationUserGroupsAuthorizationHandler> sutProvider)
|
||||
{
|
||||
sutProvider.GetDependency<ICurrentContext>().ManageUsers(contextOrganization.Id).Returns(canManageUsers);
|
||||
sutProvider.GetDependency<ICurrentContext>().ManageGroups(contextOrganization.Id).Returns(canManageGroups);
|
||||
|
||||
var context = new AuthorizationHandlerContext(
|
||||
[OrganizationUserGroupOperations.ReadAllIds],
|
||||
new ClaimsPrincipal(),
|
||||
new OrganizationScope(contextOrganization.Id));
|
||||
|
||||
await sutProvider.Sut.HandleAsync(context);
|
||||
|
||||
Assert.True(context.HasSucceeded);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task ReadAllIds_UserCannotManageUsersNorGroups_ShouldReturnFailure(CurrentContextOrganization contextOrganization,
|
||||
SutProvider<OrganizationUserGroupsAuthorizationHandler> sutProvider)
|
||||
{
|
||||
sutProvider.GetDependency<ICurrentContext>().ManageUsers(contextOrganization.Id).Returns(false);
|
||||
sutProvider.GetDependency<ICurrentContext>().ManageGroups(contextOrganization.Id).Returns(false);
|
||||
|
||||
var context = new AuthorizationHandlerContext(
|
||||
[OrganizationUserGroupOperations.ReadAllIds],
|
||||
new ClaimsPrincipal(),
|
||||
new OrganizationScope(contextOrganization.Id));
|
||||
|
||||
await sutProvider.Sut.HandleAsync(context);
|
||||
|
||||
Assert.True(context.HasFailed);
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user