1
0
mirror of https://github.com/bitwarden/server.git synced 2025-07-01 08:02:49 -05:00

[Reset Password] Admin reset actions (#1272)

* [Reset Password] Admin reset actions

* Updated thrown except for permission collision

* Updated GET/PUT password reset to use orgUser.Id for db operations
This commit is contained in:
Vincent Salucci
2021-04-20 16:58:57 -05:00
committed by GitHub
parent ba36afe69c
commit 477f679fc6
7 changed files with 155 additions and 2 deletions

View File

@ -9,7 +9,9 @@ using Bit.Core.Exceptions;
using Bit.Core.Services;
using Bit.Core.Context;
using System.Collections.Generic;
using Bit.Core.Enums;
using Bit.Core.Models.Business;
using Bit.Core.Models.Data;
namespace Bit.Api.Controllers
{
@ -87,6 +89,33 @@ namespace Bit.Api.Controllers
var responses = groupIds.Select(g => g.ToString());
return responses;
}
[HttpGet("{id}/reset-password-details")]
public async Task<OrganizationUserResetPasswordDetailsResponseModel> GetResetPasswordDetails(string orgId, string id)
{
// Make sure the calling user can reset passwords for this org
var orgGuidId = new Guid(orgId);
if (!_currentContext.ManageResetPassword(orgGuidId))
{
throw new NotFoundException();
}
var organizationUser = await _organizationUserRepository.GetByIdAsync(new Guid(id));
if (organizationUser == null || !organizationUser.UserId.HasValue)
{
throw new NotFoundException();
}
// Retrieve data necessary for response (KDF, KDF Iterations, ResetPasswordKey)
// TODO Revisit this and create SPROC to reduce DB calls
var user = await _userService.GetUserByIdAsync(organizationUser.UserId.Value);
if (user == null)
{
throw new NotFoundException();
}
return new OrganizationUserResetPasswordDetailsResponseModel(new OrganizationUserResetPasswordDetails(organizationUser, user));
}
[HttpPost("invite")]
public async Task Invite(string orgId, [FromBody]OrganizationUserInviteRequestModel model)
@ -187,6 +216,46 @@ namespace Bit.Api.Controllers
var callingUserId = _userService.GetProperUserId(User);
await _organizationService.UpdateUserResetPasswordEnrollmentAsync(new Guid(orgId), new Guid(userId), model.ResetPasswordKey, callingUserId);
}
[HttpPut("{id}/reset-password")]
public async Task PutResetPassword(string orgId, string id, [FromBody]OrganizationUserResetPasswordRequestModel model)
{
var orgGuidId = new Guid(orgId);
// Calling user must have Manage Reset Password permission
if (!_currentContext.ManageResetPassword(orgGuidId))
{
throw new NotFoundException();
}
var orgUser = await _organizationUserRepository.GetByIdAsync(new Guid(id));
if (orgUser == null || orgUser.Status != OrganizationUserStatusType.Confirmed ||
orgUser.OrganizationId != orgGuidId || string.IsNullOrEmpty(orgUser.ResetPasswordKey) ||
!orgUser.UserId.HasValue)
{
throw new BadRequestException("Organization User not valid");
}
var user = await _userService.GetUserByIdAsync(orgUser.UserId.Value);
if (user == null)
{
throw new NotFoundException();
}
var result = await _userService.AdminResetPasswordAsync(user, model.NewMasterPasswordHash, model.Key);
if (result.Succeeded)
{
return;
}
foreach (var error in result.Errors)
{
ModelState.AddModelError(string.Empty, error.Description);
}
await Task.Delay(2000);
throw new BadRequestException(ModelState);
}
[HttpDelete("{id}")]
[HttpPost("{id}/delete")]