diff --git a/persistence-modules/spring-boot-persistence-mongodb-3/pom.xml b/persistence-modules/spring-boot-persistence-mongodb-3/pom.xml
index b9a47aa703..484e0c0f7e 100644
--- a/persistence-modules/spring-boot-persistence-mongodb-3/pom.xml
+++ b/persistence-modules/spring-boot-persistence-mongodb-3/pom.xml
@@ -16,6 +16,21 @@
+
+ org.mongodb
+ mongodb-driver-sync
+ ${mongodb-driver.version}
+
+
+ org.mongodb
+ mongodb-driver-core
+ ${mongodb-driver.version}
+
+
+ org.mongodb
+ bson
+ ${mongodb-driver.version}
+
org.springframework.boot
spring-boot-starter-web
@@ -23,6 +38,16 @@
org.springframework.boot
spring-boot-starter-data-mongodb
+
+
+ org.mongodb
+ mongodb-driver-sync
+
+
+ org.mongodb
+ mongodb-driver-core
+
+
org.mongodb
@@ -37,7 +62,8 @@
- 1.6.1
+ 1.7.3
+ 4.9.1
diff --git a/persistence-modules/spring-boot-persistence-mongodb-3/src/main/java/com/baeldung/boot/csfle/config/EncryptionConfig.java b/persistence-modules/spring-boot-persistence-mongodb-3/src/main/java/com/baeldung/boot/csfle/config/EncryptionConfig.java
index 0ff97eb6c1..1a74340057 100644
--- a/persistence-modules/spring-boot-persistence-mongodb-3/src/main/java/com/baeldung/boot/csfle/config/EncryptionConfig.java
+++ b/persistence-modules/spring-boot-persistence-mongodb-3/src/main/java/com/baeldung/boot/csfle/config/EncryptionConfig.java
@@ -1,5 +1,7 @@
package com.baeldung.boot.csfle.config;
+import java.io.File;
+
import org.bson.BsonBinary;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
@@ -17,7 +19,13 @@ public class EncryptionConfig {
private String keyVaultAlias;
@Value("${com.baeldung.csfle.auto-decryption:false}")
- private Boolean autoDecryption;
+ private boolean autoDecryption;
+
+ @Value("${com.baeldung.csfle.auto-encryption:false}")
+ private boolean autoEncryption;
+
+ @Value("${com.baeldung.csfle.auto-encryption-lib:#{null}}")
+ private File autoEncryptionLib;
private BsonBinary dataKeyId;
@@ -41,7 +49,23 @@ public class EncryptionConfig {
return masterKeyPath;
}
- public Boolean getAutoDecryption() {
+ public boolean isAutoDecryption() {
return autoDecryption;
}
+
+ public boolean isAutoEncryption() {
+ return autoEncryption;
+ }
+
+ public File getAutoEncryptionLib() {
+ return autoEncryptionLib;
+ }
+
+ public String dataKeyIdUuid() {
+ if (dataKeyId == null)
+ throw new IllegalStateException("data key not initialized");
+
+ return dataKeyId.asUuid()
+ .toString();
+ }
}
diff --git a/persistence-modules/spring-boot-persistence-mongodb-3/src/main/java/com/baeldung/boot/csfle/config/MongoClientConfig.java b/persistence-modules/spring-boot-persistence-mongodb-3/src/main/java/com/baeldung/boot/csfle/config/MongoClientConfig.java
index 0dff1ec86d..19d0af08b2 100644
--- a/persistence-modules/spring-boot-persistence-mongodb-3/src/main/java/com/baeldung/boot/csfle/config/MongoClientConfig.java
+++ b/persistence-modules/spring-boot-persistence-mongodb-3/src/main/java/com/baeldung/boot/csfle/config/MongoClientConfig.java
@@ -1,14 +1,15 @@
package com.baeldung.boot.csfle.config;
+import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Arrays;
+import java.util.HashMap;
import java.util.Map;
import org.bson.BsonBinary;
import org.bson.BsonDocument;
import org.bson.Document;
-import org.bson.conversions.Bson;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
@@ -51,14 +52,10 @@ public class MongoClientConfig extends AbstractMongoClientConfiguration {
@Bean
@Override
public MongoClient mongoClient() {
- MongoClient client;
try {
- client = MongoClients.create(clientSettings());
-
ClientEncryption encryption = clientEncryption();
- encryptionConfig.setDataKeyId(createOrRetrieveDataKey(client, encryption));
-
- return client;
+ encryptionConfig.setDataKeyId(createOrRetrieveDataKey(encryption));
+ return MongoClients.create(clientSettings());
} catch (IOException e) {
throw new IllegalStateException("unable to create client", e);
}
@@ -77,19 +74,10 @@ public class MongoClientConfig extends AbstractMongoClientConfiguration {
return ClientEncryptions.create(encryptionSettings);
}
- private BsonBinary createOrRetrieveDataKey(MongoClient client, ClientEncryption encryption) {
- MongoNamespace namespace = new MongoNamespace(encryptionConfig.getKeyVaultNamespace());
- MongoCollection keyVault = client.getDatabase(namespace.getDatabaseName())
- .getCollection(namespace.getCollectionName());
-
- Bson query = Filters.in("keyAltNames", encryptionConfig.getKeyVaultAlias());
- BsonDocument key = keyVault.withDocumentClass(BsonDocument.class)
- .find(query)
- .first();
-
+ private BsonBinary createOrRetrieveDataKey(ClientEncryption encryption) {
+ BsonDocument key = encryption.getKeyByAltName(encryptionConfig.getKeyVaultAlias());
if (key == null) {
- keyVault.createIndex(Indexes.ascending("keyAltNames"), new IndexOptions().unique(true)
- .partialFilterExpression(Filters.exists("keyAltNames")));
+ createKeyUniqueIndex();
DataKeyOptions options = new DataKeyOptions();
options.keyAltNames(Arrays.asList(encryptionConfig.getKeyVaultAlias()));
@@ -99,16 +87,68 @@ public class MongoClientConfig extends AbstractMongoClientConfiguration {
}
}
+ private void createKeyUniqueIndex() {
+ try (MongoClient client = MongoClients.create(MongoClientSettings.builder()
+ .applyConnectionString(new ConnectionString(uri))
+ .build())) {
+ MongoNamespace namespace = new MongoNamespace(encryptionConfig.getKeyVaultNamespace());
+ MongoCollection keyVault = client.getDatabase(namespace.getDatabaseName())
+ .getCollection(namespace.getCollectionName());
+
+ keyVault.createIndex(Indexes.ascending("keyAltNames"), new IndexOptions().unique(true)
+ .partialFilterExpression(Filters.exists("keyAltNames")));
+ }
+ }
+
private MongoClientSettings clientSettings() throws FileNotFoundException, IOException {
Builder settings = MongoClientSettings.builder()
.applyConnectionString(new ConnectionString(uri));
- if (encryptionConfig.getAutoDecryption()) {
- settings.autoEncryptionSettings(AutoEncryptionSettings.builder()
+ if (encryptionConfig.isAutoDecryption()) {
+ AutoEncryptionSettings.Builder builder = AutoEncryptionSettings.builder()
.keyVaultNamespace(encryptionConfig.getKeyVaultNamespace())
- .kmsProviders(LocalKmsUtils.providersMap(encryptionConfig.getMasterKeyPath()))
- .bypassAutoEncryption(true)
- .build());
+ .kmsProviders(LocalKmsUtils.providersMap(encryptionConfig.getMasterKeyPath()));
+
+ if (encryptionConfig.isAutoEncryption() && encryptionConfig.getDataKeyId() != null) {
+ File autoEncryptionLib = encryptionConfig.getAutoEncryptionLib();
+ if (!autoEncryptionLib.isFile()) {
+ throw new IllegalArgumentException("encryption lib must be an existing file");
+ }
+
+ Map map = new HashMap<>();
+ map.put("cryptSharedLibRequired", true);
+ map.put("cryptSharedLibPath", autoEncryptionLib.toString());
+ builder.extraOptions(map);
+
+ String keyUuid = encryptionConfig.dataKeyIdUuid();
+ HashMap schemaMap = new HashMap<>();
+ schemaMap.put(getDatabaseName() + ".citizens",
+ BsonDocument.parse("{"
+ + " bsonType: \"object\","
+ + " encryptMetadata: {"
+ + " keyId: [UUID(\"" + keyUuid + "\")]"
+ + " },"
+ + " properties: {"
+ + " email: {"
+ + " encrypt: {"
+ + " bsonType: \"string\","
+ + " algorithm: \"AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic\""
+ + " }"
+ + " },"
+ + " birthYear: {"
+ + " encrypt: {"
+ + " bsonType: \"int\","
+ + " algorithm: \"AEAD_AES_256_CBC_HMAC_SHA_512-Random\""
+ + " }"
+ + " }"
+ + " }"
+ + "}"));
+ builder.schemaMap(schemaMap);
+ } else {
+ builder.bypassAutoEncryption(true);
+ }
+
+ settings.autoEncryptionSettings(builder.build());
}
return settings.build();
diff --git a/persistence-modules/spring-boot-persistence-mongodb-3/src/main/java/com/baeldung/boot/csfle/service/CitizenService.java b/persistence-modules/spring-boot-persistence-mongodb-3/src/main/java/com/baeldung/boot/csfle/service/CitizenService.java
index 6b3c463d0d..c93b00f3f8 100644
--- a/persistence-modules/spring-boot-persistence-mongodb-3/src/main/java/com/baeldung/boot/csfle/service/CitizenService.java
+++ b/persistence-modules/spring-boot-persistence-mongodb-3/src/main/java/com/baeldung/boot/csfle/service/CitizenService.java
@@ -35,16 +35,20 @@ public class CitizenService {
@Autowired
private ClientEncryption clientEncryption;
- public EncryptedCitizen save(Citizen citizen) {
- EncryptedCitizen encryptedCitizen = new EncryptedCitizen(citizen);
- encryptedCitizen.setEmail(encrypt(citizen.getEmail(), DETERMINISTIC_ALGORITHM));
- encryptedCitizen.setBirthYear(encrypt(citizen.getBirthYear(), RANDOM_ALGORITHM));
+ public Object save(Citizen citizen) {
+ if (encryptionConfig.isAutoEncryption()) {
+ return mongo.save(citizen);
+ } else {
+ EncryptedCitizen encryptedCitizen = new EncryptedCitizen(citizen);
+ encryptedCitizen.setEmail(encrypt(citizen.getEmail(), DETERMINISTIC_ALGORITHM));
+ encryptedCitizen.setBirthYear(encrypt(citizen.getBirthYear(), RANDOM_ALGORITHM));
- return mongo.save(encryptedCitizen);
+ return mongo.save(encryptedCitizen);
+ }
}
public List findAll() {
- if (!encryptionConfig.getAutoDecryption()) {
+ if (!encryptionConfig.isAutoDecryption()) {
List allEncrypted = mongo.findAll(EncryptedCitizen.class);
return allEncrypted.stream()
@@ -56,13 +60,20 @@ public class CitizenService {
}
public Citizen findByEmail(String email) {
- Query byEmail = new Query(Criteria.where("email")
- .is(encrypt(email, DETERMINISTIC_ALGORITHM)));
- if (!encryptionConfig.getAutoDecryption()) {
+ Criteria emailCriteria = Criteria.where("email");
+ if (encryptionConfig.isAutoEncryption()) {
+ emailCriteria.is(email);
+ } else {
+ emailCriteria
+ .is(encrypt(email, DETERMINISTIC_ALGORITHM));
+ }
+
+ Query byEmail = new Query(emailCriteria);
+ if (encryptionConfig.isAutoDecryption()) {
+ return mongo.findOne(byEmail, Citizen.class);
+ } else {
EncryptedCitizen encryptedCitizen = mongo.findOne(byEmail, EncryptedCitizen.class);
return decrypt(encryptedCitizen);
- } else {
- return mongo.findOne(byEmail, Citizen.class);
}
}
diff --git a/persistence-modules/spring-boot-persistence-mongodb-3/src/main/java/com/baeldung/boot/csfle/web/CitizenController.java b/persistence-modules/spring-boot-persistence-mongodb-3/src/main/java/com/baeldung/boot/csfle/web/CitizenController.java
index d17435fb5e..7a2b2605cd 100644
--- a/persistence-modules/spring-boot-persistence-mongodb-3/src/main/java/com/baeldung/boot/csfle/web/CitizenController.java
+++ b/persistence-modules/spring-boot-persistence-mongodb-3/src/main/java/com/baeldung/boot/csfle/web/CitizenController.java
@@ -11,7 +11,6 @@ import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import com.baeldung.boot.csfle.data.Citizen;
-import com.baeldung.boot.csfle.data.EncryptedCitizen;
import com.baeldung.boot.csfle.service.CitizenService;
@RestController
@@ -32,7 +31,7 @@ public class CitizenController {
}
@PostMapping
- public EncryptedCitizen post(@RequestBody Citizen citizen) {
+ public Object post(@RequestBody Citizen citizen) {
return service.save(citizen);
}
}
diff --git a/persistence-modules/spring-boot-persistence-mongodb-3/src/test/java/com/baeldung/boot/csfle/CitizenServiceLiveTest.java b/persistence-modules/spring-boot-persistence-mongodb-3/src/test/java/com/baeldung/boot/csfle/CitizenServiceLiveTest.java
index 471cb2883a..d57da43751 100644
--- a/persistence-modules/spring-boot-persistence-mongodb-3/src/test/java/com/baeldung/boot/csfle/CitizenServiceLiveTest.java
+++ b/persistence-modules/spring-boot-persistence-mongodb-3/src/test/java/com/baeldung/boot/csfle/CitizenServiceLiveTest.java
@@ -38,10 +38,14 @@ public class CitizenServiceLiveTest {
citizen.setName("Foo");
citizen.setEmail("foo@citizen.com");
- Binary encryptedEmail = service.encrypt(citizen.getEmail(), CitizenService.DETERMINISTIC_ALGORITHM);
+ Object saved = service.save(citizen);
+ if (saved instanceof EncryptedCitizen) {
+ Binary encryptedEmail = service.encrypt(citizen.getEmail(), CitizenService.DETERMINISTIC_ALGORITHM);
- EncryptedCitizen saved = service.save(citizen);
- assertEquals(encryptedEmail, saved.getEmail());
+ assertEquals(encryptedEmail, ((EncryptedCitizen) saved).getEmail());
+ } else {
+ assertEquals(citizen.getEmail(), ((Citizen) saved).getEmail());
+ }
}
@Test
diff --git a/persistence-modules/spring-boot-persistence-mongodb-3/src/test/resources/embedded.properties b/persistence-modules/spring-boot-persistence-mongodb-3/src/test/resources/embedded.properties
index 5325354e55..cd1c1d43c7 100644
--- a/persistence-modules/spring-boot-persistence-mongodb-3/src/test/resources/embedded.properties
+++ b/persistence-modules/spring-boot-persistence-mongodb-3/src/test/resources/embedded.properties
@@ -1,10 +1,10 @@
spring.mongodb.embedded.version=4.4.9
-spring.data.mongodb.uri=changeit
-spring.data.mongodb.database=changeit
+#spring.data.mongodb.uri=changeit
+#spring.data.mongodb.database=changeit
com.baeldung.csfle.kms-provider=local
com.baeldung.csfle.key-vault.namespace=encryption._keyVault
com.baeldung.csfle.key-vault.alias=master.key
-com.baeldung.csfle.master-key-path=/tmp/master.key
+#com.baeldung.csfle.master-key-path=/tmp/master.key
com.baeldung.csfle.auto-decryption=false