com.mongodb.async.client.internal.AsyncCryptConnection Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of mongodb-driver-async Show documentation
Show all versions of mongodb-driver-async Show documentation
The MongoDB Asynchronous Driver
/*
* 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.async.client.internal;
import com.mongodb.MongoClientException;
import com.mongodb.MongoNamespace;
import com.mongodb.ReadPreference;
import com.mongodb.WriteConcernResult;
import com.mongodb.async.SingleResultCallback;
import com.mongodb.bulk.DeleteRequest;
import com.mongodb.bulk.InsertRequest;
import com.mongodb.bulk.UpdateRequest;
import com.mongodb.connection.AsyncConnection;
import com.mongodb.connection.ConnectionDescription;
import com.mongodb.connection.QueryResult;
import com.mongodb.connection.SplittablePayload;
import com.mongodb.internal.connection.MessageSettings;
import com.mongodb.internal.connection.SplittablePayloadBsonWriter;
import com.mongodb.internal.validator.MappedFieldNameValidator;
import com.mongodb.session.SessionContext;
import org.bson.BsonBinaryReader;
import org.bson.BsonBinaryWriter;
import org.bson.BsonBinaryWriterSettings;
import org.bson.BsonDocument;
import org.bson.BsonWriter;
import org.bson.BsonWriterSettings;
import org.bson.FieldNameValidator;
import org.bson.RawBsonDocument;
import org.bson.codecs.BsonValueCodecProvider;
import org.bson.codecs.Codec;
import org.bson.codecs.Decoder;
import org.bson.codecs.DecoderContext;
import org.bson.codecs.EncoderContext;
import org.bson.codecs.RawBsonDocumentCodec;
import org.bson.codecs.configuration.CodecRegistry;
import org.bson.io.BasicOutputBuffer;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static com.mongodb.internal.operation.ServerVersionHelper.serverIsLessThanVersionFourDotTwo;
import static org.bson.codecs.configuration.CodecRegistries.fromProviders;
@SuppressWarnings("deprecation")
class AsyncCryptConnection implements AsyncConnection {
private static final CodecRegistry REGISTRY = fromProviders(new BsonValueCodecProvider());
private static final int MAX_MESSAGE_SIZE = 6000000;
private static final int MAX_DOCUMENT_SIZE = 2097152;
private final AsyncConnection wrapped;
private final Crypt crypt;
AsyncCryptConnection(final AsyncConnection wrapped, final Crypt crypt) {
this.wrapped = wrapped;
this.crypt = crypt;
}
@Override
public int getCount() {
return wrapped.getCount();
}
@Override
public AsyncCryptConnection retain() {
wrapped.retain();
return this;
}
@Override
public void release() {
wrapped.release();
}
@Override
public ConnectionDescription getDescription() {
return wrapped.getDescription();
}
@Override
public void commandAsync(final String database, final BsonDocument command, final FieldNameValidator fieldNameValidator,
final ReadPreference readPreference, final Decoder commandResultDecoder,
final SessionContext sessionContext, final SingleResultCallback callback) {
commandAsync(database, command, fieldNameValidator, readPreference, commandResultDecoder, sessionContext, true, null, null,
callback);
}
@Override
public void commandAsync(final String database, final BsonDocument command, final FieldNameValidator commandFieldNameValidator,
final ReadPreference readPreference, final Decoder commandResultDecoder,
final SessionContext sessionContext, final boolean responseExpected,
final SplittablePayload payload, final FieldNameValidator payloadFieldNameValidator,
final SingleResultCallback callback) {
if (serverIsLessThanVersionFourDotTwo(wrapped.getDescription())) {
callback.onResult(null, new MongoClientException("Auto-encryption requires a minimum MongoDB version of 4.2"));
}
BasicOutputBuffer bsonOutput = new BasicOutputBuffer();
BsonBinaryWriter bsonBinaryWriter = new BsonBinaryWriter(new BsonWriterSettings(), new BsonBinaryWriterSettings(MAX_DOCUMENT_SIZE),
bsonOutput, getFieldNameValidator(payload, commandFieldNameValidator, payloadFieldNameValidator));
BsonWriter writer = payload == null
? bsonBinaryWriter
: new SplittablePayloadBsonWriter(bsonBinaryWriter, bsonOutput, createSplittablePayloadMessageSettings(), payload);
try {
getEncoder(command).encode(writer, command, EncoderContext.builder().build());
crypt.encrypt(database, new RawBsonDocument(bsonOutput.getInternalBuffer(), 0, bsonOutput.getSize()),
new SingleResultCallback() {
@Override
public void onResult(final RawBsonDocument encryptedCommand, final Throwable t) {
if (t != null) {
callback.onResult(null, t);
} else {
wrapped.commandAsync(database, encryptedCommand, commandFieldNameValidator, readPreference,
new RawBsonDocumentCodec(), sessionContext, responseExpected, null, null,
createCommandCallback());
}
}
private SingleResultCallback createCommandCallback() {
return new SingleResultCallback() {
@Override
public void onResult(final RawBsonDocument encryptedResponse, final Throwable t) {
if (t != null) {
callback.onResult(null, t);
} else {
crypt.decrypt(encryptedResponse, createDecryptCallback());
}
}
};
}
private SingleResultCallback createDecryptCallback() {
return new SingleResultCallback() {
@Override
public void onResult(final RawBsonDocument decryptedResponse, final Throwable t) {
if (t != null) {
callback.onResult(null, t);
} else {
try {
BsonBinaryReader reader = new BsonBinaryReader(decryptedResponse.getByteBuffer().asNIO());
callback.onResult(commandResultDecoder.decode(reader, DecoderContext.builder().build()), null);
} catch (Throwable t1) {
callback.onResult(null, t1);
}
}
}
};
}
});
} catch (Throwable t) {
callback.onResult(null, t);
}
}
@SuppressWarnings("unchecked")
private Codec getEncoder(final BsonDocument command) {
return (Codec) REGISTRY.get(command.getClass());
}
private FieldNameValidator getFieldNameValidator(final SplittablePayload payload,
final FieldNameValidator commandFieldNameValidator,
final FieldNameValidator payloadFieldNameValidator) {
if (payload == null) {
return commandFieldNameValidator;
}
Map rootMap = new HashMap();
rootMap.put(payload.getPayloadName(), payloadFieldNameValidator);
return new MappedFieldNameValidator(commandFieldNameValidator, rootMap);
}
private MessageSettings createSplittablePayloadMessageSettings() {
return MessageSettings.builder()
.maxBatchCount(wrapped.getDescription().getMaxBatchCount())
.maxMessageSize(MAX_MESSAGE_SIZE)
.maxDocumentSize(MAX_DOCUMENT_SIZE)
.build();
}
// UNSUPPORTED METHODS for encryption/decryption
@Override
public void insertAsync(final MongoNamespace namespace, final boolean ordered, final InsertRequest insertRequest,
final SingleResultCallback callback) {
callback.onResult(null, new UnsupportedOperationException());
}
@Override
public void updateAsync(final MongoNamespace namespace, final boolean ordered, final UpdateRequest updateRequest,
final SingleResultCallback callback) {
callback.onResult(null, new UnsupportedOperationException());
}
@Override
public void deleteAsync(final MongoNamespace namespace, final boolean ordered, final DeleteRequest deleteRequest,
final SingleResultCallback callback) {
callback.onResult(null, new UnsupportedOperationException());
}
@Override
public void commandAsync(final String database, final BsonDocument command, final boolean slaveOk,
final FieldNameValidator fieldNameValidator, final Decoder commandResultDecoder,
final SingleResultCallback callback) {
callback.onResult(null, new UnsupportedOperationException());
}
@Override
public void queryAsync(final MongoNamespace namespace, final BsonDocument queryDocument, final BsonDocument fields,
final int numberToReturn, final int skip, final boolean slaveOk, final boolean tailableCursor,
final boolean awaitData, final boolean noCursorTimeout, final boolean partial, final boolean oplogReplay,
final Decoder resultDecoder, final SingleResultCallback> callback) {
callback.onResult(null, new UnsupportedOperationException());
}
@Override
public void queryAsync(final MongoNamespace namespace, final BsonDocument queryDocument, final BsonDocument fields,
final int skip, final int limit, final int batchSize, final boolean slaveOk, final boolean tailableCursor,
final boolean awaitData, final boolean noCursorTimeout, final boolean partial, final boolean oplogReplay,
final Decoder resultDecoder, final SingleResultCallback> callback) {
callback.onResult(null, new UnsupportedOperationException());
}
@Override
public void getMoreAsync(final MongoNamespace namespace, final long cursorId, final int numberToReturn,
final Decoder resultDecoder, final SingleResultCallback> callback) {
callback.onResult(null, new UnsupportedOperationException());
}
@Override
public void killCursorAsync(final List cursors, final SingleResultCallback callback) {
callback.onResult(null, new UnsupportedOperationException());
}
@Override
public void killCursorAsync(final MongoNamespace namespace, final List cursors, final SingleResultCallback callback) {
callback.onResult(null, new UnsupportedOperationException());
}
}