1
0
mirror of https://github.com/bitwarden/server synced 2025-12-30 15:14:02 +00:00

[PM-25652] Add endpoint to fetch key connector confirmation details (#6635)

* Add new endpoint and query for key connector

* Add unit tests
This commit is contained in:
Thomas Avery
2025-12-10 14:53:38 -06:00
committed by GitHub
parent 8064ae1e05
commit f86d1a51dd
9 changed files with 256 additions and 29 deletions

View File

@@ -1,8 +1,8 @@
#nullable enable
using Bit.Api.AdminConsole.Models.Request.Organizations;
using Bit.Api.AdminConsole.Models.Request.Organizations;
using Bit.Api.Auth.Models.Request;
using Bit.Api.Auth.Models.Request.WebAuthn;
using Bit.Api.KeyManagement.Models.Requests;
using Bit.Api.KeyManagement.Models.Responses;
using Bit.Api.KeyManagement.Validators;
using Bit.Api.Tools.Models.Request;
using Bit.Api.Vault.Models.Request;
@@ -14,6 +14,7 @@ using Bit.Core.Entities;
using Bit.Core.Exceptions;
using Bit.Core.KeyManagement.Commands.Interfaces;
using Bit.Core.KeyManagement.Models.Data;
using Bit.Core.KeyManagement.Queries.Interfaces;
using Bit.Core.KeyManagement.UserKey;
using Bit.Core.Repositories;
using Bit.Core.Services;
@@ -45,11 +46,13 @@ public class AccountsKeyManagementController : Controller
private readonly IRotationValidator<IEnumerable<WebAuthnLoginRotateKeyRequestModel>, IEnumerable<WebAuthnLoginRotateKeyData>>
_webauthnKeyValidator;
private readonly IRotationValidator<IEnumerable<OtherDeviceKeysUpdateRequestModel>, IEnumerable<Device>> _deviceValidator;
private readonly IKeyConnectorConfirmationDetailsQuery _keyConnectorConfirmationDetailsQuery;
public AccountsKeyManagementController(IUserService userService,
IFeatureService featureService,
IOrganizationUserRepository organizationUserRepository,
IEmergencyAccessRepository emergencyAccessRepository,
IKeyConnectorConfirmationDetailsQuery keyConnectorConfirmationDetailsQuery,
IRegenerateUserAsymmetricKeysCommand regenerateUserAsymmetricKeysCommand,
IRotateUserAccountKeysCommand rotateUserKeyCommandV2,
IRotationValidator<IEnumerable<CipherWithIdRequestModel>, IEnumerable<Cipher>> cipherValidator,
@@ -75,6 +78,7 @@ public class AccountsKeyManagementController : Controller
_organizationUserValidator = organizationUserValidator;
_webauthnKeyValidator = webAuthnKeyValidator;
_deviceValidator = deviceValidator;
_keyConnectorConfirmationDetailsQuery = keyConnectorConfirmationDetailsQuery;
}
[HttpPost("key-management/regenerate-keys")]
@@ -178,4 +182,17 @@ public class AccountsKeyManagementController : Controller
throw new BadRequestException(ModelState);
}
[HttpGet("key-connector/confirmation-details/{orgSsoIdentifier}")]
public async Task<KeyConnectorConfirmationDetailsResponseModel> GetKeyConnectorConfirmationDetailsAsync(string orgSsoIdentifier)
{
var user = await _userService.GetUserByPrincipalAsync(User);
if (user == null)
{
throw new UnauthorizedAccessException();
}
var details = await _keyConnectorConfirmationDetailsQuery.Run(orgSsoIdentifier, user.Id);
return new KeyConnectorConfirmationDetailsResponseModel(details);
}
}

View File

@@ -0,0 +1,24 @@
using Bit.Core.KeyManagement.Models.Data;
using Bit.Core.Models.Api;
namespace Bit.Api.KeyManagement.Models.Responses;
public class KeyConnectorConfirmationDetailsResponseModel : ResponseModel
{
private const string _objectName = "keyConnectorConfirmationDetails";
public KeyConnectorConfirmationDetailsResponseModel(KeyConnectorConfirmationDetails details,
string obj = _objectName) : base(obj)
{
ArgumentNullException.ThrowIfNull(details);
OrganizationName = details.OrganizationName;
}
public KeyConnectorConfirmationDetailsResponseModel() : base(_objectName)
{
OrganizationName = string.Empty;
}
public string OrganizationName { get; set; }
}

View File

@@ -26,5 +26,6 @@ public static class KeyManagementServiceCollectionExtensions
private static void AddKeyManagementQueries(this IServiceCollection services)
{
services.AddScoped<IUserAccountKeysQuery, UserAccountKeysQuery>();
services.AddScoped<IKeyConnectorConfirmationDetailsQuery, KeyConnectorConfirmationDetailsQuery>();
}
}

View File

@@ -0,0 +1,6 @@
namespace Bit.Core.KeyManagement.Models.Data;
public class KeyConnectorConfirmationDetails
{
public required string OrganizationName { get; set; }
}

View File

@@ -0,0 +1,8 @@
using Bit.Core.KeyManagement.Models.Data;
namespace Bit.Core.KeyManagement.Queries.Interfaces;
public interface IKeyConnectorConfirmationDetailsQuery
{
public Task<KeyConnectorConfirmationDetails> Run(string orgSsoIdentifier, Guid userId);
}

View File

@@ -0,0 +1,35 @@
using Bit.Core.Exceptions;
using Bit.Core.KeyManagement.Models.Data;
using Bit.Core.KeyManagement.Queries.Interfaces;
using Bit.Core.Repositories;
namespace Bit.Core.KeyManagement.Queries;
public class KeyConnectorConfirmationDetailsQuery : IKeyConnectorConfirmationDetailsQuery
{
private readonly IOrganizationRepository _organizationRepository;
private readonly IOrganizationUserRepository _organizationUserRepository;
public KeyConnectorConfirmationDetailsQuery(IOrganizationRepository organizationRepository, IOrganizationUserRepository organizationUserRepository)
{
_organizationRepository = organizationRepository;
_organizationUserRepository = organizationUserRepository;
}
public async Task<KeyConnectorConfirmationDetails> Run(string orgSsoIdentifier, Guid userId)
{
var org = await _organizationRepository.GetByIdentifierAsync(orgSsoIdentifier);
if (org is not { UseKeyConnector: true })
{
throw new NotFoundException();
}
var orgUser = await _organizationUserRepository.GetByOrganizationAsync(org.Id, userId);
if (orgUser == null)
{
throw new NotFoundException();
}
return new KeyConnectorConfirmationDetails { OrganizationName = org.Name, };
}
}