1
0
mirror of https://github.com/bitwarden/server.git synced 2025-04-05 21:18:13 -05:00

properly handle patch operations with path values (#2190)

This commit is contained in:
Kyle Spearrin 2022-08-15 12:08:55 -04:00 committed by GitHub
parent a89bfdfe2b
commit 62f29efb00
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 96 additions and 78 deletions

View File

@ -165,89 +165,86 @@ namespace Bit.Scim.Controllers.v2
} }
var operationHandled = false; var operationHandled = false;
foreach (var operation in model.Operations)
var replaceOp = model.Operations?.FirstOrDefault(o =>
o.Op?.ToLowerInvariant() == "replace");
if (replaceOp != null)
{ {
// Replace a list of members // Replace operations
if (replaceOp.Path?.ToLowerInvariant() == "members") if (operation.Op?.ToLowerInvariant() == "replace")
{ {
var ids = GetOperationValueIds(replaceOp.Value); // Replace a list of members
await _groupRepository.UpdateUsersAsync(group.Id, ids); if (operation.Path?.ToLowerInvariant() == "members")
operationHandled = true; {
var ids = GetOperationValueIds(operation.Value);
await _groupRepository.UpdateUsersAsync(group.Id, ids);
operationHandled = true;
}
// Replace group name from path
else if (operation.Path?.ToLowerInvariant() == "displayname")
{
group.Name = operation.Value.GetString();
await _groupService.SaveAsync(group);
operationHandled = true;
}
// Replace group name from value object
else if (string.IsNullOrWhiteSpace(operation.Path) &&
operation.Value.TryGetProperty("displayName", out var displayNameProperty))
{
group.Name = displayNameProperty.GetString();
await _groupService.SaveAsync(group);
operationHandled = true;
}
} }
// Replace group name // Add a single member
else if (replaceOp.Value.TryGetProperty("displayName", out var displayNameProperty)) else if (operation.Op?.ToLowerInvariant() == "add" &&
!string.IsNullOrWhiteSpace(operation.Path) &&
operation.Path.ToLowerInvariant().StartsWith("members[value eq "))
{ {
group.Name = displayNameProperty.GetString(); var addId = GetOperationPathId(operation.Path);
await _groupService.SaveAsync(group); if (addId.HasValue)
operationHandled = true; {
var orgUserIds = (await _groupRepository.GetManyUserIdsByIdAsync(group.Id)).ToHashSet();
orgUserIds.Add(addId.Value);
await _groupRepository.UpdateUsersAsync(group.Id, orgUserIds);
operationHandled = true;
}
} }
} // Add a list of members
else if (operation.Op?.ToLowerInvariant() == "add" &&
// Add a single member operation.Path?.ToLowerInvariant() == "members")
var addMemberOp = model.Operations?.FirstOrDefault(
o => o.Op?.ToLowerInvariant() == "add" &&
!string.IsNullOrWhiteSpace(o.Path) &&
o.Path.ToLowerInvariant().StartsWith("members[value eq "));
if (addMemberOp != null)
{
var addId = GetOperationPathId(addMemberOp.Path);
if (addId.HasValue)
{ {
var orgUserIds = (await _groupRepository.GetManyUserIdsByIdAsync(group.Id)).ToHashSet(); var orgUserIds = (await _groupRepository.GetManyUserIdsByIdAsync(group.Id)).ToHashSet();
orgUserIds.Add(addId.Value); foreach (var v in GetOperationValueIds(operation.Value))
{
orgUserIds.Add(v);
}
await _groupRepository.UpdateUsersAsync(group.Id, orgUserIds); await _groupRepository.UpdateUsersAsync(group.Id, orgUserIds);
operationHandled = true; operationHandled = true;
} }
} // Remove a single member
else if (operation.Op?.ToLowerInvariant() == "remove" &&
// Add a list of members !string.IsNullOrWhiteSpace(operation.Path) &&
var addMembersOp = model.Operations?.FirstOrDefault(o => operation.Path.ToLowerInvariant().StartsWith("members[value eq "))
o.Op?.ToLowerInvariant() == "add" &&
o.Path?.ToLowerInvariant() == "members");
if (addMembersOp != null)
{
var orgUserIds = (await _groupRepository.GetManyUserIdsByIdAsync(group.Id)).ToHashSet();
foreach (var v in GetOperationValueIds(addMembersOp.Value))
{ {
orgUserIds.Add(v); var removeId = GetOperationPathId(operation.Path);
if (removeId.HasValue)
{
await _groupService.DeleteUserAsync(group, removeId.Value);
operationHandled = true;
}
} }
await _groupRepository.UpdateUsersAsync(group.Id, orgUserIds); // Remove a list of members
operationHandled = true; else if (operation.Op?.ToLowerInvariant() == "remove" &&
} operation.Path?.ToLowerInvariant() == "members")
// Remove a single member
var removeMemberOp = model.Operations?.FirstOrDefault(
o => o.Op?.ToLowerInvariant() == "remove" &&
!string.IsNullOrWhiteSpace(o.Path) &&
o.Path.ToLowerInvariant().StartsWith("members[value eq "));
if (removeMemberOp != null)
{
var removeId = GetOperationPathId(removeMemberOp.Path);
if (removeId.HasValue)
{ {
await _groupService.DeleteUserAsync(group, removeId.Value); var orgUserIds = (await _groupRepository.GetManyUserIdsByIdAsync(group.Id)).ToHashSet();
foreach (var v in GetOperationValueIds(operation.Value))
{
orgUserIds.Remove(v);
}
await _groupRepository.UpdateUsersAsync(group.Id, orgUserIds);
operationHandled = true; operationHandled = true;
} }
} }
// Remove a list of members
var removeMembersOp = model.Operations?.FirstOrDefault(o =>
o.Op?.ToLowerInvariant() == "remove" &&
o.Path?.ToLowerInvariant() == "members");
if (removeMembersOp != null)
{
var orgUserIds = (await _groupRepository.GetManyUserIdsByIdAsync(group.Id)).ToHashSet();
foreach (var v in GetOperationValueIds(removeMembersOp.Value))
{
orgUserIds.Remove(v);
}
await _groupRepository.UpdateUsersAsync(group.Id, orgUserIds);
operationHandled = true;
}
if (!operationHandled) if (!operationHandled)
{ {
_logger.LogWarning("Group patch operation not handled: {0} : ", _logger.LogWarning("Group patch operation not handled: {0} : ",

View File

@ -224,23 +224,29 @@ namespace Bit.Scim.Controllers.v2
} }
var operationHandled = false; var operationHandled = false;
foreach (var operation in model.Operations)
var replaceOp = model.Operations?.FirstOrDefault(o =>
o.Op?.ToLowerInvariant() == "replace");
if (replaceOp != null)
{ {
if (replaceOp.Value.TryGetProperty("active", out var activeProperty)) // Replace operations
if (operation.Op?.ToLowerInvariant() == "replace")
{ {
var active = activeProperty.GetBoolean(); // Active from path
if (active && orgUser.Status == OrganizationUserStatusType.Revoked) if (operation.Path?.ToLowerInvariant() == "active")
{ {
await _organizationService.RestoreUserAsync(orgUser, null, _userService); var handled = await HandleActiveOperationAsync(orgUser, operation.Value.GetBoolean());
operationHandled = true; if (!operationHandled)
{
operationHandled = handled;
}
} }
else if (!active && orgUser.Status != OrganizationUserStatusType.Revoked) // Active from value object
else if (string.IsNullOrWhiteSpace(operation.Path) &&
operation.Value.TryGetProperty("active", out var activeProperty))
{ {
await _organizationService.RevokeUserAsync(orgUser, null); var handled = await HandleActiveOperationAsync(orgUser, activeProperty.GetBoolean());
operationHandled = true; if (!operationHandled)
{
operationHandled = handled;
}
} }
} }
} }
@ -269,5 +275,20 @@ namespace Bit.Scim.Controllers.v2
await _organizationService.DeleteUserAsync(organizationId, id, null); await _organizationService.DeleteUserAsync(organizationId, id, null);
return new NoContentResult(); return new NoContentResult();
} }
private async Task<bool> HandleActiveOperationAsync(Core.Entities.OrganizationUser orgUser, bool active)
{
if (active && orgUser.Status == OrganizationUserStatusType.Revoked)
{
await _organizationService.RestoreUserAsync(orgUser, null, _userService);
return true;
}
else if (!active && orgUser.Status != OrganizationUserStatusType.Revoked)
{
await _organizationService.RevokeUserAsync(orgUser, null);
return true;
}
return false;
}
} }
} }