Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 75eb24a

Browse files
jmikolaGromNaN
andauthored
PHPLIB-1702: Always consult server encryptedFieldsMap when dropping collections with autoEncryption enabled (#1745)
* PHPLIB-1702: Always consult server encryptedFieldsMap when dropping collections * Bump tests/drivers-evergreen-tools to a332144 Necessary to fix PyMongo compat with MongoDB 4.0 * Detect metadata collections only when auto encryption is enabled on the client * Bump tests/specifications to 0aee4aa Necessary to fix change stream tests for server 8.2+ --------- Co-authored-by: Jérôme Tamarelle <jerome@tamarelle.net>
1 parent ae3821a commit 75eb24a

File tree

7 files changed

+130
-14
lines changed

7 files changed

+130
-14
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: 10 additions & 2 deletions
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,9 +536,9 @@ 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)
533-
?? get_encrypted_fields_from_server($this->databaseName, $this->collectionName, $this->manager, $server);
541+
?? get_encrypted_fields_from_server($this->databaseName, $this->collectionName, $server);
534542
}
535543

536544
$operation = isset($options['encryptedFields'])

‎src/Database.php

Lines changed: 11 additions & 2 deletions
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,9 +418,9 @@ 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)
415-
?? get_encrypted_fields_from_server($this->databaseName, $collectionName, $this->manager, $server);
423+
?? get_encrypted_fields_from_server($this->databaseName, $collectionName, $server);
416424
}
417425

418426
$operation = isset($options['encryptedFields'])
@@ -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);

‎src/functions.php

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -201,13 +201,8 @@ function get_encrypted_fields_from_driver(string $databaseName, string $collecti
201201
* @see Database::dropCollection()
202202
* @return array|object|null
203203
*/
204-
function get_encrypted_fields_from_server(string $databaseName, string $collectionName, Manager$manager, Server $server)
204+
function get_encrypted_fields_from_server(string $databaseName, string $collectionName, Server $server)
205205
{
206-
// No-op if the encryptedFieldsMap autoEncryption driver option was omitted
207-
if ($manager->getEncryptedFieldsMap() === null) {
208-
return null;
209-
}
210-
211206
$collectionInfoIterator = (new ListCollections($databaseName, ['filter' => ['name' => $collectionName]]))->execute($server);
212207

213208
foreach ($collectionInfoIterator as $collectionInfo) {
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
<?php
2+
3+
namespace MongoDB\Tests\Functions;
4+
5+
use MongoDB\BSON\Binary;
6+
use MongoDB\BSON\Regex;
7+
use MongoDB\Collection;
8+
use MongoDB\Database;
9+
use MongoDB\Driver\ClientEncryption;
10+
use MongoDB\Driver\WriteConcern;
11+
use MongoDB\Tests\FunctionalTestCase;
12+
13+
use function preg_quote;
14+
use function str_repeat;
15+
16+
class GetEncryptedFieldsFromServerFunctionalTest extends FunctionalTestCase
17+
{
18+
private ClientEncryption $clientEncryption;
19+
private Collection $keyVaultCollection;
20+
private Database $database;
21+
22+
public function setUp(): void
23+
{
24+
parent::setUp();
25+
26+
$this->skipIfClientSideEncryptionIsNotSupported();
27+
28+
if ($this->isStandalone()) {
29+
$this->markTestSkipped('Queryable encryption requires replica sets');
30+
}
31+
32+
$this->skipIfServerVersion('<', '7.0.0', 'Queryable encryption requires MongoDB 7.0 or later');
33+
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]);
43+
44+
// Ensure the key vault collection is dropped before each test
45+
$this->keyVaultCollection = $client->getCollection('keyvault', 'datakeys', ['writeConcern' => new WriteConcern(WriteConcern::MAJORITY)]);
46+
$this->keyVaultCollection->drop();
47+
48+
$this->clientEncryption = $client->createClientEncryption($encryptionOptions);
49+
50+
$this->database = $client->getDatabase($this->getDatabaseName());
51+
}
52+
53+
public function tearDown(): void
54+
{
55+
$this->keyVaultCollection?->drop();
56+
}
57+
58+
/** @see https://jira.mongodb.org/browse/PHPLIB-1702 */
59+
public function testDatabaseDropCollectionConsultsEncryptedFieldsFromServer(): void
60+
{
61+
$this->database->createEncryptedCollection(
62+
$this->getCollectionName(),
63+
$this->clientEncryption,
64+
'local',
65+
null,
66+
['encryptedFields' => ['fields' => []]],
67+
);
68+
69+
$this->assertCountCollections(3, $this->getCollectionName(), 'createEncryptedCollection should create three collections');
70+
71+
$this->database->dropCollection($this->getCollectionName());
72+
73+
$this->assertCountCollections(0, $this->getCollectionName());
74+
}
75+
76+
/** @see https://jira.mongodb.org/browse/PHPLIB-1702 */
77+
public function testCollectionDropConsultsEncryptedFieldsFromServer(): void
78+
{
79+
$this->database->createEncryptedCollection(
80+
$this->getCollectionName(),
81+
$this->clientEncryption,
82+
'local',
83+
null,
84+
['encryptedFields' => ['fields' => []]],
85+
);
86+
87+
$this->assertCountCollections(3, $this->getCollectionName(), 'createEncryptedCollection should create three collections');
88+
89+
$this->database->getCollection($this->getCollectionName())->drop();
90+
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);
100+
}
101+
}

‎tests/drivers-evergreen-tools

‎tests/specifications

Submodule specifications updated 71 files

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /