mirror of
https://github.com/bitwarden/server.git
synced 2025-05-29 07:14:50 -05:00
Update opaque login with password and update cipherconfig model
This commit is contained in:
parent
0b34f09fc7
commit
d617004435
@ -15,6 +15,7 @@ using Bit.Core.AdminConsole.Services;
|
|||||||
using Bit.Core.Auth.Entities;
|
using Bit.Core.Auth.Entities;
|
||||||
using Bit.Core.Auth.Models.Api.Request.Accounts;
|
using Bit.Core.Auth.Models.Api.Request.Accounts;
|
||||||
using Bit.Core.Auth.Models.Data;
|
using Bit.Core.Auth.Models.Data;
|
||||||
|
using Bit.Core.Auth.Services;
|
||||||
using Bit.Core.Auth.UserFeatures.TdeOffboardingPassword.Interfaces;
|
using Bit.Core.Auth.UserFeatures.TdeOffboardingPassword.Interfaces;
|
||||||
using Bit.Core.Auth.UserFeatures.UserMasterPassword.Interfaces;
|
using Bit.Core.Auth.UserFeatures.UserMasterPassword.Interfaces;
|
||||||
using Bit.Core.Entities;
|
using Bit.Core.Entities;
|
||||||
@ -57,6 +58,7 @@ public class AccountsController : Controller
|
|||||||
_organizationUserValidator;
|
_organizationUserValidator;
|
||||||
private readonly IRotationValidator<IEnumerable<WebAuthnLoginRotateKeyRequestModel>, IEnumerable<WebAuthnLoginRotateKeyData>>
|
private readonly IRotationValidator<IEnumerable<WebAuthnLoginRotateKeyRequestModel>, IEnumerable<WebAuthnLoginRotateKeyData>>
|
||||||
_webauthnKeyValidator;
|
_webauthnKeyValidator;
|
||||||
|
private readonly IOpaqueKeyExchangeService _opaqueKeyExchangeService;
|
||||||
|
|
||||||
|
|
||||||
public AccountsController(
|
public AccountsController(
|
||||||
@ -76,7 +78,8 @@ public class AccountsController : Controller
|
|||||||
emergencyAccessValidator,
|
emergencyAccessValidator,
|
||||||
IRotationValidator<IEnumerable<ResetPasswordWithOrgIdRequestModel>, IReadOnlyList<OrganizationUser>>
|
IRotationValidator<IEnumerable<ResetPasswordWithOrgIdRequestModel>, IReadOnlyList<OrganizationUser>>
|
||||||
organizationUserValidator,
|
organizationUserValidator,
|
||||||
IRotationValidator<IEnumerable<WebAuthnLoginRotateKeyRequestModel>, IEnumerable<WebAuthnLoginRotateKeyData>> webAuthnKeyValidator
|
IRotationValidator<IEnumerable<WebAuthnLoginRotateKeyRequestModel>, IEnumerable<WebAuthnLoginRotateKeyData>> webAuthnKeyValidator,
|
||||||
|
IOpaqueKeyExchangeService opaqueKeyExchangeService
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
_organizationService = organizationService;
|
_organizationService = organizationService;
|
||||||
@ -94,6 +97,7 @@ public class AccountsController : Controller
|
|||||||
_emergencyAccessValidator = emergencyAccessValidator;
|
_emergencyAccessValidator = emergencyAccessValidator;
|
||||||
_organizationUserValidator = organizationUserValidator;
|
_organizationUserValidator = organizationUserValidator;
|
||||||
_webauthnKeyValidator = webAuthnKeyValidator;
|
_webauthnKeyValidator = webAuthnKeyValidator;
|
||||||
|
_opaqueKeyExchangeService = opaqueKeyExchangeService;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -209,8 +213,14 @@ public class AccountsController : Controller
|
|||||||
throw new UnauthorizedAccessException();
|
throw new UnauthorizedAccessException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Guid? sessionId = null;
|
||||||
|
if (model.OpaqueSessionId != null)
|
||||||
|
{
|
||||||
|
sessionId = Guid.Parse(model.OpaqueSessionId);
|
||||||
|
}
|
||||||
|
|
||||||
var result = await _userService.ChangePasswordAsync(user, model.MasterPasswordHash,
|
var result = await _userService.ChangePasswordAsync(user, model.MasterPasswordHash,
|
||||||
model.NewMasterPasswordHash, model.MasterPasswordHint, model.Key);
|
model.NewMasterPasswordHash, model.MasterPasswordHint, model.Key, sessionId);
|
||||||
if (result.Succeeded)
|
if (result.Succeeded)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
|
@ -27,7 +27,7 @@ public class OpaqueKeyExchangeController : Controller
|
|||||||
public async Task<OpaqueRegistrationStartResponse> StartRegistrationAsync([FromBody] OpaqueRegistrationStartRequest request)
|
public async Task<OpaqueRegistrationStartResponse> StartRegistrationAsync([FromBody] OpaqueRegistrationStartRequest request)
|
||||||
{
|
{
|
||||||
var user = await _userService.GetUserByPrincipalAsync(User);
|
var user = await _userService.GetUserByPrincipalAsync(User);
|
||||||
var result = await _opaqueKeyExchangeService.StartRegistration(Convert.FromBase64String(request.RegistrationRequest), user, request.CipherConfiguration);
|
var result = await _opaqueKeyExchangeService.StartRegistration(Convert.FromBase64String(request.RegistrationRequest), user, request.CipherConfiguration.ToNativeConfiguration());
|
||||||
return new OpaqueRegistrationStartResponse(result.Item1, Convert.ToBase64String(result.Item2));
|
return new OpaqueRegistrationStartResponse(result.Item1, Convert.ToBase64String(result.Item2));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,4 +11,5 @@ public class PasswordRequestModel : SecretVerificationRequestModel
|
|||||||
public string MasterPasswordHint { get; set; }
|
public string MasterPasswordHint { get; set; }
|
||||||
[Required]
|
[Required]
|
||||||
public string Key { get; set; }
|
public string Key { get; set; }
|
||||||
|
public string OpaqueSessionId { get; set; }
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,50 @@
|
|||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
using Bitwarden.OPAQUE;
|
|
||||||
|
|
||||||
namespace Bit.Api.Auth.Models.Request.Opaque;
|
namespace Bit.Api.Auth.Models.Request.Opaque;
|
||||||
|
|
||||||
|
|
||||||
public class OpaqueRegistrationStartRequest
|
public class OpaqueRegistrationStartRequest
|
||||||
{
|
{
|
||||||
[Required]
|
[Required]
|
||||||
public String RegistrationRequest { get; set; }
|
public string RegistrationRequest { get; set; }
|
||||||
[Required]
|
[Required]
|
||||||
public CipherConfiguration CipherConfiguration { get; set; }
|
public CipherConfiguration CipherConfiguration { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class CipherConfiguration
|
||||||
|
{
|
||||||
|
static string OpaqueKe3Ristretto3DHArgonSuite = "OPAQUE_3_RISTRETTO255_OPRF_RISTRETTO255_KEGROUP_3DH_KEX_ARGON2ID13_KSF";
|
||||||
|
|
||||||
|
[Required]
|
||||||
|
public string CipherSuite { get; set; }
|
||||||
|
public Argon2KsfParameters Argon2Parameters { get; set; }
|
||||||
|
|
||||||
|
public Bitwarden.OPAQUE.CipherConfiguration ToNativeConfiguration()
|
||||||
|
{
|
||||||
|
if (CipherSuite == OpaqueKe3Ristretto3DHArgonSuite)
|
||||||
|
{
|
||||||
|
return new Bitwarden.OPAQUE.CipherConfiguration
|
||||||
|
{
|
||||||
|
OprfCS = Bitwarden.OPAQUE.OprfCS.Ristretto255,
|
||||||
|
KeGroup = Bitwarden.OPAQUE.KeGroup.Ristretto255,
|
||||||
|
KeyExchange = Bitwarden.OPAQUE.KeyExchange.TripleDH,
|
||||||
|
KSF = new Bitwarden.OPAQUE.Argon2id(Argon2Parameters.iterations, Argon2Parameters.memory, Argon2Parameters.parallelism)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new Exception("Unsupported cipher suite");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Argon2KsfParameters
|
||||||
|
{
|
||||||
|
// Memory in KiB
|
||||||
|
[Required]
|
||||||
|
public int memory;
|
||||||
|
[Required]
|
||||||
|
public int iterations;
|
||||||
|
[Required]
|
||||||
|
public int parallelism;
|
||||||
|
}
|
||||||
|
@ -37,9 +37,6 @@ public class OpaqueKeyExchangeService : IOpaqueKeyExchangeService
|
|||||||
{
|
{
|
||||||
var registrationFinish = _bitwardenOpaque.FinishRegistration(cipherConfiguration, registrationUpload);
|
var registrationFinish = _bitwardenOpaque.FinishRegistration(cipherConfiguration, registrationUpload);
|
||||||
SessionStore.RegisterSessions[sessionId].serverRegistration = registrationFinish.serverRegistration;
|
SessionStore.RegisterSessions[sessionId].serverRegistration = registrationFinish.serverRegistration;
|
||||||
|
|
||||||
// todo move to changepassword
|
|
||||||
SetActive(sessionId, user);
|
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
|
@ -44,7 +44,7 @@ public interface IUserService
|
|||||||
Task InitiateEmailChangeAsync(User user, string newEmail);
|
Task InitiateEmailChangeAsync(User user, string newEmail);
|
||||||
Task<IdentityResult> ChangeEmailAsync(User user, string masterPassword, string newEmail, string newMasterPassword,
|
Task<IdentityResult> ChangeEmailAsync(User user, string masterPassword, string newEmail, string newMasterPassword,
|
||||||
string token, string key);
|
string token, string key);
|
||||||
Task<IdentityResult> ChangePasswordAsync(User user, string masterPassword, string newMasterPassword, string passwordHint, string key);
|
Task<IdentityResult> ChangePasswordAsync(User user, string masterPassword, string newMasterPassword, string passwordHint, string key, Guid? opaqueSessionId);
|
||||||
Task<IdentityResult> SetKeyConnectorKeyAsync(User user, string key, string orgIdentifier);
|
Task<IdentityResult> SetKeyConnectorKeyAsync(User user, string key, string orgIdentifier);
|
||||||
Task<IdentityResult> ConvertToKeyConnectorAsync(User user);
|
Task<IdentityResult> ConvertToKeyConnectorAsync(User user);
|
||||||
Task<IdentityResult> AdminResetPasswordAsync(OrganizationUserType type, Guid orgId, Guid id, string newMasterPassword, string key);
|
Task<IdentityResult> AdminResetPasswordAsync(OrganizationUserType type, Guid orgId, Guid id, string newMasterPassword, string key);
|
||||||
|
@ -11,6 +11,7 @@ using Bit.Core.AdminConsole.Services;
|
|||||||
using Bit.Core.Auth.Enums;
|
using Bit.Core.Auth.Enums;
|
||||||
using Bit.Core.Auth.Models;
|
using Bit.Core.Auth.Models;
|
||||||
using Bit.Core.Auth.Models.Business.Tokenables;
|
using Bit.Core.Auth.Models.Business.Tokenables;
|
||||||
|
using Bit.Core.Auth.Services;
|
||||||
using Bit.Core.Billing.Models;
|
using Bit.Core.Billing.Models;
|
||||||
using Bit.Core.Billing.Models.Sales;
|
using Bit.Core.Billing.Models.Sales;
|
||||||
using Bit.Core.Billing.Services;
|
using Bit.Core.Billing.Services;
|
||||||
@ -78,6 +79,7 @@ public class UserService : UserManager<User>, IUserService, IDisposable
|
|||||||
private readonly IRemoveOrganizationUserCommand _removeOrganizationUserCommand;
|
private readonly IRemoveOrganizationUserCommand _removeOrganizationUserCommand;
|
||||||
private readonly IRevokeNonCompliantOrganizationUserCommand _revokeNonCompliantOrganizationUserCommand;
|
private readonly IRevokeNonCompliantOrganizationUserCommand _revokeNonCompliantOrganizationUserCommand;
|
||||||
private readonly IDistributedCache _distributedCache;
|
private readonly IDistributedCache _distributedCache;
|
||||||
|
private readonly IOpaqueKeyExchangeService _opaqueKeyExchangeService;
|
||||||
|
|
||||||
public UserService(
|
public UserService(
|
||||||
IUserRepository userRepository,
|
IUserRepository userRepository,
|
||||||
@ -115,7 +117,8 @@ public class UserService : UserManager<User>, IUserService, IDisposable
|
|||||||
IPremiumUserBillingService premiumUserBillingService,
|
IPremiumUserBillingService premiumUserBillingService,
|
||||||
IRemoveOrganizationUserCommand removeOrganizationUserCommand,
|
IRemoveOrganizationUserCommand removeOrganizationUserCommand,
|
||||||
IRevokeNonCompliantOrganizationUserCommand revokeNonCompliantOrganizationUserCommand,
|
IRevokeNonCompliantOrganizationUserCommand revokeNonCompliantOrganizationUserCommand,
|
||||||
IDistributedCache distributedCache)
|
IDistributedCache distributedCache,
|
||||||
|
IOpaqueKeyExchangeService opaqueKeyExchangeService)
|
||||||
: base(
|
: base(
|
||||||
store,
|
store,
|
||||||
optionsAccessor,
|
optionsAccessor,
|
||||||
@ -159,6 +162,7 @@ public class UserService : UserManager<User>, IUserService, IDisposable
|
|||||||
_removeOrganizationUserCommand = removeOrganizationUserCommand;
|
_removeOrganizationUserCommand = removeOrganizationUserCommand;
|
||||||
_revokeNonCompliantOrganizationUserCommand = revokeNonCompliantOrganizationUserCommand;
|
_revokeNonCompliantOrganizationUserCommand = revokeNonCompliantOrganizationUserCommand;
|
||||||
_distributedCache = distributedCache;
|
_distributedCache = distributedCache;
|
||||||
|
_opaqueKeyExchangeService = opaqueKeyExchangeService;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Guid? GetProperUserId(ClaimsPrincipal principal)
|
public Guid? GetProperUserId(ClaimsPrincipal principal)
|
||||||
@ -643,7 +647,7 @@ public class UserService : UserManager<User>, IUserService, IDisposable
|
|||||||
}
|
}
|
||||||
|
|
||||||
public async Task<IdentityResult> ChangePasswordAsync(User user, string masterPassword, string newMasterPassword, string passwordHint,
|
public async Task<IdentityResult> ChangePasswordAsync(User user, string masterPassword, string newMasterPassword, string passwordHint,
|
||||||
string key)
|
string key, Guid? opaqueSessionId)
|
||||||
{
|
{
|
||||||
if (user == null)
|
if (user == null)
|
||||||
{
|
{
|
||||||
@ -664,6 +668,14 @@ public class UserService : UserManager<User>, IUserService, IDisposable
|
|||||||
user.Key = key;
|
user.Key = key;
|
||||||
user.MasterPasswordHint = passwordHint;
|
user.MasterPasswordHint = passwordHint;
|
||||||
|
|
||||||
|
if (opaqueSessionId != null)
|
||||||
|
{
|
||||||
|
_opaqueKeyExchangeService.SetActive((Guid)opaqueSessionId, user);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_opaqueKeyExchangeService.Unenroll(user);
|
||||||
|
}
|
||||||
await _userRepository.ReplaceAsync(user);
|
await _userRepository.ReplaceAsync(user);
|
||||||
await _eventService.LogUserEventAsync(user.Id, EventType.User_ChangedPassword);
|
await _eventService.LogUserEventAsync(user.Id, EventType.User_ChangedPassword);
|
||||||
await _pushService.PushLogOutAsync(user.Id, true);
|
await _pushService.PushLogOutAsync(user.Id, true);
|
||||||
@ -804,6 +816,8 @@ public class UserService : UserManager<User>, IUserService, IDisposable
|
|||||||
user.ForcePasswordReset = true;
|
user.ForcePasswordReset = true;
|
||||||
user.Key = key;
|
user.Key = key;
|
||||||
|
|
||||||
|
// TODO: Add support
|
||||||
|
_opaqueKeyExchangeService.Unenroll(user);
|
||||||
await _userRepository.ReplaceAsync(user);
|
await _userRepository.ReplaceAsync(user);
|
||||||
await _mailService.SendAdminResetPasswordEmailAsync(user.Email, user.Name, org.DisplayName());
|
await _mailService.SendAdminResetPasswordEmailAsync(user.Email, user.Name, org.DisplayName());
|
||||||
await _eventService.LogOrganizationUserEventAsync(orgUser, EventType.OrganizationUser_AdminResetPassword);
|
await _eventService.LogOrganizationUserEventAsync(orgUser, EventType.OrganizationUser_AdminResetPassword);
|
||||||
@ -830,6 +844,8 @@ public class UserService : UserManager<User>, IUserService, IDisposable
|
|||||||
user.Key = key;
|
user.Key = key;
|
||||||
user.MasterPasswordHint = hint;
|
user.MasterPasswordHint = hint;
|
||||||
|
|
||||||
|
// TODO: Add support
|
||||||
|
_opaqueKeyExchangeService.Unenroll(user);
|
||||||
await _userRepository.ReplaceAsync(user);
|
await _userRepository.ReplaceAsync(user);
|
||||||
await _mailService.SendUpdatedTempPasswordEmailAsync(user.Email, user.Name);
|
await _mailService.SendUpdatedTempPasswordEmailAsync(user.Email, user.Name);
|
||||||
await _eventService.LogUserEventAsync(user.Id, EventType.User_UpdatedTempPassword);
|
await _eventService.LogUserEventAsync(user.Id, EventType.User_UpdatedTempPassword);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user