Skip to content

Commit 544119f

Browse files
DmitryLukyanovjyemin
authored andcommitted
Add ViewAreProhibited and ExternalKeyVault FLE tests.
1 parent 09decfa commit 544119f

File tree

10 files changed

+677
-2
lines changed

10 files changed

+677
-2
lines changed

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -238,7 +238,9 @@ public void onResult(final RawBsonDocument result, final Throwable t) {
238238
@Override
239239
public void close() {
240240
mongoCrypt.close();
241-
commandMarker.close();
241+
if (commandMarker != null) {
242+
commandMarker.close();
243+
}
242244
keyRetriever.close();
243245
}
244246

driver-async/src/test/functional/com/mongodb/async/client/ClientSideEncryptionCorpusTest.java

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
import org.bson.Document;
3333
import org.bson.UuidRepresentation;
3434
import org.bson.codecs.UuidCodec;
35+
import org.junit.After;
3536
import org.junit.Before;
3637
import org.junit.Test;
3738
import org.junit.runner.RunWith;
@@ -285,4 +286,30 @@ public static Collection<Object[]> data() {
285286
return Arrays.asList(new Object[]{true}, new Object[]{false});
286287
}
287288

289+
@After
290+
public void after() {
291+
if (client != null) {
292+
try {
293+
client.close();
294+
} catch (Exception e) {
295+
// ignore
296+
}
297+
}
298+
299+
if (autoEncryptingClient != null) {
300+
try {
301+
autoEncryptingClient.close();
302+
} catch (Exception e) {
303+
// ignore
304+
}
305+
}
306+
307+
if (clientEncryption != null) {
308+
try {
309+
clientEncryption.close();
310+
} catch (Exception e) {
311+
// ignore
312+
}
313+
}
314+
}
288315
}
Lines changed: 186 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,186 @@
1+
/*
2+
* Copyright 2008-present MongoDB, Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.mongodb.async.client;
18+
19+
import com.mongodb.ClientEncryptionSettings;
20+
import com.mongodb.AutoEncryptionSettings;
21+
import com.mongodb.MongoClientSettings;
22+
import com.mongodb.MongoCredential;
23+
import com.mongodb.MongoSecurityException;
24+
import com.mongodb.async.FutureResultCallback;
25+
import com.mongodb.async.client.vault.ClientEncryption;
26+
import com.mongodb.async.client.vault.ClientEncryptions;
27+
import com.mongodb.client.model.vault.EncryptOptions;
28+
import org.bson.BsonBinary;
29+
import org.bson.BsonBinarySubType;
30+
import org.bson.BsonDocument;
31+
import org.bson.BsonString;
32+
import org.junit.After;
33+
import org.junit.Before;
34+
import org.junit.Test;
35+
import org.junit.runner.RunWith;
36+
import org.junit.runners.Parameterized;
37+
38+
import java.io.File;
39+
import java.io.IOException;
40+
import java.net.URISyntaxException;
41+
import java.util.Arrays;
42+
import java.util.Base64;
43+
import java.util.Collection;
44+
import java.util.HashMap;
45+
import java.util.Map;
46+
47+
import static com.mongodb.ClusterFixture.isNotAtLeastJava8;
48+
import static com.mongodb.ClusterFixture.serverVersionAtLeast;
49+
import static com.mongodb.async.client.Fixture.getMongoClientBuilderFromConnectionString;
50+
import static com.mongodb.async.client.Fixture.getMongoClient;
51+
import static org.junit.Assert.assertEquals;
52+
import static org.junit.Assume.assumeFalse;
53+
import static org.junit.Assume.assumeTrue;
54+
import static util.JsonPoweredTestHelper.getTestDocument;
55+
56+
@RunWith(Parameterized.class)
57+
public class ClientSideEncryptionExternalKeyVaultTest {
58+
private MongoClient client, clientEncrypted;
59+
private ClientEncryption clientEncryption;
60+
private final boolean withExternalKeyVault;
61+
62+
public ClientSideEncryptionExternalKeyVaultTest(final boolean withExternalKeyVault) {
63+
this.withExternalKeyVault = withExternalKeyVault;
64+
}
65+
66+
@Before
67+
public void setUp() throws IOException, URISyntaxException {
68+
assumeFalse(isNotAtLeastJava8());
69+
assumeTrue(serverVersionAtLeast(4, 1));
70+
assumeTrue("Encryption test with external keyVault is disabled",
71+
System.getProperty("org.mongodb.test.awsAccessKeyId") != null
72+
&& !System.getProperty("org.mongodb.test.awsAccessKeyId").isEmpty());
73+
74+
/* Step 1: get unencrypted client and recreate keys collection */
75+
client = getMongoClient();
76+
MongoDatabase admin = client.getDatabase("admin");
77+
MongoCollection<BsonDocument> datakeys = admin.getCollection("datakeys", BsonDocument.class);
78+
FutureResultCallback<Void> voidCallback = new FutureResultCallback<Void>();
79+
datakeys.drop(voidCallback);
80+
voidCallback.get();
81+
82+
voidCallback = new FutureResultCallback<Void>();
83+
datakeys.insertOne(bsonDocumentFromPath("external-key.json"), voidCallback);
84+
voidCallback.get();
85+
86+
/* Step 2: create encryption objects. */
87+
Map<String, Map<String, Object>> kmsProviders = new HashMap<String, Map<String, Object>>();
88+
Map<String, Object> localMasterkey = new HashMap<String, Object>();
89+
Map<String, BsonDocument> schemaMap = new HashMap<String, BsonDocument>();
90+
91+
byte[] localMasterkeyBytes = Base64.getDecoder().decode("Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBM"
92+
+ "UN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk");
93+
localMasterkey.put("key", localMasterkeyBytes);
94+
kmsProviders.put("local", localMasterkey);
95+
schemaMap.put("db.coll", bsonDocumentFromPath("external-schema.json"));
96+
97+
AutoEncryptionSettings.Builder autoEncryptionSettingsBuilder = AutoEncryptionSettings.builder()
98+
.keyVaultNamespace("admin.datakeys")
99+
.kmsProviders(kmsProviders)
100+
.schemaMap(schemaMap);
101+
102+
MongoClientSettings externalClientSettings = null;
103+
if (withExternalKeyVault) {
104+
externalClientSettings = getMongoClientBuilderFromConnectionString()
105+
.credential(MongoCredential.createCredential("fake-user", "admin", "fake-pwd".toCharArray()))
106+
.build();
107+
autoEncryptionSettingsBuilder.keyVaultMongoClientSettings(externalClientSettings);
108+
}
109+
110+
AutoEncryptionSettings autoEncryptionSettings = autoEncryptionSettingsBuilder.build();
111+
112+
MongoClientSettings clientSettings = getMongoClientBuilderFromConnectionString()
113+
.autoEncryptionSettings(autoEncryptionSettings)
114+
.build();
115+
clientEncrypted = MongoClients.create(clientSettings);
116+
117+
ClientEncryptionSettings.Builder clientEncryptionSettingsBuilder = ClientEncryptionSettings.builder().
118+
keyVaultMongoClientSettings(getMongoClientBuilderFromConnectionString().build())
119+
.kmsProviders(kmsProviders)
120+
.keyVaultNamespace("admin.datakeys");
121+
122+
if (withExternalKeyVault) {
123+
clientEncryptionSettingsBuilder.keyVaultMongoClientSettings(externalClientSettings);
124+
}
125+
126+
ClientEncryptionSettings clientEncryptionSettings = clientEncryptionSettingsBuilder.build();
127+
clientEncryption = ClientEncryptions.create(clientEncryptionSettings);
128+
}
129+
130+
@Test
131+
public void testExternal() {
132+
boolean authExceptionThrown = false;
133+
MongoCollection<BsonDocument> coll = clientEncrypted
134+
.getDatabase("db")
135+
.getCollection("coll", BsonDocument.class);
136+
FutureResultCallback<Void> voidCallback;
137+
try {
138+
voidCallback = new FutureResultCallback<Void>();
139+
coll.insertOne(new BsonDocument().append("encrypted", new BsonString("test")), voidCallback);
140+
voidCallback.get();
141+
} catch (MongoSecurityException mse) {
142+
authExceptionThrown = true;
143+
}
144+
assertEquals(authExceptionThrown, withExternalKeyVault);
145+
146+
EncryptOptions encryptOptions = new EncryptOptions("AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic")
147+
.keyId(new BsonBinary(BsonBinarySubType.UUID_STANDARD, Base64.getDecoder().decode("LOCALAAAAAAAAAAAAAAAAA==")));
148+
authExceptionThrown = false;
149+
try {
150+
FutureResultCallback<BsonBinary> bsonBinaryCallback = new FutureResultCallback<BsonBinary>();
151+
clientEncryption.encrypt(new BsonString("test"), encryptOptions, bsonBinaryCallback);
152+
bsonBinaryCallback.get();
153+
} catch (MongoSecurityException mse) {
154+
authExceptionThrown = true;
155+
}
156+
assertEquals(authExceptionThrown, withExternalKeyVault);
157+
}
158+
159+
private static BsonDocument bsonDocumentFromPath(final String path) throws IOException, URISyntaxException {
160+
return getTestDocument(new File(ClientSideEncryptionExternalKeyVaultTest.class
161+
.getResource("/client-side-encryption-external/" + path).toURI()));
162+
}
163+
164+
@Parameterized.Parameters(name = "withExternalKeyVault: {0}")
165+
public static Collection<Object[]> data() {
166+
return Arrays.asList(new Object[]{true}, new Object[]{false});
167+
}
168+
169+
@After
170+
public void after() {
171+
if (clientEncrypted != null) {
172+
try {
173+
clientEncrypted.close();
174+
} catch (Exception e) {
175+
// ignore
176+
}
177+
}
178+
if (clientEncryption != null) {
179+
try {
180+
clientEncryption.close();
181+
} catch (Exception e) {
182+
// ignore
183+
}
184+
}
185+
}
186+
}
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
/*
2+
* Copyright 2008-present MongoDB, Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.mongodb.async.client;
18+
19+
import com.mongodb.AutoEncryptionSettings;
20+
import com.mongodb.MongoClientSettings;
21+
import com.mongodb.MongoException;
22+
import com.mongodb.async.FutureResultCallback;
23+
import org.bson.BsonDocument;
24+
import org.bson.BsonString;
25+
import org.junit.After;
26+
import org.junit.Before;
27+
import org.junit.Test;
28+
29+
import java.util.Base64;
30+
import java.util.Collections;
31+
import java.util.HashMap;
32+
import java.util.Map;
33+
34+
import static com.mongodb.ClusterFixture.isNotAtLeastJava8;
35+
import static com.mongodb.ClusterFixture.serverVersionAtLeast;
36+
import static junit.framework.TestCase.assertTrue;
37+
import static com.mongodb.async.client.Fixture.getMongoClientBuilderFromConnectionString;
38+
import static com.mongodb.async.client.Fixture.getMongoClient;
39+
import static org.junit.Assume.assumeFalse;
40+
import static org.junit.Assume.assumeTrue;
41+
import static org.junit.Assert.fail;
42+
43+
public class ClientSideEncryptionViewAreProhibitedTest {
44+
private MongoClient clientEncrypted;
45+
46+
@Before
47+
public void setUp() {
48+
assumeFalse(isNotAtLeastJava8());
49+
assumeTrue(serverVersionAtLeast(4, 1));
50+
assumeTrue("Encryption test with external keyVault is disabled",
51+
System.getProperty("org.mongodb.test.awsAccessKeyId") != null
52+
&& !System.getProperty("org.mongodb.test.awsAccessKeyId").isEmpty());
53+
54+
MongoClient client = getMongoClient();
55+
56+
MongoDatabase db = client.getDatabase("db");
57+
FutureResultCallback<Void> voidCallback = new FutureResultCallback<Void>();
58+
db.getCollection("view").drop(voidCallback);
59+
voidCallback.get();
60+
61+
voidCallback = new FutureResultCallback<Void>();
62+
db.createView("view", "coll", Collections.<BsonDocument>emptyList(), voidCallback);
63+
voidCallback.get();
64+
65+
Map<String, Map<String, Object>> kmsProviders = new HashMap<String, Map<String, Object>>();
66+
Map<String, Object> localMasterkey = new HashMap<String, Object>();
67+
68+
byte[] localMasterkeyBytes = Base64.getDecoder().decode("Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBM"
69+
+ "UN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk");
70+
localMasterkey.put("key", localMasterkeyBytes);
71+
kmsProviders.put("local", localMasterkey);
72+
73+
AutoEncryptionSettings.Builder autoEncryptionSettingsBuilder = AutoEncryptionSettings.builder()
74+
.keyVaultNamespace("admin.datakeys")
75+
.kmsProviders(kmsProviders);
76+
77+
AutoEncryptionSettings autoEncryptionSettings = autoEncryptionSettingsBuilder.build();
78+
79+
MongoClientSettings.Builder clientSettingsBuilder = getMongoClientBuilderFromConnectionString();
80+
MongoClientSettings clientSettings = clientSettingsBuilder
81+
.autoEncryptionSettings(autoEncryptionSettings)
82+
.build();
83+
clientEncrypted = MongoClients.create(clientSettings);
84+
}
85+
86+
@Test
87+
public void shouldThrowError() {
88+
MongoCollection<BsonDocument> coll = clientEncrypted
89+
.getDatabase("db")
90+
.getCollection("view", BsonDocument.class);
91+
try {
92+
FutureResultCallback<Void> voidCallback = new FutureResultCallback<Void>();
93+
coll.insertOne(new BsonDocument().append("encrypted", new BsonString("test")), voidCallback);
94+
voidCallback.get();
95+
fail();
96+
} catch (MongoException me) {
97+
assertTrue(me.getMessage().contains("cannot auto encrypt a view"));
98+
}
99+
}
100+
101+
@After
102+
public void after() {
103+
if (clientEncrypted != null) {
104+
clientEncrypted.close();
105+
}
106+
}
107+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
{
2+
"status": {
3+
"$numberInt": "1"
4+
},
5+
"_id": {
6+
"$binary": {
7+
"base64": "LOCALAAAAAAAAAAAAAAAAA==",
8+
"subType": "04"
9+
}
10+
},
11+
"masterKey": {
12+
"provider": "local"
13+
},
14+
"updateDate": {
15+
"$date": {
16+
"$numberLong": "1557827033449"
17+
}
18+
},
19+
"keyMaterial": {
20+
"$binary": {
21+
"base64": "Ce9HSz/HKKGkIt4uyy+jDuKGA+rLC2cycykMo6vc8jXxqa1UVDYHWq1r+vZKbnnSRBfB981akzRKZCFpC05CTyFqDhXv6OnMjpG97OZEREGIsHEYiJkBW0jJJvfLLgeLsEpBzsro9FztGGXASxyxFRZFhXvHxyiLOKrdWfs7X1O/iK3pEoHMx6uSNSfUOgbebLfIqW7TO++iQS5g1xovXA==",
22+
"subType": "00"
23+
}
24+
},
25+
"creationDate": {
26+
"$date": {
27+
"$numberLong": "1557827033449"
28+
}
29+
},
30+
"keyAltNames": [ "local" ]
31+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
{
2+
"properties": {
3+
"encrypted": {
4+
"encrypt": {
5+
"keyId": [
6+
{
7+
"$binary": {
8+
"base64": "LOCALAAAAAAAAAAAAAAAAA==",
9+
"subType": "04"
10+
}
11+
}
12+
],
13+
"bsonType": "string",
14+
"algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic"
15+
}
16+
}
17+
},
18+
"bsonType": "object"
19+
}

0 commit comments

Comments
 (0)