Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@

package com.mongodb.client.model.vault;

import com.mongodb.annotations.Alpha;
import com.mongodb.annotations.Reason;
import com.mongodb.lang.Nullable;
import org.bson.BsonBinary;

Expand All @@ -31,6 +33,7 @@ public class EncryptOptions {
private Long contentionFactor;
private String queryType;
private RangeOptions rangeOptions;
private TextOptions textOptions;

/**
* Construct an instance with the given algorithm.
Expand All @@ -51,8 +54,13 @@ public EncryptOptions(final String algorithm) {
* <li>Indexed</li>
* <li>Unindexed</li>
* <li>Range</li>
* <li>TextPreview</li>
* </ul>
*
* <p>The "TextPreview" algorithm is in preview and should be used for experimental workloads only.
* These features are unstable and their security is not guaranteed until released as Generally Available (GA).
* The GA version of these features may not be backwards compatible with the preview version.</p>
*
* @return the encryption algorithm
*/
public String getAlgorithm() {
Expand Down Expand Up @@ -141,8 +149,8 @@ public Long getContentionFactor() {
/**
* The QueryType.
*
* <p>Currently, we support only "equality" or "range" queryType.</p>
* <p>It is an error to set queryType when the algorithm is not "Indexed" or "Range".</p>
* <p>Currently, we support only "equality", "range", "prefixPreview", "suffixPreview" or "substringPreview" queryType.</p>
* <p>It is an error to set queryType when the algorithm is not "Indexed", "Range" or "TextPreview".</p>
* @param queryType the query type
* @return this
* @since 4.7
Expand Down Expand Up @@ -194,6 +202,36 @@ public RangeOptions getRangeOptions() {
return rangeOptions;
}

/**
* The TextOptions
*
* <p>It is an error to set TextOptions when the algorithm is not "TextPreview".
* @param textOptions the text options
* @return this
* @since 5.6
* @mongodb.server.release 8.2
* @mongodb.driver.manual /core/queryable-encryption/ queryable encryption
*/
@Alpha(Reason.SERVER)
public EncryptOptions textOptions(@Nullable final TextOptions textOptions) {
this.textOptions = textOptions;
return this;
}

/**
* Gets the TextOptions
* @see #textOptions(TextOptions)
* @return the text options or null if not set
* @since 5.6
* @mongodb.server.release 8.2
* @mongodb.driver.manual /core/queryable-encryption/ queryable encryption
*/
@Alpha(Reason.SERVER)
@Nullable
public TextOptions getTextOptions() {
return textOptions;
}

@Override
public String toString() {
return "EncryptOptions{"
Expand Down
187 changes: 187 additions & 0 deletions driver-core/src/main/com/mongodb/client/model/vault/TextOptions.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,187 @@
/*
* Copyright 2008-present MongoDB, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.mongodb.client.model.vault;

import com.mongodb.annotations.Alpha;
import com.mongodb.annotations.Reason;
import com.mongodb.lang.Nullable;
import org.bson.BsonDocument;

/**
* Text options for a Queryable Encryption field that supports text queries.
*
* <p>Note: TextOptions is in Alpha and subject to backwards breaking changes.
*
* @since 5.6
* @mongodb.server.release 8.2
* @mongodb.driver.manual /core/queryable-encryption/ queryable encryption
*/
@Alpha(Reason.SERVER)
public class TextOptions {
private Boolean caseSensitive;
private Boolean diacriticSensitive;
@Nullable
private BsonDocument prefixOptions;
@Nullable
private BsonDocument suffixOptions;
@Nullable
private BsonDocument substringOptions;

/**
* Construct a new instance
*/
public TextOptions() {
}

/**
* @return true if text indexes for this field are case sensitive.
*/
public boolean getCaseSensitive() {
return caseSensitive;
}

/**
* Set case sensitivity
*
* @param caseSensitive true if text indexes are case sensitive
* @return this
*/
public TextOptions caseSensitive(final boolean caseSensitive) {
this.caseSensitive = caseSensitive;
return this;
}

/**
* @return true if text indexes are diacritic sensitive
*/
public boolean getDiacriticSensitive() {
return diacriticSensitive;
}

/**
* Set diacritic sensitivity
*
* @param diacriticSensitive true if text indexes are diacritic sensitive
* @return this
*/
public TextOptions diacriticSensitive(final boolean diacriticSensitive) {
this.diacriticSensitive = diacriticSensitive;
return this;
}

/**
* Set the prefix options.
*
* <p>Expected to be a {@link BsonDocument} in the format of:</p>
*
* <pre>
* {@code
* {
* // strMinQueryLength is the minimum allowed query length. Querying with a shorter string will error.
* strMinQueryLength: BsonInt32,
* // strMaxQueryLength is the maximum allowed query length. Querying with a longer string will error.
* strMaxQueryLength: BsonInt32
* }
* }
* </pre>
*
* @param prefixOptions the prefix options or null
* @return this
*/
public TextOptions prefixOptions(@Nullable final BsonDocument prefixOptions) {
this.prefixOptions = prefixOptions;
return this;
}

/**
* @see #prefixOptions(BsonDocument)
* @return the prefix options document or null
*/
@Nullable
public BsonDocument getPrefixOptions() {
return prefixOptions;
}

/**
* Set the suffix options.
*
* <p>Expected to be a {@link BsonDocument} in the format of:</p>
*
* <pre>
* {@code
* {
* // strMinQueryLength is the minimum allowed query length. Querying with a shorter string will error.
* strMinQueryLength: BsonInt32,
* // strMaxQueryLength is the maximum allowed query length. Querying with a longer string will error.
* strMaxQueryLength: BsonInt32
* }
* }
* </pre>
*
* @param suffixOptions the suffix options or null
* @return this
*/
public TextOptions suffixOptions(@Nullable final BsonDocument suffixOptions) {
this.suffixOptions = suffixOptions;
return this;
}

/**
* @see #suffixOptions(BsonDocument)
* @return the suffix options document or null
*/
@Nullable
public BsonDocument getSuffixOptions() {
return suffixOptions;
}

/**
* Set the substring options.
*
* <p>Expected to be a {@link BsonDocument} in the format of:</p>
*
* <pre>
* {@code
* {
* // strMaxLength is the maximum allowed length to insert. Inserting longer strings will error.
* strMaxLength: BsonInt32,
* // strMinQueryLength is the minimum allowed query length. Querying with a shorter string will error.
* strMinQueryLength: BsonInt32,
* // strMaxQueryLength is the maximum allowed query length. Querying with a longer string will error.
* strMaxQueryLength: BsonInt32
* }
* }
* </pre>
*
* @param substringOptions the substring options or null
* @return this
*/
public TextOptions substringOptions(@Nullable final BsonDocument substringOptions) {
this.substringOptions = substringOptions;
return this;
}

/**
* @see #substringOptions(BsonDocument)
* @return the substring options document or null
*/
@Nullable
public BsonDocument getSubstringOptions() {
return substringOptions;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@

import com.mongodb.client.model.vault.EncryptOptions;
import com.mongodb.client.model.vault.RangeOptions;
import com.mongodb.client.model.vault.TextOptions;
import com.mongodb.internal.crypt.capi.MongoExplicitEncryptOptions;
import org.bson.BsonBoolean;
import org.bson.BsonDocument;
import org.bson.BsonInt32;
import org.bson.BsonInt64;
Expand Down Expand Up @@ -70,6 +72,30 @@ public static MongoExplicitEncryptOptions asMongoExplicitEncryptOptions(final En
}
encryptOptionsBuilder.rangeOptions(rangeOptionsBsonDocument);
}

TextOptions textOptions = options.getTextOptions();
if (textOptions != null) {
BsonDocument textOptionsDocument = new BsonDocument();
textOptionsDocument.put("caseSensitive", BsonBoolean.valueOf(textOptions.getCaseSensitive()));
textOptionsDocument.put("diacriticSensitive", BsonBoolean.valueOf(textOptions.getDiacriticSensitive()));

BsonDocument substringOptions = textOptions.getSubstringOptions();
if (substringOptions != null) {
textOptionsDocument.put("substring", substringOptions);
}

BsonDocument prefixOptions = textOptions.getPrefixOptions();
if (prefixOptions != null) {
textOptionsDocument.put("prefix", prefixOptions);
}

BsonDocument suffixOptions = textOptions.getSuffixOptions();
if (suffixOptions != null) {
textOptionsDocument.put("suffix", suffixOptions);
}
encryptOptionsBuilder.textOptions(textOptionsDocument);
}

return encryptOptionsBuilder.build();
}
private EncryptOptionsHelper() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@
import com.mongodb.internal.connection.StreamFactoryFactory;
import com.mongodb.internal.connection.TlsChannelStreamFactoryFactory;
import com.mongodb.internal.connection.netty.NettyStreamFactoryFactory;
import com.mongodb.internal.crypt.capi.CAPI;
import com.mongodb.internal.operation.BatchCursor;
import com.mongodb.internal.operation.CommandReadOperation;
import com.mongodb.internal.operation.DropDatabaseOperation;
Expand Down Expand Up @@ -148,6 +149,7 @@ public final class ClusterFixture {
private static final Map<ReadPreference, ReadWriteBinding> BINDING_MAP = new HashMap<>();
private static final Map<ReadPreference, AsyncReadWriteBinding> ASYNC_BINDING_MAP = new HashMap<>();

private static ServerVersion mongoCryptVersion;
private static ServerVersion serverVersion;
private static BsonDocument serverParameters;

Expand Down Expand Up @@ -181,6 +183,13 @@ public static ClusterDescription getClusterDescription(final Cluster cluster) {
}
}

public static ServerVersion getMongoCryptVersion() {
if (mongoCryptVersion == null) {
mongoCryptVersion = new ServerVersion(getVersionList(CAPI.mongocrypt_version(null).toString()));
}
return mongoCryptVersion;
}

public static ServerVersion getServerVersion() {
if (serverVersion == null) {
serverVersion = getVersion(new CommandReadOperation<>("admin",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@

import static com.mongodb.ClusterFixture.executeAsync;
import static com.mongodb.ClusterFixture.getBinding;
import static java.lang.String.format;
import static java.util.Arrays.asList;
import static java.util.Collections.singletonList;

Expand Down Expand Up @@ -154,6 +155,16 @@ public void drop(final WriteConcern writeConcern) {
drop(namespace, writeConcern);
}

public void dropAndCreate(final BsonDocument createOptions) {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is now part of the Spec and ensures that fresh encryption collections are made. This ensures __safeContent__ values are predictable and testable.

// Drop the collection and any encryption collections: enxcol_.<collectionName>.esc and enxcol_.<collectionName>.ecoc
drop(namespace, WriteConcern.MAJORITY);
drop(new MongoNamespace(namespace.getDatabaseName(), format("enxcol_.%s.esc", namespace.getCollectionName())),
WriteConcern.MAJORITY);
drop(new MongoNamespace(namespace.getDatabaseName(), format("enxcol_.%s.ecoc", namespace.getCollectionName())),
WriteConcern.MAJORITY);
create(WriteConcern.MAJORITY, createOptions);
}

public void create() {
create(namespace.getCollectionName(), new CreateCollectionOptions(), WriteConcern.ACKNOWLEDGED);
}
Expand Down
Loading