Skip to content

Commit 4b75b13

Browse files
committed
Add "fields" property to encryptedFieldsMap config
1 parent 81a7ddb commit 4b75b13

File tree

7 files changed

+371
-329
lines changed

7 files changed

+371
-329
lines changed

docs/encryption.rst

Lines changed: 39 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -79,26 +79,37 @@ Example of configuration for AWS
7979
Encrypted Fields Map
8080
--------------------
8181

82-
You can configure which fields are encrypted in each collection by specifying the
82+
The encrypted fields are set to the collection when you create it, and the MongoDB
83+
client will query the server for the collection schema before performing any
84+
operations. For additional security, you can also specify the encrypted fields
85+
in the connection configuration, which allows the client to use local rules
86+
instead of downloading the remote schema from the server, that could potentially
87+
be tampered with if an attacker compromises the server.
88+
89+
The Encrypted Fields Maps is a list of all encrypted fields associated with all
90+
the collection namespaces that has encryption enabled. To configure it, you
91+
can run a command that extract the encrypted fields from the server and generate
92+
the ``encryptedFieldsMap`` configuration.
93+
94+
.. code-block:: console
95+
96+
php bin/console doctrine:mongodb:dump-encrypted-fields-map --format yaml
97+
98+
The output of the command will be a YAML configuration for the
8399
``autoEncryption.encryptedFieldsMap`` option in the connection configuration.
84-
This setting is **recommended** for improved security and performance.
85100

86101
- If the connection ``encryptedFieldsMap`` object contains a key for the specified
87-
collection, the client uses that object to perform automatic Queryable Encryption,
88-
rather than using the remote schema. At minimum, the local rules must encrypt
89-
all fields that the remote schema does.
102+
collection namespace, the client uses that object to perform automatic
103+
Queryable Encryption, rather than using the remote schema. At minimum, the
104+
local rules must encrypt all fields that the remote schema does.
90105

91106
- If the connection ``encryptedFieldsMap`` object doesn't contain a key for the
92-
specified collection, the client downloads the server-side remote schema for
93-
the collection and uses it instead.
107+
specified collection namespace, the client downloads the server-side remote
108+
schema for the collection and uses it instead.
94109

95110
For more details, see the official MongoDB documentation:
96111
`Encrypted Fields and Enabled Queries <https://www.mongodb.com/docs/manual/core/queryable-encryption/fundamentals/encrypt-and-query/>`_.
97112

98-
Note that there is no ``fields`` key in the configuration of each collection
99-
for the bundle configuration. Instead, you directly specify the list of
100-
encrypted fields as an array under the collection namespace.
101-
102113
.. tabs::
103114

104115
.. group-tab:: YAML
@@ -111,9 +122,10 @@ encrypted fields as an array under the collection namespace.
111122
autoEncryption:
112123
encryptedFieldsMap:
113124
"mydatabase.mycollection":
114-
- keyId: { $binary: { base64: 2CSosXLSTEKaYphcSnUuCw==, subType: '04' } }
115-
path: "sensitive_field"
116-
bsonType: "string"
125+
fields:
126+
- keyId: { $binary: { base64: 2CSosXLSTEKaYphcSnUuCw==, subType: '04' } }
127+
path: "sensitive_field"
128+
bsonType: "string"
117129
118130
.. group-tab:: XML
119131

@@ -124,11 +136,13 @@ encrypted fields as an array under the collection namespace.
124136
<doctrine:encryptedFieldsMap>
125137
<![CDATA[
126138
{
127-
"mydatabase.mycollection": [
128-
"keyId": { "$binary": { "base64": "2CSosXLSTEKaYphcSnUuCw==", "subType": "04" } },
129-
"path": "sensitive_field",
130-
"bsonType": "string"
131-
]
139+
"mydatabase.mycollection": {
140+
fields: [
141+
"keyId": { "$binary": { "base64": "2CSosXLSTEKaYphcSnUuCw==", "subType": "04" } },
142+
"path": "sensitive_field",
143+
"bsonType": "string"
144+
]
145+
}
132146
}
133147
]]>
134148
</doctrine:encryptedFieldsMap>
@@ -146,10 +160,12 @@ encrypted fields as an array under the collection namespace.
146160
->autoEncryption([
147161
'encryptedFieldsMap' => [
148162
'mydatabase.mycollection' => [
149-
[
150-
'path' => 'sensitive_field',
151-
'keyId' => ['$binary' => ['base64' => '2CSosXLSTEKaYphcSnUuCw==', 'subType' => '04' ] ],
152-
'bsonType' => 'string',
163+
'fields' => [
164+
[
165+
'path' => 'sensitive_field',
166+
'keyId' => ['$binary' => ['base64' => '2CSosXLSTEKaYphcSnUuCw==', 'subType' => '04' ] ],
167+
'bsonType' => 'string',
168+
],
153169
],
154170
],
155171
],

src/Command/DumpEncryptedFieldsMapCommand.php

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,8 @@ protected function execute(InputInterface $input, OutputInterface $output): int
7777
}
7878

7979
foreach ($encryptedFieldsMap as $ns => $encryptedFields) {
80-
$encryptedFieldsMap[$ns] = json_decode(PackedArray::fromPHP($encryptedFields['fields'])->toRelaxedExtendedJSON(), true);
80+
// Keep only the "fields" key and ignore "escCollection" and "ecocCollection"
81+
$encryptedFieldsMap[$ns] = ['fields' => json_decode(PackedArray::fromPHP($encryptedFields['fields'])->toRelaxedExtendedJSON(), true)];
8182
}
8283

8384
$io->section(sprintf('Dumping encrypted fields map for document manager "%s"', $name));
@@ -105,9 +106,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int
105106

106107
private function getDocumentNamespace(ClassMetadata $metadata, string $defaultDb): string
107108
{
108-
$db = $metadata->getDatabase();
109-
$db = $db ?: $defaultDb;
110-
$db = $db ?: 'doctrine';
109+
$db = $metadata->getDatabase() ?: $defaultDb ?: 'doctrine';
111110

112111
return $db . '.' . $metadata->getCollection();
113112
}

src/DependencyInjection/Configuration.php

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -407,20 +407,24 @@ private function addConnectionsSection(ArrayNodeDefinition $rootNode): void
407407
return $v;
408408
})->end()
409409
->prototype('array')
410-
->prototype('array')
411-
->children()
412-
->scalarNode('path')->isRequired()->cannotBeEmpty()->end()
413-
->scalarNode('bsonType')->isRequired()->cannotBeEmpty()->end()
414-
->variableNode('keyId')->isRequired()->cannotBeEmpty()->end()
415-
->arrayNode('queries')
410+
->children()
411+
->arrayNode('fields')
412+
->prototype('array')
416413
->children()
417-
->scalarNode('queryType')->isRequired()->cannotBeEmpty()->end()
418-
->variableNode('min')->end()
419-
->variableNode('max')->end()
420-
->integerNode('sparsity')->end()
421-
->integerNode('precision')->end()
422-
->integerNode('trimFactor')->end()
423-
->integerNode('contention')->end()
414+
->scalarNode('path')->isRequired()->cannotBeEmpty()->end()
415+
->scalarNode('bsonType')->isRequired()->cannotBeEmpty()->end()
416+
->variableNode('keyId')->isRequired()->cannotBeEmpty()->end()
417+
->arrayNode('queries')
418+
->children()
419+
->scalarNode('queryType')->isRequired()->cannotBeEmpty()->end()
420+
->variableNode('min')->end()
421+
->variableNode('max')->end()
422+
->integerNode('sparsity')->end()
423+
->integerNode('precision')->end()
424+
->integerNode('trimFactor')->end()
425+
->integerNode('contention')->end()
426+
->end()
427+
->end()
424428
->end()
425429
->end()
426430
->end()

src/DependencyInjection/DoctrineMongoDBExtension.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -549,7 +549,7 @@ private function normalizeAutoEncryption(array $autoEncryption, string $defaultD
549549
foreach ($autoEncryption['encryptedFieldsMap'] as &$value) {
550550
// Wrap the encrypted fields in a 'fields' key as required the encryptedFieldsMap structure.
551551
// Some values can be BSON binary, date or numbers, the extended JSON format is used to convert them BSON document.
552-
$value = (new Definition(BsonDocument::class))->setFactory([BsonDocument::class, 'fromJSON'])->setArguments([json_encode(['fields' => $value])]);
552+
$value = (new Definition(BsonDocument::class))->setFactory([BsonDocument::class, 'fromJSON'])->setArguments([json_encode($value)]);
553553
}
554554
}
555555

0 commit comments

Comments
 (0)