1
0
mirror of https://github.com/bitwarden/server.git synced 2025-02-16 01:51:21 +01:00

[EC-338] Update SCIM code naming conventions (revoked/restore) (#2140)

* Keep old endpoints but mark as deprecated
* Do not change existing sproc naming
This commit is contained in:
Thomas Rittson 2022-07-25 10:47:44 +10:00 committed by GitHub
parent cf16be16c6
commit f6a18db582
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 93 additions and 61 deletions

View File

@ -191,13 +191,13 @@ namespace Bit.Scim.Controllers.v2
}); });
} }
if (model.Active && orgUser.Status == OrganizationUserStatusType.Deactivated) if (model.Active && orgUser.Status == OrganizationUserStatusType.Revoked)
{ {
await _organizationService.ActivateUserAsync(orgUser, null); await _organizationService.RestoreUserAsync(orgUser, null);
} }
else if (!model.Active && orgUser.Status != OrganizationUserStatusType.Deactivated) else if (!model.Active && orgUser.Status != OrganizationUserStatusType.Revoked)
{ {
await _organizationService.DeactivateUserAsync(orgUser, null); await _organizationService.RevokeUserAsync(orgUser, null);
} }
// Have to get full details object for response model // Have to get full details object for response model
@ -227,14 +227,14 @@ namespace Bit.Scim.Controllers.v2
if (replaceOp.Value.TryGetProperty("active", out var activeProperty)) if (replaceOp.Value.TryGetProperty("active", out var activeProperty))
{ {
var active = activeProperty.GetBoolean(); var active = activeProperty.GetBoolean();
if (active && orgUser.Status == OrganizationUserStatusType.Deactivated) if (active && orgUser.Status == OrganizationUserStatusType.Revoked)
{ {
await _organizationService.ActivateUserAsync(orgUser, null); await _organizationService.RestoreUserAsync(orgUser, null);
operationHandled = true; operationHandled = true;
} }
else if (!active && orgUser.Status != OrganizationUserStatusType.Deactivated) else if (!active && orgUser.Status != OrganizationUserStatusType.Revoked)
{ {
await _organizationService.DeactivateUserAsync(orgUser, null); await _organizationService.RevokeUserAsync(orgUser, null);
operationHandled = true; operationHandled = true;
} }
} }

View File

@ -20,7 +20,7 @@ namespace Bit.Scim.Models
DisplayName = orgUser.Name; DisplayName = orgUser.Name;
Emails = new List<EmailModel> { new EmailModel(orgUser.Email) }; Emails = new List<EmailModel> { new EmailModel(orgUser.Email) };
Name = new NameModel(orgUser.Name); Name = new NameModel(orgUser.Name);
Active = orgUser.Status != Core.Enums.OrganizationUserStatusType.Deactivated; Active = orgUser.Status != Core.Enums.OrganizationUserStatusType.Revoked;
} }
public string Id { get; set; } public string Id { get; set; }

View File

@ -373,35 +373,67 @@ namespace Bit.Api.Controllers
new OrganizationUserBulkResponseModel(r.Item1.Id, r.Item2))); new OrganizationUserBulkResponseModel(r.Item1.Id, r.Item2)));
} }
[Obsolete("2022-07-22 Moved to {id}/revoke endpoint")]
[HttpPatch("{id}/deactivate")] [HttpPatch("{id}/deactivate")]
[HttpPut("{id}/deactivate")] [HttpPut("{id}/deactivate")]
public async Task Deactivate(Guid orgId, Guid id) public async Task Deactivate(Guid orgId, Guid id)
{ {
await ActivateOrDeactivateUserAsync(orgId, id, _organizationService.DeactivateUserAsync); await RevokeAsync(orgId, id);
} }
[Obsolete("2022-07-22 Moved to /revoke endpoint")]
[HttpPatch("deactivate")] [HttpPatch("deactivate")]
[HttpPut("deactivate")] [HttpPut("deactivate")]
public async Task<ListResponseModel<OrganizationUserBulkResponseModel>> BulkDeactivate(Guid orgId, [FromBody] OrganizationUserBulkRequestModel model) public async Task<ListResponseModel<OrganizationUserBulkResponseModel>> BulkDeactivate(Guid orgId, [FromBody] OrganizationUserBulkRequestModel model)
{ {
return await ActivateOrDeactivateUsersAsync(orgId, model, _organizationService.DeactivateUsersAsync); return await BulkRevokeAsync(orgId, model);
} }
[Obsolete("2022-07-22 Moved to {id}/restore endpoint")]
[HttpPatch("{id}/activate")] [HttpPatch("{id}/activate")]
[HttpPut("{id}/activate")] [HttpPut("{id}/activate")]
public async Task Activate(Guid orgId, Guid id) public async Task Activate(Guid orgId, Guid id)
{ {
await ActivateOrDeactivateUserAsync(orgId, id, _organizationService.ActivateUserAsync); await RestoreAsync(orgId, id);
} }
[Obsolete("2022-07-22 Moved to /restore endpoint")]
[HttpPatch("activate")] [HttpPatch("activate")]
[HttpPut("activate")] [HttpPut("activate")]
public async Task<ListResponseModel<OrganizationUserBulkResponseModel>> BulkActivate(Guid orgId, [FromBody] OrganizationUserBulkRequestModel model) public async Task<ListResponseModel<OrganizationUserBulkResponseModel>> BulkActivate(Guid orgId, [FromBody] OrganizationUserBulkRequestModel model)
{ {
return await ActivateOrDeactivateUsersAsync(orgId, model, _organizationService.ActivateUsersAsync); return await BulkRestoreAsync(orgId, model);
} }
private async Task ActivateOrDeactivateUserAsync( [HttpPatch("{id}/revoke")]
[HttpPut("{id}/revoke")]
public async Task RevokeAsync(Guid orgId, Guid id)
{
await RestoreOrRevokeUserAsync(orgId, id, _organizationService.RevokeUserAsync);
}
[HttpPatch("revoke")]
[HttpPut("revoke")]
public async Task<ListResponseModel<OrganizationUserBulkResponseModel>> BulkRevokeAsync(Guid orgId, [FromBody] OrganizationUserBulkRequestModel model)
{
return await RestoreOrRevokeUsersAsync(orgId, model, _organizationService.RevokeUsersAsync);
}
[HttpPatch("{id}/restore")]
[HttpPut("{id}/restore")]
public async Task RestoreAsync(Guid orgId, Guid id)
{
await RestoreOrRevokeUserAsync(orgId, id, _organizationService.RestoreUserAsync);
}
[HttpPatch("restore")]
[HttpPut("restore")]
public async Task<ListResponseModel<OrganizationUserBulkResponseModel>> BulkRestoreAsync(Guid orgId, [FromBody] OrganizationUserBulkRequestModel model)
{
return await RestoreOrRevokeUsersAsync(orgId, model, _organizationService.RestoreUsersAsync);
}
private async Task RestoreOrRevokeUserAsync(
Guid orgId, Guid orgId,
Guid id, Guid id,
Func<OrganizationUser, Guid?, Task> statusAction) Func<OrganizationUser, Guid?, Task> statusAction)
@ -421,7 +453,7 @@ namespace Bit.Api.Controllers
await statusAction(orgUser, userId); await statusAction(orgUser, userId);
} }
private async Task<ListResponseModel<OrganizationUserBulkResponseModel>> ActivateOrDeactivateUsersAsync( private async Task<ListResponseModel<OrganizationUserBulkResponseModel>> RestoreOrRevokeUsersAsync(
Guid orgId, Guid orgId,
OrganizationUserBulkRequestModel model, OrganizationUserBulkRequestModel model,
Func<Guid, IEnumerable<Guid>, Guid?, Task<List<Tuple<OrganizationUser, string>>>> statusAction) Func<Guid, IEnumerable<Guid>, Guid?, Task<List<Tuple<OrganizationUser, string>>>> statusAction)

View File

@ -51,8 +51,8 @@
OrganizationUser_AdminResetPassword = 1508, OrganizationUser_AdminResetPassword = 1508,
OrganizationUser_ResetSsoLink = 1509, OrganizationUser_ResetSsoLink = 1509,
OrganizationUser_FirstSsoLogin = 1510, OrganizationUser_FirstSsoLogin = 1510,
OrganizationUser_Deactivated = 1511, OrganizationUser_Revoked = 1511,
OrganizationUser_Activated = 1512, OrganizationUser_Restored = 1512,
Organization_Updated = 1600, Organization_Updated = 1600,
Organization_PurgedVault = 1601, Organization_PurgedVault = 1601,

View File

@ -5,6 +5,6 @@
Invited = 0, Invited = 0,
Accepted = 1, Accepted = 1,
Confirmed = 2, Confirmed = 2,
Deactivated = -1, Revoked = -1,
} }
} }

View File

@ -36,7 +36,7 @@ namespace Bit.Core.Repositories
Task<OrganizationUser> GetByOrganizationEmailAsync(Guid organizationId, string email); Task<OrganizationUser> GetByOrganizationEmailAsync(Guid organizationId, string email);
Task<IEnumerable<OrganizationUserPublicKey>> GetManyPublicKeysByOrganizationUserAsync(Guid organizationId, IEnumerable<Guid> Ids); Task<IEnumerable<OrganizationUserPublicKey>> GetManyPublicKeysByOrganizationUserAsync(Guid organizationId, IEnumerable<Guid> Ids);
Task<IEnumerable<OrganizationUserUserDetails>> GetManyByMinimumRoleAsync(Guid organizationId, OrganizationUserType minRole); Task<IEnumerable<OrganizationUserUserDetails>> GetManyByMinimumRoleAsync(Guid organizationId, OrganizationUserType minRole);
Task DeactivateAsync(Guid id); Task RevokeAsync(Guid id);
Task ActivateAsync(Guid id, OrganizationUserStatusType status); Task RestoreAsync(Guid id, OrganizationUserStatusType status);
} }
} }

View File

@ -58,11 +58,11 @@ namespace Bit.Core.Services
Task DeleteSsoUserAsync(Guid userId, Guid? organizationId); Task DeleteSsoUserAsync(Guid userId, Guid? organizationId);
Task<Organization> UpdateOrganizationKeysAsync(Guid orgId, string publicKey, string privateKey); Task<Organization> UpdateOrganizationKeysAsync(Guid orgId, string publicKey, string privateKey);
Task<bool> HasConfirmedOwnersExceptAsync(Guid organizationId, IEnumerable<Guid> organizationUsersId, bool includeProvider = true); Task<bool> HasConfirmedOwnersExceptAsync(Guid organizationId, IEnumerable<Guid> organizationUsersId, bool includeProvider = true);
Task DeactivateUserAsync(OrganizationUser organizationUser, Guid? disablingUserId); Task RevokeUserAsync(OrganizationUser organizationUser, Guid? revokingUserId);
Task<List<Tuple<OrganizationUser, string>>> DeactivateUsersAsync(Guid organizationId, Task<List<Tuple<OrganizationUser, string>>> RevokeUsersAsync(Guid organizationId,
IEnumerable<Guid> organizationUserIds, Guid? disablingUserId); IEnumerable<Guid> organizationUserIds, Guid? revokingUserId);
Task ActivateUserAsync(OrganizationUser organizationUser, Guid? enablingUserId); Task RestoreUserAsync(OrganizationUser organizationUser, Guid? restoringUserId);
Task<List<Tuple<OrganizationUser, string>>> ActivateUsersAsync(Guid organizationId, Task<List<Tuple<OrganizationUser, string>>> RestoreUsersAsync(Guid organizationId,
IEnumerable<Guid> organizationUserIds, Guid? enablingUserId); IEnumerable<Guid> organizationUserIds, Guid? restoringUserId);
} }
} }

View File

@ -2213,19 +2213,19 @@ namespace Bit.Core.Services
} }
} }
public async Task DeactivateUserAsync(OrganizationUser organizationUser, Guid? disablingUserId) public async Task RevokeUserAsync(OrganizationUser organizationUser, Guid? revokingUserId)
{ {
if (organizationUser.Status == OrganizationUserStatusType.Deactivated) if (organizationUser.Status == OrganizationUserStatusType.Revoked)
{ {
throw new BadRequestException("Already revoked."); throw new BadRequestException("Already revoked.");
} }
if (disablingUserId.HasValue && organizationUser.UserId == disablingUserId.Value) if (revokingUserId.HasValue && organizationUser.UserId == revokingUserId.Value)
{ {
throw new BadRequestException("You cannot revoke yourself."); throw new BadRequestException("You cannot revoke yourself.");
} }
if (organizationUser.Type == OrganizationUserType.Owner && disablingUserId.HasValue && if (organizationUser.Type == OrganizationUserType.Owner && revokingUserId.HasValue &&
!await _currentContext.OrganizationOwner(organizationUser.OrganizationId)) !await _currentContext.OrganizationOwner(organizationUser.OrganizationId))
{ {
throw new BadRequestException("Only owners can revoke other owners."); throw new BadRequestException("Only owners can revoke other owners.");
@ -2236,13 +2236,13 @@ namespace Bit.Core.Services
throw new BadRequestException("Organization must have at least one confirmed owner."); throw new BadRequestException("Organization must have at least one confirmed owner.");
} }
await _organizationUserRepository.DeactivateAsync(organizationUser.Id); await _organizationUserRepository.RevokeAsync(organizationUser.Id);
organizationUser.Status = OrganizationUserStatusType.Deactivated; organizationUser.Status = OrganizationUserStatusType.Revoked;
await _eventService.LogOrganizationUserEventAsync(organizationUser, EventType.OrganizationUser_Deactivated); await _eventService.LogOrganizationUserEventAsync(organizationUser, EventType.OrganizationUser_Revoked);
} }
public async Task<List<Tuple<OrganizationUser, string>>> DeactivateUsersAsync(Guid organizationId, public async Task<List<Tuple<OrganizationUser, string>>> RevokeUsersAsync(Guid organizationId,
IEnumerable<Guid> organizationUserIds, Guid? disablingUserId) IEnumerable<Guid> organizationUserIds, Guid? revokingUserId)
{ {
var orgUsers = await _organizationUserRepository.GetManyAsync(organizationUserIds); var orgUsers = await _organizationUserRepository.GetManyAsync(organizationUserIds);
var filteredUsers = orgUsers.Where(u => u.OrganizationId == organizationId) var filteredUsers = orgUsers.Where(u => u.OrganizationId == organizationId)
@ -2259,7 +2259,7 @@ namespace Bit.Core.Services
} }
var deletingUserIsOwner = false; var deletingUserIsOwner = false;
if (disablingUserId.HasValue) if (revokingUserId.HasValue)
{ {
deletingUserIsOwner = await _currentContext.OrganizationOwner(organizationId); deletingUserIsOwner = await _currentContext.OrganizationOwner(organizationId);
} }
@ -2270,24 +2270,24 @@ namespace Bit.Core.Services
{ {
try try
{ {
if (organizationUser.Status == OrganizationUserStatusType.Deactivated) if (organizationUser.Status == OrganizationUserStatusType.Revoked)
{ {
throw new BadRequestException("Already revoked."); throw new BadRequestException("Already revoked.");
} }
if (disablingUserId.HasValue && organizationUser.UserId == disablingUserId) if (revokingUserId.HasValue && organizationUser.UserId == revokingUserId)
{ {
throw new BadRequestException("You cannot revoke yourself."); throw new BadRequestException("You cannot revoke yourself.");
} }
if (organizationUser.Type == OrganizationUserType.Owner && disablingUserId.HasValue && !deletingUserIsOwner) if (organizationUser.Type == OrganizationUserType.Owner && revokingUserId.HasValue && !deletingUserIsOwner)
{ {
throw new BadRequestException("Only owners can revoke other owners."); throw new BadRequestException("Only owners can revoke other owners.");
} }
await _organizationUserRepository.DeactivateAsync(organizationUser.Id); await _organizationUserRepository.RevokeAsync(organizationUser.Id);
organizationUser.Status = OrganizationUserStatusType.Deactivated; organizationUser.Status = OrganizationUserStatusType.Revoked;
await _eventService.LogOrganizationUserEventAsync(organizationUser, EventType.OrganizationUser_Deactivated); await _eventService.LogOrganizationUserEventAsync(organizationUser, EventType.OrganizationUser_Revoked);
result.Add(Tuple.Create(organizationUser, "")); result.Add(Tuple.Create(organizationUser, ""));
} }
@ -2300,19 +2300,19 @@ namespace Bit.Core.Services
return result; return result;
} }
public async Task ActivateUserAsync(OrganizationUser organizationUser, Guid? enablingUserId) public async Task RestoreUserAsync(OrganizationUser organizationUser, Guid? restoringUserId)
{ {
if (organizationUser.Status != OrganizationUserStatusType.Deactivated) if (organizationUser.Status != OrganizationUserStatusType.Revoked)
{ {
throw new BadRequestException("Already active."); throw new BadRequestException("Already active.");
} }
if (enablingUserId.HasValue && organizationUser.UserId == enablingUserId.Value) if (restoringUserId.HasValue && organizationUser.UserId == restoringUserId.Value)
{ {
throw new BadRequestException("You cannot restore yourself."); throw new BadRequestException("You cannot restore yourself.");
} }
if (organizationUser.Type == OrganizationUserType.Owner && enablingUserId.HasValue && if (organizationUser.Type == OrganizationUserType.Owner && restoringUserId.HasValue &&
!await _currentContext.OrganizationOwner(organizationUser.OrganizationId)) !await _currentContext.OrganizationOwner(organizationUser.OrganizationId))
{ {
throw new BadRequestException("Only owners can restore other owners."); throw new BadRequestException("Only owners can restore other owners.");
@ -2320,13 +2320,13 @@ namespace Bit.Core.Services
var status = GetPriorActiveOrganizationUserStatusType(organizationUser); var status = GetPriorActiveOrganizationUserStatusType(organizationUser);
await _organizationUserRepository.ActivateAsync(organizationUser.Id, status); await _organizationUserRepository.RestoreAsync(organizationUser.Id, status);
organizationUser.Status = status; organizationUser.Status = status;
await _eventService.LogOrganizationUserEventAsync(organizationUser, EventType.OrganizationUser_Activated); await _eventService.LogOrganizationUserEventAsync(organizationUser, EventType.OrganizationUser_Restored);
} }
public async Task<List<Tuple<OrganizationUser, string>>> ActivateUsersAsync(Guid organizationId, public async Task<List<Tuple<OrganizationUser, string>>> RestoreUsersAsync(Guid organizationId,
IEnumerable<Guid> organizationUserIds, Guid? enablingUserId) IEnumerable<Guid> organizationUserIds, Guid? restoringUserId)
{ {
var orgUsers = await _organizationUserRepository.GetManyAsync(organizationUserIds); var orgUsers = await _organizationUserRepository.GetManyAsync(organizationUserIds);
var filteredUsers = orgUsers.Where(u => u.OrganizationId == organizationId) var filteredUsers = orgUsers.Where(u => u.OrganizationId == organizationId)
@ -2338,7 +2338,7 @@ namespace Bit.Core.Services
} }
var deletingUserIsOwner = false; var deletingUserIsOwner = false;
if (enablingUserId.HasValue) if (restoringUserId.HasValue)
{ {
deletingUserIsOwner = await _currentContext.OrganizationOwner(organizationId); deletingUserIsOwner = await _currentContext.OrganizationOwner(organizationId);
} }
@ -2349,26 +2349,26 @@ namespace Bit.Core.Services
{ {
try try
{ {
if (organizationUser.Status != OrganizationUserStatusType.Deactivated) if (organizationUser.Status != OrganizationUserStatusType.Revoked)
{ {
throw new BadRequestException("Already active."); throw new BadRequestException("Already active.");
} }
if (enablingUserId.HasValue && organizationUser.UserId == enablingUserId) if (restoringUserId.HasValue && organizationUser.UserId == restoringUserId)
{ {
throw new BadRequestException("You cannot restore yourself."); throw new BadRequestException("You cannot restore yourself.");
} }
if (organizationUser.Type == OrganizationUserType.Owner && enablingUserId.HasValue && !deletingUserIsOwner) if (organizationUser.Type == OrganizationUserType.Owner && restoringUserId.HasValue && !deletingUserIsOwner)
{ {
throw new BadRequestException("Only owners can restore other owners."); throw new BadRequestException("Only owners can restore other owners.");
} }
var status = GetPriorActiveOrganizationUserStatusType(organizationUser); var status = GetPriorActiveOrganizationUserStatusType(organizationUser);
await _organizationUserRepository.ActivateAsync(organizationUser.Id, status); await _organizationUserRepository.RestoreAsync(organizationUser.Id, status);
organizationUser.Status = status; organizationUser.Status = status;
await _eventService.LogOrganizationUserEventAsync(organizationUser, EventType.OrganizationUser_Activated); await _eventService.LogOrganizationUserEventAsync(organizationUser, EventType.OrganizationUser_Restored);
result.Add(Tuple.Create(organizationUser, "")); result.Add(Tuple.Create(organizationUser, ""));
} }

View File

@ -406,7 +406,7 @@ namespace Bit.Infrastructure.Dapper.Repositories
} }
} }
public async Task DeactivateAsync(Guid id) public async Task RevokeAsync(Guid id)
{ {
using (var connection = new SqlConnection(ConnectionString)) using (var connection = new SqlConnection(ConnectionString))
{ {
@ -417,7 +417,7 @@ namespace Bit.Infrastructure.Dapper.Repositories
} }
} }
public async Task ActivateAsync(Guid id, OrganizationUserStatusType status) public async Task RestoreAsync(Guid id, OrganizationUserStatusType status)
{ {
using (var connection = new SqlConnection(ConnectionString)) using (var connection = new SqlConnection(ConnectionString))
{ {

View File

@ -424,7 +424,7 @@ namespace Bit.Infrastructure.EntityFramework.Repositories
} }
} }
public async Task DeactivateAsync(Guid id) public async Task RevokeAsync(Guid id)
{ {
using (var scope = ServiceScopeFactory.CreateScope()) using (var scope = ServiceScopeFactory.CreateScope())
{ {
@ -433,7 +433,7 @@ namespace Bit.Infrastructure.EntityFramework.Repositories
if (orgUser != null) if (orgUser != null)
{ {
dbContext.Update(orgUser); dbContext.Update(orgUser);
orgUser.Status = OrganizationUserStatusType.Deactivated; orgUser.Status = OrganizationUserStatusType.Revoked;
await dbContext.SaveChangesAsync(); await dbContext.SaveChangesAsync();
if (orgUser.UserId.HasValue) if (orgUser.UserId.HasValue)
{ {
@ -443,7 +443,7 @@ namespace Bit.Infrastructure.EntityFramework.Repositories
} }
} }
public async Task ActivateAsync(Guid id, OrganizationUserStatusType status) public async Task RestoreAsync(Guid id, OrganizationUserStatusType status)
{ {
using (var scope = ServiceScopeFactory.CreateScope()) using (var scope = ServiceScopeFactory.CreateScope())
{ {