@@ -446,6 +446,106 @@ def create_key_vault(vault, *data_keys):
446446 return vault
447447
448448
449+ class TestDataKeyDoubleEncryption (EncryptionIntegrationTest ):
450+
451+ @classmethod
452+ @unittest .skipUnless (all (AWS_CREDS .values ()),
453+ 'AWS environment credentials are not set' )
454+ def setUpClass (cls ):
455+ super (TestDataKeyDoubleEncryption , cls ).setUpClass ()
456+
457+ @staticmethod
458+ def kms_providers ():
459+ return {'aws' : AWS_CREDS , 'local' : {'key' : LOCAL_MASTER_KEY }}
460+
461+ def test_data_key (self ):
462+ self .client .db .coll .drop ()
463+ vault = create_key_vault (self .client .admin .datakeys )
464+ self .addCleanup (vault .drop )
465+
466+ # Configure the encrypted field via the local schema_map option.
467+ schemas = {
468+ "db.coll" : {
469+ "bsonType" : "object" ,
470+ "properties" : {
471+ "encrypted_placeholder" : {
472+ "encrypt" : {
473+ "keyId" : "/placeholder" ,
474+ "bsonType" : "string" ,
475+ "algorithm" : "AEAD_AES_256_CBC_HMAC_SHA_512-Random"
476+ }
477+ }
478+ }
479+ }
480+ }
481+ opts = AutoEncryptionOpts (
482+ self .kms_providers (), 'admin.datakeys' , schema_map = schemas )
483+ client_encrypted = rs_or_single_client (
484+ auto_encryption_opts = opts , uuidRepresentation = 'standard' )
485+ self .addCleanup (client_encrypted .close )
486+
487+ client_encryption = ClientEncryption (
488+ self .kms_providers (), 'admin.datakeys' , client_context .client )
489+ self .addCleanup (client_encryption .close )
490+
491+ # Local create data key.
492+ local_datakey_id = client_encryption .create_data_key (
493+ 'local' , key_alt_names = ['local_altname' ])
494+ self .assertIsInstance (local_datakey_id , uuid .UUID )
495+ docs = list (vault .find ({'_id' : local_datakey_id }))
496+ self .assertEqual (len (docs ), 1 )
497+ self .assertEqual (docs [0 ]['masterKey' ]['provider' ], 'local' )
498+
499+ # Local encrypt by key_id.
500+ local_encrypted = client_encryption .encrypt (
501+ 'hello local' , Algorithm .Deterministic , key_id = local_datakey_id )
502+ self .assertEncrypted (local_encrypted )
503+ client_encrypted .db .coll .insert_one (
504+ {'_id' : 'local' , 'value' : local_encrypted })
505+ doc_decrypted = client_encrypted .db .coll .find_one ({'_id' : 'local' })
506+ self .assertEqual (doc_decrypted ['value' ], 'hello local' )
507+
508+ # Local encrypt by key_alt_name.
509+ local_encrypted_altname = client_encryption .encrypt (
510+ 'hello local' , Algorithm .Deterministic ,
511+ key_alt_name = 'local_altname' )
512+ self .assertEqual (local_encrypted_altname , local_encrypted )
513+
514+ # AWS create data key.
515+ master_key = {
516+ 'region' : 'us-east-1' ,
517+ 'key' : 'arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-'
518+ '9f25-e30687b580d0'
519+ }
520+ aws_datakey_id = client_encryption .create_data_key (
521+ 'aws' , master_key = master_key , key_alt_names = ['aws_altname' ])
522+ self .assertIsInstance (aws_datakey_id , uuid .UUID )
523+ docs = list (vault .find ({'_id' : aws_datakey_id }))
524+ self .assertEqual (len (docs ), 1 )
525+ self .assertEqual (docs [0 ]['masterKey' ]['provider' ], 'aws' )
526+
527+ # AWS encrypt by key_id.
528+ aws_encrypted = client_encryption .encrypt (
529+ 'hello aws' , Algorithm .Deterministic , key_id = aws_datakey_id )
530+ self .assertEncrypted (aws_encrypted )
531+ client_encrypted .db .coll .insert_one (
532+ {'_id' : 'aws' , 'value' : aws_encrypted })
533+ doc_decrypted = client_encrypted .db .coll .find_one ({'_id' : 'aws' })
534+ self .assertEqual (doc_decrypted ['value' ], 'hello aws' )
535+
536+ # AWS encrypt by key_alt_name.
537+ aws_encrypted_altname = client_encryption .encrypt (
538+ 'hello aws' , Algorithm .Deterministic , key_alt_name = 'aws_altname' )
539+ self .assertEqual (aws_encrypted_altname , aws_encrypted )
540+
541+ # Explicitly encrypting an auto encrypted field.
542+ msg = ('Cannot encrypt element of type binData because schema '
543+ 'requires that type is one of: \[ string \]' )
544+ with self .assertRaisesRegex (EncryptionError , msg ):
545+ client_encrypted .db .coll .insert_one (
546+ {'encrypted_placeholder' : local_encrypted })
547+
548+
449549class TestExternalKeyVault (EncryptionIntegrationTest ):
450550
451551 @staticmethod
0 commit comments