-
Notifications
You must be signed in to change notification settings - Fork 29
INTPYTHON-527 Add Queryable Encryption support #329
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
django_mongodb_backend/management/commands/get_encrypted_fields_map.py
Outdated
Show resolved
Hide resolved
django_mongodb_backend/management/commands/get_encrypted_fields_map.py
Outdated
Show resolved
Hide resolved
django_mongodb_backend/management/commands/get_encrypted_fields_map.py
Outdated
Show resolved
Hide resolved
django_mongodb_backend/management/commands/get_encrypted_fields_map.py
Outdated
Show resolved
Hide resolved
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
26874aa
to
f32d62b
Compare
django_mongodb_backend/schema.py
Outdated
field_list = [] | ||
for field in fields: | ||
if getattr(field, "encrypted", False): | ||
key_alt_name = f"{db_table}_{field.column}" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this sufficient to avoid collisions? Unlikely as it may be:
db_table = "foo"
column = "bar_id"
db_table = "foo_bar"
column = "id"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well now that you mention it, how about a double separator ? {db_table}__{field.column}
would pass that test with these key alt names:
- foo__bar_id
- foo_bar__id
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A period may be a more typical separator, including to indicate nested fields.
1169c04
to
d04bdbb
Compare
ccd2f36
to
94c1dc2
Compare
The spec says: "encryptedFieldsMap maps a collection namespace to an encryptedFields." In this commit, we clarify the distinction between encrypted fields map and encrypted fields.
- Test Python tutorial models (still unencrypted in this commit) - Test all supported encrypted fields. - Test equality and range query type queries - Test management command - Test schema - Removed test router - Removed test_base
- EncryptedEmbeddedModel for encrypted objects - EmbeddedModel for models with encrypted fields
e1077a1
to
d48ebc9
Compare
db_table = model._meta.db_table | ||
field_list = [] | ||
for field in fields: | ||
if isinstance(field, EmbeddedModelField): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about PolymorphicEmbeddedFields or EmbeddedModelArrayFIeld? The design doc still needs a list of all encrypted fields that will be implemented, I think.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Those could be added because I think the existing embedded models are doing all the work.
django_mongodb_backend/models.py
Outdated
class EncryptedEmbeddedModel(EmbeddedModel): | ||
encrypted = True | ||
|
||
class Meta: | ||
abstract = True | ||
required_db_features = {"supports_queryable_encryption"} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
EncryptedEmbeddedModel
isn't present in the design doc. Did you thinking change? I don't see what purpose it serves.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Without it, I get this:
django.core.exceptions.ImproperlyConfigured: No kms_provider found in database router.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
EncryptedEmbeddedModel
isn't present in the design doc. Did you thinking change? I don't see what purpose it serves.
And yes the design doc needs to be updated.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Without it, I get this:
django.core.exceptions.ImproperlyConfigured: No kms_provider found in database router.
The encryption_ tests pass for me without it. We shouldn't be trying to resolve a kms_provider for an embedded model anyway.
tests/encryption_/models.py
Outdated
patient_name = models.CharField(max_length=255) | ||
patient_id = models.BigIntegerField() | ||
patient_record = EmbeddedModelField(PatientRecord) | ||
patient_record = EncryptedEmbeddedModelField(PatientRecord) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Per design doc, this is supposed to be EmbeddedModelField
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch!
django_mongodb_backend/models.py
Outdated
class EncryptedEmbeddedModel(EmbeddedModel): | ||
encrypted = True | ||
|
||
class Meta: | ||
abstract = True | ||
required_db_features = {"supports_queryable_encryption"} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Embedded models aren't created anyway, so required_db_features = {"supports_queryable_encryption"}
would serve no purpose.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems to facilitate use of the skip
decorator.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The purpose of required_db_features
is to prevent the model from being created if the database doesn't support it. Since SchemaEditor
already ignores embedded models, required_db_features
serves no purpose here.
django_mongodb_backend/utils.py
Outdated
if getattr(field, "encrypted", False): | ||
return True | ||
|
||
return bool(issubclass(model, EncryptedEmbeddedModel)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If the model has encrypted fields, the loop above would already have returned True. This would only be executed if the model doesn't have any encrypted fields. :-D
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is for the case when an EncryptedEmbeddedModel
has no encrypted fields but itself is encrypted e.g. Billing
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The code that calls model_has_encrypted_fields()
shouldn't receive embedded models. Embedded models don't have their own collection, so they aren't going to be passed to SchemaEditor._create_collection()
and neither are they returned by router.get_migratable_models()
in showencryptedfieldsmap.py
.
I don't see EncryptedEmbeddedModel serving any purpose. If I missed something, revert my commit.
Previous attempts and additional context here: