mirror of
https://github.com/bitwarden/server.git
synced 2025-07-05 10:02:47 -05:00
[AC-2084] Include Collection permissions for admin endpoints (#3793)
* [AC-2084] Add documentation to existing collection repository getters * [AC-2084] Add new CollectionAdminDetails model * [AC-2084] Add SQL and migration scripts * [AC-2084] Introduce new repository methods to include permission details for collections * [AC-2084] Add EF repository methods and integration tests * [AC-2084] Update CollectionsController and response models * [AC-2084] Fix failing SqlServer test * [AC-2084] Clean up admin endpoint response models - vNext endpoints should now always return CollectionDetailsResponse models - Update constructors in CollectionDetailsResponseModel to be more explicit and add named static constructors for additional clarity * [AC-2084] Fix failing tests * [AC-2084] Fix potential provider/member bug * [AC-2084] Fix broken collections controller * [AC-2084] Cleanup collection response model types and constructors * [AC-2084] Remove redundant authorization check * [AC-2084] Cleanup ambiguous model name * [AC-2084] Add GroupBy clause to sprocs * [AC-2084] Add GroupBy logic to EF repository * [AC-2084] Update collection repository tests * [AC-2084] Update migration script date * Update migration script date --------- Co-authored-by: Thomas Rittson <31796059+eliykat@users.noreply.github.com> Co-authored-by: kejaeger <138028972+kejaeger@users.noreply.github.com>
This commit is contained in:
@ -553,47 +553,38 @@ public class CollectionsController : Controller
|
||||
private async Task<CollectionAccessDetailsResponseModel> GetDetails_vNext(Guid id)
|
||||
{
|
||||
// New flexible collections logic
|
||||
var (collection, access) = await _collectionRepository.GetByIdWithAccessAsync(id);
|
||||
var authorized = (await _authorizationService.AuthorizeAsync(User, collection, BulkCollectionOperations.ReadWithAccess)).Succeeded;
|
||||
var collectionAdminDetails =
|
||||
await _collectionRepository.GetByIdWithPermissionsAsync(id, _currentContext.UserId, true);
|
||||
|
||||
var authorized = (await _authorizationService.AuthorizeAsync(User, collectionAdminDetails, BulkCollectionOperations.ReadWithAccess)).Succeeded;
|
||||
if (!authorized)
|
||||
{
|
||||
throw new NotFoundException();
|
||||
}
|
||||
|
||||
return new CollectionAccessDetailsResponseModel(collection, access.Groups, access.Users);
|
||||
return new CollectionAccessDetailsResponseModel(collectionAdminDetails);
|
||||
}
|
||||
|
||||
private async Task<ListResponseModel<CollectionAccessDetailsResponseModel>> GetManyWithDetails_vNext(Guid orgId)
|
||||
{
|
||||
// We always need to know which collections the current user is assigned to
|
||||
var assignedOrgCollections = await _collectionRepository
|
||||
.GetManyByUserIdWithAccessAsync(_currentContext.UserId.Value, orgId, true);
|
||||
var allOrgCollections = await _collectionRepository.GetManyByOrganizationIdWithPermissionsAsync(
|
||||
orgId, _currentContext.UserId.Value, true);
|
||||
|
||||
var readAllAuthorized =
|
||||
(await _authorizationService.AuthorizeAsync(User, CollectionOperations.ReadAllWithAccess(orgId))).Succeeded;
|
||||
if (readAllAuthorized)
|
||||
{
|
||||
// The user can view all collections, but they may not always be assigned to all of them
|
||||
var allOrgCollections = await _collectionRepository.GetManyByOrganizationIdWithAccessAsync(orgId);
|
||||
|
||||
return new ListResponseModel<CollectionAccessDetailsResponseModel>(allOrgCollections.Select(c =>
|
||||
new CollectionAccessDetailsResponseModel(c.Item1, c.Item2.Groups, c.Item2.Users)
|
||||
{
|
||||
// Manually determine which collections they're assigned to
|
||||
Assigned = assignedOrgCollections.Any(ac => ac.Item1.Id == c.Item1.Id)
|
||||
})
|
||||
return new ListResponseModel<CollectionAccessDetailsResponseModel>(
|
||||
allOrgCollections.Select(c => new CollectionAccessDetailsResponseModel(c))
|
||||
);
|
||||
}
|
||||
|
||||
// Filter the assigned collections to only return those where the user has Manage permission
|
||||
var manageableOrgCollections = assignedOrgCollections.Where(c => c.Item1.Manage).ToList();
|
||||
// Filter collections to only return those where the user has Manage permission
|
||||
var manageableOrgCollections = allOrgCollections.Where(c => c.Manage).ToList();
|
||||
|
||||
return new ListResponseModel<CollectionAccessDetailsResponseModel>(manageableOrgCollections.Select(c =>
|
||||
new CollectionAccessDetailsResponseModel(c.Item1, c.Item2.Groups, c.Item2.Users)
|
||||
{
|
||||
Assigned = true // Mapping from manageableOrgCollections implies they're all assigned
|
||||
})
|
||||
);
|
||||
new CollectionAccessDetailsResponseModel(c)
|
||||
));
|
||||
}
|
||||
|
||||
private async Task<ListResponseModel<CollectionResponseModel>> GetByOrgId_vNext(Guid orgId)
|
||||
@ -629,7 +620,7 @@ public class CollectionsController : Controller
|
||||
return responses;
|
||||
}
|
||||
|
||||
private async Task<CollectionResponseModel> Post_vNext(Guid orgId, [FromBody] CollectionRequestModel model)
|
||||
private async Task<CollectionAccessDetailsResponseModel> Post_vNext(Guid orgId, [FromBody] CollectionRequestModel model)
|
||||
{
|
||||
var collection = model.ToCollection(orgId);
|
||||
|
||||
@ -644,21 +635,18 @@ public class CollectionsController : Controller
|
||||
|
||||
await _collectionService.SaveAsync(collection, groups, users);
|
||||
|
||||
if (!_currentContext.UserId.HasValue || await _currentContext.ProviderUserForOrgAsync(orgId))
|
||||
if (!_currentContext.UserId.HasValue || (_currentContext.GetOrganization(orgId) == null && await _currentContext.ProviderUserForOrgAsync(orgId)))
|
||||
{
|
||||
return new CollectionResponseModel(collection);
|
||||
return new CollectionAccessDetailsResponseModel(collection);
|
||||
}
|
||||
|
||||
// If we have a user, fetch the collection to get the latest permission details
|
||||
var userCollectionDetails = await _collectionRepository.GetByIdAsync(collection.Id,
|
||||
_currentContext.UserId.Value, await FlexibleCollectionsIsEnabledAsync(collection.OrganizationId));
|
||||
// If we have a user, fetch the latest collection permission details
|
||||
var collectionWithPermissions = await _collectionRepository.GetByIdWithPermissionsAsync(collection.Id, _currentContext.UserId.Value, false);
|
||||
|
||||
return userCollectionDetails == null
|
||||
? new CollectionResponseModel(collection)
|
||||
: new CollectionDetailsResponseModel(userCollectionDetails);
|
||||
return new CollectionAccessDetailsResponseModel(collectionWithPermissions);
|
||||
}
|
||||
|
||||
private async Task<CollectionResponseModel> Put_vNext(Guid id, CollectionRequestModel model)
|
||||
private async Task<CollectionAccessDetailsResponseModel> Put_vNext(Guid id, CollectionRequestModel model)
|
||||
{
|
||||
var collection = await _collectionRepository.GetByIdAsync(id);
|
||||
var authorized = (await _authorizationService.AuthorizeAsync(User, collection, BulkCollectionOperations.Update)).Succeeded;
|
||||
@ -671,17 +659,15 @@ public class CollectionsController : Controller
|
||||
var users = model.Users?.Select(g => g.ToSelectionReadOnly());
|
||||
await _collectionService.SaveAsync(model.ToCollection(collection), groups, users);
|
||||
|
||||
if (!_currentContext.UserId.HasValue || await _currentContext.ProviderUserForOrgAsync(collection.OrganizationId))
|
||||
if (!_currentContext.UserId.HasValue || (_currentContext.GetOrganization(collection.OrganizationId) == null && await _currentContext.ProviderUserForOrgAsync(collection.OrganizationId)))
|
||||
{
|
||||
return new CollectionResponseModel(collection);
|
||||
return new CollectionAccessDetailsResponseModel(collection);
|
||||
}
|
||||
|
||||
// If we have a user, fetch the collection details to get the latest permission details for the user
|
||||
var updatedCollectionDetails = await _collectionRepository.GetByIdAsync(id, _currentContext.UserId.Value, await FlexibleCollectionsIsEnabledAsync(collection.OrganizationId));
|
||||
// If we have a user, fetch the latest collection permission details
|
||||
var collectionWithPermissions = await _collectionRepository.GetByIdWithPermissionsAsync(collection.Id, _currentContext.UserId.Value, false);
|
||||
|
||||
return updatedCollectionDetails == null
|
||||
? new CollectionResponseModel(collection)
|
||||
: new CollectionDetailsResponseModel(updatedCollectionDetails);
|
||||
return new CollectionAccessDetailsResponseModel(collectionWithPermissions);
|
||||
}
|
||||
|
||||
private async Task PutUsers_vNext(Guid id, IEnumerable<SelectionReadOnlyRequestModel> model)
|
||||
|
Reference in New Issue
Block a user