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

@ -0,0 +1,13 @@
using System.ComponentModel.DataAnnotations;
namespace Bit.Core.Models.Api
{
public class OrganizationUserResetPasswordRequestModel
{
[Required]
[StringLength(300)]
public string NewMasterPasswordHash { get; set; }
[Required]
public string Key { get; set; }
}
}

View File

@ -23,6 +23,7 @@ namespace Bit.Core.Models.Api
Status = organizationUser.Status;
AccessAll = organizationUser.AccessAll;
Permissions = CoreHelpers.LoadClassFromJsonData<Permissions>(organizationUser.Permissions);
ResetPasswordEnrolled = !string.IsNullOrEmpty(organizationUser.ResetPasswordKey);
}
public OrganizationUserResponseModel(OrganizationUserUserDetails organizationUser, string obj = "organizationUser")
@ -39,6 +40,7 @@ namespace Bit.Core.Models.Api
Status = organizationUser.Status;
AccessAll = organizationUser.AccessAll;
Permissions = CoreHelpers.LoadClassFromJsonData<Permissions>(organizationUser.Permissions);
ResetPasswordEnrolled = !string.IsNullOrEmpty(organizationUser.ResetPasswordKey);
}
public string Id { get; set; }
@ -47,6 +49,7 @@ namespace Bit.Core.Models.Api
public OrganizationUserStatusType Status { get; set; }
public bool AccessAll { get; set; }
public Permissions Permissions { get; set; }
public bool ResetPasswordEnrolled { get; set; }
}
public class OrganizationUserDetailsResponseModel : OrganizationUserResponseModel
@ -83,4 +86,24 @@ namespace Bit.Core.Models.Api
public bool TwoFactorEnabled { get; set; }
public bool SsoBound { get; set; }
}
public class OrganizationUserResetPasswordDetailsResponseModel : ResponseModel
{
public OrganizationUserResetPasswordDetailsResponseModel(OrganizationUserResetPasswordDetails orgUser,
string obj = "organizationUserResetPasswordDetails") : base(obj)
{
if (orgUser == null)
{
throw new ArgumentNullException(nameof(orgUser));
}
Kdf = orgUser.Kdf;
KdfIterations = orgUser.KdfIterations;
ResetPasswordKey = orgUser.ResetPasswordKey;
}
public KdfType Kdf { get; set; }
public int KdfIterations { get; set; }
public string ResetPasswordKey { get; set; }
}
}

View File

@ -30,7 +30,7 @@ namespace Bit.Core.Models.Api
SsoBound = !string.IsNullOrWhiteSpace(organization.SsoExternalId);
Identifier = organization.Identifier;
Permissions = CoreHelpers.LoadClassFromJsonData<Permissions>(organization.Permissions);
ResetPasswordKey = organization.ResetPasswordKey;
ResetPasswordEnrolled = organization.ResetPasswordKey != null;
UserId = organization.UserId?.ToString();
}
@ -57,7 +57,7 @@ namespace Bit.Core.Models.Api
public bool SsoBound { get; set; }
public string Identifier { get; set; }
public Permissions Permissions { get; set; }
public string ResetPasswordKey { get; set; }
public bool ResetPasswordEnrolled { get; set; }
public string UserId { get; set; }
}
}

View File

@ -0,0 +1,29 @@
using System;
using Bit.Core.Enums;
using Bit.Core.Models.Table;
namespace Bit.Core.Models.Data
{
public class OrganizationUserResetPasswordDetails
{
public OrganizationUserResetPasswordDetails(OrganizationUser orgUser, User user)
{
if (orgUser == null)
{
throw new ArgumentNullException(nameof(orgUser));
}
if (user == null)
{
throw new ArgumentNullException(nameof(user));
}
Kdf = user.Kdf;
KdfIterations = user.KdfIterations;
ResetPasswordKey = orgUser.ResetPasswordKey;
}
public KdfType Kdf { get; set; }
public int KdfIterations { get; set; }
public string ResetPasswordKey { get; set; }
}
}

View File

@ -34,6 +34,7 @@ namespace Bit.Core.Services
string token, string key);
Task<IdentityResult> ChangePasswordAsync(User user, string masterPassword, string newMasterPassword, string key);
Task<IdentityResult> SetPasswordAsync(User user, string newMasterPassword, string key, string orgIdentifier = null);
Task<IdentityResult> AdminResetPasswordAsync(User user, string newMasterPassword, string key);
Task<IdentityResult> ChangeKdfAsync(User user, string masterPassword, string newMasterPassword, string key,
KdfType kdf, int kdfIterations);
Task<IdentityResult> UpdateKeyAsync(User user, string masterPassword, string key, string privateKey,

View File

@ -600,6 +600,24 @@ namespace Bit.Core.Services
return IdentityResult.Success;
}
public async Task<IdentityResult> AdminResetPasswordAsync(User user, string newMasterPassword, string key)
{
var result = await UpdatePasswordHash(user, newMasterPassword);
if (!result.Succeeded)
{
return result;
}
user.RevisionDate = user.AccountRevisionDate = DateTime.UtcNow;
user.Key = key;
await _userRepository.ReplaceAsync(user);
await _eventService.LogUserEventAsync(user.Id, EventType.User_ChangedPassword);
await _pushService.PushLogOutAsync(user.Id);
return IdentityResult.Success;
}
public async Task<IdentityResult> ChangeKdfAsync(User user, string masterPassword, string newMasterPassword,
string key, KdfType kdf, int kdfIterations)