Skip to content

Commit 51617c4

Browse files
committed
Fix path attribute in encrypted fields schema
- Recursive calls to _get_encrypted_fields now updates the path to include the parent_model
1 parent 472b397 commit 51617c4

File tree

3 files changed

+36
-21
lines changed

3 files changed

+36
-21
lines changed

django_mongodb_backend/schema.py

Lines changed: 24 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -488,17 +488,21 @@ def _create_collection(self, model):
488488
# Unencrypted path
489489
db.create_collection(db_table)
490490

491-
def _get_encrypted_fields(self, model, create_data_keys=False, key_alt_name=None):
491+
def _get_encrypted_fields(
492+
self, model, create_data_keys=False, key_alt_name=None, parent_model=None
493+
):
492494
"""
493495
Recursively collect encryption schema data for only encrypted fields in a model.
494496
Returns None if no encrypted fields are found anywhere in the model hierarchy.
495497
496-
key_alt_name is the base path for this level, typically model._meta.db_table.
498+
key_alt_name is the base path used for keyAltNames.
499+
parent_model is the dot-notated path inside the document for schema mapping.
497500
"""
498501
connection = self.connection
499502
client = connection.connection
500503
fields = model._meta.fields
501504
key_alt_name = key_alt_name or model._meta.db_table
505+
parent_model = parent_model or ""
502506

503507
options = client._options
504508
auto_encryption_opts = getattr(options, "auto_encryption_opts", None)
@@ -515,49 +519,51 @@ def _get_encrypted_fields(self, model, create_data_keys=False, key_alt_name=None
515519
field_list = []
516520

517521
for field in fields:
518-
new_path = f"{key_alt_name}.{field.column}"
522+
new_key_alt_name = f"{key_alt_name}.{field.column}"
523+
new_parent_model = f"{parent_model}.{field.column}" if parent_model else field.column
519524

520525
# --- EmbeddedModelField ---
521526
if isinstance(field, EmbeddedModelField):
522527
if getattr(field, "encrypted", False):
523-
# Entire sub-object is encrypted
528+
# Entire sub-object encrypted
524529
if create_data_keys:
525530
if not client_encryption:
526531
raise ImproperlyConfigured("client_encryption is not configured.")
527532
data_key = client_encryption.create_data_key(
528533
kms_provider=kms_provider,
529534
master_key=master_key,
530-
key_alt_names=[new_path],
535+
key_alt_names=[new_key_alt_name],
531536
)
532537
else:
533538
if key_vault_collection is None:
534539
raise ImproperlyConfigured(
535-
f"Encrypted field {new_path} detected but no key vault configured"
540+
f"Encrypted field {new_key_alt_name} detected "
541+
"but no key vault configured"
536542
)
537-
key_doc = key_vault_collection.find_one({"keyAltNames": new_path})
543+
key_doc = key_vault_collection.find_one({"keyAltNames": new_key_alt_name})
538544
if not key_doc:
539545
raise ValueError(
540-
f"No key found in keyvault for keyAltName={new_path}. "
546+
f"No key found in keyvault for keyAltName={new_key_alt_name}. "
541547
"Run with '--create-data-keys' to create missing keys."
542548
)
543549
data_key = key_doc["_id"]
544550

545551
field_dict = {
546552
"bsonType": "object",
547-
"path": field.column,
553+
"path": new_parent_model,
548554
"keyId": data_key,
549555
}
550556
if getattr(field, "queries", False):
551557
field_dict["queries"] = field.queries
552558

553559
field_list.append(field_dict)
554560
else:
555-
# Not encrypting whole object — recurse first then
556-
# conditionally extend field list
561+
# Recurse into embedded model
557562
embedded_result = self._get_encrypted_fields(
558563
field.embedded_model,
559564
create_data_keys=create_data_keys,
560-
key_alt_name=new_path,
565+
key_alt_name=new_key_alt_name,
566+
parent_model=new_parent_model,
561567
)
562568
if embedded_result and embedded_result.get("fields"):
563569
field_list.extend(embedded_result["fields"])
@@ -571,24 +577,25 @@ def _get_encrypted_fields(self, model, create_data_keys=False, key_alt_name=None
571577
data_key = client_encryption.create_data_key(
572578
kms_provider=kms_provider,
573579
master_key=master_key,
574-
key_alt_names=[new_path],
580+
key_alt_names=[new_key_alt_name],
575581
)
576582
else:
577583
if key_vault_collection is None:
578584
raise ImproperlyConfigured(
579-
f"Encrypted field {new_path} detected but no key vault configured"
585+
f"Encrypted field {new_key_alt_name} detected "
586+
"but no key vault configured"
580587
)
581-
key_doc = key_vault_collection.find_one({"keyAltNames": new_path})
588+
key_doc = key_vault_collection.find_one({"keyAltNames": new_key_alt_name})
582589
if not key_doc:
583590
raise ValueError(
584-
f"No key found in keyvault for keyAltName={new_path}. "
591+
f"No key found in keyvault for keyAltName={new_key_alt_name}. "
585592
"Run with '--create-data-keys' to create missing keys."
586593
)
587594
data_key = key_doc["_id"]
588595

589596
field_dict = {
590597
"bsonType": field.db_type(connection),
591-
"path": field.column,
598+
"path": new_parent_model,
592599
"keyId": data_key,
593600
}
594601
if getattr(field, "queries", False):

tests/encryption_/test_management.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,12 @@ class CommandTests(EncryptionTestCase):
1313
expected_maps = {
1414
"encryption__patient": {
1515
"fields": [
16-
{"bsonType": "string", "path": "ssn", "queries": {"queryType": "equality"}},
17-
{"bsonType": "object", "path": "billing"},
16+
{
17+
"bsonType": "string",
18+
"path": "patient_record.ssn",
19+
"queries": {"queryType": "equality"},
20+
},
21+
{"bsonType": "object", "path": "patient_record.billing"},
1822
]
1923
},
2024
# Equality-queryable fields

tests/encryption_/test_schema.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,12 @@ class SchemaTests(EncryptionTestCase):
1010
expected_map = {
1111
"Patient": {
1212
"fields": [
13-
{"bsonType": "string", "path": "ssn", "queries": {"queryType": "equality"}},
14-
{"bsonType": "object", "path": "billing"},
13+
{
14+
"bsonType": "string",
15+
"path": "patient_record.ssn",
16+
"queries": {"queryType": "equality"},
17+
},
18+
{"bsonType": "object", "path": "patient_record.billing"},
1519
]
1620
},
1721
"EncryptedBinaryTest": {

0 commit comments

Comments
 (0)