Skip to content

Commit

Permalink
Code review feedback
Browse files Browse the repository at this point in the history
Demonstrates schema validation errors in example scripts

Relocates local schema section after server-side schema, and clarifies that it should be used in conjunction with server-side schemas (not instead of).

Revise comments and variable names in scripts and update expected output for tests accordingly.
  • Loading branch information
jmikola committed Jul 10, 2023
1 parent 29db0f8 commit b4bfd0e
Show file tree
Hide file tree
Showing 10 changed files with 260 additions and 219 deletions.
13 changes: 8 additions & 5 deletions docs/examples/create_data_key.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,21 +11,24 @@
// Generate a secure local key to use for this script
$localKey = new Binary(random_bytes(96));

/* Create a client with no encryption options. Additionally, create a
* ClientEncryption object to manage data keys. */
// Create a client with no encryption options
$client = new Client($uri);

// Create a ClientEncryption object to manage data encryption keys
$clientEncryption = $client->createClientEncryption([
'keyVaultNamespace' => 'encryption.__keyVault',
'kmsProviders' => [
'local' => ['key' => $localKey],
],
]);

/* Drop the key vault collection and create an encryption key. This would
* typically be done during application deployment. To store the key ID for
* later use, you can use serialize() or var_export(). */
/* Create a new key vault collection for this script. The application must also
* ensure that a unique index exists for keyAltNames. */
$client->selectCollection('encryption', '__keyVault')->drop();
$client->selectCollection('encryption', '__keyVault')->createIndex(['keyAltNames' => 1], ['unique' => true]);

/* Create a data encryption key. To store the key ID for later use, you can use
* serialize(), var_export(), etc. */
$keyId = $clientEncryption->createDataKey('local');

print_r($keyId);
Expand Down
74 changes: 44 additions & 30 deletions docs/examples/csfle-automatic_encryption-local_schema.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
use MongoDB\BSON\Binary;
use MongoDB\Client;
use MongoDB\Driver\ClientEncryption;
use MongoDB\Driver\Exception\ServerException;

require __DIR__ . '/../../vendor/autoload.php';

Expand All @@ -11,62 +12,75 @@
// Generate a secure local key to use for this script
$localKey = new Binary(random_bytes(96));

/* Create a client with no encryption options. Additionally, create a
* ClientEncryption object to manage data keys. */
// Create a client with no encryption options
$client = new Client($uri);

// Create a ClientEncryption object to manage data encryption keys
$clientEncryption = $client->createClientEncryption([
'keyVaultNamespace' => 'encryption.__keyVault',
'kmsProviders' => [
'local' => ['key' => $localKey],
],
]);

/* Drop the key vault collection and create an encryption key. Alternatively,
* this key ID could be read from a configuration file. */
/* Create a new key vault collection and data encryption key for this script.
* Alternatively, this key ID could be read from a configuration file. */
$client->selectCollection('encryption', '__keyVault')->drop();
$client->selectCollection('encryption', '__keyVault')->createIndex(['keyAltNames' => 1], ['unique' => true]);
$keyId = $clientEncryption->createDataKey('local');

/* Create a client with automatic encryption enabled. Specify a schemaMap option
* to enforce a local JSON schema. */
/* Define a JSON schema for the encrypted collection. Since this only utilizes
* encryption schema syntax, it can be used for both the server-side and local
* schema. */
$schema = [
'bsonType' => 'object',
'properties' => [
'encryptedField' => [
'encrypt' => [
'keyId' => [$keyId],
'bsonType' => 'string',
'algorithm' => ClientEncryption::AEAD_AES_256_CBC_HMAC_SHA_512_DETERMINISTIC,
],
],
],
];

/* Create another client with automatic encryption enabled. Configure a local
* schema for the encrypted collection using the "schemaMap" option. */
$encryptedClient = new Client($uri, [], [
'autoEncryption' => [
'keyVaultNamespace' => 'encryption.__keyVault',
'kmsProviders' => ['local' => ['key' => $localKey]],
'schemaMap' => [
'test.coll' => [
'bsonType' => 'object',
'properties' => [
'encryptedField' => [
'encrypt' => [
'keyId' => [$keyId],
'bsonType' => 'string',
'algorithm' => ClientEncryption::AEAD_AES_256_CBC_HMAC_SHA_512_DETERMINISTIC,
],
],
],
],
],
'schemaMap' => ['test.coll' => $schema],
],
]);

// Drop and create the collection.
/* Create a new collection for this script. Configure a server-side schema by
* explicitly creating the collection with a "validator" option.
*
* Note: without a server-side schema, another client could potentially insert
* unencrypted data into the collection. Therefore, a local schema should always
* be used in conjunction with a server-side schema. */
$encryptedClient->selectDatabase('test')->dropCollection('coll');
$encryptedClient->selectDatabase('test')->createCollection('coll');
$encryptedClient->selectDatabase('test')->createCollection('coll', ['validator' => ['$jsonSchema' => $schema]]);
$encryptedCollection = $encryptedClient->selectCollection('test', 'coll');

/* Using the encrypted client, insert and find a document. The encrypted field
* will be automatically encrypted and decrypted. */
$encryptedCollection->insertOne([
'_id' => 1,
'encryptedField' => 'mySecret',
]);
/* Using the encrypted client, insert and find a document to demonstrate that
* the encrypted field is automatically encrypted and decrypted. */
$encryptedCollection->insertOne(['_id' => 1, 'encryptedField' => 'mySecret']);

print_r($encryptedCollection->findOne(['_id' => 1]));

/* Using the client configured without encryption, find the same document and
* observe that the field is not automatically decrypted. Additionally, the JSON
* schema will prohibit inserting a document with an unencrypted field value. */
* observe that the field is not automatically decrypted. */
$unencryptedCollection = $client->selectCollection('test', 'coll');

print_r($unencryptedCollection->findOne(['_id' => 1]));

/* Attempt to insert another document with an unencrypted field value to
* demonstrate that the server-side schema is enforced. */
try {
$unencryptedCollection->insertOne(['_id' => 2, 'encryptedField' => 'myOtherSecret']);
} catch (ServerException $e) {
printf("Error inserting document: %s\n", $e->getMessage());
}
57 changes: 31 additions & 26 deletions docs/examples/csfle-automatic_encryption-server_side_schema.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
use MongoDB\BSON\Binary;
use MongoDB\Client;
use MongoDB\Driver\ClientEncryption;
use MongoDB\Driver\Exception\ServerException;

require __DIR__ . '/../../vendor/autoload.php';

Expand All @@ -11,63 +12,67 @@
// Generate a secure local key to use for this script
$localKey = new Binary(random_bytes(96));

/* Create a client with no encryption options. Additionally, create a
* ClientEncryption object to manage data keys. */
// Create a client with no encryption options
$client = new Client($uri);

// Create a ClientEncryption object to manage data encryption keys
$clientEncryption = $client->createClientEncryption([
'keyVaultNamespace' => 'encryption.__keyVault',
'kmsProviders' => [
'local' => ['key' => $localKey],
],
]);

/* Drop the key vault collection and create an encryption key. Alternatively,
* this key ID could be read from a configuration file. */
/* Create a new key vault collection and data encryption key for this script.
* Alternatively, this key ID could be read from a configuration file. */
$client->selectCollection('encryption', '__keyVault')->drop();
$client->selectCollection('encryption', '__keyVault')->createIndex(['keyAltNames' => 1], ['unique' => true]);
$keyId = $clientEncryption->createDataKey('local');

// Create a client with automatic encryption enabled
// Create another client with automatic encryption enabled
$encryptedClient = new Client($uri, [], [
'autoEncryption' => [
'keyVaultNamespace' => 'encryption.__keyVault',
'kmsProviders' => ['local' => ['key' => $localKey]],
],
]);

/* Drop and create the collection. Specify a validator option when creating the
* collection to enforce a server-side JSON schema. */
$validator = [
'$jsonSchema' => [
'bsonType' => 'object',
'properties' => [
'encryptedField' => [
'encrypt' => [
'keyId' => [$keyId],
'bsonType' => 'string',
'algorithm' => ClientEncryption::AEAD_AES_256_CBC_HMAC_SHA_512_DETERMINISTIC,
],
// Define a JSON schema for the encrypted collection
$schema = [
'bsonType' => 'object',
'properties' => [
'encryptedField' => [
'encrypt' => [
'keyId' => [$keyId],
'bsonType' => 'string',
'algorithm' => ClientEncryption::AEAD_AES_256_CBC_HMAC_SHA_512_DETERMINISTIC,
],
],
],
];

/* Create a new collection for this script. Configure a server-side schema by
* explicitly creating the collection with a "validator" option. */
$encryptedClient->selectDatabase('test')->dropCollection('coll');
$encryptedClient->selectDatabase('test')->createCollection('coll', ['validator' => $validator]);
$encryptedClient->selectDatabase('test')->createCollection('coll', ['validator' => ['$jsonSchema' => $schema]]);
$encryptedCollection = $encryptedClient->selectCollection('test', 'coll');

/* Using the encrypted client, insert and find a document. The encrypted field
* will be automatically encrypted and decrypted. */
$encryptedCollection->insertOne([
'_id' => 1,
'encryptedField' => 'mySecret',
]);
/* Using the encrypted client, insert and find a document to demonstrate that
* the encrypted field is automatically encrypted and decrypted. */
$encryptedCollection->insertOne(['_id' => 1, 'encryptedField' => 'mySecret']);

print_r($encryptedCollection->findOne(['_id' => 1]));

/* Using the client configured without encryption, find the same document and
* observe that the field is not automatically decrypted. Additionally, the JSON
* schema will prohibit inserting a document with an unencrypted field value. */
* observe that the field is not automatically decrypted. */
$unencryptedCollection = $client->selectCollection('test', 'coll');

print_r($unencryptedCollection->findOne(['_id' => 1]));

/* Attempt to insert another document with an unencrypted field value to
* demonstrate that the server-side schema is enforced. */
try {
$unencryptedCollection->insertOne(['_id' => 2, 'encryptedField' => 'myOtherSecret']);
} catch (ServerException $e) {
printf("Error inserting document: %s\n", $e->getMessage());
}
24 changes: 13 additions & 11 deletions docs/examples/csfle-explicit_encryption.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,23 +11,24 @@
// Generate a secure local key to use for this script
$localKey = new Binary(random_bytes(96));

/* Create a client with no encryption options. Additionally, create a
* ClientEncryption object to manage data keys. */
// Create a client with no encryption options
$client = new Client($uri);

// Create a ClientEncryption object to manage data encryption keys
$clientEncryption = $client->createClientEncryption([
'keyVaultNamespace' => 'encryption.__keyVault',
'kmsProviders' => [
'local' => ['key' => $localKey],
],
]);

/* Drop the key vault collection and create an encryption key. Alternatively,
* this key ID could be read from a configuration file. */
/* Create a new key vault collection and data encryption key for this script.
* Alternatively, this key ID could be read from a configuration file. */
$client->selectCollection('encryption', '__keyVault')->drop();
$client->selectCollection('encryption', '__keyVault')->createIndex(['keyAltNames' => 1], ['unique' => true]);
$keyId = $clientEncryption->createDataKey('local');

// Select and drop a collection to use for this example
// Create a new collection for this script
$collection = $client->selectCollection('test', 'coll');
$collection->drop();

Expand All @@ -37,12 +38,13 @@
'keyId' => $keyId,
]);

$collection->insertOne(['encryptedField' => $encryptedValue]);
$collection->insertOne(['_id' => 1, 'encryptedField' => $encryptedValue]);

/* Query for the document. The field will not be automatically decrypted
* because the client was not configured with an autoEncryption driver option.
* Manually decrypt the field value using the ClientEncryption object. */
/* Using the client configured without encryption, find the document and observe
* that the field is not automatically decrypted. */
$document = $collection->findOne();

print_r($document->encryptedField);
print_r($clientEncryption->decrypt($document->encryptedField));
print_r($document);

// Manually decrypt the field
printf("Decrypted: %s\n", $clientEncryption->decrypt($document->encryptedField));

Check failure on line 50 in docs/examples/csfle-explicit_encryption.php

View workflow job for this annotation

GitHub Actions / Psalm

MixedArgument

docs/examples/csfle-explicit_encryption.php:50:27: MixedArgument: Argument 2 of printf cannot be mixed, expecting float|int|string (see https://psalm.dev/030)
17 changes: 9 additions & 8 deletions docs/examples/csfle-explicit_encryption_automatic_decryption.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,20 +20,21 @@
],
]);

// Create a ClientEncryption object to manage data keys
// Create a ClientEncryption object to manage data encryption keys
$clientEncryption = $client->createClientEncryption([
'keyVaultNamespace' => 'encryption.__keyVault',
'kmsProviders' => [
'local' => ['key' => $localKey],
],
]);

/* Drop the key vault collection and create an encryption key. Alternatively,
* this key ID could be read from a configuration file. */
/* Create a new key vault collection and data encryption key for this script.
* Alternatively, this key ID could be read from a configuration file. */
$client->selectCollection('encryption', '__keyVault')->drop();
$client->selectCollection('encryption', '__keyVault')->createIndex(['keyAltNames' => 1], ['unique' => true]);
$keyId = $clientEncryption->createDataKey('local');

// Select and drop a collection to use for this example
// Create a new collection for this script
$collection = $client->selectCollection('test', 'coll');
$collection->drop();

Expand All @@ -43,10 +44,10 @@
'keyId' => $keyId,
]);

$collection->insertOne(['encryptedField' => $encryptedValue]);
$collection->insertOne(['_id' => 1, 'encryptedField' => $encryptedValue]);

/* Query for the document. The field will still be automatically decrypted
* because the client was configured with an autoEncryption driver option. */
/* Using the client configured with encryption (but not automatic encryption),
* find the document and observe that the field is automatically decrypted. */
$document = $collection->findOne();

print_r($document->encryptedField);
print_r($document);
21 changes: 16 additions & 5 deletions docs/examples/key_alt_name.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
use MongoDB\BSON\Binary;
use MongoDB\Client;
use MongoDB\Driver\ClientEncryption;
use MongoDB\Driver\Exception\ServerException;

require __DIR__ . '/../../vendor/autoload.php';

Expand All @@ -11,23 +12,33 @@
// Generate a secure local key to use for this script
$localKey = new Binary(random_bytes(96));

/* Create a client with no encryption options. Additionally, create a
* ClientEncryption object to manage data keys. */
// Create a client with no encryption options
$client = new Client($uri);

// Create a ClientEncryption object to manage data encryption keys
$clientEncryption = $client->createClientEncryption([
'keyVaultNamespace' => 'encryption.__keyVault',
'kmsProviders' => [
'local' => ['key' => $localKey],
],
]);

/* Drop the key vault collection and create an encryption key with an alternate
* name. This would typically be done during application deployment. To store
* the key ID for later use, you can use serialize() or var_export(). */
/* Create a new key vault collection for this script. The application must also
* ensure that a unique index exists for keyAltNames. */
$client->selectCollection('encryption', '__keyVault')->drop();
$client->selectCollection('encryption', '__keyVault')->createIndex(['keyAltNames' => 1], ['unique' => true]);

// Create a data encryption key with an alternate name
$clientEncryption->createDataKey('local', ['keyAltNames' => ['myDataKey']]);

/* Attempt to create a second key with the same name to demonstrate that the
* unique index is enforced. */
try {
$clientEncryption->createDataKey('local', ['keyAltNames' => ['myDataKey']]);
} catch (ServerException $e) {
printf("Error creating key: %s\n", $e->getMessage());
}

// Encrypt a value, using the "keyAltName" option instead of "keyId"
$encryptedValue = $clientEncryption->encrypt('mySecret', [
'algorithm' => ClientEncryption::AEAD_AES_256_CBC_HMAC_SHA_512_DETERMINISTIC,
Expand Down
Loading

0 comments on commit b4bfd0e

Please sign in to comment.