mirror of
https://github.com/bitwarden/server
synced 2026-01-17 07:53:36 +00:00
[PM-29556] Fix: changing organization plan nulls out public and private keys (#6738)
Main fix: only assign new key value where old keys are not set and new keys have been provided. Refactors: - use consistent DTO model for keypairs - delete duplicate property assignment for new orgs
This commit is contained in:
@@ -99,8 +99,8 @@ public class CloudOrganizationSignUpCommand(
|
||||
ReferenceData = signup.Owner.ReferenceData,
|
||||
Enabled = true,
|
||||
LicenseKey = CoreHelpers.SecureRandomString(20),
|
||||
PublicKey = signup.PublicKey,
|
||||
PrivateKey = signup.PrivateKey,
|
||||
PublicKey = signup.Keys?.PublicKey,
|
||||
PrivateKey = signup.Keys?.WrappedPrivateKey,
|
||||
CreationDate = DateTime.UtcNow,
|
||||
RevisionDate = DateTime.UtcNow,
|
||||
Status = OrganizationStatusType.Created,
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
using Bit.Core.AdminConsole.Entities;
|
||||
using Bit.Core.KeyManagement.Models.Data;
|
||||
|
||||
namespace Bit.Core.AdminConsole.OrganizationFeatures.Organizations;
|
||||
|
||||
public static class OrganizationExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Updates the organization public and private keys if provided and not already set.
|
||||
/// This is legacy code for old organizations that were not created with a public/private keypair.
|
||||
/// It is a soft migration that will silently migrate organizations when they perform certain actions,
|
||||
/// e.g. change their details or upgrade their plan.
|
||||
/// </summary>
|
||||
public static void BackfillPublicPrivateKeys(this Organization organization, PublicKeyEncryptionKeyPairData? keyPair)
|
||||
{
|
||||
// Only backfill if both new keys are provided and both old keys are missing.
|
||||
if (string.IsNullOrWhiteSpace(keyPair?.PublicKey) ||
|
||||
string.IsNullOrWhiteSpace(keyPair.WrappedPrivateKey) ||
|
||||
!string.IsNullOrWhiteSpace(organization.PublicKey) ||
|
||||
!string.IsNullOrWhiteSpace(organization.PrivateKey))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
organization.PublicKey = keyPair.PublicKey;
|
||||
organization.PrivateKey = keyPair.WrappedPrivateKey;
|
||||
}
|
||||
}
|
||||
@@ -93,8 +93,8 @@ public class ProviderClientOrganizationSignUpCommand : IProviderClientOrganizati
|
||||
ReferenceData = signup.Owner.ReferenceData,
|
||||
Enabled = true,
|
||||
LicenseKey = CoreHelpers.SecureRandomString(20),
|
||||
PublicKey = signup.PublicKey,
|
||||
PrivateKey = signup.PrivateKey,
|
||||
PublicKey = signup.Keys?.PublicKey,
|
||||
PrivateKey = signup.Keys?.WrappedPrivateKey,
|
||||
CreationDate = DateTime.UtcNow,
|
||||
RevisionDate = DateTime.UtcNow,
|
||||
Status = OrganizationStatusType.Created,
|
||||
|
||||
@@ -39,8 +39,20 @@ public class OrganizationUpdateCommand(
|
||||
var originalBillingEmail = organization.BillingEmail;
|
||||
|
||||
// Apply updates to organization
|
||||
organization.UpdateDetails(request);
|
||||
organization.BackfillPublicPrivateKeys(request);
|
||||
// These values may or may not be sent by the client depending on the operation being performed.
|
||||
// Skip any values not provided.
|
||||
if (request.Name is not null)
|
||||
{
|
||||
organization.Name = request.Name;
|
||||
}
|
||||
|
||||
if (request.BillingEmail is not null)
|
||||
{
|
||||
organization.BillingEmail = request.BillingEmail.ToLowerInvariant().Trim();
|
||||
}
|
||||
|
||||
organization.BackfillPublicPrivateKeys(request.Keys);
|
||||
|
||||
await organizationService.ReplaceAndUpdateCacheAsync(organization, EventType.Organization_Updated);
|
||||
|
||||
// Update billing information in Stripe if required
|
||||
@@ -56,7 +68,7 @@ public class OrganizationUpdateCommand(
|
||||
/// </summary>
|
||||
private async Task<Organization> UpdateSelfHostedAsync(Organization organization, OrganizationUpdateRequest request)
|
||||
{
|
||||
organization.BackfillPublicPrivateKeys(request);
|
||||
organization.BackfillPublicPrivateKeys(request.Keys);
|
||||
await organizationService.ReplaceAndUpdateCacheAsync(organization, EventType.Organization_Updated);
|
||||
return organization;
|
||||
}
|
||||
|
||||
@@ -1,43 +0,0 @@
|
||||
using Bit.Core.AdminConsole.Entities;
|
||||
|
||||
namespace Bit.Core.AdminConsole.OrganizationFeatures.Organizations.Update;
|
||||
|
||||
public static class OrganizationUpdateExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Updates the organization name and/or billing email.
|
||||
/// Any null property on the request object will be skipped.
|
||||
/// </summary>
|
||||
public static void UpdateDetails(this Organization organization, OrganizationUpdateRequest request)
|
||||
{
|
||||
// These values may or may not be sent by the client depending on the operation being performed.
|
||||
// Skip any values not provided.
|
||||
if (request.Name is not null)
|
||||
{
|
||||
organization.Name = request.Name;
|
||||
}
|
||||
|
||||
if (request.BillingEmail is not null)
|
||||
{
|
||||
organization.BillingEmail = request.BillingEmail.ToLowerInvariant().Trim();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the organization public and private keys if provided and not already set.
|
||||
/// This is legacy code for old organizations that were not created with a public/private keypair. It is a soft
|
||||
/// migration that will silently migrate organizations when they change their details.
|
||||
/// </summary>
|
||||
public static void BackfillPublicPrivateKeys(this Organization organization, OrganizationUpdateRequest request)
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(request.PublicKey) && string.IsNullOrWhiteSpace(organization.PublicKey))
|
||||
{
|
||||
organization.PublicKey = request.PublicKey;
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(request.EncryptedPrivateKey) && string.IsNullOrWhiteSpace(organization.PrivateKey))
|
||||
{
|
||||
organization.PrivateKey = request.EncryptedPrivateKey;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,6 @@
|
||||
namespace Bit.Core.AdminConsole.OrganizationFeatures.Organizations.Update;
|
||||
using Bit.Core.KeyManagement.Models.Data;
|
||||
|
||||
namespace Bit.Core.AdminConsole.OrganizationFeatures.Organizations.Update;
|
||||
|
||||
/// <summary>
|
||||
/// Request model for updating the name, billing email, and/or public-private keys for an organization (legacy migration code).
|
||||
@@ -22,12 +24,7 @@ public record OrganizationUpdateRequest
|
||||
public string? BillingEmail { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// The organization's public key to set (optional, only set if not already present on the organization).
|
||||
/// The organization's public/private key pair to set (optional, only set if not already present on the organization).
|
||||
/// </summary>
|
||||
public string? PublicKey { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// The organization's encrypted private key to set (optional, only set if not already present on the organization).
|
||||
/// </summary>
|
||||
public string? EncryptedPrivateKey { get; init; }
|
||||
public PublicKeyEncryptionKeyPairData? Keys { get; init; }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user