Skip to content

Commit 6332c14

Browse files
authored
Fix MongoClient leak in auto-encryption (#1142)
When AutoEncryptionSettings#keyVaultMongoClientSettings is non-null and AutoEncryptionSettings#isBypassAutoEncryption is false, the second internal MongoClient is now closed when the containing MongoClient is closed. The bug is fixed in both the synchronous and reactive streams drivers. JAVA-4993
1 parent f256e42 commit 6332c14

File tree

4 files changed

+39
-25
lines changed

4 files changed

+39
-25
lines changed

driver-reactive-streams/src/main/com/mongodb/reactivestreams/client/internal/crypt/Crypt.java

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,9 @@ public class Crypt implements Closeable {
6464
private final KeyManagementService keyManagementService;
6565
private final boolean bypassAutoEncryption;
6666
@Nullable
67-
private final MongoClient internalClient;
67+
private final MongoClient collectionInfoRetrieverClient;
68+
@Nullable
69+
private final MongoClient keyVaultClient;
6870

6971
/**
7072
* Create an instance to use for explicit encryption and decryption, and data key creation.
@@ -81,7 +83,7 @@ public class Crypt implements Closeable {
8183
final Map<String, Map<String, Object>> kmsProviders,
8284
final Map<String, Supplier<Map<String, Object>>> kmsProviderPropertySuppliers) {
8385
this(mongoCrypt, keyRetriever, keyManagementService, kmsProviders, kmsProviderPropertySuppliers,
84-
false, null, null, null);
86+
false, null, null, null, null);
8587
}
8688

8789
/**
@@ -95,7 +97,8 @@ public class Crypt implements Closeable {
9597
* @param bypassAutoEncryption the bypass auto encryption flag
9698
* @param collectionInfoRetriever the collection info retriever
9799
* @param commandMarker the command marker
98-
* @param internalClient the internal mongo client
100+
* @param collectionInfoRetrieverClient the collection info retriever mongo client
101+
* @param keyVaultClient the key vault mongo client
99102
*/
100103
Crypt(final MongoCrypt mongoCrypt,
101104
final KeyRetriever keyRetriever,
@@ -105,7 +108,8 @@ public class Crypt implements Closeable {
105108
final boolean bypassAutoEncryption,
106109
@Nullable final CollectionInfoRetriever collectionInfoRetriever,
107110
@Nullable final CommandMarker commandMarker,
108-
@Nullable final MongoClient internalClient) {
111+
@Nullable final MongoClient collectionInfoRetrieverClient,
112+
@Nullable final MongoClient keyVaultClient) {
109113
this.mongoCrypt = mongoCrypt;
110114
this.keyRetriever = keyRetriever;
111115
this.keyManagementService = keyManagementService;
@@ -114,7 +118,8 @@ public class Crypt implements Closeable {
114118
this.bypassAutoEncryption = bypassAutoEncryption;
115119
this.collectionInfoRetriever = collectionInfoRetriever;
116120
this.commandMarker = commandMarker;
117-
this.internalClient = internalClient;
121+
this.collectionInfoRetrieverClient = collectionInfoRetrieverClient;
122+
this.keyVaultClient = keyVaultClient;
118123
}
119124

120125
/**
@@ -227,8 +232,9 @@ public void close() {
227232
//noinspection EmptyTryBlock
228233
try (MongoCrypt ignored = this.mongoCrypt;
229234
CommandMarker ignored1 = this.commandMarker;
230-
MongoClient ignored2 = this.internalClient;
231-
KeyManagementService ignored3 = this.keyManagementService
235+
MongoClient ignored2 = this.collectionInfoRetrieverClient;
236+
MongoClient ignored3 = this.keyVaultClient;
237+
KeyManagementService ignored4 = this.keyManagementService
232238
) {
233239
// just using try-with-resources to ensure they all get closed, even in the case of exceptions
234240
}

driver-reactive-streams/src/main/com/mongodb/reactivestreams/client/internal/crypt/Crypts.java

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -42,17 +42,17 @@ private Crypts() {
4242
}
4343

4444
public static Crypt createCrypt(final MongoClientImpl client, final AutoEncryptionSettings settings) {
45-
MongoClient internalClient = null;
45+
MongoClient sharedInternalClient = null;
4646
MongoClientSettings keyVaultMongoClientSettings = settings.getKeyVaultMongoClientSettings();
4747
if (keyVaultMongoClientSettings == null || !settings.isBypassAutoEncryption()) {
48-
MongoClientSettings mongoClientSettings = MongoClientSettings.builder(client.getSettings())
48+
MongoClientSettings defaultInternalMongoClientSettings = MongoClientSettings.builder(client.getSettings())
4949
.applyToConnectionPoolSettings(builder -> builder.minSize(0))
5050
.autoEncryptionSettings(null)
5151
.build();
52-
internalClient = MongoClients.create(mongoClientSettings);
52+
sharedInternalClient = MongoClients.create(defaultInternalMongoClientSettings);
5353
}
5454
MongoClient keyVaultClient = keyVaultMongoClientSettings == null
55-
? internalClient : MongoClients.create(keyVaultMongoClientSettings);
55+
? sharedInternalClient : MongoClients.create(keyVaultMongoClientSettings);
5656
MongoCrypt mongoCrypt = MongoCrypts.create(createMongoCryptOptions(settings));
5757
return new Crypt(
5858
mongoCrypt,
@@ -61,9 +61,10 @@ public static Crypt createCrypt(final MongoClientImpl client, final AutoEncrypti
6161
settings.getKmsProviders(),
6262
settings.getKmsProviderPropertySuppliers(),
6363
settings.isBypassAutoEncryption(),
64-
settings.isBypassAutoEncryption() ? null : new CollectionInfoRetriever(internalClient),
64+
settings.isBypassAutoEncryption() ? null : new CollectionInfoRetriever(sharedInternalClient),
6565
new CommandMarker(mongoCrypt, settings),
66-
internalClient);
66+
sharedInternalClient,
67+
keyVaultClient);
6768
}
6869

6970
public static Crypt create(final MongoClient keyVaultClient, final ClientEncryptionSettings settings) {

driver-sync/src/main/com/mongodb/client/internal/Crypt.java

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,10 @@ public class Crypt implements Closeable {
6363
private final KeyRetriever keyRetriever;
6464
private final KeyManagementService keyManagementService;
6565
private final boolean bypassAutoEncryption;
66-
private final MongoClient internalClient;
66+
@Nullable
67+
private final MongoClient collectionInfoRetrieverClient;
68+
@Nullable
69+
private final MongoClient keyVaultClient;
6770

6871

6972
/**
@@ -81,7 +84,7 @@ public class Crypt implements Closeable {
8184
final Map<String, Map<String, Object>> kmsProviders,
8285
final Map<String, Supplier<Map<String, Object>>> kmsProviderPropertySuppliers) {
8386
this(mongoCrypt, keyRetriever, keyManagementService, kmsProviders, kmsProviderPropertySuppliers,
84-
false, null, null, null);
87+
false, null, null, null, null);
8588
}
8689

8790
/**
@@ -95,7 +98,8 @@ public class Crypt implements Closeable {
9598
* @param bypassAutoEncryption the bypass auto encryption flag
9699
* @param collectionInfoRetriever the collection info retriever
97100
* @param commandMarker the command marker
98-
* @param internalClient the internal mongo client
101+
* @param collectionInfoRetrieverClient the collection info retriever mongo client
102+
* @param keyVaultClient the key vault mongo client
99103
*/
100104
Crypt(final MongoCrypt mongoCrypt,
101105
final KeyRetriever keyRetriever,
@@ -105,7 +109,8 @@ public class Crypt implements Closeable {
105109
final boolean bypassAutoEncryption,
106110
@Nullable final CollectionInfoRetriever collectionInfoRetriever,
107111
@Nullable final CommandMarker commandMarker,
108-
@Nullable final MongoClient internalClient) {
112+
@Nullable final MongoClient collectionInfoRetrieverClient,
113+
@Nullable final MongoClient keyVaultClient) {
109114
this.mongoCrypt = mongoCrypt;
110115
this.keyRetriever = keyRetriever;
111116
this.keyManagementService = keyManagementService;
@@ -114,7 +119,8 @@ public class Crypt implements Closeable {
114119
this.bypassAutoEncryption = bypassAutoEncryption;
115120
this.collectionInfoRetriever = collectionInfoRetriever;
116121
this.commandMarker = commandMarker;
117-
this.internalClient = internalClient;
122+
this.collectionInfoRetrieverClient = collectionInfoRetrieverClient;
123+
this.keyVaultClient = keyVaultClient;
118124
}
119125

120126
/**
@@ -260,7 +266,8 @@ public void close() {
260266
//noinspection EmptyTryBlock
261267
try (MongoCrypt ignored = this.mongoCrypt;
262268
CommandMarker ignored1 = this.commandMarker;
263-
MongoClient ignored2 = this.internalClient
269+
MongoClient ignored2 = this.collectionInfoRetrieverClient;
270+
MongoClient ignored3 = this.keyVaultClient
264271
) {
265272
// just using try-with-resources to ensure they all get closed, even in the case of exceptions
266273
}

driver-sync/src/main/com/mongodb/client/internal/Crypts.java

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -36,17 +36,17 @@
3636
public final class Crypts {
3737

3838
public static Crypt createCrypt(final MongoClientImpl client, final AutoEncryptionSettings settings) {
39-
MongoClient internalClient = null;
39+
MongoClient sharedInternalClient = null;
4040
MongoClientSettings keyVaultMongoClientSettings = settings.getKeyVaultMongoClientSettings();
4141
if (keyVaultMongoClientSettings == null || !settings.isBypassAutoEncryption()) {
42-
MongoClientSettings mongoClientSettings = MongoClientSettings.builder(client.getSettings())
42+
MongoClientSettings defaultInternalMongoClientSettings = MongoClientSettings.builder(client.getSettings())
4343
.applyToConnectionPoolSettings(builder -> builder.minSize(0))
4444
.autoEncryptionSettings(null)
4545
.build();
46-
internalClient = MongoClients.create(mongoClientSettings);
46+
sharedInternalClient = MongoClients.create(defaultInternalMongoClientSettings);
4747
}
4848
MongoClient keyVaultClient = keyVaultMongoClientSettings == null
49-
? internalClient : MongoClients.create(keyVaultMongoClientSettings);
49+
? sharedInternalClient : MongoClients.create(keyVaultMongoClientSettings);
5050
MongoCrypt mongoCrypt = MongoCrypts.create(createMongoCryptOptions(settings));
5151
return new Crypt(
5252
mongoCrypt,
@@ -55,9 +55,9 @@ public static Crypt createCrypt(final MongoClientImpl client, final AutoEncrypti
5555
settings.getKmsProviders(),
5656
settings.getKmsProviderPropertySuppliers(),
5757
settings.isBypassAutoEncryption(),
58-
settings.isBypassAutoEncryption() ? null : new CollectionInfoRetriever(internalClient),
58+
settings.isBypassAutoEncryption() ? null : new CollectionInfoRetriever(sharedInternalClient),
5959
new CommandMarker(mongoCrypt, settings),
60-
internalClient);
60+
sharedInternalClient, keyVaultClient);
6161
}
6262

6363
static Crypt create(final MongoClient keyVaultClient, final ClientEncryptionSettings settings) {

0 commit comments

Comments
 (0)