Skip to content

Commit ef8d1e2

Browse files
committed
PYTHON-1926 Raise an error for unsupported encryption operations
1 parent 8d693e8 commit ef8d1e2

File tree

5 files changed

+73
-5
lines changed

5 files changed

+73
-5
lines changed

.evergreen/config.yml

+2-3
Original file line numberDiff line numberDiff line change
@@ -1119,9 +1119,8 @@ buildvariants:
11191119
display_name: "Encryption ${platform} ${auth-ssl}"
11201120
tasks: &encryption-server-versions
11211121
- ".4.2"
1122-
# TODO: PYTHON-1926
1123-
# - ".4.0"
1124-
# - ".2.6"
1122+
- ".4.0"
1123+
- ".2.6"
11251124

11261125
- matrix_name: "tests-no-36-plus"
11271126
matrix_spec:

pymongo/collection.py

+16-2
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
from pymongo.errors import (BulkWriteError,
4141
ConfigurationError,
4242
InvalidName,
43+
InvalidOperation,
4344
OperationFailure)
4445
from pymongo.helpers import (_check_write_command_response,
4546
_raise_last_error)
@@ -1474,7 +1475,8 @@ def find_raw_batches(self, *args, **kwargs):
14741475
>>> for batch in cursor:
14751476
... print(bson.decode_all(batch))
14761477
1477-
.. note:: find_raw_batches does not support sessions.
1478+
.. note:: find_raw_batches does not support sessions or auto
1479+
encryption.
14781480
14791481
.. versionadded:: 3.6
14801482
"""
@@ -1483,6 +1485,12 @@ def find_raw_batches(self, *args, **kwargs):
14831485
if "session" in kwargs:
14841486
raise ConfigurationError(
14851487
"find_raw_batches does not support sessions")
1488+
1489+
# OP_MSG is required to support encryption.
1490+
if self.__database.client._encrypter:
1491+
raise InvalidOperation(
1492+
"find_raw_batches does not support auto encryption")
1493+
14861494
return RawBatchCursor(self, *args, **kwargs)
14871495

14881496
def parallel_scan(self, num_cursors, session=None, **kwargs):
@@ -2388,7 +2396,8 @@ def aggregate_raw_batches(self, pipeline, **kwargs):
23882396
>>> for batch in cursor:
23892397
... print(bson.decode_all(batch))
23902398
2391-
.. note:: aggregate_raw_batches does not support sessions.
2399+
.. note:: aggregate_raw_batches does not support sessions or auto
2400+
encryption.
23922401
23932402
.. versionadded:: 3.6
23942403
"""
@@ -2398,6 +2407,11 @@ def aggregate_raw_batches(self, pipeline, **kwargs):
23982407
raise ConfigurationError(
23992408
"aggregate_raw_batches does not support sessions")
24002409

2410+
# OP_MSG is required to support encryption.
2411+
if self.__database.client._encrypter:
2412+
raise InvalidOperation(
2413+
"aggregate_raw_batches does not support auto encryption")
2414+
24012415
return self._aggregate(_CollectionRawAggregationCommand,
24022416
pipeline,
24032417
RawBatchCommandCursor,

pymongo/cursor.py

+4
Original file line numberDiff line numberDiff line change
@@ -944,6 +944,10 @@ def __send_message(self, operation):
944944
Can raise ConnectionFailure.
945945
"""
946946
client = self.__collection.database.client
947+
# OP_MSG is required to support exhaust cursors with encryption.
948+
if client._encrypter and self.__exhaust:
949+
raise InvalidOperation(
950+
"exhaust cursors do not support auto encryption")
947951

948952
try:
949953
response = client._run_operation_with_response(

pymongo/mongo_client.py

+6
Original file line numberDiff line numberDiff line change
@@ -1222,6 +1222,12 @@ def _get_socket(self, server, session, exhaust=False):
12221222
with server.get_socket(
12231223
self.__all_credentials, checkout=exhaust) as sock_info:
12241224
err_handler.contribute_socket(sock_info)
1225+
if (self._encrypter and
1226+
not self._encrypter._bypass_auto_encryption and
1227+
sock_info.max_wire_version < 8):
1228+
raise ConfigurationError(
1229+
'Auto-encryption requires a minimum MongoDB version '
1230+
'of 4.2')
12251231
yield sock_info
12261232

12271233
def _select_server(self, server_selector, session, address=None):

test/test_encryption.py

+45
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
from bson.json_util import JSONOptions
3434
from bson.son import SON
3535

36+
from pymongo.cursor import CursorType
3637
from pymongo.errors import (ConfigurationError,
3738
EncryptionError,
3839
InvalidOperation,
@@ -41,6 +42,7 @@
4142
ClientEncryption)
4243
from pymongo.encryption_options import AutoEncryptionOpts, _HAVE_PYMONGOCRYPT
4344
from pymongo.mongo_client import MongoClient
45+
from pymongo.operations import InsertOne
4446
from pymongo.write_concern import WriteConcern
4547

4648
from test import unittest, IntegrationTest, PyMongoTestCase, client_context
@@ -256,6 +258,48 @@ def test_use_after_close(self):
256258
client.admin.command('isMaster')
257259

258260

261+
class TestClientMaxWireVersion(IntegrationTest):
262+
263+
@classmethod
264+
@unittest.skipUnless(_HAVE_PYMONGOCRYPT, 'pymongocrypt is not installed')
265+
def setUpClass(cls):
266+
super(TestClientMaxWireVersion, cls).setUpClass()
267+
268+
@client_context.require_version_max(4, 0, 99)
269+
def test_raise_max_wire_version_error(self):
270+
opts = AutoEncryptionOpts(KMS_PROVIDERS, 'admin.datakeys')
271+
client = rs_or_single_client(auto_encryption_opts=opts)
272+
self.addCleanup(client.close)
273+
msg = 'Auto-encryption requires a minimum MongoDB version of 4.2'
274+
with self.assertRaisesRegex(ConfigurationError, msg):
275+
client.test.test.insert_one({})
276+
with self.assertRaisesRegex(ConfigurationError, msg):
277+
client.admin.command('isMaster')
278+
with self.assertRaisesRegex(ConfigurationError, msg):
279+
client.test.test.find_one({})
280+
with self.assertRaisesRegex(ConfigurationError, msg):
281+
client.test.test.bulk_write([InsertOne({})])
282+
283+
def test_raise_unsupported_error(self):
284+
opts = AutoEncryptionOpts(KMS_PROVIDERS, 'admin.datakeys')
285+
client = rs_or_single_client(auto_encryption_opts=opts)
286+
self.addCleanup(client.close)
287+
msg = 'find_raw_batches does not support auto encryption'
288+
with self.assertRaisesRegex(InvalidOperation, msg):
289+
client.test.test.find_raw_batches({})
290+
291+
msg = 'aggregate_raw_batches does not support auto encryption'
292+
with self.assertRaisesRegex(InvalidOperation, msg):
293+
client.test.test.aggregate_raw_batches([])
294+
295+
if client_context.is_mongos:
296+
msg = 'Exhaust cursors are not supported by mongos'
297+
else:
298+
msg = 'exhaust cursors do not support auto encryption'
299+
with self.assertRaisesRegex(InvalidOperation, msg):
300+
next(client.test.test.find(cursor_type=CursorType.EXHAUST))
301+
302+
259303
class TestExplicitSimple(EncryptionIntegrationTest):
260304

261305
def test_encrypt_decrypt(self):
@@ -403,6 +447,7 @@ class TestSpec(SpecRunner):
403447

404448
@classmethod
405449
@unittest.skipUnless(_HAVE_PYMONGOCRYPT, 'pymongocrypt is not installed')
450+
@client_context.require_version_min(3, 6) # SpecRunner requires sessions.
406451
def setUpClass(cls):
407452
super(TestSpec, cls).setUpClass()
408453

0 commit comments

Comments
 (0)