1
0
mirror of https://github.com/bitwarden/server.git synced 2025-04-05 05:00:19 -05:00

feat (opaque-ke) : moved endpoints to Identity.

This commit is contained in:
Ike Kottlowski 2025-03-20 14:59:34 -04:00
parent 7f997246e5
commit 525174068f
No known key found for this signature in database
GPG Key ID: C86308E3DCA6D76F
4 changed files with 30 additions and 18 deletions

View File

@ -209,11 +209,12 @@ public class AccountsController : Controller
throw new UnauthorizedAccessException(); throw new UnauthorizedAccessException();
} }
// TODO: should this be feature flagged
Guid? opaqueSessionId = null; Guid? opaqueSessionId = null;
if (model.OpaqueSessionId != null) if(_featureService.IsEnabled(FeatureFlagKeys.OpaqueKeyExchange)){
{ if (model.OpaqueSessionId != null)
opaqueSessionId = Guid.Parse(model.OpaqueSessionId); {
opaqueSessionId = Guid.Parse(model.OpaqueSessionId);
}
} }
var result = await _userService.ChangePasswordAsync(user, model.MasterPasswordHash, var result = await _userService.ChangePasswordAsync(user, model.MasterPasswordHash,

View File

@ -28,7 +28,7 @@ public interface IOpaqueKeyExchangeService
/// <returns>void</returns> /// <returns>void</returns>
public Task<bool> FinishRegistration(Guid sessionId, byte[] registrationUpload, User user, RotateableOpaqueKeyset keyset); public Task<bool> FinishRegistration(Guid sessionId, byte[] registrationUpload, User user, RotateableOpaqueKeyset keyset);
/// <summary> /// <summary>
/// Returns server crypto material for the client to consume and reply with a login request to the identity/token endpoint. /// Returns server crypto material for the client to consume and reply to the finish-login endpoint for authentication.
/// To protect against account enumeration we will always return a deterministic response based on the user's email. /// To protect against account enumeration we will always return a deterministic response based on the user's email.
/// </summary> /// </summary>
/// <param name="request">client crypto material</param> /// <param name="request">client crypto material</param>

View File

@ -1,7 +1,6 @@
using System.Diagnostics; using System.Diagnostics;
using System.Text; using System.Text;
using System.Text.Json; using System.Text.Json;
using Bit.Api.Auth.Models.Response.Opaque;
using Bit.Core; using Bit.Core;
using Bit.Core.Auth.Enums; using Bit.Core.Auth.Enums;
using Bit.Core.Auth.Models.Api.Request.Accounts; using Bit.Core.Auth.Models.Api.Request.Accounts;
@ -291,15 +290,6 @@ public class AccountsController : Controller
}; };
} }
// TODO: (1) This should be on own controller (2) reconcile this w/ start login on existing controller
[HttpPost("opaque-ke/start-login")]
[RequireFeature(FeatureFlagKeys.OpaqueKeyExchange)]
public async Task<OpaqueLoginStartResponse> GetOpaqueKeyExchangeStartLoginMaterial([FromBody] OpaqueLoginStartRequest request)
{
var result = await _opaqueKeyExchangeService.StartLogin(Convert.FromBase64String(request.CredentialRequest), request.Email);
return new OpaqueLoginStartResponse(result.Item1, Convert.ToBase64String(result.Item2));
}
private UserKdfInformation GetDefaultKdf(string email) private UserKdfInformation GetDefaultKdf(string email)
{ {
if (_defaultKdfHmacKey == null) if (_defaultKdfHmacKey == null)

View File

@ -1,3 +1,5 @@
using Bit.Api.Auth.Models.Request.Opaque;
using Bit.Api.Auth.Models.Response.Opaque;
using Bit.Core; using Bit.Core;
using Bit.Core.Auth.Models.Api.Request.Opaque; using Bit.Core.Auth.Models.Api.Request.Opaque;
using Bit.Core.Auth.Models.Api.Response.Opaque; using Bit.Core.Auth.Models.Api.Response.Opaque;
@ -7,11 +9,10 @@ using Bit.Core.Utilities;
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
namespace Bit.Api.Auth.Controllers; namespace Bit.Identity.Controllers;
// TODO: move to identity
[RequireFeature(FeatureFlagKeys.OpaqueKeyExchange)] [RequireFeature(FeatureFlagKeys.OpaqueKeyExchange)]
[Route("opaque")] [Route("opaque-ke")]
[Authorize("Application")] [Authorize("Application")]
public class OpaqueKeyExchangeController( public class OpaqueKeyExchangeController(
IOpaqueKeyExchangeService opaqueKeyExchangeService, IOpaqueKeyExchangeService opaqueKeyExchangeService,
@ -37,6 +38,8 @@ public class OpaqueKeyExchangeController(
{ {
var user = await _userService.GetUserByPrincipalAsync(User) var user = await _userService.GetUserByPrincipalAsync(User)
?? throw new UnauthorizedAccessException(); ?? throw new UnauthorizedAccessException();
// todo check response
await _opaqueKeyExchangeService.FinishRegistration( await _opaqueKeyExchangeService.FinishRegistration(
request.SessionId, Convert.FromBase64String(request.RegistrationUpload), user, request.KeySet); request.SessionId, Convert.FromBase64String(request.RegistrationUpload), user, request.KeySet);
} }
@ -46,6 +49,24 @@ public class OpaqueKeyExchangeController(
{ {
var user = await _userService.GetUserByPrincipalAsync(User) var user = await _userService.GetUserByPrincipalAsync(User)
?? throw new UnauthorizedAccessException(); ?? throw new UnauthorizedAccessException();
// todo check response
await _opaqueKeyExchangeService.WriteCacheCredentialToDatabase(request.SessionId, user); await _opaqueKeyExchangeService.WriteCacheCredentialToDatabase(request.SessionId, user);
} }
[AllowAnonymous]
[HttpPost("start-login")]
public async Task<OpaqueLoginStartResponse> StartOpaqueLoginAsync([FromBody] OpaqueLoginStartRequest request)
{
var result = await _opaqueKeyExchangeService.StartLogin(Convert.FromBase64String(request.CredentialRequest), request.Email);
return new OpaqueLoginStartResponse(result.Item1, Convert.ToBase64String(result.Item2));
}
[AllowAnonymous]
[HttpPost("finish-login")]
public async Task<bool> FinishLoginAsync([FromBody] OpaqueLoginFinishRequest request)
{
var result = await _opaqueKeyExchangeService.FinishLogin(
request.SessionId, Convert.FromBase64String(request.CredentialFinalization));
return result;
}
} }