From f6a18db582c8fdcd01c9b0aaae247517ee9f659e Mon Sep 17 00:00:00 2001 From: Thomas Rittson <31796059+eliykat@users.noreply.github.com> Date: Mon, 25 Jul 2022 10:47:44 +1000 Subject: [PATCH] [EC-338] Update SCIM code naming conventions (revoked/restore) (#2140) * Keep old endpoints but mark as deprecated * Do not change existing sproc naming --- .../Scim/Controllers/v2/UsersController.cs | 16 ++--- .../src/Scim/Models/ScimUserResponseModel.cs | 2 +- .../OrganizationUsersController.cs | 44 ++++++++++++-- src/Core/Enums/EventType.cs | 4 +- src/Core/Enums/OrganizationUserStatusType.cs | 2 +- .../IOrganizationUserRepository.cs | 4 +- src/Core/Services/IOrganizationService.cs | 12 ++-- .../Implementations/OrganizationService.cs | 60 +++++++++---------- .../OrganizationUserRepository.cs | 4 +- .../OrganizationUserRepository.cs | 6 +- 10 files changed, 93 insertions(+), 61 deletions(-) diff --git a/bitwarden_license/src/Scim/Controllers/v2/UsersController.cs b/bitwarden_license/src/Scim/Controllers/v2/UsersController.cs index 0a068f916..ca01c8ee1 100644 --- a/bitwarden_license/src/Scim/Controllers/v2/UsersController.cs +++ b/bitwarden_license/src/Scim/Controllers/v2/UsersController.cs @@ -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 @@ -227,14 +227,14 @@ namespace Bit.Scim.Controllers.v2 if (replaceOp.Value.TryGetProperty("active", out var activeProperty)) { 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; } - 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; } } diff --git a/bitwarden_license/src/Scim/Models/ScimUserResponseModel.cs b/bitwarden_license/src/Scim/Models/ScimUserResponseModel.cs index 12401de9d..6f9650661 100644 --- a/bitwarden_license/src/Scim/Models/ScimUserResponseModel.cs +++ b/bitwarden_license/src/Scim/Models/ScimUserResponseModel.cs @@ -20,7 +20,7 @@ namespace Bit.Scim.Models DisplayName = orgUser.Name; Emails = new List { new EmailModel(orgUser.Email) }; Name = new NameModel(orgUser.Name); - Active = orgUser.Status != Core.Enums.OrganizationUserStatusType.Deactivated; + Active = orgUser.Status != Core.Enums.OrganizationUserStatusType.Revoked; } public string Id { get; set; } diff --git a/src/Api/Controllers/OrganizationUsersController.cs b/src/Api/Controllers/OrganizationUsersController.cs index 3ed84311e..1df8aaef4 100644 --- a/src/Api/Controllers/OrganizationUsersController.cs +++ b/src/Api/Controllers/OrganizationUsersController.cs @@ -373,35 +373,67 @@ namespace Bit.Api.Controllers new OrganizationUserBulkResponseModel(r.Item1.Id, r.Item2))); } + [Obsolete("2022-07-22 Moved to {id}/revoke endpoint")] [HttpPatch("{id}/deactivate")] [HttpPut("{id}/deactivate")] 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")] [HttpPut("deactivate")] public async Task> 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")] [HttpPut("{id}/activate")] 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")] [HttpPut("activate")] public async Task> 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> 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> BulkRestoreAsync(Guid orgId, [FromBody] OrganizationUserBulkRequestModel model) + { + return await RestoreOrRevokeUsersAsync(orgId, model, _organizationService.RestoreUsersAsync); + } + + private async Task RestoreOrRevokeUserAsync( Guid orgId, Guid id, Func statusAction) @@ -421,7 +453,7 @@ namespace Bit.Api.Controllers await statusAction(orgUser, userId); } - private async Task> ActivateOrDeactivateUsersAsync( + private async Task> RestoreOrRevokeUsersAsync( Guid orgId, OrganizationUserBulkRequestModel model, Func, Guid?, Task>>> statusAction) diff --git a/src/Core/Enums/EventType.cs b/src/Core/Enums/EventType.cs index 56a627a04..acce76c33 100644 --- a/src/Core/Enums/EventType.cs +++ b/src/Core/Enums/EventType.cs @@ -51,8 +51,8 @@ OrganizationUser_AdminResetPassword = 1508, OrganizationUser_ResetSsoLink = 1509, OrganizationUser_FirstSsoLogin = 1510, - OrganizationUser_Deactivated = 1511, - OrganizationUser_Activated = 1512, + OrganizationUser_Revoked = 1511, + OrganizationUser_Restored = 1512, Organization_Updated = 1600, Organization_PurgedVault = 1601, diff --git a/src/Core/Enums/OrganizationUserStatusType.cs b/src/Core/Enums/OrganizationUserStatusType.cs index 592d5bcd7..8c39c053f 100644 --- a/src/Core/Enums/OrganizationUserStatusType.cs +++ b/src/Core/Enums/OrganizationUserStatusType.cs @@ -5,6 +5,6 @@ Invited = 0, Accepted = 1, Confirmed = 2, - Deactivated = -1, + Revoked = -1, } } diff --git a/src/Core/Repositories/IOrganizationUserRepository.cs b/src/Core/Repositories/IOrganizationUserRepository.cs index 6b3438e74..8597adb52 100644 --- a/src/Core/Repositories/IOrganizationUserRepository.cs +++ b/src/Core/Repositories/IOrganizationUserRepository.cs @@ -36,7 +36,7 @@ namespace Bit.Core.Repositories Task GetByOrganizationEmailAsync(Guid organizationId, string email); Task> GetManyPublicKeysByOrganizationUserAsync(Guid organizationId, IEnumerable Ids); Task> GetManyByMinimumRoleAsync(Guid organizationId, OrganizationUserType minRole); - Task DeactivateAsync(Guid id); - Task ActivateAsync(Guid id, OrganizationUserStatusType status); + Task RevokeAsync(Guid id); + Task RestoreAsync(Guid id, OrganizationUserStatusType status); } } diff --git a/src/Core/Services/IOrganizationService.cs b/src/Core/Services/IOrganizationService.cs index a2a12a66d..a0dbe1e63 100644 --- a/src/Core/Services/IOrganizationService.cs +++ b/src/Core/Services/IOrganizationService.cs @@ -58,11 +58,11 @@ namespace Bit.Core.Services Task DeleteSsoUserAsync(Guid userId, Guid? organizationId); Task UpdateOrganizationKeysAsync(Guid orgId, string publicKey, string privateKey); Task HasConfirmedOwnersExceptAsync(Guid organizationId, IEnumerable organizationUsersId, bool includeProvider = true); - Task DeactivateUserAsync(OrganizationUser organizationUser, Guid? disablingUserId); - Task>> DeactivateUsersAsync(Guid organizationId, - IEnumerable organizationUserIds, Guid? disablingUserId); - Task ActivateUserAsync(OrganizationUser organizationUser, Guid? enablingUserId); - Task>> ActivateUsersAsync(Guid organizationId, - IEnumerable organizationUserIds, Guid? enablingUserId); + Task RevokeUserAsync(OrganizationUser organizationUser, Guid? revokingUserId); + Task>> RevokeUsersAsync(Guid organizationId, + IEnumerable organizationUserIds, Guid? revokingUserId); + Task RestoreUserAsync(OrganizationUser organizationUser, Guid? restoringUserId); + Task>> RestoreUsersAsync(Guid organizationId, + IEnumerable organizationUserIds, Guid? restoringUserId); } } diff --git a/src/Core/Services/Implementations/OrganizationService.cs b/src/Core/Services/Implementations/OrganizationService.cs index 6326d2713..da26f1fc2 100644 --- a/src/Core/Services/Implementations/OrganizationService.cs +++ b/src/Core/Services/Implementations/OrganizationService.cs @@ -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."); } - if (disablingUserId.HasValue && organizationUser.UserId == disablingUserId.Value) + if (revokingUserId.HasValue && organizationUser.UserId == revokingUserId.Value) { 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)) { 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."); } - await _organizationUserRepository.DeactivateAsync(organizationUser.Id); - organizationUser.Status = OrganizationUserStatusType.Deactivated; - await _eventService.LogOrganizationUserEventAsync(organizationUser, EventType.OrganizationUser_Deactivated); + await _organizationUserRepository.RevokeAsync(organizationUser.Id); + organizationUser.Status = OrganizationUserStatusType.Revoked; + await _eventService.LogOrganizationUserEventAsync(organizationUser, EventType.OrganizationUser_Revoked); } - public async Task>> DeactivateUsersAsync(Guid organizationId, - IEnumerable organizationUserIds, Guid? disablingUserId) + public async Task>> RevokeUsersAsync(Guid organizationId, + IEnumerable organizationUserIds, Guid? revokingUserId) { var orgUsers = await _organizationUserRepository.GetManyAsync(organizationUserIds); var filteredUsers = orgUsers.Where(u => u.OrganizationId == organizationId) @@ -2259,7 +2259,7 @@ namespace Bit.Core.Services } var deletingUserIsOwner = false; - if (disablingUserId.HasValue) + if (revokingUserId.HasValue) { deletingUserIsOwner = await _currentContext.OrganizationOwner(organizationId); } @@ -2270,24 +2270,24 @@ namespace Bit.Core.Services { try { - if (organizationUser.Status == OrganizationUserStatusType.Deactivated) + if (organizationUser.Status == OrganizationUserStatusType.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."); } - 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."); } - await _organizationUserRepository.DeactivateAsync(organizationUser.Id); - organizationUser.Status = OrganizationUserStatusType.Deactivated; - await _eventService.LogOrganizationUserEventAsync(organizationUser, EventType.OrganizationUser_Deactivated); + await _organizationUserRepository.RevokeAsync(organizationUser.Id); + organizationUser.Status = OrganizationUserStatusType.Revoked; + await _eventService.LogOrganizationUserEventAsync(organizationUser, EventType.OrganizationUser_Revoked); result.Add(Tuple.Create(organizationUser, "")); } @@ -2300,19 +2300,19 @@ namespace Bit.Core.Services 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."); } - if (enablingUserId.HasValue && organizationUser.UserId == enablingUserId.Value) + if (restoringUserId.HasValue && organizationUser.UserId == restoringUserId.Value) { 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)) { throw new BadRequestException("Only owners can restore other owners."); @@ -2320,13 +2320,13 @@ namespace Bit.Core.Services var status = GetPriorActiveOrganizationUserStatusType(organizationUser); - await _organizationUserRepository.ActivateAsync(organizationUser.Id, status); + await _organizationUserRepository.RestoreAsync(organizationUser.Id, status); organizationUser.Status = status; - await _eventService.LogOrganizationUserEventAsync(organizationUser, EventType.OrganizationUser_Activated); + await _eventService.LogOrganizationUserEventAsync(organizationUser, EventType.OrganizationUser_Restored); } - public async Task>> ActivateUsersAsync(Guid organizationId, - IEnumerable organizationUserIds, Guid? enablingUserId) + public async Task>> RestoreUsersAsync(Guid organizationId, + IEnumerable organizationUserIds, Guid? restoringUserId) { var orgUsers = await _organizationUserRepository.GetManyAsync(organizationUserIds); var filteredUsers = orgUsers.Where(u => u.OrganizationId == organizationId) @@ -2338,7 +2338,7 @@ namespace Bit.Core.Services } var deletingUserIsOwner = false; - if (enablingUserId.HasValue) + if (restoringUserId.HasValue) { deletingUserIsOwner = await _currentContext.OrganizationOwner(organizationId); } @@ -2349,26 +2349,26 @@ namespace Bit.Core.Services { try { - if (organizationUser.Status != OrganizationUserStatusType.Deactivated) + if (organizationUser.Status != OrganizationUserStatusType.Revoked) { throw new BadRequestException("Already active."); } - if (enablingUserId.HasValue && organizationUser.UserId == enablingUserId) + if (restoringUserId.HasValue && organizationUser.UserId == restoringUserId) { 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."); } var status = GetPriorActiveOrganizationUserStatusType(organizationUser); - await _organizationUserRepository.ActivateAsync(organizationUser.Id, status); + await _organizationUserRepository.RestoreAsync(organizationUser.Id, status); organizationUser.Status = status; - await _eventService.LogOrganizationUserEventAsync(organizationUser, EventType.OrganizationUser_Activated); + await _eventService.LogOrganizationUserEventAsync(organizationUser, EventType.OrganizationUser_Restored); result.Add(Tuple.Create(organizationUser, "")); } diff --git a/src/Infrastructure.Dapper/Repositories/OrganizationUserRepository.cs b/src/Infrastructure.Dapper/Repositories/OrganizationUserRepository.cs index 913cd8f43..856fcb7a4 100644 --- a/src/Infrastructure.Dapper/Repositories/OrganizationUserRepository.cs +++ b/src/Infrastructure.Dapper/Repositories/OrganizationUserRepository.cs @@ -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)) { @@ -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)) { diff --git a/src/Infrastructure.EntityFramework/Repositories/OrganizationUserRepository.cs b/src/Infrastructure.EntityFramework/Repositories/OrganizationUserRepository.cs index 226c51c0f..0c0383182 100644 --- a/src/Infrastructure.EntityFramework/Repositories/OrganizationUserRepository.cs +++ b/src/Infrastructure.EntityFramework/Repositories/OrganizationUserRepository.cs @@ -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()) { @@ -433,7 +433,7 @@ namespace Bit.Infrastructure.EntityFramework.Repositories if (orgUser != null) { dbContext.Update(orgUser); - orgUser.Status = OrganizationUserStatusType.Deactivated; + orgUser.Status = OrganizationUserStatusType.Revoked; await dbContext.SaveChangesAsync(); 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()) {