1
0
mirror of https://github.com/bitwarden/server synced 2026-02-09 05:00:32 +00:00

[PM-24055] - Collection Users and Groups null on Public response (#6713)

* Integration test around getting and saving collection with group/user permissions

* This adds groups to the collections returned.

* Added new stored procedures so we don't accidentally wipe out access due to null parameters.

* wrapping all calls in transaction in the event that there is an error.
This commit is contained in:
Jared McCannon
2025-12-17 11:34:17 -06:00
committed by GitHub
parent 886ba9ae6d
commit de504d800b
10 changed files with 609 additions and 17 deletions

View File

@@ -226,7 +226,6 @@ public class CollectionRepository : Repository<Collection, Guid>, ICollectionRep
{
obj.SetNewId();
var objWithGroupsAndUsers = JsonSerializer.Deserialize<CollectionWithGroupsAndUsers>(JsonSerializer.Serialize(obj))!;
objWithGroupsAndUsers.Groups = groups != null ? groups.ToArrayTVP() : Enumerable.Empty<CollectionAccessSelection>().ToArrayTVP();
@@ -243,18 +242,52 @@ public class CollectionRepository : Repository<Collection, Guid>, ICollectionRep
public async Task ReplaceAsync(Collection obj, IEnumerable<CollectionAccessSelection>? groups, IEnumerable<CollectionAccessSelection>? users)
{
var objWithGroupsAndUsers = JsonSerializer.Deserialize<CollectionWithGroupsAndUsers>(JsonSerializer.Serialize(obj))!;
objWithGroupsAndUsers.Groups = groups != null ? groups.ToArrayTVP() : Enumerable.Empty<CollectionAccessSelection>().ToArrayTVP();
objWithGroupsAndUsers.Users = users != null ? users.ToArrayTVP() : Enumerable.Empty<CollectionAccessSelection>().ToArrayTVP();
using (var connection = new SqlConnection(ConnectionString))
await using var connection = new SqlConnection(ConnectionString);
await connection.OpenAsync();
await using var transaction = await connection.BeginTransactionAsync();
try
{
var results = await connection.ExecuteAsync(
$"[{Schema}].[Collection_UpdateWithGroupsAndUsers]",
objWithGroupsAndUsers,
commandType: CommandType.StoredProcedure);
if (groups == null && users == null)
{
await connection.ExecuteAsync(
$"[{Schema}].[Collection_Update]",
obj,
commandType: CommandType.StoredProcedure,
transaction: transaction);
}
else if (groups != null && users == null)
{
await connection.ExecuteAsync(
$"[{Schema}].[Collection_UpdateWithGroups]",
new CollectionWithGroups(obj, groups),
commandType: CommandType.StoredProcedure,
transaction: transaction);
}
else if (groups == null && users != null)
{
await connection.ExecuteAsync(
$"[{Schema}].[Collection_UpdateWithUsers]",
new CollectionWithUsers(obj, users),
commandType: CommandType.StoredProcedure,
transaction: transaction);
}
else if (groups != null && users != null)
{
await connection.ExecuteAsync(
$"[{Schema}].[Collection_UpdateWithGroupsAndUsers]",
new CollectionWithGroupsAndUsers(obj, groups, users),
commandType: CommandType.StoredProcedure,
transaction: transaction);
}
await transaction.CommitAsync();
}
catch
{
await transaction.RollbackAsync();
throw;
}
}
public async Task DeleteManyAsync(IEnumerable<Guid> collectionIds)
@@ -424,9 +457,70 @@ public class CollectionRepository : Repository<Collection, Guid>, ICollectionRep
public class CollectionWithGroupsAndUsers : Collection
{
public CollectionWithGroupsAndUsers() { }
public CollectionWithGroupsAndUsers(Collection collection,
IEnumerable<CollectionAccessSelection> groups,
IEnumerable<CollectionAccessSelection> users)
{
Id = collection.Id;
Name = collection.Name;
OrganizationId = collection.OrganizationId;
CreationDate = collection.CreationDate;
RevisionDate = collection.RevisionDate;
Type = collection.Type;
ExternalId = collection.ExternalId;
DefaultUserCollectionEmail = collection.DefaultUserCollectionEmail;
Groups = groups.ToArrayTVP();
Users = users.ToArrayTVP();
}
[DisallowNull]
public DataTable? Groups { get; set; }
[DisallowNull]
public DataTable? Users { get; set; }
}
public class CollectionWithGroups : Collection
{
public CollectionWithGroups() { }
public CollectionWithGroups(Collection collection, IEnumerable<CollectionAccessSelection> groups)
{
Id = collection.Id;
Name = collection.Name;
OrganizationId = collection.OrganizationId;
CreationDate = collection.CreationDate;
RevisionDate = collection.RevisionDate;
Type = collection.Type;
ExternalId = collection.ExternalId;
DefaultUserCollectionEmail = collection.DefaultUserCollectionEmail;
Groups = groups.ToArrayTVP();
}
[DisallowNull]
public DataTable? Groups { get; set; }
}
public class CollectionWithUsers : Collection
{
public CollectionWithUsers() { }
public CollectionWithUsers(Collection collection, IEnumerable<CollectionAccessSelection> users)
{
Id = collection.Id;
Name = collection.Name;
OrganizationId = collection.OrganizationId;
CreationDate = collection.CreationDate;
RevisionDate = collection.RevisionDate;
Type = collection.Type;
ExternalId = collection.ExternalId;
DefaultUserCollectionEmail = collection.DefaultUserCollectionEmail;
Users = users.ToArrayTVP();
}
[DisallowNull]
public DataTable? Users { get; set; }
}
}