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 1495822bc0..0ff97eb6c1 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 @@ -4,8 +4,6 @@ import org.bson.BsonBinary; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Configuration; -import com.mongodb.client.vault.ClientEncryption; - @Configuration public class EncryptionConfig { @@ -21,18 +19,8 @@ public class EncryptionConfig { @Value("${com.baeldung.csfle.auto-decryption:false}") private Boolean autoDecryption; - private ClientEncryption encryption; - private BsonBinary dataKeyId; - public void setEncryption(ClientEncryption encryption) { - this.encryption = encryption; - } - - public ClientEncryption getEncryption() { - return encryption; - } - public void setDataKeyId(BsonBinary dataKeyId) { this.dataKeyId = dataKeyId; } 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 29076f4e61..e63034a5b5 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 @@ -11,12 +11,12 @@ 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; import org.springframework.context.annotation.Configuration; import org.springframework.data.mongodb.config.AbstractMongoClientConfiguration; import org.springframework.data.mongodb.core.convert.MongoCustomConversions; -import com.baeldung.boot.csfle.config.converter.IntegerConverter; -import com.baeldung.boot.csfle.config.converter.StringConverter; +import com.baeldung.boot.csfle.config.converter.BinaryConverter; import com.mongodb.AutoEncryptionSettings; import com.mongodb.ClientEncryptionSettings; import com.mongodb.ConnectionString; @@ -52,16 +52,17 @@ public class MongoClientConfig extends AbstractMongoClientConfiguration { @Override public MongoCustomConversions customConversions() { - return new MongoCustomConversions(Arrays.asList(new StringConverter(encryptionConfig), new IntegerConverter(encryptionConfig))); + return new MongoCustomConversions(Arrays.asList(new BinaryConverter())); } + @Bean @Override public MongoClient mongoClient() { MongoClient client; try { client = MongoClients.create(clientSettings()); - ClientEncryption encryption = createClientEncryption(); + ClientEncryption encryption = clientEncryption(); encryptionConfig.setDataKeyId(createOrRetrieveDataKey(client, encryption)); return client; @@ -70,6 +71,19 @@ public class MongoClientConfig extends AbstractMongoClientConfiguration { } } + @Bean + public ClientEncryption clientEncryption() throws FileNotFoundException, IOException { + Map> kmsProviders = LocalKmsUtils.providersMap(encryptionConfig.getMasterKeyPath()); + + ClientEncryptionSettings encryptionSettings = ClientEncryptionSettings.builder() + .keyVaultMongoClientSettings(clientSettings()) + .keyVaultNamespace(encryptionConfig.getKeyVaultNamespace()) + .kmsProviders(kmsProviders) + .build(); + + return ClientEncryptions.create(encryptionSettings); + } + private BsonBinary createOrRetrieveDataKey(MongoClient client, ClientEncryption encryption) { MongoNamespace namespace = new MongoNamespace(encryptionConfig.getKeyVaultNamespace()); MongoCollection keyVault = client.getDatabase(namespace.getDatabaseName()) @@ -92,19 +106,6 @@ public class MongoClientConfig extends AbstractMongoClientConfiguration { } } - private ClientEncryption createClientEncryption() throws FileNotFoundException, IOException { - Map> kmsProviders = LocalKmsUtils.providersMap(encryptionConfig.getMasterKeyPath()); - - ClientEncryptionSettings encryptionSettings = ClientEncryptionSettings.builder() - .keyVaultMongoClientSettings(clientSettings()) - .keyVaultNamespace(encryptionConfig.getKeyVaultNamespace()) - .kmsProviders(kmsProviders) - .build(); - - encryptionConfig.setEncryption(ClientEncryptions.create(encryptionSettings)); - return encryptionConfig.getEncryption(); - } - private MongoClientSettings clientSettings() throws FileNotFoundException, IOException { Builder settings = MongoClientSettings.builder() .applyConnectionString(new ConnectionString(uri)); diff --git a/persistence-modules/spring-boot-persistence-mongodb-3/src/main/java/com/baeldung/boot/csfle/config/converter/BinaryConverter.java b/persistence-modules/spring-boot-persistence-mongodb-3/src/main/java/com/baeldung/boot/csfle/config/converter/BinaryConverter.java new file mode 100644 index 0000000000..15231551fc --- /dev/null +++ b/persistence-modules/spring-boot-persistence-mongodb-3/src/main/java/com/baeldung/boot/csfle/config/converter/BinaryConverter.java @@ -0,0 +1,13 @@ +package com.baeldung.boot.csfle.config.converter; + +import org.bson.BsonBinary; +import org.bson.types.Binary; +import org.springframework.core.convert.converter.Converter; + +public class BinaryConverter implements Converter { + + @Override + public BsonBinary convert(Binary source) { + return new BsonBinary(source.getType(), source.getData()); + } +} diff --git a/persistence-modules/spring-boot-persistence-mongodb-3/src/main/java/com/baeldung/boot/csfle/config/converter/IntegerConverter.java b/persistence-modules/spring-boot-persistence-mongodb-3/src/main/java/com/baeldung/boot/csfle/config/converter/IntegerConverter.java deleted file mode 100644 index 020513ebff..0000000000 --- a/persistence-modules/spring-boot-persistence-mongodb-3/src/main/java/com/baeldung/boot/csfle/config/converter/IntegerConverter.java +++ /dev/null @@ -1,27 +0,0 @@ -package com.baeldung.boot.csfle.config.converter; - -import org.bson.BsonBinary; -import org.bson.BsonValue; -import org.bson.types.Binary; -import org.springframework.core.convert.converter.Converter; - -import com.baeldung.boot.csfle.config.EncryptionConfig; - -public class IntegerConverter implements Converter { - - private EncryptionConfig encryptionConfig; - - public IntegerConverter(EncryptionConfig config) { - this.encryptionConfig = config; - } - - @Override - public Integer convert(Binary source) { - BsonBinary bin = new BsonBinary(source.getType(), source.getData()); - BsonValue value = encryptionConfig.getEncryption() - .decrypt(bin); - - return value.asInt32() - .getValue(); - } -} diff --git a/persistence-modules/spring-boot-persistence-mongodb-3/src/main/java/com/baeldung/boot/csfle/config/converter/StringConverter.java b/persistence-modules/spring-boot-persistence-mongodb-3/src/main/java/com/baeldung/boot/csfle/config/converter/StringConverter.java deleted file mode 100644 index 7f8193ce43..0000000000 --- a/persistence-modules/spring-boot-persistence-mongodb-3/src/main/java/com/baeldung/boot/csfle/config/converter/StringConverter.java +++ /dev/null @@ -1,27 +0,0 @@ -package com.baeldung.boot.csfle.config.converter; - -import org.bson.BsonBinary; -import org.bson.BsonValue; -import org.bson.types.Binary; -import org.springframework.core.convert.converter.Converter; - -import com.baeldung.boot.csfle.config.EncryptionConfig; - -public class StringConverter implements Converter { - - private EncryptionConfig encryptionConfig; - - public StringConverter(EncryptionConfig config) { - this.encryptionConfig = config; - } - - @Override - public String convert(Binary source) { - BsonBinary bin = new BsonBinary(source.getType(), source.getData()); - BsonValue value = encryptionConfig.getEncryption() - .decrypt(bin); - - return value.asString() - .getValue(); - } -} 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 9cc0753289..91b5940b25 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 @@ -1,6 +1,7 @@ package com.baeldung.boot.csfle.service; import java.util.List; +import java.util.stream.Collectors; import org.bson.BsonBinary; import org.bson.BsonInt32; @@ -16,6 +17,7 @@ import com.baeldung.boot.csfle.config.EncryptionConfig; import com.baeldung.boot.csfle.data.Citizen; import com.baeldung.boot.csfle.data.EncryptedCitizen; import com.mongodb.client.model.vault.EncryptOptions; +import com.mongodb.client.vault.ClientEncryption; @Service public class CitizenService { @@ -29,6 +31,9 @@ public class CitizenService { @Autowired private EncryptionConfig encryptionConfig; + @Autowired + private ClientEncryption clientEncryption; + public EncryptedCitizen save(Citizen citizen) { EncryptedCitizen encryptedCitizen = new EncryptedCitizen(citizen); encryptedCitizen.setEmail(encrypt(citizen.getEmail(), DETERMINISTIC_ALGORITHM)); @@ -38,26 +43,68 @@ public class CitizenService { } public List findAll() { - return mongo.findAll(Citizen.class); + if (!encryptionConfig.getAutoDecryption()) { + List allEncrypted = mongo.findAll(EncryptedCitizen.class); + + return allEncrypted.stream() + .map(this::decrypt) + .collect(Collectors.toList()); + } else { + return mongo.findAll(Citizen.class); + } } public Citizen findByEmail(String email) { Query byEmail = new Query(Criteria.where("email") .is(encrypt(email, DETERMINISTIC_ALGORITHM))); - return mongo.findOne(byEmail, Citizen.class); + if (!encryptionConfig.getAutoDecryption()) { + EncryptedCitizen encryptedCitizen = mongo.findOne(byEmail, EncryptedCitizen.class); + return decrypt(encryptedCitizen); + } else { + return mongo.findOne(byEmail, Citizen.class); + } } public BsonBinary encrypt(Object value, String algorithm) { if (value == null) return null; - BsonValue bsonValue = value instanceof Integer - ? new BsonInt32((Integer) value) - : new BsonString(value.toString()); + BsonValue bsonValue; + if (value instanceof Integer) { + bsonValue = new BsonInt32((Integer) value); + } else if (value instanceof String) { + bsonValue = new BsonString((String) value); + } else { + throw new IllegalArgumentException("unsupported type: " + value.getClass()); + } EncryptOptions options = new EncryptOptions(algorithm); options.keyId(encryptionConfig.getDataKeyId()); - return encryptionConfig.getEncryption() - .encrypt(bsonValue, options); + return clientEncryption.encrypt(bsonValue, options); + } + + public BsonValue decryptProperty(BsonBinary value) { + if (value == null) + return null; + + return clientEncryption.decrypt(value); + } + + private Citizen decrypt(EncryptedCitizen encrypted) { + Citizen citizen = new Citizen(encrypted); + + BsonValue decryptedBirthYear = decryptProperty(encrypted.getBirthYear()); + if (decryptedBirthYear != null) { + citizen.setBirthYear(decryptedBirthYear.asInt32() + .intValue()); + } + + BsonValue decryptedEmail = decryptProperty(encrypted.getEmail()); + if (decryptedEmail != null) { + citizen.setEmail(decryptedEmail.asString() + .getValue()); + } + + return citizen; } }