Skip to content

Commit 878e5cd

Browse files
committed
Detect metadata collections only when auto encryption is enabled on the client
1 parent 8ef5fe6 commit 878e5cd

File tree

4 files changed

+49
-21
lines changed

4 files changed

+49
-21
lines changed

src/Client.php

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,8 @@ class Client
8383

8484
private WriteConcern $writeConcern;
8585

86+
private bool $autoEncryptionEnabled;
87+
8688
/**
8789
* Constructs a new Client instance.
8890
*
@@ -134,6 +136,7 @@ public function __construct(?string $uri = null, array $uriOptions = [], array $
134136
$this->uri = $uri ?? self::DEFAULT_URI;
135137
$this->builderEncoder = $driverOptions['builderEncoder'] ?? new BuilderEncoder();
136138
$this->typeMap = $driverOptions['typeMap'];
139+
$this->autoEncryptionEnabled = isset($driverOptions['autoEncryption']['keyVaultNamespace']);
137140

138141
$driverOptions = array_diff_key($driverOptions, ['builderEncoder' => 1, 'typeMap' => 1]);
139142

@@ -258,7 +261,7 @@ public function dropDatabase(string $databaseName, array $options = [])
258261
*/
259262
public function getCollection(string $databaseName, string $collectionName, array $options = []): Collection
260263
{
261-
$options += ['typeMap' => $this->typeMap, 'builderEncoder' => $this->builderEncoder];
264+
$options += ['typeMap' => $this->typeMap, 'builderEncoder' => $this->builderEncoder, 'autoEncryptionEnabled' => $this->autoEncryptionEnabled];
262265

263266
return new Collection($this->manager, $databaseName, $collectionName, $options);
264267
}
@@ -273,7 +276,7 @@ public function getCollection(string $databaseName, string $collectionName, arra
273276
*/
274277
public function getDatabase(string $databaseName, array $options = []): Database
275278
{
276-
$options += ['typeMap' => $this->typeMap, 'builderEncoder' => $this->builderEncoder];
279+
$options += ['typeMap' => $this->typeMap, 'builderEncoder' => $this->builderEncoder, 'autoEncryptionEnabled' => $this->autoEncryptionEnabled];
277280

278281
return new Database($this->manager, $databaseName, $options);
279282
}

src/Collection.php

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@
7777
use function array_key_exists;
7878
use function current;
7979
use function is_array;
80+
use function is_bool;
8081
use function sprintf;
8182
use function strlen;
8283
use function trigger_error;
@@ -106,6 +107,8 @@ class Collection
106107

107108
private WriteConcern $writeConcern;
108109

110+
private bool $autoEncryptionEnabled;
111+
109112
/**
110113
* Constructs new Collection instance.
111114
*
@@ -173,12 +176,17 @@ public function __construct(private Manager $manager, private string $databaseNa
173176
throw InvalidArgumentException::invalidType('"writeConcern" option', $options['writeConcern'], WriteConcern::class);
174177
}
175178

179+
if (isset($options['autoEncryptionEnabled']) && ! is_bool($options['autoEncryptionEnabled'])) {
180+
throw InvalidArgumentException::invalidType('"autoEncryptionEnabled" option', $options['autoEncryptionEnabled'], 'boolean');
181+
}
182+
176183
$this->builderEncoder = $options['builderEncoder'] ?? new BuilderEncoder();
177184
$this->codec = $options['codec'] ?? null;
178185
$this->readConcern = $options['readConcern'] ?? $this->manager->getReadConcern();
179186
$this->readPreference = $options['readPreference'] ?? $this->manager->getReadPreference();
180187
$this->typeMap = $options['typeMap'] ?? self::DEFAULT_TYPE_MAP;
181188
$this->writeConcern = $options['writeConcern'] ?? $this->manager->getWriteConcern();
189+
$this->autoEncryptionEnabled = $options['autoEncryptionEnabled'] ?? false;
182190
}
183191

184192
/**
@@ -528,7 +536,7 @@ public function drop(array $options = [])
528536

529537
$server = select_server_for_write($this->manager, $options);
530538

531-
if (! isset($options['encryptedFields'])) {
539+
if ($this->autoEncryptionEnabled && ! isset($options['encryptedFields'])) {
532540
$options['encryptedFields'] = get_encrypted_fields_from_driver($this->databaseName, $this->collectionName, $this->manager)
533541
?? get_encrypted_fields_from_server($this->databaseName, $this->collectionName, $server);
534542
}

src/Database.php

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@
5555
use Traversable;
5656

5757
use function is_array;
58+
use function is_bool;
5859
use function sprintf;
5960
use function strlen;
6061
use function trigger_error;
@@ -82,6 +83,8 @@ class Database
8283

8384
private WriteConcern $writeConcern;
8485

86+
private bool $autoEncryptionEnabled;
87+
8588
/**
8689
* Constructs new Database instance.
8790
*
@@ -138,11 +141,16 @@ public function __construct(private Manager $manager, private string $databaseNa
138141
throw InvalidArgumentException::invalidType('"writeConcern" option', $options['writeConcern'], WriteConcern::class);
139142
}
140143

144+
if (isset($options['autoEncryptionEnabled']) && ! is_bool($options['autoEncryptionEnabled'])) {
145+
throw InvalidArgumentException::invalidType('"autoEncryptionEnabled" option', $options['autoEncryptionEnabled'], 'boolean');
146+
}
147+
141148
$this->builderEncoder = $options['builderEncoder'] ?? new BuilderEncoder();
142149
$this->readConcern = $options['readConcern'] ?? $this->manager->getReadConcern();
143150
$this->readPreference = $options['readPreference'] ?? $this->manager->getReadPreference();
144151
$this->typeMap = $options['typeMap'] ?? self::DEFAULT_TYPE_MAP;
145152
$this->writeConcern = $options['writeConcern'] ?? $this->manager->getWriteConcern();
153+
$this->autoEncryptionEnabled = $options['autoEncryptionEnabled'] ?? false;
146154
}
147155

148156
/**
@@ -410,7 +418,7 @@ public function dropCollection(string $collectionName, array $options = [])
410418
$options['writeConcern'] = $this->writeConcern;
411419
}
412420

413-
if (! isset($options['encryptedFields'])) {
421+
if ($this->autoEncryptionEnabled && ! isset($options['encryptedFields'])) {
414422
$options['encryptedFields'] = get_encrypted_fields_from_driver($this->databaseName, $collectionName, $this->manager)
415423
?? get_encrypted_fields_from_server($this->databaseName, $collectionName, $server);
416424
}
@@ -439,6 +447,7 @@ public function getCollection(string $collectionName, array $options = []): Coll
439447
'readPreference' => $this->readPreference,
440448
'typeMap' => $this->typeMap,
441449
'writeConcern' => $this->writeConcern,
450+
'autoEncryptionEnabled' => $this->autoEncryptionEnabled,
442451
];
443452

444453
return new Collection($this->manager, $this->databaseName, $collectionName, $options);

tests/Functions/GetEncryptedFieldsFromServerFunctionalTest.php

Lines changed: 25 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,14 @@
33
namespace MongoDB\Tests\Functions;
44

55
use MongoDB\BSON\Binary;
6+
use MongoDB\BSON\Regex;
67
use MongoDB\Collection;
78
use MongoDB\Database;
89
use MongoDB\Driver\ClientEncryption;
910
use MongoDB\Driver\WriteConcern;
1011
use MongoDB\Tests\FunctionalTestCase;
1112

12-
use function iterator_count;
13+
use function preg_quote;
1314
use function str_repeat;
1415

1516
class GetEncryptedFieldsFromServerFunctionalTest extends FunctionalTestCase
@@ -30,30 +31,33 @@ public function setUp(): void
3031

3132
$this->skipIfServerVersion('<', '7.0.0', 'Queryable encryption requires MongoDB 7.0 or later');
3233

33-
$client = static::createTestClient();
34+
$encryptionOptions = [
35+
'keyVaultNamespace' => 'keyvault.datakeys',
36+
'kmsProviders' => [
37+
'local' => [
38+
'key' => new Binary(str_repeat("\0", 96)), // 96-byte local master key
39+
],
40+
],
41+
];
42+
$client = static::createTestClient(driverOptions: ['autoEncryption' => $encryptionOptions]);
3443

3544
// Ensure the key vault collection is dropped before each test
3645
$this->keyVaultCollection = $client->getCollection('keyvault', 'datakeys', ['writeConcern' => new WriteConcern(WriteConcern::MAJORITY)]);
3746
$this->keyVaultCollection->drop();
3847

39-
$this->clientEncryption = $client->createClientEncryption([
40-
'keyVaultNamespace' => $this->keyVaultCollection->getNamespace(),
41-
'kmsProviders' => ['local' => ['key' => new Binary(str_repeat("\0", 96)) ]],
42-
]);
48+
$this->clientEncryption = $client->createClientEncryption($encryptionOptions);
4349

4450
$this->database = $client->getDatabase($this->getDatabaseName());
4551
}
4652

4753
public function tearDown(): void
4854
{
49-
$this->keyVaultCollection->drop();
55+
$this->keyVaultCollection?->drop();
5056
}
5157

5258
/** @see https://jira.mongodb.org/browse/PHPLIB-1702 */
5359
public function testDatabaseDropCollectionConsultsEncryptedFieldsFromServer(): void
5460
{
55-
$originalNumCollections = iterator_count($this->database->listCollectionNames());
56-
5761
$this->database->createEncryptedCollection(
5862
$this->getCollectionName(),
5963
$this->clientEncryption,
@@ -62,19 +66,16 @@ public function testDatabaseDropCollectionConsultsEncryptedFieldsFromServer(): v
6266
['encryptedFields' => ['fields' => []]],
6367
);
6468

65-
// createEncryptedCollection should create three collections
66-
$this->assertCount($originalNumCollections + 3, $this->database->listCollectionNames());
69+
$this->assertCountCollections(3, $this->getCollectionName(), 'createEncryptedCollection should create three collections');
6770

6871
$this->database->dropCollection($this->getCollectionName());
6972

70-
$this->assertCount($originalNumCollections, $this->database->listCollectionNames());
73+
$this->assertCountCollections(0, $this->getCollectionName());
7174
}
7275

7376
/** @see https://jira.mongodb.org/browse/PHPLIB-1702 */
7477
public function testCollectionDropConsultsEncryptedFieldsFromServer(): void
7578
{
76-
$originalNumCollections = iterator_count($this->database->listCollectionNames());
77-
7879
$this->database->createEncryptedCollection(
7980
$this->getCollectionName(),
8081
$this->clientEncryption,
@@ -83,11 +84,18 @@ public function testCollectionDropConsultsEncryptedFieldsFromServer(): void
8384
['encryptedFields' => ['fields' => []]],
8485
);
8586

86-
// createEncryptedCollection should create three collections
87-
$this->assertCount($originalNumCollections + 3, $this->database->listCollectionNames());
87+
$this->assertCountCollections(3, $this->getCollectionName(), 'createEncryptedCollection should create three collections');
8888

8989
$this->database->getCollection($this->getCollectionName())->drop();
9090

91-
$this->assertCount($originalNumCollections, $this->database->listCollectionNames());
91+
$this->assertCountCollections(0, $this->getCollectionName());
92+
}
93+
94+
private function assertCountCollections(int $expected, $collectionName, string $message = ''): void
95+
{
96+
$collectionNames = $this->database->listCollectionNames([
97+
'filter' => ['name' => new Regex(preg_quote($collectionName))],
98+
]);
99+
$this->assertCount($expected, $collectionNames, $message);
92100
}
93101
}

0 commit comments

Comments
 (0)