1
0
mirror of https://github.com/bitwarden/server.git synced 2025-07-03 17:12:49 -05:00

[AC-1125] Enforce org setting for creating/deleting collections (#3241)

* [AC-1117] Add manage permission (#3126)

* Update sql files to add Manage permission

* Add migration script

* Rename collection manage migration file to remove duplicate migration date

* Migrations

* Add manage to models

* Add manage to repository

* Add constraint to Manage columns

* Migration lint fixes

* Add manage to OrganizationUserUserDetails_ReadWithCollectionsById

* Add missing manage fields

* Add 'Manage' to UserCollectionDetails

* Use CREATE OR ALTER where possible

* [AC-1374] Limit collection creation/deletion to Owner/Admin (#3145)

* feat: update org table with new column, write migration, refs AC-1374

* feat: update views with new column, refs AC-1374

* feat: Alter sprocs (org create/update) to include new column, refs AC-1374

* feat: update entity/data/request/response models to handle new column, refs AC-1374

* feat: update necessary Provider related views during migration, refs AC-1374

* fix: update org create to default new column to false, refs AC-1374

* feat: added new API/request model for collection management and removed property from update request model, refs AC-1374

* fix: renamed migration script to be after secrets manage beta column changes, refs AC-1374

* fix: dotnet format, refs AC-1374

* feat: add ef migrations to reflect mssql changes, refs AC-1374

* fix: dotnet format, refs AC-1374

* feat: update API signature to accept Guid and explain Cd verbiage, refs AC-1374

* feat: created collection auth handler/operations, added LimitCollectionCdOwnerAdmin to CurrentContentOrganization, refs AC-1125

* feat: create vault service collection extensions and register with base services, refs AC-1125

* feat: deprecated CurrentContext.CreateNewCollections, refs AC-1125

* feat: deprecate DeleteAnyCollection for single resource usages, refs AC-1125

* feat: move service registration to api, update references, refs AC-1125

* feat: add bulk delete authorization handler, refs AC-1125

* feat: always assign user and give manage access on create, refs AC-1125

* fix: updated CurrentContextOrganization type, refs AC-1125

* feat: combined existing collection authorization handlers/operations, refs AC-1125

* fix: OrganizationServiceTests -> CurrentContentOrganization typo, refs AC-1125

* fix: format, refs AC-1125

* fix: update collection controller tests, refs AC-1125

* fix: dotnet format, refs AC-1125

* feat: removed extra BulkAuthorizationHandler, refs AC-1125

* fix: dotnet format, refs AC-1125

* fix: change string to guid for org id, update bulk delete request model, refs AC-1125

* fix: remove delete many collection check, refs AC-1125

* fix: clean up collection auth handler, refs AC-1125

* fix: format fix for CollectionOperations, refs AC-1125

* fix: removed unnecessary owner check, add org null check to custom permission validation, refs AC-1125

* fix: remove unused methods in CurrentContext, refs AC-1125

* fix: removed obsolete test, fixed failling delete many test, refs AC-1125

* fix: CollectionAuthorizationHandlerTests fixes, refs AC-1125

* fix: OrganizationServiceTests fix broken test by mocking GetOrganization, refs AC-1125

* fix: CollectionAuthorizationHandler - remove unused repository, refs AC-1125

* feat: moved UserId null check to common method, refs AC-1125

* fix: updated auth handler tests to remove dependency on requirement for common code checks, refs AC-1125

* feat: updated conditionals/comments for create/delete methods within colleciton auth handler, refs AC-1125

* feat: added create/delete collection auth handler success methods, refs AC-1125

* fix: new up permissions to prevent excessive null checks, refs AC-1125

* fix: remove old reference to CreateNewCollections, refs AC-1125

* fix: typo within ViewAssignedCollections method, refs AC-1125

---------

Co-authored-by: Robyn MacCallum <robyntmaccallum@gmail.com>
This commit is contained in:
Vincent Salucci
2023-09-18 17:02:53 -05:00
committed by GitHub
parent acd3997133
commit 34dfdc53aa
14 changed files with 386 additions and 285 deletions

View File

@ -1,5 +1,6 @@
using Bit.Api.Models.Request;
using Bit.Api.Models.Response;
using Bit.Api.Vault.AuthorizationHandlers.Collections;
using Bit.Core.Context;
using Bit.Core.Entities;
using Bit.Core.Exceptions;
@ -20,19 +21,22 @@ public class CollectionsController : Controller
private readonly IDeleteCollectionCommand _deleteCollectionCommand;
private readonly IUserService _userService;
private readonly ICurrentContext _currentContext;
private readonly IAuthorizationService _authorizationService;
public CollectionsController(
ICollectionRepository collectionRepository,
ICollectionService collectionService,
IDeleteCollectionCommand deleteCollectionCommand,
IUserService userService,
ICurrentContext currentContext)
ICurrentContext currentContext,
IAuthorizationService authorizationService)
{
_collectionRepository = collectionRepository;
_collectionService = collectionService;
_deleteCollectionCommand = deleteCollectionCommand;
_userService = userService;
_currentContext = currentContext;
_authorizationService = authorizationService;
}
[HttpGet("{id}")]
@ -62,6 +66,7 @@ public class CollectionsController : Controller
{
throw new NotFoundException();
}
return new CollectionAccessDetailsResponseModel(collection, access.Groups, access.Users);
}
else
@ -72,6 +77,7 @@ public class CollectionsController : Controller
{
throw new NotFoundException();
}
return new CollectionAccessDetailsResponseModel(collection, access.Groups, access.Users);
}
}
@ -79,13 +85,15 @@ public class CollectionsController : Controller
[HttpGet("details")]
public async Task<ListResponseModel<CollectionAccessDetailsResponseModel>> GetManyWithDetails(Guid orgId)
{
if (!await ViewAtLeastOneCollectionAsync(orgId) && !await _currentContext.ManageUsers(orgId) && !await _currentContext.ManageGroups(orgId))
if (!await ViewAtLeastOneCollectionAsync(orgId) && !await _currentContext.ManageUsers(orgId) &&
!await _currentContext.ManageGroups(orgId))
{
throw new NotFoundException();
}
// We always need to know which collections the current user is assigned to
var assignedOrgCollections = await _collectionRepository.GetManyByUserIdWithAccessAsync(_currentContext.UserId.Value, orgId);
var assignedOrgCollections =
await _collectionRepository.GetManyByUserIdWithAccessAsync(_currentContext.UserId.Value, orgId);
if (await _currentContext.ViewAllCollections(orgId) || await _currentContext.ManageUsers(orgId))
{
@ -141,8 +149,8 @@ public class CollectionsController : Controller
{
var collection = model.ToCollection(orgId);
if (!await CanCreateCollection(orgId, collection.Id) &&
!await CanEditCollectionAsync(orgId, collection.Id))
var result = await _authorizationService.AuthorizeAsync(User, collection, CollectionOperations.Create);
if (!result.Succeeded)
{
throw new NotFoundException();
}
@ -150,10 +158,7 @@ public class CollectionsController : Controller
var groups = model.Groups?.Select(g => g.ToSelectionReadOnly());
var users = model.Users?.Select(g => g.ToSelectionReadOnly());
var assignUserToCollection = !(await _currentContext.EditAnyCollection(orgId)) &&
await _currentContext.EditAssignedCollections(orgId);
await _collectionService.SaveAsync(collection, groups, users, assignUserToCollection ? _currentContext.UserId : null);
await _collectionService.SaveAsync(collection, groups, users, _currentContext.UserId);
return new CollectionResponseModel(collection);
}
@ -189,12 +194,13 @@ public class CollectionsController : Controller
[HttpPost("{id}/delete")]
public async Task Delete(Guid orgId, Guid id)
{
if (!await CanDeleteCollectionAsync(orgId, id))
var collection = await GetCollectionAsync(id, orgId);
var result = await _authorizationService.AuthorizeAsync(User, collection, CollectionOperations.Delete);
if (!result.Succeeded)
{
throw new NotFoundException();
}
var collection = await GetCollectionAsync(id, orgId);
await _deleteCollectionCommand.DeleteAsync(collection);
}
@ -202,22 +208,14 @@ public class CollectionsController : Controller
[HttpPost("delete")]
public async Task DeleteMany([FromBody] CollectionBulkDeleteRequestModel model)
{
var orgId = new Guid(model.OrganizationId);
var collectionIds = model.Ids.Select(i => new Guid(i));
if (!await _currentContext.DeleteAssignedCollections(orgId) && !await _currentContext.DeleteAnyCollection(orgId))
var collections = await _collectionRepository.GetManyByManyIdsAsync(model.Ids);
var result = await _authorizationService.AuthorizeAsync(User, collections, CollectionOperations.Delete);
if (!result.Succeeded)
{
throw new NotFoundException();
}
var userCollections = await _collectionService.GetOrganizationCollectionsAsync(orgId);
var filteredCollections = userCollections.Where(c => collectionIds.Contains(c.Id) && c.OrganizationId == orgId);
if (!filteredCollections.Any())
{
throw new BadRequestException("No collections found.");
}
await _deleteCollectionCommand.DeleteManyAsync(filteredCollections);
await _deleteCollectionCommand.DeleteManyAsync(collections);
}
[HttpDelete("{id}/user/{orgUserId}")]
@ -248,17 +246,6 @@ public class CollectionsController : Controller
return collection;
}
private async Task<bool> CanCreateCollection(Guid orgId, Guid collectionId)
{
if (collectionId != default)
{
return false;
}
return await _currentContext.CreateNewCollections(orgId);
}
private async Task<bool> CanEditCollectionAsync(Guid orgId, Guid collectionId)
{
if (collectionId == default)
@ -273,28 +260,8 @@ public class CollectionsController : Controller
if (await _currentContext.EditAssignedCollections(orgId))
{
var collectionDetails = await _collectionRepository.GetByIdAsync(collectionId, _currentContext.UserId.Value);
return collectionDetails != null;
}
return false;
}
private async Task<bool> CanDeleteCollectionAsync(Guid orgId, Guid collectionId)
{
if (collectionId == default)
{
return false;
}
if (await _currentContext.DeleteAnyCollection(orgId))
{
return true;
}
if (await _currentContext.DeleteAssignedCollections(orgId))
{
var collectionDetails = await _collectionRepository.GetByIdAsync(collectionId, _currentContext.UserId.Value);
var collectionDetails =
await _collectionRepository.GetByIdAsync(collectionId, _currentContext.UserId.Value);
return collectionDetails != null;
}
@ -315,7 +282,8 @@ public class CollectionsController : Controller
if (await _currentContext.ViewAssignedCollections(orgId))
{
var collectionDetails = await _collectionRepository.GetByIdAsync(collectionId, _currentContext.UserId.Value);
var collectionDetails =
await _collectionRepository.GetByIdAsync(collectionId, _currentContext.UserId.Value);
return collectionDetails != null;
}