Skip to content
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

MONGOCRYPT-661 enable "range" by default #861

Merged
merged 12 commits into from
Jul 16, 2024
5 changes: 0 additions & 5 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,6 @@ option (ENABLE_PIC
)
option (ENABLE_BUILD_FOR_PPA "Maintainer-only option for preparing PPA build" OFF)
option (ENABLE_ONLINE_TESTS "Enable online tests and the csfle utility. Requires libmongoc." ON)
# TODO MONGOCRYPT-661 When range V2 is default, remove this option.
option (ENABLE_USE_RANGE_V2 "Enable the use_range_v2 flag by default for queryable encryption" OFF)
if (ENABLE_USE_RANGE_V2)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DQE_USE_RANGE_V2")
endif ()

if (ENABLE_WINDOWS_STATIC_RUNTIME)
if (POLICY CMP0091)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -583,9 +583,8 @@ public interface mongocrypt_random_fn extends Callback {
mongocrypt_ctx_setopt_query_type (mongocrypt_ctx_t ctx, cstring query_type, int len);

/**
* Set options for explicit encryption with the "rangePreview" algorithm.
* NOTE: The RangePreview algorithm is experimental only. It is not intended for
* public use.
* Set options for explicit encryption with the "range" algorithm.
* NOTE: "range" is currently unstable API and subject to backwards breaking changes.
*
* opts is a BSON document of the form:
* {
Expand Down Expand Up @@ -887,9 +886,8 @@ public interface mongocrypt_random_fn extends Callback {
/**
* Explicit helper method to encrypt a Match Expression or Aggregate Expression.
* Contexts created for explicit encryption will not go through mongocryptd.
* Requires query_type to be "rangePreview".
* NOTE: The RangePreview algorithm is experimental only. It is not intended for
* public use.
* Requires query_type to be "range".
* NOTE: "range" is currently unstable API and subject to backwards breaking changes.
*
* This method expects the passed-in BSON to be of the form:
* { "v" : FLE2RangeFindDriverSpec }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ public Builder queryType(final String queryType) {
/**
* The Range Options.
*
* <p>It is an error to set rangeOptions when the algorithm is not "rangePreview".</p>
* <p>It is an error to set rangeOptions when the algorithm is not "range".</p>
*
* @param rangeOptions the range options
* @return this
Expand Down Expand Up @@ -202,11 +202,13 @@ private MongoExplicitEncryptOptions(Builder builder) {
this.contentionFactor = builder.contentionFactor;
this.queryType = builder.queryType;
this.rangeOptions = builder.rangeOptions;
if (!(Objects.equals(algorithm, "Indexed") || Objects.equals(algorithm, "RangePreview"))) {
if (!(Objects.equals(algorithm, "Indexed") || Objects.equals(algorithm, "Range"))) {
if (contentionFactor != null) {
throw new IllegalStateException("Invalid configuration, contentionFactor can only be set if algorithm is 'Indexed' or 'RangePreview'");
throw new IllegalStateException(
"Invalid configuration, contentionFactor can only be set if algorithm is 'Indexed' or 'Range'");
} else if (queryType != null) {
throw new IllegalStateException("Invalid configuration, queryType can only be set if algorithm is 'Indexed' or 'RangePreview'");
throw new IllegalStateException(
"Invalid configuration, queryType can only be set if algorithm is 'Indexed' or 'Range'");
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
import static org.junit.jupiter.api.Assertions.assertIterableEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertThrows;


@SuppressWarnings("SameParameterValue")
Expand Down Expand Up @@ -210,8 +211,8 @@ public void testExplicitExpressionEncryption() {

MongoExplicitEncryptOptions options = MongoExplicitEncryptOptions.builder()
.keyId(new BsonBinary(BsonBinarySubType.UUID_STANDARD, Base64.getDecoder().decode("q83vqxI0mHYSNBI0VniQEg==")))
.algorithm("RangePreview")
.queryType("rangePreview")
.algorithm("Range")
.queryType("range")
.contentionFactor(4L)
.rangeOptions(rangeOptions)
.build();
Expand All @@ -230,6 +231,47 @@ public void testExplicitExpressionEncryption() {
mongoCrypt.close();
}

@Test
public void testRangePreviewQueryTypeIsNotSupported() {
MongoCrypt mongoCrypt = createMongoCrypt();
assertNotNull(mongoCrypt);

BsonDocument valueToEncrypt = getResourceAsDocument("fle2-find-range-explicit-v2/int32/value-to-encrypt.json");
BsonDocument rangeOptions = getResourceAsDocument("fle2-find-range-explicit-v2/int32/rangeopts.json");

MongoExplicitEncryptOptions options = MongoExplicitEncryptOptions.builder()
.keyId(new BsonBinary(BsonBinarySubType.UUID_STANDARD, Base64.getDecoder().decode("q83vqxI0mHYSNBI0VniQEg==")))
.algorithm("Range")
.queryType("rangePreview")
.contentionFactor(4L)
.rangeOptions(rangeOptions)
.build();

MongoCryptException exp = assertThrows(MongoCryptException.class, () -> mongoCrypt.createEncryptExpressionContext(valueToEncrypt, options));
assertEquals("Query type 'rangePreview' is deprecated, please use 'range'", exp.getMessage());
mongoCrypt.close();
}

@Test
public void testRangePreviewAlgorithmIsNotSupported() {
MongoCrypt mongoCrypt = createMongoCrypt();
assertNotNull(mongoCrypt);

BsonDocument rangeOptions = getResourceAsDocument("fle2-find-range-explicit-v2/int32/rangeopts.json");

IllegalStateException illegalStateException = assertThrows(IllegalStateException.class, () -> MongoExplicitEncryptOptions.builder()
.keyId(new BsonBinary(BsonBinarySubType.UUID_STANDARD, Base64.getDecoder().decode("q83vqxI0mHYSNBI0VniQEg==")))
.algorithm("RangePreview")
.queryType("range")
.contentionFactor(4L)
.rangeOptions(rangeOptions)
.build());

assertEquals("Invalid configuration, contentionFactor can only be set if algorithm is 'Indexed' or 'Range'",
illegalStateException.getMessage());
mongoCrypt.close();
}

@Test
public void testExplicitEncryptionDecryptionKeyAltName() throws IOException, URISyntaxException {
MongoCrypt mongoCrypt = createMongoCrypt();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,8 @@
},
"sparsity": {
"$numberLong": "1"
},
"trimFactor": {
"$numberInt": "1"
}
}
15 changes: 4 additions & 11 deletions bindings/python/pymongocrypt/binding.py
Original file line number Diff line number Diff line change
Expand Up @@ -664,9 +664,7 @@ def _parse_version(version):
/// String constant for setopt_algorithm "Random" encryption
/// String constant for setopt_algorithm "Indexed" explicit encryption
/// String constant for setopt_algorithm "Unindexed" explicit encryption
/// String constant for setopt_algorithm "rangePreview" explicit encryption (deprecated in favor of "range")
/// NOTE: "rangePreview" is experimental only and is not intended for public use.
/// API for "rangePreview" may be removed in a future release.
// DEPRECATED: support "RangePreview" has been removed in favor of "range".
// NOTE: "Range" is currently unstable API and subject to backwards breaking changes.

/**
Expand Down Expand Up @@ -849,10 +847,8 @@ def _parse_version(version):
/**
* Explicit helper method to encrypt a Match Expression or Aggregate Expression.
* Contexts created for explicit encryption will not go through mongocryptd.
* Requires query_type to be "range" or "rangePreview".
* Requires query_type to be "range".
*
* NOTE: "rangePreview" is experimental only and is not intended for public use.
* API for "rangePreview" may be removed in a future release.
* NOTE: "range" is currently unstable API and subject to backwards breaking changes.
*
* This method expects the passed-in BSON to be of the form:
Expand Down Expand Up @@ -1363,7 +1359,7 @@ def _parse_version(version):
void mongocrypt_setopt_bypass_query_analysis(mongocrypt_t *crypt);

/**
* @brief Opt-into use of Queryable Encryption Range V2 protocol.
* DEPRECATED: Use of `mongocrypt_setopt_use_range_v2` is deprecated. Range V2 is always enabled.
* NOTE: "range" is currently unstable API and subject to backwards breaking changes.
*
* @param[in] crypt The @ref mongocrypt_t object.
Expand Down Expand Up @@ -1436,11 +1432,8 @@ def _parse_version(version):
bool mongocrypt_ctx_setopt_algorithm_range(mongocrypt_ctx_t *ctx, mongocrypt_binary_t *opts);

/// String constants for setopt_query_type
// 'rangePreview' is deprecated in favor of range.
/// NOTE: "rangePreview" is experimental only and is not intended for public use.
/// API for "rangePreview" may be removed in a future release.
// DEPRECATED: Support "rangePreview" has been removed in favor of "range".
/// NOTE: "range" is currently unstable API and subject to backwards breaking changes.

"""
)

Expand Down
3 changes: 0 additions & 3 deletions bindings/python/pymongocrypt/mongocrypt.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,9 +60,6 @@ def __init__(self, options, callback):
self.__crypt = lib.mongocrypt_new()
if self.__crypt == ffi.NULL:
raise MongoCryptError("unable to create new mongocrypt object")
if options.enable_range_v2:
if not lib.mongocrypt_setopt_use_range_v2(self.__crypt):
raise MongoCryptError("unable to enable QE Range Protocol V2")

try:
self.__init()
Expand Down
6 changes: 3 additions & 3 deletions bindings/python/pymongocrypt/options.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ def __init__(
crypt_shared_lib_path=None,
crypt_shared_lib_required=False,
bypass_encryption=False,
enable_range_v2=False,
):
"""Options for :class:`MongoCrypt`.

Expand Down Expand Up @@ -54,7 +53,9 @@ def __init__(
- `crypt_shared_lib_required`: Whether to require a crypt_shared
library.
- `bypass_encryption`: Whether to bypass encryption.
- `enable_range_v2`: Whether to enable range V2.

.. versionremoved:: 1.11
Removed the ``enable_range_v2`` parameter.

.. versionadded:: 1.10
Added the ``enable_range_v2`` parameter.
Expand Down Expand Up @@ -143,7 +144,6 @@ def __init__(
self.crypt_shared_lib_path = crypt_shared_lib_path
self.crypt_shared_lib_required = crypt_shared_lib_required
self.bypass_encryption = bypass_encryption
self.enable_range_v2 = enable_range_v2


class ExplicitEncryptOpts:
Expand Down
4 changes: 1 addition & 3 deletions bindings/python/test/performance/perf_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,9 +79,7 @@ def tearDownModule():

class TestBulkDecryption(unittest.TestCase):
def setUp(self):
opts = MongoCryptOptions(
{"local": {"key": LOCAL_MASTER_KEY}}, enable_range_v2=True
)
opts = MongoCryptOptions({"local": {"key": LOCAL_MASTER_KEY}})
callback = MockCallback(key_docs=[bson_data("keyDocument.json")])
self.mongocrypt = MongoCrypt(opts, callback)
self.encrypter = ExplicitEncrypter(callback, opts)
Expand Down
72 changes: 33 additions & 39 deletions bindings/python/test/test_mongocrypt.py
Original file line number Diff line number Diff line change
Expand Up @@ -193,14 +193,6 @@ def test_mongocrypt_options_validation(self):
):
MongoCryptOptions(valid_kms, encrypted_fields_map={})

def test_mongocrypt_options_range(self):
opts = MongoCryptOptions({"local": {"key": b"\x00" * 96}})
self.assertFalse(opts.enable_range_v2)
opts.enable_range_v2 = True
self.assertTrue(opts.enable_range_v2)
opts = MongoCryptOptions({"local": {"key": b"\x00" * 96}}, enable_range_v2=True)
self.assertTrue(opts.enable_range_v2)


class TestMongoCrypt(unittest.TestCase):
maxDiff = None
Expand Down Expand Up @@ -381,9 +373,7 @@ def test_encrypt_encrypted_fields_map(self):
encrypted_fields_map = bson_data(
"compact/success/encrypted-field-config-map.json"
)
mc = self.create_mongocrypt(
encrypted_fields_map=encrypted_fields_map, enable_range_v2=True
)
mc = self.create_mongocrypt(encrypted_fields_map=encrypted_fields_map)
self.addCleanup(mc.close)
with mc.encryption_context("db", bson_data("compact/success/cmd.json")) as ctx:
self.assertEqual(ctx.state, lib.MONGOCRYPT_CTX_NEED_MONGO_KEYS)
Expand Down Expand Up @@ -782,8 +772,7 @@ def mongo_crypt_opts():
{
"aws": {"accessKeyId": "example", "secretAccessKey": "example"},
"local": {"key": b"\x00" * 96},
},
enable_range_v2=True,
}
)

async def _test_encrypt_decrypt(self, key_id=None, key_alt_name=None):
Expand Down Expand Up @@ -1212,13 +1201,12 @@ class TestExplicitEncryption(unittest.TestCase):
maxDiff = None

@staticmethod
def mongo_crypt_opts(enable_range_v2=True):
def mongo_crypt_opts():
return MongoCryptOptions(
{
"aws": {"accessKeyId": "example", "secretAccessKey": "example"},
"local": {"key": b"\x00" * 96},
},
enable_range_v2=enable_range_v2,
}
)

def _test_encrypt_decrypt(self, key_id=None, key_alt_name=None):
Expand Down Expand Up @@ -1424,30 +1412,36 @@ def test_range_query_int32(self):
self.assertEqual(encrypted_val, adjust_range_counter(encrypted_val, expected))

def test_rangePreview_query_int32(self):
key_path = "keys/ABCDEFAB123498761234123456789012-local-document.json"
key_id = json_data(key_path)["_id"]
encrypter = ExplicitEncrypter(
MockCallback(
key_docs=[bson_data(key_path)], kms_reply=http_data("kms-reply.txt")
),
self.mongo_crypt_opts(enable_range_v2=False),
)
self.addCleanup(encrypter.close)
# Expect error attempting to use 'rangePreview'
with self.assertRaisesRegex(
MongoCryptError,
"Algorithm 'rangePreview' is deprecated, please use 'range'",
):
key_path = "keys/ABCDEFAB123498761234123456789012-local-document.json"
key_id = json_data(key_path)["_id"]
encrypter = ExplicitEncrypter(
MockCallback(
key_docs=[bson_data(key_path)], kms_reply=http_data("kms-reply.txt")
),
self.mongo_crypt_opts(),
)
self.addCleanup(encrypter.close)

range_opts = bson_data("fle2-find-rangePreview-explicit/int32/rangeopts.json")
value = bson_data("fle2-find-rangePreview-explicit/int32/value-to-encrypt.json")
expected = json_data("fle2-find-range-explicit-v2/int32/encrypted-payload.json")
encrypted = encrypter.encrypt(
value,
"rangePreview",
key_id=key_id,
query_type="rangePreview",
contention_factor=4,
range_opts=range_opts,
is_expression=True,
)
encrypted_val = bson.decode(encrypted, OPTS)
self.assertEqual(encrypted_val, adjust_range_counter(encrypted_val, expected))
range_opts = bson_data(
"fle2-find-rangePreview-explicit/int32/rangeopts.json"
)
value = bson_data(
"fle2-find-rangePreview-explicit/int32/value-to-encrypt.json"
)
encrypter.encrypt(
value,
"rangePreview",
key_id=key_id,
query_type="rangePreview",
contention_factor=4,
range_opts=range_opts,
is_expression=True,
)


def read(filename, **kwargs):
Expand Down
2 changes: 0 additions & 2 deletions src/mongocrypt-opts.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,7 @@ void _mongocrypt_opts_kms_providers_init(_mongocrypt_opts_kms_providers_t *kms_p
void _mongocrypt_opts_init(_mongocrypt_opts_t *opts) {
BSON_ASSERT_PARAM(opts);
memset(opts, 0, sizeof(*opts));
#ifdef QE_USE_RANGE_V2
opts->use_range_v2 = true;
#endif
_mongocrypt_opts_kms_providers_init(&opts->kms_providers);
}

Expand Down
2 changes: 1 addition & 1 deletion src/mongocrypt.c
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ bool mongocrypt_setopt_fle2v2(mongocrypt_t *crypt, bool enable) {
bool mongocrypt_setopt_use_range_v2(mongocrypt_t *crypt) {
ASSERT_MONGOCRYPT_PARAM_UNINIT(crypt);

crypt->opts.use_range_v2 = true;
// Nothing to do. As of MONGOCRYPT-661, rangeV2 is the default.
return true;
}

Expand Down
Loading
Loading