mirror of
https://github.com/bitwarden/server.git
synced 2024-11-25 12:45:18 +01:00
[PM-1033] refactor: UpdateUserResetPasswordEnrollmentCommand
This commit is contained in:
parent
dc503b3035
commit
43df689c7f
@ -8,6 +8,8 @@ using Bit.Core.Exceptions;
|
|||||||
using Bit.Core.Models.Business;
|
using Bit.Core.Models.Business;
|
||||||
using Bit.Core.Models.Data.Organizations.OrganizationUsers;
|
using Bit.Core.Models.Data.Organizations.OrganizationUsers;
|
||||||
using Bit.Core.Models.Data.Organizations.Policies;
|
using Bit.Core.Models.Data.Organizations.Policies;
|
||||||
|
using Bit.Core.OrganizationFeatures.OrganizationUsers;
|
||||||
|
using Bit.Core.OrganizationFeatures.OrganizationUsers.Interfaces;
|
||||||
using Bit.Core.Repositories;
|
using Bit.Core.Repositories;
|
||||||
using Bit.Core.Services;
|
using Bit.Core.Services;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
@ -27,6 +29,7 @@ public class OrganizationUsersController : Controller
|
|||||||
private readonly IUserService _userService;
|
private readonly IUserService _userService;
|
||||||
private readonly IPolicyRepository _policyRepository;
|
private readonly IPolicyRepository _policyRepository;
|
||||||
private readonly ICurrentContext _currentContext;
|
private readonly ICurrentContext _currentContext;
|
||||||
|
private readonly IUpdateUserResetPasswordEnrollmentCommand _updateUserResetPasswordEnrollmentCommand;
|
||||||
|
|
||||||
public OrganizationUsersController(
|
public OrganizationUsersController(
|
||||||
IOrganizationRepository organizationRepository,
|
IOrganizationRepository organizationRepository,
|
||||||
@ -36,6 +39,7 @@ public class OrganizationUsersController : Controller
|
|||||||
IGroupRepository groupRepository,
|
IGroupRepository groupRepository,
|
||||||
IUserService userService,
|
IUserService userService,
|
||||||
IPolicyRepository policyRepository,
|
IPolicyRepository policyRepository,
|
||||||
|
IUpdateUserResetPasswordEnrollmentCommand updateUserResetPasswordEnrollmentCommand,
|
||||||
ICurrentContext currentContext)
|
ICurrentContext currentContext)
|
||||||
{
|
{
|
||||||
_organizationRepository = organizationRepository;
|
_organizationRepository = organizationRepository;
|
||||||
@ -45,6 +49,7 @@ public class OrganizationUsersController : Controller
|
|||||||
_groupRepository = groupRepository;
|
_groupRepository = groupRepository;
|
||||||
_userService = userService;
|
_userService = userService;
|
||||||
_policyRepository = policyRepository;
|
_policyRepository = policyRepository;
|
||||||
|
_updateUserResetPasswordEnrollmentCommand = updateUserResetPasswordEnrollmentCommand;
|
||||||
_currentContext = currentContext;
|
_currentContext = currentContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -213,7 +218,7 @@ public class OrganizationUsersController : Controller
|
|||||||
|
|
||||||
if (useMasterPasswordPolicy)
|
if (useMasterPasswordPolicy)
|
||||||
{
|
{
|
||||||
await _organizationService.UpdateUserResetPasswordEnrollmentAsync(orgId, user.Id, model.ResetPasswordKey, _userService, user.Id);
|
await _updateUserResetPasswordEnrollmentCommand.UpdateAsync(orgId, user.Id, model.ResetPasswordKey, user.Id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -314,8 +319,14 @@ public class OrganizationUsersController : Controller
|
|||||||
}
|
}
|
||||||
|
|
||||||
var callingUserId = user.Id;
|
var callingUserId = user.Id;
|
||||||
await _organizationService.UpdateUserResetPasswordEnrollmentAsync(
|
await _updateUserResetPasswordEnrollmentCommand.UpdateAsync(
|
||||||
new Guid(orgId), new Guid(userId), model.ResetPasswordKey, _userService, callingUserId);
|
new Guid(orgId), new Guid(userId), model.ResetPasswordKey, callingUserId);
|
||||||
|
|
||||||
|
//if (orgUser.Status == OrganizationUserStatusType.Invited)
|
||||||
|
//{
|
||||||
|
// var user = await _userRepository.GetByIdAsync(userId);
|
||||||
|
// await _organizationService.AcceptUserAsync(orgUser, user, _userService);
|
||||||
|
//}
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpPut("{id}/reset-password")]
|
[HttpPut("{id}/reset-password")]
|
||||||
|
@ -15,6 +15,8 @@ using Bit.Core.OrganizationFeatures.OrganizationSponsorships.FamiliesForEnterpri
|
|||||||
using Bit.Core.OrganizationFeatures.OrganizationSponsorships.FamiliesForEnterprise.Cloud;
|
using Bit.Core.OrganizationFeatures.OrganizationSponsorships.FamiliesForEnterprise.Cloud;
|
||||||
using Bit.Core.OrganizationFeatures.OrganizationSponsorships.FamiliesForEnterprise.Interfaces;
|
using Bit.Core.OrganizationFeatures.OrganizationSponsorships.FamiliesForEnterprise.Interfaces;
|
||||||
using Bit.Core.OrganizationFeatures.OrganizationSponsorships.FamiliesForEnterprise.SelfHosted;
|
using Bit.Core.OrganizationFeatures.OrganizationSponsorships.FamiliesForEnterprise.SelfHosted;
|
||||||
|
using Bit.Core.OrganizationFeatures.OrganizationUsers;
|
||||||
|
using Bit.Core.OrganizationFeatures.OrganizationUsers.Interfaces;
|
||||||
using Bit.Core.Services;
|
using Bit.Core.Services;
|
||||||
using Bit.Core.Settings;
|
using Bit.Core.Settings;
|
||||||
using Bit.Core.Tokens;
|
using Bit.Core.Tokens;
|
||||||
@ -38,6 +40,7 @@ public static class OrganizationServiceCollectionExtensions
|
|||||||
services.AddOrganizationGroupCommands();
|
services.AddOrganizationGroupCommands();
|
||||||
services.AddOrganizationLicenseCommandsQueries();
|
services.AddOrganizationLicenseCommandsQueries();
|
||||||
services.AddOrganizationDomainCommandsQueries();
|
services.AddOrganizationDomainCommandsQueries();
|
||||||
|
services.AddOrganizationUserCommandsQueries();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void AddOrganizationConnectionCommands(this IServiceCollection services)
|
private static void AddOrganizationConnectionCommands(this IServiceCollection services)
|
||||||
@ -107,6 +110,11 @@ public static class OrganizationServiceCollectionExtensions
|
|||||||
services.AddScoped<IDeleteOrganizationDomainCommand, DeleteOrganizationDomainCommand>();
|
services.AddScoped<IDeleteOrganizationDomainCommand, DeleteOrganizationDomainCommand>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void AddOrganizationUserCommandsQueries(this IServiceCollection services)
|
||||||
|
{
|
||||||
|
services.AddScoped<IUpdateUserResetPasswordEnrollmentCommand, UpdateUserResetPasswordEnrollmentCommand>();
|
||||||
|
}
|
||||||
|
|
||||||
private static void AddTokenizers(this IServiceCollection services)
|
private static void AddTokenizers(this IServiceCollection services)
|
||||||
{
|
{
|
||||||
services.AddSingleton<IDataProtectorTokenFactory<OrganizationSponsorshipOfferTokenable>>(serviceProvider =>
|
services.AddSingleton<IDataProtectorTokenFactory<OrganizationSponsorshipOfferTokenable>>(serviceProvider =>
|
||||||
|
@ -0,0 +1,7 @@
|
|||||||
|
namespace Bit.Core.OrganizationFeatures.OrganizationUsers.Interfaces;
|
||||||
|
|
||||||
|
public interface IUpdateUserResetPasswordEnrollmentCommand
|
||||||
|
{
|
||||||
|
Task UpdateAsync(Guid organizationId, Guid userId, string resetPasswordKey, Guid? callingUserId);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,73 @@
|
|||||||
|
using System.Text.Json;
|
||||||
|
using Bit.Core.Enums;
|
||||||
|
using Bit.Core.Exceptions;
|
||||||
|
using Bit.Core.Models.Data.Organizations.Policies;
|
||||||
|
using Bit.Core.OrganizationFeatures.OrganizationUsers.Interfaces;
|
||||||
|
using Bit.Core.Repositories;
|
||||||
|
using Bit.Core.Services;
|
||||||
|
using Bit.Core.Utilities;
|
||||||
|
|
||||||
|
namespace Bit.Core.OrganizationFeatures.OrganizationUsers;
|
||||||
|
|
||||||
|
public class UpdateUserResetPasswordEnrollmentCommand : IUpdateUserResetPasswordEnrollmentCommand
|
||||||
|
{
|
||||||
|
private readonly IOrganizationRepository _organizationRepository;
|
||||||
|
private readonly IOrganizationUserRepository _organizationUserRepository;
|
||||||
|
private readonly IEventService _eventService;
|
||||||
|
private readonly IPolicyRepository _policyRepository;
|
||||||
|
|
||||||
|
public UpdateUserResetPasswordEnrollmentCommand(
|
||||||
|
IOrganizationRepository organizationRepository,
|
||||||
|
IOrganizationUserRepository organizationUserRepository,
|
||||||
|
IEventService eventService,
|
||||||
|
IPolicyRepository policyRepository)
|
||||||
|
{
|
||||||
|
_organizationRepository = organizationRepository;
|
||||||
|
_organizationUserRepository = organizationUserRepository;
|
||||||
|
_eventService = eventService;
|
||||||
|
_policyRepository = policyRepository;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task UpdateAsync(Guid organizationId, Guid userId, string resetPasswordKey, Guid? callingUserId)
|
||||||
|
{
|
||||||
|
// Org User must be the same as the calling user and the organization ID associated with the user must match passed org ID
|
||||||
|
var orgUser = await _organizationUserRepository.GetByOrganizationAsync(organizationId, userId);
|
||||||
|
if (!callingUserId.HasValue || orgUser == null || orgUser.UserId != callingUserId.Value ||
|
||||||
|
orgUser.OrganizationId != organizationId)
|
||||||
|
{
|
||||||
|
throw new BadRequestException("User not valid.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure the organization has the ability to use password reset
|
||||||
|
var org = await _organizationRepository.GetByIdAsync(organizationId);
|
||||||
|
if (org == null || !org.UseResetPassword)
|
||||||
|
{
|
||||||
|
throw new BadRequestException("Organization does not allow password reset enrollment.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure the organization has the policy enabled
|
||||||
|
var resetPasswordPolicy =
|
||||||
|
await _policyRepository.GetByOrganizationIdTypeAsync(organizationId, PolicyType.ResetPassword);
|
||||||
|
if (resetPasswordPolicy == null || !resetPasswordPolicy.Enabled)
|
||||||
|
{
|
||||||
|
throw new BadRequestException("Organization does not have the password reset policy enabled.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Block the user from withdrawal if auto enrollment is enabled
|
||||||
|
if (resetPasswordKey == null && resetPasswordPolicy.Data != null)
|
||||||
|
{
|
||||||
|
var data = JsonSerializer.Deserialize<ResetPasswordDataModel>(resetPasswordPolicy.Data, JsonHelpers.IgnoreCase);
|
||||||
|
|
||||||
|
if (data?.AutoEnrollEnabled ?? false)
|
||||||
|
{
|
||||||
|
throw new BadRequestException("Due to an Enterprise Policy, you are not allowed to withdraw from Password Reset.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
orgUser.ResetPasswordKey = resetPasswordKey;
|
||||||
|
await _organizationUserRepository.ReplaceAsync(orgUser);
|
||||||
|
await _eventService.LogOrganizationUserEventAsync(orgUser, resetPasswordKey != null ?
|
||||||
|
EventType.OrganizationUser_ResetPassword_Enroll : EventType.OrganizationUser_ResetPassword_Withdraw);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -55,7 +55,6 @@ public interface IOrganizationService
|
|||||||
Task<List<Tuple<OrganizationUser, string>>> DeleteUsersAsync(Guid organizationId,
|
Task<List<Tuple<OrganizationUser, string>>> DeleteUsersAsync(Guid organizationId,
|
||||||
IEnumerable<Guid> organizationUserIds, Guid? deletingUserId);
|
IEnumerable<Guid> organizationUserIds, Guid? deletingUserId);
|
||||||
Task UpdateUserGroupsAsync(OrganizationUser organizationUser, IEnumerable<Guid> groupIds, Guid? loggedInUserId);
|
Task UpdateUserGroupsAsync(OrganizationUser organizationUser, IEnumerable<Guid> groupIds, Guid? loggedInUserId);
|
||||||
Task UpdateUserResetPasswordEnrollmentAsync(Guid organizationId, Guid userId, string resetPasswordKey, IUserService userService, Guid? callingUserId);
|
|
||||||
Task ImportAsync(Guid organizationId, Guid? importingUserId, IEnumerable<ImportedGroup> groups,
|
Task ImportAsync(Guid organizationId, Guid? importingUserId, IEnumerable<ImportedGroup> groups,
|
||||||
IEnumerable<ImportedOrganizationUser> newUsers, IEnumerable<string> removeUserExternalIds,
|
IEnumerable<ImportedOrganizationUser> newUsers, IEnumerable<string> removeUserExternalIds,
|
||||||
bool overwriteExisting);
|
bool overwriteExisting);
|
||||||
|
@ -11,7 +11,6 @@ using Bit.Core.Enums.Provider;
|
|||||||
using Bit.Core.Exceptions;
|
using Bit.Core.Exceptions;
|
||||||
using Bit.Core.Models.Business;
|
using Bit.Core.Models.Business;
|
||||||
using Bit.Core.Models.Data;
|
using Bit.Core.Models.Data;
|
||||||
using Bit.Core.Models.Data.Organizations.Policies;
|
|
||||||
using Bit.Core.Repositories;
|
using Bit.Core.Repositories;
|
||||||
using Bit.Core.Settings;
|
using Bit.Core.Settings;
|
||||||
using Bit.Core.Tools.Enums;
|
using Bit.Core.Tools.Enums;
|
||||||
@ -38,7 +37,6 @@ public class OrganizationService : IOrganizationService
|
|||||||
private readonly IDeviceRepository _deviceRepository;
|
private readonly IDeviceRepository _deviceRepository;
|
||||||
private readonly ILicensingService _licensingService;
|
private readonly ILicensingService _licensingService;
|
||||||
private readonly IEventService _eventService;
|
private readonly IEventService _eventService;
|
||||||
private readonly IInstallationRepository _installationRepository;
|
|
||||||
private readonly IApplicationCacheService _applicationCacheService;
|
private readonly IApplicationCacheService _applicationCacheService;
|
||||||
private readonly IPaymentService _paymentService;
|
private readonly IPaymentService _paymentService;
|
||||||
private readonly IPolicyRepository _policyRepository;
|
private readonly IPolicyRepository _policyRepository;
|
||||||
@ -67,7 +65,6 @@ public class OrganizationService : IOrganizationService
|
|||||||
IDeviceRepository deviceRepository,
|
IDeviceRepository deviceRepository,
|
||||||
ILicensingService licensingService,
|
ILicensingService licensingService,
|
||||||
IEventService eventService,
|
IEventService eventService,
|
||||||
IInstallationRepository installationRepository,
|
|
||||||
IApplicationCacheService applicationCacheService,
|
IApplicationCacheService applicationCacheService,
|
||||||
IPaymentService paymentService,
|
IPaymentService paymentService,
|
||||||
IPolicyRepository policyRepository,
|
IPolicyRepository policyRepository,
|
||||||
@ -95,7 +92,6 @@ public class OrganizationService : IOrganizationService
|
|||||||
_deviceRepository = deviceRepository;
|
_deviceRepository = deviceRepository;
|
||||||
_licensingService = licensingService;
|
_licensingService = licensingService;
|
||||||
_eventService = eventService;
|
_eventService = eventService;
|
||||||
_installationRepository = installationRepository;
|
|
||||||
_applicationCacheService = applicationCacheService;
|
_applicationCacheService = applicationCacheService;
|
||||||
_paymentService = paymentService;
|
_paymentService = paymentService;
|
||||||
_policyRepository = policyRepository;
|
_policyRepository = policyRepository;
|
||||||
@ -1734,54 +1730,6 @@ public class OrganizationService : IOrganizationService
|
|||||||
EventType.OrganizationUser_UpdatedGroups);
|
EventType.OrganizationUser_UpdatedGroups);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task UpdateUserResetPasswordEnrollmentAsync(Guid organizationId, Guid userId, string resetPasswordKey, IUserService userService, Guid? callingUserId)
|
|
||||||
{
|
|
||||||
// Org User must be the same as the calling user and the organization ID associated with the user must match passed org ID
|
|
||||||
var orgUser = await _organizationUserRepository.GetByOrganizationAsync(organizationId, userId);
|
|
||||||
if (!callingUserId.HasValue || orgUser == null || orgUser.UserId != callingUserId.Value ||
|
|
||||||
orgUser.OrganizationId != organizationId)
|
|
||||||
{
|
|
||||||
throw new BadRequestException("User not valid.");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Make sure the organization has the ability to use password reset
|
|
||||||
var org = await _organizationRepository.GetByIdAsync(organizationId);
|
|
||||||
if (org == null || !org.UseResetPassword)
|
|
||||||
{
|
|
||||||
throw new BadRequestException("Organization does not allow password reset enrollment.");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Make sure the organization has the policy enabled
|
|
||||||
var resetPasswordPolicy =
|
|
||||||
await _policyRepository.GetByOrganizationIdTypeAsync(organizationId, PolicyType.ResetPassword);
|
|
||||||
if (resetPasswordPolicy == null || !resetPasswordPolicy.Enabled)
|
|
||||||
{
|
|
||||||
throw new BadRequestException("Organization does not have the password reset policy enabled.");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Block the user from withdrawal if auto enrollment is enabled
|
|
||||||
if (resetPasswordKey == null && resetPasswordPolicy.Data != null)
|
|
||||||
{
|
|
||||||
var data = JsonSerializer.Deserialize<ResetPasswordDataModel>(resetPasswordPolicy.Data, JsonHelpers.IgnoreCase);
|
|
||||||
|
|
||||||
if (data?.AutoEnrollEnabled ?? false)
|
|
||||||
{
|
|
||||||
throw new BadRequestException("Due to an Enterprise Policy, you are not allowed to withdraw from Password Reset.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
orgUser.ResetPasswordKey = resetPasswordKey;
|
|
||||||
await _organizationUserRepository.ReplaceAsync(orgUser);
|
|
||||||
await _eventService.LogOrganizationUserEventAsync(orgUser, resetPasswordKey != null ?
|
|
||||||
EventType.OrganizationUser_ResetPassword_Enroll : EventType.OrganizationUser_ResetPassword_Withdraw);
|
|
||||||
|
|
||||||
if (orgUser.Status == OrganizationUserStatusType.Invited)
|
|
||||||
{
|
|
||||||
var user = await _userRepository.GetByIdAsync(userId);
|
|
||||||
await AcceptUserAsync(orgUser, user, userService);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<OrganizationUser> InviteUserAsync(Guid organizationId, Guid? invitingUserId, string email,
|
public async Task<OrganizationUser> InviteUserAsync(Guid organizationId, Guid? invitingUserId, string email,
|
||||||
OrganizationUserType type, bool accessAll, string externalId, IEnumerable<CollectionAccessSelection> collections,
|
OrganizationUserType type, bool accessAll, string externalId, IEnumerable<CollectionAccessSelection> collections,
|
||||||
IEnumerable<Guid> groups)
|
IEnumerable<Guid> groups)
|
||||||
|
Loading…
Reference in New Issue
Block a user