|
15 | 15 | use MongoDB\Driver\Exception\ConnectionTimeoutException;
|
16 | 16 | use MongoDB\Driver\Exception\EncryptionException;
|
17 | 17 | use MongoDB\Driver\Exception\RuntimeException;
|
| 18 | +use MongoDB\Driver\Exception\ServerException; |
18 | 19 | use MongoDB\Driver\Monitoring\CommandFailedEvent;
|
19 | 20 | use MongoDB\Driver\Monitoring\CommandStartedEvent;
|
20 | 21 | use MongoDB\Driver\Monitoring\CommandSubscriber;
|
@@ -1403,6 +1404,93 @@ static function (self $test, ClientEncryption $clientEncryption, Client $encrypt
|
1403 | 1404 | ];
|
1404 | 1405 | }
|
1405 | 1406 |
|
| 1407 | + /** |
| 1408 | + * Prose test 13: Unique Index on keyAltNames |
| 1409 | + * |
| 1410 | + * @see https://github.com/mongodb/specifications/blob/master/source/client-side-encryption/tests/README.rst#unique-index-on-keyaltnames |
| 1411 | + * @dataProvider provideUniqueIndexOnKeyAltNamesTests |
| 1412 | + */ |
| 1413 | + public function testUniqueIndexOnKeyAltNames(Closure $test): void |
| 1414 | + { |
| 1415 | + // Test setup |
| 1416 | + $client = static::createTestClient(); |
| 1417 | + |
| 1418 | + // Ensure that the key vault is dropped with a majority write concern |
| 1419 | + self::insertKeyVaultData($client, []); |
| 1420 | + |
| 1421 | + $client->selectCollection('keyvault', 'datakeys')->createIndex( |
| 1422 | + ['keyAltNames' => 1], |
| 1423 | + [ |
| 1424 | + 'unique' => true, |
| 1425 | + 'partialFilterExpression' => ['keyAltNames' => ['$exists' => true]], |
| 1426 | + 'writeConcern' => new WriteConcern(WriteConcern::MAJORITY), |
| 1427 | + ] |
| 1428 | + ); |
| 1429 | + |
| 1430 | + $clientEncryption = new ClientEncryption([ |
| 1431 | + 'keyVaultClient' => $client->getManager(), |
| 1432 | + 'keyVaultNamespace' => 'keyvault.datakeys', |
| 1433 | + 'kmsProviders' => ['local' => ['key' => new Binary(base64_decode(self::LOCAL_MASTERKEY), 0)]], |
| 1434 | + ]); |
| 1435 | + |
| 1436 | + $clientEncryption->createDataKey('local', ['keyAltNames' => ['def']]); |
| 1437 | + |
| 1438 | + $test($this, $client, $clientEncryption); |
| 1439 | + } |
| 1440 | + |
| 1441 | + public static function provideUniqueIndexOnKeyAltNamesTests() |
| 1442 | + { |
| 1443 | + // See: https://github.com/mongodb/specifications/blob/master/source/client-side-encryption/tests/README.rst#case-1-createdatakey |
| 1444 | + yield 'Case 1: createDataKey()' => [ |
| 1445 | + static function (self $test, Client $client, ClientEncryption $clientEncryption): void { |
| 1446 | + $clientEncryption->createDataKey('local', ['keyAltNames' => ['abc']]); |
| 1447 | + |
| 1448 | + try { |
| 1449 | + $clientEncryption->createDataKey('local', ['keyAltNames' => ['abc']]); |
| 1450 | + $test->fail('Expected exception to be thrown'); |
| 1451 | + } catch (ServerException $e) { |
| 1452 | + $test->assertSame(11000 /* DuplicateKey */, $e->getCode()); |
| 1453 | + } |
| 1454 | + |
| 1455 | + try { |
| 1456 | + $clientEncryption->createDataKey('local', ['keyAltNames' => ['def']]); |
| 1457 | + $test->fail('Expected exception to be thrown'); |
| 1458 | + } catch (ServerException $e) { |
| 1459 | + $test->assertSame(11000 /* DuplicateKey */, $e->getCode()); |
| 1460 | + } |
| 1461 | + }, |
| 1462 | + ]; |
| 1463 | + |
| 1464 | + // See: https://github.com/mongodb/specifications/blob/master/source/client-side-encryption/tests/README.rst#case-2-addkeyaltname |
| 1465 | + yield 'Case 2: addKeyAltName()' => [ |
| 1466 | + static function (self $test, Client $client, ClientEncryption $clientEncryption): void { |
| 1467 | + $keyId = $clientEncryption->createDataKey('local'); |
| 1468 | + |
| 1469 | + $keyBeforeUpdate = $clientEncryption->addKeyAltName($keyId, 'abc'); |
| 1470 | + $test->assertObjectNotHasAttribute('keyAltNames', $keyBeforeUpdate); |
| 1471 | + |
| 1472 | + $keyBeforeUpdate = $clientEncryption->addKeyAltName($keyId, 'abc'); |
| 1473 | + $test->assertObjectHasAttribute('keyAltNames', $keyBeforeUpdate); |
| 1474 | + $test->assertIsArray($keyBeforeUpdate->keyAltNames); |
| 1475 | + $test->assertContains('abc', $keyBeforeUpdate->keyAltNames); |
| 1476 | + |
| 1477 | + try { |
| 1478 | + $clientEncryption->addKeyAltName($keyId, 'def'); |
| 1479 | + $test->fail('Expected exception to be thrown'); |
| 1480 | + } catch (ServerException $e) { |
| 1481 | + $test->assertSame(11000 /* DuplicateKey */, $e->getCode()); |
| 1482 | + } |
| 1483 | + |
| 1484 | + $originalKeyId = $clientEncryption->getKeyByAltName('def')->_id; |
| 1485 | + |
| 1486 | + $originalKeyBeforeUpdate = $clientEncryption->addKeyAltName($originalKeyId, 'def'); |
| 1487 | + $test->assertObjectHasAttribute('keyAltNames', $originalKeyBeforeUpdate); |
| 1488 | + $test->assertIsArray($originalKeyBeforeUpdate->keyAltNames); |
| 1489 | + $test->assertContains('def', $originalKeyBeforeUpdate->keyAltNames); |
| 1490 | + }, |
| 1491 | + ]; |
| 1492 | + } |
| 1493 | + |
1406 | 1494 | /**
|
1407 | 1495 | * Prose test 14: Decryption Events
|
1408 | 1496 | *
|
@@ -1552,6 +1640,84 @@ static function (self $test, Client $setupClient, ClientEncryption $clientEncryp
|
1552 | 1640 | ];
|
1553 | 1641 | }
|
1554 | 1642 |
|
| 1643 | + /** |
| 1644 | + * Prose test 16: RewrapManyDataKey |
| 1645 | + * |
| 1646 | + * @see https://github.com/mongodb/specifications/blob/master/source/client-side-encryption/tests/README.rst#rewrap |
| 1647 | + * @dataProvider provideRewrapManyDataKeySrcAndDstProviders |
| 1648 | + */ |
| 1649 | + public function testRewrapManyDataKey(string $srcProvider, string $dstProvider): void |
| 1650 | + { |
| 1651 | + $providerMasterKeys = [ |
| 1652 | + 'aws' => ['region' => 'us-east-1', 'key' => 'arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0'], |
| 1653 | + 'azure' => ['keyVaultEndpoint' => 'key-vault-csfle.vault.azure.net', 'keyName' => 'key-name-csfle'], |
| 1654 | + 'gcp' => ['projectId' => 'devprod-drivers', 'location' => 'global', 'keyRing' => 'key-ring-csfle', 'keyName' => 'key-name-csfle'], |
| 1655 | + 'kmip' => [], |
| 1656 | + ]; |
| 1657 | + |
| 1658 | + // Test setup |
| 1659 | + $client = static::createTestClient(); |
| 1660 | + |
| 1661 | + // Ensure that the key vault is dropped with a majority write concern |
| 1662 | + self::insertKeyVaultData($client, []); |
| 1663 | + |
| 1664 | + $clientEncryptionOpts = [ |
| 1665 | + 'keyVaultNamespace' => 'keyvault.datakeys', |
| 1666 | + 'kmsProviders' => [ |
| 1667 | + 'aws' => Context::getAWSCredentials(), |
| 1668 | + 'azure' => Context::getAzureCredentials(), |
| 1669 | + 'gcp' => Context::getGCPCredentials(), |
| 1670 | + 'kmip' => ['endpoint' => Context::getKmipEndpoint()], |
| 1671 | + 'local' => ['key' => new Binary(base64_decode(self::LOCAL_MASTERKEY), 0)], |
| 1672 | + ], |
| 1673 | + 'tlsOptions' => [ |
| 1674 | + 'kmip' => Context::getKmsTlsOptions(), |
| 1675 | + ], |
| 1676 | + ]; |
| 1677 | + |
| 1678 | + $clientEncryption1 = $client->createClientEncryption($clientEncryptionOpts); |
| 1679 | + |
| 1680 | + $createDataKeyOpts = []; |
| 1681 | + |
| 1682 | + if (isset($providerMasterKeys[$srcProvider])) { |
| 1683 | + $createDataKeyOpts['masterKey'] = $providerMasterKeys[$srcProvider]; |
| 1684 | + } |
| 1685 | + |
| 1686 | + $keyId = $clientEncryption1->createDataKey($srcProvider, $createDataKeyOpts); |
| 1687 | + |
| 1688 | + $ciphertext = $clientEncryption1->encrypt('test', ['algorithm' => ClientEncryption::AEAD_AES_256_CBC_HMAC_SHA_512_DETERMINISTIC, 'keyId' => $keyId]); |
| 1689 | + |
| 1690 | + $clientEncryption2 = $client->createClientEncryption($clientEncryptionOpts); |
| 1691 | + |
| 1692 | + $rewrapManyDataKeyOpts = ['provider' => $dstProvider]; |
| 1693 | + |
| 1694 | + if (isset($providerMasterKeys[$dstProvider])) { |
| 1695 | + $rewrapManyDataKeyOpts['masterKey'] = $providerMasterKeys[$dstProvider]; |
| 1696 | + } |
| 1697 | + |
| 1698 | + $result = $clientEncryption2->rewrapManyDataKey([], $rewrapManyDataKeyOpts); |
| 1699 | + |
| 1700 | + $this->assertObjectHasAttribute('bulkWriteResult', $result); |
| 1701 | + $this->assertIsObject($result->bulkWriteResult); |
| 1702 | + // libmongoc uses different field names for its BulkWriteResult |
| 1703 | + $this->assertObjectHasAttribute('nModified', $result->bulkWriteResult); |
| 1704 | + $this->assertSame(1, $result->bulkWriteResult->nModified); |
| 1705 | + |
| 1706 | + $this->assertSame('test', $clientEncryption1->decrypt($ciphertext)); |
| 1707 | + $this->assertSame('test', $clientEncryption2->decrypt($ciphertext)); |
| 1708 | + } |
| 1709 | + |
| 1710 | + public static function provideRewrapManyDataKeySrcAndDstProviders() |
| 1711 | + { |
| 1712 | + $providers = ['aws', 'azure', 'gcp', 'kmip', 'local']; |
| 1713 | + |
| 1714 | + foreach ($providers as $srcProvider) { |
| 1715 | + foreach ($providers as $dstProvider) { |
| 1716 | + yield [$srcProvider, $dstProvider]; |
| 1717 | + } |
| 1718 | + } |
| 1719 | + } |
| 1720 | + |
1555 | 1721 | private function createInt64(string $value): Int64
|
1556 | 1722 | {
|
1557 | 1723 | $array = sprintf('a:1:{s:7:"integer";s:%d:"%s";}', strlen($value), $value);
|
|
0 commit comments