Skip to content

Commit ba240da

Browse files
committed
Split MasterKey and KmsProvider options to a distinct config
1 parent 8f9cfc8 commit ba240da

File tree

6 files changed

+159
-172
lines changed

6 files changed

+159
-172
lines changed

lib/Doctrine/ODM/MongoDB/Configuration.php

Lines changed: 77 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@
2626
use InvalidArgumentException;
2727
use Jean85\PrettyVersions;
2828
use LogicException;
29+
use MongoDB\Client;
30+
use MongoDB\Driver\Manager;
2931
use MongoDB\Driver\WriteConcern;
3032
use ProxyManager\Configuration as ProxyManagerConfiguration;
3133
use ProxyManager\Factory\LazyLoadingGhostFactory;
@@ -36,12 +38,10 @@
3638
use Throwable;
3739

3840
use function array_diff_key;
41+
use function array_intersect_key;
3942
use function array_key_exists;
40-
use function array_key_first;
4143
use function class_exists;
42-
use function count;
4344
use function interface_exists;
44-
use function is_array;
4545
use function is_string;
4646
use function sprintf;
4747
use function trigger_deprecation;
@@ -58,14 +58,7 @@
5858
* $dm = DocumentManager::create(new Connection(), $config);
5959
*
6060
* @phpstan-import-type CommitOptions from UnitOfWork
61-
* @phpstan-type AutoEncryptionOptions array{
62-
* keyVaultNamespace: string,
63-
* kmsProviders: array<string, array<string, mixed>>,
64-
* kmsProvider?: string,
65-
* masterKey?: array<string, mixed>|null,
66-
* tlsOptions?: array{kmip: array{tlsCAFile: string, tlsCertificateKeyFile: string}},
67-
* ...
68-
* }
61+
* @phpstan-type KmsProvider array{name: string, ...}
6962
*/
7063
class Configuration
7164
{
@@ -138,7 +131,9 @@ class Configuration
138131
* proxyDir?: string,
139132
* proxyNamespace?: string,
140133
* repositoryFactory?: RepositoryFactory,
141-
* autoEncryption?: AutoEncryptionOptions,
134+
* kmsProvider?: KmsProvider,
135+
* defaultMasterKey?: array<string, mixed>|null,
136+
* autoEncryption?: array<string, mixed>,
142137
* }
143138
*/
144139
private array $attributes = [];
@@ -168,16 +163,34 @@ public function getDriverOptions(): array
168163
],
169164
];
170165

171-
if (isset($this->attributes['autoEncryption'])) {
172-
$driverOptions['autoEncryption'] = array_diff_key(
173-
$this->attributes['autoEncryption'],
174-
['kmsProvider' => 0, 'masterKey' => 0],
175-
);
166+
if (isset($this->attributes['kmsProvider'])) {
167+
$driverOptions['autoEncryption'] = $this->getAutoEncryptionOptions();
176168
}
177169

178170
return $driverOptions;
179171
}
180172

173+
/**
174+
* Get options to create a ClientEncryption instance.
175+
*
176+
* @see https://www.php.net/manual/en/mongodb-driver-clientencryption.construct.php
177+
*
178+
* @return array{keyVaultClient?: Client|Manager, keyVaultNamespace: string, kmsProviders: array<string, mixed>, tlsOptions?: array<string, mixed>}
179+
*/
180+
public function getClientEncryptionOptions(): array
181+
{
182+
if (! isset($this->attributes['kmsProvider'])) {
183+
throw new ConfigurationException('MongoDB client encryption options are not set in configuration');
184+
}
185+
186+
return array_intersect_key($this->getAutoEncryptionOptions(), [
187+
'keyVaultClient' => 1,
188+
'keyVaultNamespace' => 1,
189+
'kmsProviders' => 1,
190+
'tlsOptions' => 1,
191+
]);
192+
}
193+
181194
/**
182195
* Adds a namespace under a certain alias.
183196
*/
@@ -696,69 +709,72 @@ public function isLazyGhostObjectEnabled(): bool
696709
}
697710

698711
/**
699-
* Set the options for auto-encryption.
712+
* Set the KMS provider to use for auto-encryption. The name of the KMS provider
713+
* must be specified in the 'name' key of the array.
700714
*
701715
* @see https://www.php.net/manual/en/mongodb-driver-clientencryption.construct.php
702716
*
703-
* @phpstan-param AutoEncryptionOptions $options
704-
*
705-
* @throws InvalidArgumentException If the options are invalid.
717+
* @param KmsProvider $kmsProvider
706718
*/
707-
public function setAutoEncryption(array $options): void
719+
public function setKmsProvider(array $kmsProvider): void
708720
{
709-
if (! isset($options['keyVaultNamespace']) || ! is_string($options['keyVaultNamespace'])) {
710-
throw new InvalidArgumentException('The "keyVaultNamespace" encryption option is required.');
711-
}
712-
713-
if (! is_array($options['kmsProviders'] ?? null) || count($options['kmsProviders']) === 0) {
714-
throw new InvalidArgumentException('The "kmsProviders" encryption option is required and must be a non-empty.');
721+
if (! isset($kmsProvider['name'])) {
722+
throw new ConfigurationException('The "name" KMS provider option is required.');
715723
}
716724

717-
if (! isset($options['kmsProvider']) && count($options['kmsProviders']) > 1) {
718-
throw new InvalidArgumentException('The "kmsProvider" encryption option is required when multiple KMS providers are specified.');
725+
if (! is_string($kmsProvider['name'])) {
726+
throw new ConfigurationException('The "name" KMS provider option must be a non-empty string.');
719727
}
720728

721-
$options['kmsProvider'] ??= array_key_first($options['kmsProviders']);
722-
723-
if (! array_key_exists($options['kmsProvider'], $options['kmsProviders'])) {
724-
throw new InvalidArgumentException(sprintf('The "kmsProvider" encryption option "%s" is not defined in the "kmsProviders" option.', $options['kmsProvider']));
725-
}
726-
727-
if ($options['kmsProvider'] !== 'local' && ! isset($options['masterKey'])) {
728-
throw new InvalidArgumentException('The "masterKey" option is required when the KMS provider is not "local".');
729-
}
729+
$this->attributes['kmsProvider'] = $kmsProvider;
730+
}
730731

731-
$this->attributes['autoEncryption'] = $options;
732+
/**
733+
* Set the default master key to use when creating encrypted collections.
734+
*
735+
* @param array<string, mixed>|null $masterKey
736+
*/
737+
public function setDefaultMasterKey(?array $masterKey): void
738+
{
739+
$this->attributes['defaultMasterKey'] = $masterKey;
732740
}
733741

734742
/**
735-
* Get the options for auto-encryption.
743+
* Set the options for auto-encryption.
736744
*
737-
* @see https://www.php.net/manual/en/mongodb-driver-clientencryption.construct.php
745+
* @see https://www.php.net/manual/en/mongodb-driver-manager.construct.php
738746
*
739-
* @phpstan-return AutoEncryptionOptions
747+
* @param array{ keyVaultClient?: Client|Manager, keyVaultNamespace?: string, tlsOptions?: array<string, mixed>, schemaMap?: array<string, mixed>, encryptedFieldsMap?: array<string, mixed>, extraOptions?: array<string, mixed>} $options
740748
*/
741-
public function getAutoEncryption(): ?array
749+
public function setAutoEncryption(array $options): void
742750
{
743-
return $this->attributes['autoEncryption'] ?? null;
751+
if (isset($options['kmsProviders'])) {
752+
throw new ConfigurationException('The "kmsProviders" encryption option must be set using the "setKmsProvider()" method.');
753+
}
754+
755+
$this->attributes['autoEncryption'] = $options;
744756
}
745757

746758
/**
747-
* Get the KMS provider name used for auto-encryption.
759+
* Get the default KMS provider name used when creating encrypted collections.
748760
*/
749-
public function getKmsProvider(): ?string
761+
public function getDefaultKmsProvider(): ?string
750762
{
751-
return $this->attributes['autoEncryption']['kmsProvider'] ?? null;
763+
return $this->attributes['kmsProvider']['name'] ?? null;
752764
}
753765

754766
/**
755-
* Get the master key used for auto-encryption.
767+
* Get the default master key used when creating encrypted collections.
756768
*
757769
* @return array<string, mixed>|null
758770
*/
759-
public function getMasterKey(): ?array
771+
public function getDefaultMasterKey(): ?array
760772
{
761-
return $this->attributes['autoEncryption']['masterKey'] ?? null;
773+
if (! isset($this->attributes['kmsProvider']) || $this->attributes['kmsProvider']['name'] === 'local') {
774+
return null;
775+
}
776+
777+
return $this->attributes['defaultMasterKey'] ?? throw new ConfigurationException(sprintf('The "masterKey" configuration is required for the KMS provider "%s".', $this->attributes['kmsProvider']['name']));
762778
}
763779

764780
private static function getVersion(): string
@@ -773,6 +789,16 @@ private static function getVersion(): string
773789

774790
return self::$version;
775791
}
792+
793+
/** @return array<string, mixed> */
794+
private function getAutoEncryptionOptions(): array
795+
{
796+
return [
797+
'kmsProviders' => [$this->attributes['kmsProvider']['name'] => array_diff_key($this->attributes['kmsProvider'], ['name' => 0])],
798+
'keyVaultNamespace' => $this->getDefaultDB() . '.datakeys',
799+
...$this->attributes['autoEncryption'] ?? [],
800+
];
801+
}
776802
}
777803

778804
interface_exists(MappingDriver::class);

lib/Doctrine/ODM/MongoDB/ConfigurationException.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,4 +27,9 @@ public static function proxyDirMissing(): self
2727
{
2828
return new self('No proxy directory was configured. Please set a target directory first!');
2929
}
30+
31+
public static function kmsProvidersNotSupported(): self
32+
{
33+
return new self('Setting multiple KMS providers is not supported. Please set a single KMS provider in your configuration.');
34+
}
3035
}

lib/Doctrine/ODM/MongoDB/DocumentManager.php

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -223,17 +223,17 @@ public function getClient(): Client
223223
/** @internal */
224224
public function getClientEncryption(): ClientEncryption
225225
{
226-
$autoEncryptionOptions = $this->config->getAutoEncryption();
226+
if (isset($this->clientEncryption)) {
227+
return $this->clientEncryption;
228+
}
229+
230+
$options = $this->config->getClientEncryptionOptions();
227231

228-
if (! $autoEncryptionOptions) {
232+
if (! $options) {
229233
throw new RuntimeException('Auto-encryption is not enabled.');
230234
}
231235

232-
return $this->clientEncryption ??= $this->client->createClientEncryption([
233-
'keyVaultNamespace' => $autoEncryptionOptions['keyVaultNamespace'],
234-
'kmsProviders' => $autoEncryptionOptions['kmsProviders'],
235-
'tlsOptions' => $autoEncryptionOptions['tlsOptions'] ?? [],
236-
]);
236+
return $this->clientEncryption = $this->client->createClientEncryption($options);
237237
}
238238

239239
/** Gets the metadata factory used to gather the metadata of classes. */

lib/Doctrine/ODM/MongoDB/SchemaManager.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -645,7 +645,7 @@ public function createDocumentCollection(string $documentName, ?int $maxTimeMs =
645645
}
646646

647647
// Encryption is enabled only if the KMS provider is set and at least one field is encrypted
648-
if ($this->dm->getConfiguration()->getAutoEncryption()) {
648+
if ($this->dm->getConfiguration()->getDefaultKmsProvider()) {
649649
$encryptedFields = (new EncryptionFieldMap($this->dm->getMetadataFactory()))->getEncryptionFieldMap($class->name);
650650

651651
if ($encryptedFields) {
@@ -657,8 +657,8 @@ public function createDocumentCollection(string $documentName, ?int $maxTimeMs =
657657
$this->dm->getDocumentDatabase($documentName)->createEncryptedCollection(
658658
$class->getCollection(),
659659
$this->dm->getClientEncryption(),
660-
$this->dm->getConfiguration()->getKmsProvider(),
661-
$this->dm->getConfiguration()->getMasterKey(),
660+
$this->dm->getConfiguration()->getDefaultKmsProvider(),
661+
$this->dm->getConfiguration()->getDefaultMasterKey(),
662662
$this->getWriteOptions($maxTimeMs, $writeConcern, $options),
663663
);
664664
} else {

0 commit comments

Comments
 (0)