Skip to content

Commit 8e508c7

Browse files
committed
Code review fixes (2/2)
1 parent 518a1bc commit 8e508c7

File tree

11 files changed

+54
-100
lines changed

11 files changed

+54
-100
lines changed

.evergreen/config.yml

Lines changed: 0 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -90,28 +90,6 @@ buildvariants:
9090
tasks:
9191
- name: run-tests
9292

93-
- name: tests-7-noauth-nossl
94-
display_name: Run Tests 7.0 NoAuth NoSSL
95-
run_on: rhel87-small
96-
expansions:
97-
MONGODB_VERSION: "7.0"
98-
TOPOLOGY: server
99-
AUTH: "noauth"
100-
SSL: "nossl"
101-
tasks:
102-
- name: run-tests
103-
104-
- name: tests-7-auth-ssl
105-
display_name: Run Tests 7.0 Auth SSL
106-
run_on: rhel87-small
107-
expansions:
108-
MONGODB_VERSION: "7.0"
109-
TOPOLOGY: server
110-
AUTH: "auth"
111-
SSL: "ssl"
112-
tasks:
113-
- name: run-tests
114-
11593
- name: tests-8-noauth-nossl
11694
display_name: Run Tests 8.0 NoAuth NoSSL
11795
run_on: rhel87-small

django_mongodb_backend/routers.py

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@
22
from django.core.exceptions import ImproperlyConfigured
33
from django.db.utils import ConnectionRouter
44

5-
from .model_utils import model_has_encrypted_fields
6-
75

86
class MongoRouter:
97
def allow_migrate(self, db, app_label, model_name=None, **hints):
@@ -19,7 +17,6 @@ def allow_migrate(self, db, app_label, model_name=None, **hints):
1917
model = apps.get_model(app_label, model_name)
2018
except LookupError:
2119
return None
22-
2320
return False if issubclass(model, EmbeddedModel) else None
2421

2522

@@ -30,9 +27,7 @@ def kms_provider(self, model, *args, **kwargs):
3027
result = func(model, *args, **kwargs)
3128
if result is not None:
3229
return result
33-
if model_has_encrypted_fields(model):
34-
raise ImproperlyConfigured("No kms_provider found in database router.")
35-
return None
30+
raise ImproperlyConfigured("No kms_provider found in database router.")
3631

3732

3833
def register_routers():

django_mongodb_backend/schema.py

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -439,8 +439,7 @@ def _create_collection(self, model):
439439
raise ImproperlyConfigured(
440440
"Encrypted fields found but "
441441
f"DATABASES[{self.connection.alias}]['OPTIONS'] is missing "
442-
"auto_encryption_opts. Please set `auto_encryption_opts` "
443-
"in the connection settings."
442+
"auto_encryption_opts."
444443
)
445444
encrypted_fields_map = getattr(auto_encryption_opts, "_encrypted_fields_map", None)
446445
if not encrypted_fields_map:
@@ -475,17 +474,17 @@ def _get_encrypted_fields_map(self, model, client, create_new_keys=False):
475474
for field in fields:
476475
if getattr(field, "encrypted", False):
477476
key_alt_name = f"{db_table}_{field.column}"
478-
if not create_new_keys:
479-
key_doc = key_vault_collection.find_one({"keyAltNames": key_alt_name})
480-
if not key_doc:
481-
raise ValueError(f"No key found in keyvault for keyAltName={key_alt_name}")
482-
data_key = key_doc["_id"]
483-
else:
477+
if create_new_keys:
484478
data_key = client_encryption.create_data_key(
485479
kms_provider=kms_provider,
486480
master_key=master_key,
487481
key_alt_names=[key_alt_name],
488482
)
483+
else:
484+
key_doc = key_vault_collection.find_one({"keyAltNames": key_alt_name})
485+
if not key_doc:
486+
raise ValueError(f"No key found in keyvault for keyAltName={key_alt_name}")
487+
data_key = key_doc["_id"]
489488
field_dict = {
490489
"bsonType": field.db_type(connection),
491490
"path": field.column,

docs/source/howto/queryable-encryption.rst

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -35,24 +35,22 @@ Encryption in Django, as well as a KMS provider and credentials.
3535

3636
Here's how to set it up in your Django settings::
3737

38+
import os
39+
3840
from django_mongodb_backend import parse_uri
3941
from pymongo.encryption_options import AutoEncryptionOpts
4042

4143
DATABASES = {
42-
"default": parse_uri(
43-
DATABASE_URL,
44-
db_name="my_database",
45-
),
44+
4645
"encrypted": parse_uri(
4746
DATABASE_URL,
48-
options: {
47+
options={
4948
"auto_encryption_opts": AutoEncryptionOpts(
5049
key_vault_namespace="my_encrypted_database.keyvault",
5150
kms_providers={"local": {"key": os.urandom(96)}},
52-
),
51+
)
5352
},
54-
db_name="my_encrypted_database",
55-
"KMS_CREDENTIALS": {},
53+
db_name="encrypted",
5654
),
5755
}
5856

@@ -123,6 +121,9 @@ Settings
123121
Now include the crypt shared library path and generated schema map in your
124122
Django settings::
125123

124+
from bson.binary import Binary
125+
from pymongo.encryption_options import AutoEncryptionOpts
126+
126127
127128
DATABASES["encrypted"] = {
128129

docs/source/ref/queryable-encryption.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ before storing it in the database.
3333
+----------------------------------------+------------------------------------------------------+
3434
| ``EncryptedDecimalField`` | :class:`~django.db.models.DecimalField` |
3535
+----------------------------------------+------------------------------------------------------+
36+
| ``EncryptedDurationField`` | :class:`~django.db.models.DurationField` |
37+
+----------------------------------------+------------------------------------------------------+
3638
| ``EncryptedFloatField`` | :class:`~django.db.models.FloatField` |
3739
+----------------------------------------+------------------------------------------------------+
3840
| ``EncryptedGenericIPAddressField`` | :class:`~django.db.models.GenericIPAddressField` |

docs/source/ref/settings.rst

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,19 +7,37 @@ Settings
77
Queryable Encryption
88
====================
99

10-
The following :setting:`django:DATABASES` inner options have been added to
11-
support KMS configuration for Queryable Encryption.
12-
13-
.. setting:: DATABASE-KMS-PROVIDERS
14-
15-
``KMS_PROVIDERS``
16-
-----------------
17-
18-
Default: ``{}``
10+
The following :setting:`django:DATABASES` inner options support KMS
11+
configuration for Queryable Encryption.
1912

2013
.. setting:: DATABASE-KMS-CREDENTIALS
2114

2215
``KMS_CREDENTIALS``
2316
-------------------
2417

2518
Default: ``{}``
19+
20+
Queryable Encryption requires a KMS provider to encrypt and decrypt data. Django
21+
MongoDB Backend supports configuring KMS credentials and providers for Queryable
22+
Encryption via the ``KMS_CREDENTIALS`` setting in the ``DATABASES``
23+
configuration and the ``kms_provider`` method on the ``DatabaseRouter``.
24+
25+
E.g. to configure AWS KMS credentials:
26+
27+
.. code-block:: python
28+
29+
KMS_CREDENTIALS = {
30+
"aws": {
31+
"key": os.getenv("AWS_KEY_ARN", ""),
32+
"region": os.getenv("AWS_KEY_REGION", ""),
33+
},
34+
}
35+
DATABASES = {
36+
#
37+
}
38+
DATABASES["encrypted"]["KMS_CREDENTIALS"] = KMS_CREDENTIALS
39+
40+
Please refer to :ref:`manual:qe-fundamentals-kms-providers` for more information
41+
on configuring KMS providers and credentials as well as
42+
:doc:`manual:core/queryable-encryption/fundamentals/keys-key-vaults` for
43+
information on creating and managing data encryption keys.

tests/encryption_/models.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -52,9 +52,7 @@ class PatientRecord(models.Model):
5252
ssn = EncryptedCharField(max_length=11, queries=EQUALITY_QUERY)
5353
birth_date = EncryptedDateField(queries=RANGE_QUERY)
5454
profile_picture = EncryptedBinaryField(queries=EQUALITY_QUERY)
55-
patient_age = EncryptedSmallIntegerField(
56-
"patient_age", queries={**RANGE_QUERY, "min": 0, "max": 100}
57-
)
55+
patient_age = EncryptedSmallIntegerField(queries={**RANGE_QUERY, "min": 0, "max": 100})
5856
weight = EncryptedFloatField(queries=RANGE_QUERY)
5957

6058
# TODO: Embed Billing model
@@ -65,7 +63,7 @@ class Meta:
6563

6664

6765
class Patient(models.Model):
68-
patient_id = EncryptedIntegerField("patient_id", queries=EQUALITY_QUERY)
66+
patient_id = EncryptedIntegerField(queries=EQUALITY_QUERY)
6967
patient_name = EncryptedCharField(max_length=100)
7068
patient_notes = EncryptedTextField(queries=EQUALITY_QUERY)
7169
registration_date = EncryptedDateTimeField(queries=EQUALITY_QUERY)

tests/encryption_/test_base.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@ class QueryableEncryptionTestCase(TransactionTestCase):
1919
available_apps = ["encryption_"]
2020

2121
def setUp(self):
22+
"""
23+
Used in schema and field tests.
24+
"""
2225
self.appointment = Appointment.objects.create(time="8:00")
2326
self.billing = Billing.objects.create(
2427
cc_type="Visa", cc_number=1234567890123456, account_balance=100.50
@@ -42,6 +45,3 @@ def setUp(self):
4245
is_active=True,
4346
4447
)
45-
46-
# TODO: Embed billing and patient_record models in patient model
47-
# then add tests

tests/encryption_/test_fields.py

Lines changed: 1 addition & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
from bson.binary import Binary
55
from django.conf import settings
66
from django.db import connections
7-
from django.test import override_settings, skipUnlessDBFeature
7+
from django.test import override_settings
88

99
from .models import (
1010
Appointment,
@@ -18,40 +18,8 @@
1818
from .test_base import QueryableEncryptionTestCase
1919

2020

21-
@skipUnlessDBFeature("supports_queryable_encryption")
2221
@override_settings(DATABASE_ROUTERS=[TestEncryptedRouter()])
2322
class QueryableEncryptionFieldTests(QueryableEncryptionTestCase):
24-
databases = {"default", "encrypted"}
25-
available_apps = ["encryption_"]
26-
27-
def setUp(self):
28-
self.appointment = Appointment.objects.create(time="8:00")
29-
self.billing = Billing.objects.create(
30-
cc_type="Visa", cc_number=1234567890123456, account_balance=100.50
31-
)
32-
self.portal_user = PatientPortalUser.objects.create(
33-
ip_address="127.0.0.1",
34-
url="https://example.com",
35-
)
36-
self.patientrecord = PatientRecord.objects.create(
37-
ssn="123-45-6789",
38-
birth_date="1970-01-01",
39-
profile_picture=b"image data",
40-
weight=175.5,
41-
patient_age=47,
42-
)
43-
self.patient = Patient.objects.create(
44-
patient_id=1,
45-
patient_name="John Doe",
46-
patient_notes="patient notes " * 25,
47-
registration_date=datetime(2023, 10, 1, 12, 0, 0),
48-
is_active=True,
49-
50-
)
51-
52-
# TODO: Embed billing and patient_record models in patient model
53-
# then add tests
54-
5523
def test_appointment(self):
5624
self.assertEqual(Appointment.objects.get(time="8:00").time, time(8, 0))
5725

tests/encryption_/test_management.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,20 +5,18 @@
55
from bson import json_util
66
from django.core.management import call_command
77
from django.db import connections
8-
from django.test import modify_settings, override_settings, skipUnlessDBFeature
8+
from django.test import modify_settings, override_settings
99
from pymongo.encryption import AutoEncryptionOpts
1010

1111
from .routers import TestEncryptedRouter
1212
from .test_base import QueryableEncryptionTestCase
1313

1414

15-
@skipUnlessDBFeature("supports_queryable_encryption")
1615
@modify_settings(
1716
INSTALLED_APPS={"prepend": "django_mongodb_backend"},
1817
)
1918
@override_settings(DATABASE_ROUTERS=[TestEncryptedRouter()])
2019
class QueryableEncryptionCommandTests(QueryableEncryptionTestCase):
21-
databases = {"default", "encrypted"}
2220
available_apps = ["django_mongodb_backend", "encryption_"]
2321
maxDiff = None
2422
expected_patient_record = {

0 commit comments

Comments
 (0)