From cd4cec735000fea3905484bd8e600968eabb51f8 Mon Sep 17 00:00:00 2001 From: Christoph Strobl Date: Wed, 19 Jun 2019 10:35:11 +0200 Subject: [PATCH 1/4] DATAMONGO-2306 - Prepare issue branch. --- pom.xml | 2 +- spring-data-mongodb-benchmarks/pom.xml | 2 +- spring-data-mongodb-distribution/pom.xml | 2 +- spring-data-mongodb/pom.xml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/pom.xml b/pom.xml index 4aacfba029..06d9d76578 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ org.springframework.data spring-data-mongodb-parent - 2.2.0.BUILD-SNAPSHOT + 2.2.0.DATAMONGO-2306-SNAPSHOT pom Spring Data MongoDB diff --git a/spring-data-mongodb-benchmarks/pom.xml b/spring-data-mongodb-benchmarks/pom.xml index bb7d9f03cc..9fc0ab77b4 100644 --- a/spring-data-mongodb-benchmarks/pom.xml +++ b/spring-data-mongodb-benchmarks/pom.xml @@ -7,7 +7,7 @@ org.springframework.data spring-data-mongodb-parent - 2.2.0.BUILD-SNAPSHOT + 2.2.0.DATAMONGO-2306-SNAPSHOT ../pom.xml diff --git a/spring-data-mongodb-distribution/pom.xml b/spring-data-mongodb-distribution/pom.xml index b32dcba387..63ed8736d0 100644 --- a/spring-data-mongodb-distribution/pom.xml +++ b/spring-data-mongodb-distribution/pom.xml @@ -14,7 +14,7 @@ org.springframework.data spring-data-mongodb-parent - 2.2.0.BUILD-SNAPSHOT + 2.2.0.DATAMONGO-2306-SNAPSHOT ../pom.xml diff --git a/spring-data-mongodb/pom.xml b/spring-data-mongodb/pom.xml index b611cf01a8..4af3ccf2d5 100644 --- a/spring-data-mongodb/pom.xml +++ b/spring-data-mongodb/pom.xml @@ -11,7 +11,7 @@ org.springframework.data spring-data-mongodb-parent - 2.2.0.BUILD-SNAPSHOT + 2.2.0.DATAMONGO-2306-SNAPSHOT ../pom.xml From 76332cdbb8f4836a68280de3c4d871e2de0a53af Mon Sep 17 00:00:00 2001 From: Christoph Strobl Date: Wed, 19 Jun 2019 14:16:39 +0200 Subject: [PATCH 2/4] DATAMONGO-2306 - Add field level encryption to JSON Schema. We now support encrypted fields via MongoJsonSchema and allow XML configuration of com.mongodb.AutoEncryptionSettings via a dedicated factory bean. --- .../core/MongoClientOptionsFactoryBean.java | 15 +- .../MongoEncryptionSettingsFactoryBean.java | 119 ++++++++++++++ .../IdentifiableJsonSchemaProperty.java | 145 ++++++++++++++++++ .../mongodb/core/schema/JsonSchemaObject.java | 42 +++++ .../core/schema/JsonSchemaProperty.java | 22 +-- .../data/mongodb/config/spring-mongo-2.2.xsd | 21 +++ ...ngoEncryptionSettingsFactoryBeanTests.java | 50 ++++++ .../core/schema/MongoJsonSchemaUnitTests.java | 16 ++ .../asciidoc/reference/mongo-json-schema.adoc | 22 +++ 9 files changed, 441 insertions(+), 11 deletions(-) create mode 100644 spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoEncryptionSettingsFactoryBean.java create mode 100644 spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/MongoEncryptionSettingsFactoryBeanTests.java diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoClientOptionsFactoryBean.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoClientOptionsFactoryBean.java index d3e169a180..249815ccf0 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoClientOptionsFactoryBean.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoClientOptionsFactoryBean.java @@ -22,6 +22,7 @@ import org.springframework.data.mongodb.MongoDbFactory; import org.springframework.lang.Nullable; +import com.mongodb.AutoEncryptionSettings; import com.mongodb.DBDecoderFactory; import com.mongodb.DBEncoderFactory; import com.mongodb.MongoClient; @@ -73,6 +74,7 @@ public class MongoClientOptionsFactoryBean extends AbstractFactoryBean { + + private boolean bypassAutoEncryption; + private String keyVaultNamespace; + private Map extraOptions; + private MongoClientSettings keyVaultClientSettings; + private Map> kmsProviders; + private Map schemaMap; + + /** + * @param bypassAutoEncryption + * @see AutoEncryptionSettings.Builder#bypassAutoEncryption(boolean) + */ + public void setBypassAutoEncryption(boolean bypassAutoEncryption) { + this.bypassAutoEncryption = bypassAutoEncryption; + } + + /** + * @param extraOptions + * @see AutoEncryptionSettings.Builder#extraOptions(Map) + */ + public void setExtraOptions(Map extraOptions) { + this.extraOptions = extraOptions; + } + + /** + * @param keyVaultNamespace + * @see AutoEncryptionSettings.Builder#keyVaultNamespace(String) + */ + public void setKeyVaultNamespace(String keyVaultNamespace) { + this.keyVaultNamespace = keyVaultNamespace; + } + + /** + * @param keyVaultClientSettings + * @see AutoEncryptionSettings.Builder#keyVaultMongoClientSettings(MongoClientSettings) + */ + public void setKeyVaultClientSettings(MongoClientSettings keyVaultClientSettings) { + this.keyVaultClientSettings = keyVaultClientSettings; + } + + /** + * @param kmsProviders + * @see AutoEncryptionSettings.Builder#kmsProviders(Map) + */ + public void setKmsProviders(Map> kmsProviders) { + this.kmsProviders = kmsProviders; + } + + /** + * @param schemaMap + * @see AutoEncryptionSettings.Builder#schemaMap(Map) + */ + public void setSchemaMap(Map schemaMap) { + this.schemaMap = schemaMap; + } + + /* + * (non-Javadoc) + * @see org.springframework.beans.factory.FactoryBean#getObject() + */ + @Override + public AutoEncryptionSettings getObject() { + + return AutoEncryptionSettings.builder() // + .bypassAutoEncryption(bypassAutoEncryption) // + .keyVaultNamespace(keyVaultNamespace) // + .keyVaultMongoClientSettings(keyVaultClientSettings) // + .kmsProviders(orEmpty(kmsProviders)) // + .extraOptions(orEmpty(extraOptions)) // + .schemaMap(orEmpty(schemaMap)) // + .build(); + } + + private Map orEmpty(Map source) { + return source != null ? source : Collections.emptyMap(); + } + + /* + * (non-Javadoc) + * @see org.springframework.beans.factory.FactoryBean#getObjectType() + */ + @Override + public Class getObjectType() { + return AutoEncryptionSettings.class; + } +} diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/schema/IdentifiableJsonSchemaProperty.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/schema/IdentifiableJsonSchemaProperty.java index bf2e801865..1a097f4abf 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/schema/IdentifiableJsonSchemaProperty.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/schema/IdentifiableJsonSchemaProperty.java @@ -30,7 +30,9 @@ import org.springframework.data.mongodb.core.schema.TypedJsonSchemaObject.ObjectJsonSchemaObject; import org.springframework.data.mongodb.core.schema.TypedJsonSchemaObject.StringJsonSchemaObject; import org.springframework.data.mongodb.core.schema.TypedJsonSchemaObject.TimestampJsonSchemaObject; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; +import org.springframework.util.ObjectUtils; /** * {@link JsonSchemaProperty} implementation. @@ -1044,4 +1046,147 @@ public boolean isRequired() { return required; } } + + /** + * {@link JsonSchemaProperty} implementation for encrypted fields. + * + * @author Christoph Strobl + * @since 2.2 + */ + public static class EncryptedJsonSchemaProperty implements JsonSchemaProperty { + + private final JsonSchemaProperty targetProperty; + private final @Nullable String algorithm; + private final @Nullable char[] keyId; + private final @Nullable char[] iv; + + /** + * Create new instance of {@link EncryptedJsonSchemaProperty} wrapping the given {@link JsonSchemaProperty target}. + * + * @param target must not be {@literal null}. + */ + public EncryptedJsonSchemaProperty(JsonSchemaProperty target) { + this(target, null, null, null); + } + + private EncryptedJsonSchemaProperty(JsonSchemaProperty target, @Nullable String algorithm, @Nullable char[] keyId, + @Nullable char[] iv) { + + Assert.notNull(target, "Target must not be null!"); + this.targetProperty = target; + this.algorithm = algorithm; + this.keyId = keyId; + this.iv = iv; + } + + /** + * Create new instance of {@link EncryptedJsonSchemaProperty} wrapping the given {@link JsonSchemaProperty target}. + * + * @param target must not be {@literal null}. + * @return new instance of {@link EncryptedJsonSchemaProperty}. + */ + public static EncryptedJsonSchemaProperty encrypted(JsonSchemaProperty target) { + return new EncryptedJsonSchemaProperty(target); + } + + /** + * Use {@literal AEAD_AES_256_CBC_HMAC_SHA_512-Random} algorithm. + * + * @return new instance of {@link EncryptedJsonSchemaProperty}. + */ + public EncryptedJsonSchemaProperty aead_aes_256_cbc_hmac_sha_512_random() { + return algorithm("AEAD_AES_256_CBC_HMAC_SHA_512-Random"); + } + + /** + * Use {@literal AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic} algorithm. + * + * @return new instance of {@link EncryptedJsonSchemaProperty}. + */ + public EncryptedJsonSchemaProperty aead_aes_256_cbc_hmac_sha_512_deterministic() { + return algorithm("AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic"); + } + + /** + * Use the given algorithm identified via its name. + * + * @return new instance of {@link EncryptedJsonSchemaProperty}. + */ + public EncryptedJsonSchemaProperty algorithm(String algorithm) { + return new EncryptedJsonSchemaProperty(targetProperty, algorithm, keyId, iv); + } + + /** + * @param key + * @return + */ + public EncryptedJsonSchemaProperty keyId(char[] key) { + return new EncryptedJsonSchemaProperty(targetProperty, algorithm, key, iv); + } + + public EncryptedJsonSchemaProperty keyId(String key) { + return keyId(key.toCharArray()); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.mongodb.core.schema.JsonSchemaObject#toDocument() + */ + @Override + public Document toDocument() { + + Document doc = targetProperty.toDocument(); + Document propertySpecification = doc.get(targetProperty.getIdentifier(), Document.class); + + Document enc = new Document(); + + if (!ObjectUtils.isEmpty(keyId)) { + enc.append("keyId", new String(keyId)); + } + + Type type = extractPropertyType(propertySpecification); + if (type != null) { + + propertySpecification.remove(type.representation()); + enc.append("bsonType", type.toBsonType().value()); // TODO: no samples with type -> is it bson type all the way? + } + + enc.append("algorithm", algorithm); + + propertySpecification.append("encrypt", enc); + + return doc; + } + + /* + * (non-Javadoc) + * @see org.springframework.data.mongodb.core.schema.JsonSchemaProperty#getIdentifier() + */ + @Override + public String getIdentifier() { + return targetProperty.getIdentifier(); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.mongodb.core.schema.JsonSchemaObject#getTypes() + */ + @Override + public Set getTypes() { + return targetProperty.getTypes(); + } + + @Nullable + private Type extractPropertyType(Document source) { + + if (source.containsKey("type")) { + return Type.of(source.get("type", String.class)); + } + if (source.containsKey("bsonType")) { + return Type.of(source.get("bsonType", String.class)); + } + + return null; + } + } } diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/schema/JsonSchemaObject.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/schema/JsonSchemaObject.java index 375845ada8..5f0421272c 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/schema/JsonSchemaObject.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/schema/JsonSchemaObject.java @@ -15,6 +15,7 @@ */ package org.springframework.data.mongodb.core.schema; +import lombok.EqualsAndHashCode; import lombok.RequiredArgsConstructor; import java.math.BigDecimal; @@ -428,6 +429,23 @@ static Type jsonTypeOf(String name) { return new JsonType(name); } + /** + * Create a {@link Type} with its default {@link Type#representation() representation} via the name. + * + * @param name must not be {@literal null}. + * @return the matching type instance. + * @since 2.2 + */ + static Type of(String name) { + + Type type = jsonTypeOf(name); + if (jsonTypes().contains(type)) { + return type; + } + + return bsonTypeOf(name); + } + /** * @return all known JSON types. */ @@ -456,11 +474,34 @@ static Set bsonTypes() { */ Object value(); + /** + * Get the {@literal bsonType} representation of the given type. + * + * @return never {@literal null}. + * @since 2.2 + */ + default Type toBsonType() { + + if (representation().equals("bsonType")) { + return this; + } + + if (value().equals(Type.booleanType().value())) { + return bsonTypeOf("bool"); + } + if (value().equals(Type.numberType().value())) { + return bsonTypeOf("long"); + } + + return bsonTypeOf((String) value()); + } + /** * @author Christpoh Strobl * @since 2.1 */ @RequiredArgsConstructor + @EqualsAndHashCode class JsonType implements Type { private final String name; @@ -489,6 +530,7 @@ public String value() { * @since 2.1 */ @RequiredArgsConstructor + @EqualsAndHashCode class BsonType implements Type { private final String name; diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/schema/JsonSchemaProperty.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/schema/JsonSchemaProperty.java index 36a44eb3f8..3bd149c53a 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/schema/JsonSchemaProperty.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/schema/JsonSchemaProperty.java @@ -18,18 +18,9 @@ import lombok.AccessLevel; import lombok.RequiredArgsConstructor; -import org.springframework.data.mongodb.core.schema.IdentifiableJsonSchemaProperty.ArrayJsonSchemaProperty; -import org.springframework.data.mongodb.core.schema.IdentifiableJsonSchemaProperty.BooleanJsonSchemaProperty; -import org.springframework.data.mongodb.core.schema.IdentifiableJsonSchemaProperty.DateJsonSchemaProperty; -import org.springframework.data.mongodb.core.schema.IdentifiableJsonSchemaProperty.NullJsonSchemaProperty; -import org.springframework.data.mongodb.core.schema.IdentifiableJsonSchemaProperty.NumericJsonSchemaProperty; -import org.springframework.data.mongodb.core.schema.IdentifiableJsonSchemaProperty.ObjectJsonSchemaProperty; -import org.springframework.data.mongodb.core.schema.IdentifiableJsonSchemaProperty.RequiredJsonSchemaProperty; -import org.springframework.data.mongodb.core.schema.IdentifiableJsonSchemaProperty.StringJsonSchemaProperty; -import org.springframework.data.mongodb.core.schema.IdentifiableJsonSchemaProperty.TimestampJsonSchemaProperty; -import org.springframework.data.mongodb.core.schema.IdentifiableJsonSchemaProperty.UntypedJsonSchemaProperty; import org.springframework.data.mongodb.core.schema.TypedJsonSchemaObject.NumericJsonSchemaObject; import org.springframework.data.mongodb.core.schema.TypedJsonSchemaObject.ObjectJsonSchemaObject; +import org.springframework.data.mongodb.core.schema.IdentifiableJsonSchemaProperty.*; import org.springframework.lang.Nullable; /** @@ -68,6 +59,17 @@ static UntypedJsonSchemaProperty untyped(String identifier) { return new UntypedJsonSchemaProperty(identifier, JsonSchemaObject.untyped()); } + /** + * Turns the given target property into an {@link EncryptedJsonSchemaProperty ecrypted} one. + * + * @param property must not be {@literal null}. + * @return new instance of {@link EncryptedJsonSchemaProperty}. + * @since 2.2 + */ + static EncryptedJsonSchemaProperty encrypted(JsonSchemaProperty property) { + return EncryptedJsonSchemaProperty.encrypted(property); + } + /** * Creates a new {@link StringJsonSchemaProperty} with given {@literal identifier} of {@code type : 'string'}. * diff --git a/spring-data-mongodb/src/main/resources/org/springframework/data/mongodb/config/spring-mongo-2.2.xsd b/spring-data-mongodb/src/main/resources/org/springframework/data/mongodb/config/spring-mongo-2.2.xsd index 3b27d2a2fa..bc1c52091a 100644 --- a/spring-data-mongodb/src/main/resources/org/springframework/data/mongodb/config/spring-mongo-2.2.xsd +++ b/spring-data-mongodb/src/main/resources/org/springframework/data/mongodb/config/spring-mongo-2.2.xsd @@ -311,6 +311,20 @@ The name of the MongoClient object that determines what server to monitor. (by d + + + + + + + + + + + + @@ -546,6 +560,13 @@ The SSLSocketFactory to use for the SSL connection. If none is configured here, ]]> + + + + + diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/MongoEncryptionSettingsFactoryBeanTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/MongoEncryptionSettingsFactoryBeanTests.java new file mode 100644 index 0000000000..c701e7e058 --- /dev/null +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/MongoEncryptionSettingsFactoryBeanTests.java @@ -0,0 +1,50 @@ +/* + * Copyright 2019 the original author or authors. + * + * 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 + * + * https://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 org.springframework.data.mongodb.core; + +import static org.assertj.core.api.Assertions.*; + +import org.junit.Test; +import org.springframework.beans.factory.support.DefaultListableBeanFactory; +import org.springframework.beans.factory.support.RootBeanDefinition; +import org.springframework.test.util.ReflectionTestUtils; + +import com.mongodb.AutoEncryptionSettings; + +/** + * Integration tests for {@link MongoEncryptionSettingsFactoryBean}. + * + * @author Christoph Strobl + */ +public class MongoEncryptionSettingsFactoryBeanTests { + + @Test // DATAMONGO-2306 + public void createsAutoEncryptionSettings() { + + RootBeanDefinition definition = new RootBeanDefinition(MongoEncryptionSettingsFactoryBean.class); + definition.getPropertyValues().addPropertyValue("bypassAutoEncryption", true); + definition.getPropertyValues().addPropertyValue("keyVaultNamespace", "ns"); + + DefaultListableBeanFactory factory = new DefaultListableBeanFactory(); + factory.registerBeanDefinition("factory", definition); + + MongoEncryptionSettingsFactoryBean bean = factory.getBean("&factory", MongoEncryptionSettingsFactoryBean.class); + assertThat(ReflectionTestUtils.getField(bean, "bypassAutoEncryption")).isEqualTo(true); + + AutoEncryptionSettings target = factory.getBean(AutoEncryptionSettings.class); + assertThat(target.getKeyVaultNamespace()).isEqualTo("ns"); + } +} diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/schema/MongoJsonSchemaUnitTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/schema/MongoJsonSchemaUnitTests.java index edc2c6f4fd..aa85b01a6c 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/schema/MongoJsonSchemaUnitTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/schema/MongoJsonSchemaUnitTests.java @@ -15,6 +15,7 @@ */ package org.springframework.data.mongodb.core.schema; +import static org.springframework.data.mongodb.core.schema.JsonSchemaProperty.*; import static org.springframework.data.mongodb.test.util.Assertions.*; import java.util.Arrays; @@ -71,6 +72,21 @@ public void rendersRequiredPropertiesCorrectly() { new Document("lastname", new Document("type", "string"))))); } + @Test // DATAMONGO-2306 + public void rendersEncryptedPropertyCorrectly() { + + MongoJsonSchema schema = MongoJsonSchema.builder().properties( // + encrypted(string("ssn")) // + .aead_aes_256_cbc_hmac_sha_512_deterministic() // + .keyId("*key0_id") // + ).build(); + + assertThat(schema.toDocument()).isEqualTo(new Document("$jsonSchema", + new Document("type", "object").append("properties", + new Document("ssn", new Document("encrypt", new Document("keyId", "*key0_id") + .append("algorithm", "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic").append("bsonType", "string")))))); + } + @Test(expected = IllegalArgumentException.class) // DATAMONGO-1835 public void throwsExceptionOnNullRoot() { MongoJsonSchema.of((JsonSchemaObject) null); diff --git a/src/main/asciidoc/reference/mongo-json-schema.adoc b/src/main/asciidoc/reference/mongo-json-schema.adoc index 2f1bcf840a..e4e7f05c53 100644 --- a/src/main/asciidoc/reference/mongo-json-schema.adoc +++ b/src/main/asciidoc/reference/mongo-json-schema.adoc @@ -205,6 +205,28 @@ template.find(query(matchingDocumentStructure(schema)), Person.class); ---- ==== +[[mongo.jsonSchema.encrypted-fields]] +==== Encrypted Fields + +MongoDB 4.2 https://docs.mongodb.com/master/core/security-client-side-encryption/[Field Level Encryption] allows to directly secure certain properties. + +Properties can be wrapped within an encrypted property when setting up the JSON Schema as shown in the example below. + +.Client-Side Field Level Encryption via Json Schema +==== +[source,java] +---- +MongoJsonSchema schema = MongoJsonSchema.builder() + .properties( + encrypted(string("ssn")) + .algorithm("AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic") + .keyId("*key0_id") + ).build(); +---- +==== + +NOTE: Make sure to set the drivers `com.mongodb.AutoEncryptionSettings` to use client side encryption. + [[mongo.jsonSchema.types]] ==== JSON Schema Types From 665aff47e2414eb20c6e9b0d6c52cb08a031fcff Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Mon, 1 Jul 2019 14:18:04 +0200 Subject: [PATCH 3/4] DATAMONGO-2306 - Polishing. Add Nullable annotation to nullable method args. Remove IV from JSON Schema as it is not listed in Mongo specs. Tweak wording in docs. --- .../MongoEncryptionSettingsFactoryBean.java | 3 ++- .../IdentifiableJsonSchemaProperty.java | 21 +++++++------------ .../asciidoc/reference/mongo-json-schema.adoc | 4 ++-- 3 files changed, 11 insertions(+), 17 deletions(-) diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoEncryptionSettingsFactoryBean.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoEncryptionSettingsFactoryBean.java index 65cd689c06..f09759039b 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoEncryptionSettingsFactoryBean.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoEncryptionSettingsFactoryBean.java @@ -20,6 +20,7 @@ import org.bson.BsonDocument; import org.springframework.beans.factory.FactoryBean; +import org.springframework.lang.Nullable; import com.mongodb.AutoEncryptionSettings; import com.mongodb.MongoClientSettings; @@ -104,7 +105,7 @@ public AutoEncryptionSettings getObject() { .build(); } - private Map orEmpty(Map source) { + private Map orEmpty(@Nullable Map source) { return source != null ? source : Collections.emptyMap(); } diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/schema/IdentifiableJsonSchemaProperty.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/schema/IdentifiableJsonSchemaProperty.java index 1a097f4abf..0057d7d06b 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/schema/IdentifiableJsonSchemaProperty.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/schema/IdentifiableJsonSchemaProperty.java @@ -1057,8 +1057,7 @@ public static class EncryptedJsonSchemaProperty implements JsonSchemaProperty { private final JsonSchemaProperty targetProperty; private final @Nullable String algorithm; - private final @Nullable char[] keyId; - private final @Nullable char[] iv; + private final @Nullable String keyId; /** * Create new instance of {@link EncryptedJsonSchemaProperty} wrapping the given {@link JsonSchemaProperty target}. @@ -1066,17 +1065,15 @@ public static class EncryptedJsonSchemaProperty implements JsonSchemaProperty { * @param target must not be {@literal null}. */ public EncryptedJsonSchemaProperty(JsonSchemaProperty target) { - this(target, null, null, null); + this(target, null, null); } - private EncryptedJsonSchemaProperty(JsonSchemaProperty target, @Nullable String algorithm, @Nullable char[] keyId, - @Nullable char[] iv) { + private EncryptedJsonSchemaProperty(JsonSchemaProperty target, @Nullable String algorithm, @Nullable String keyId) { Assert.notNull(target, "Target must not be null!"); this.targetProperty = target; this.algorithm = algorithm; this.keyId = keyId; - this.iv = iv; } /** @@ -1113,19 +1110,15 @@ public EncryptedJsonSchemaProperty aead_aes_256_cbc_hmac_sha_512_deterministic() * @return new instance of {@link EncryptedJsonSchemaProperty}. */ public EncryptedJsonSchemaProperty algorithm(String algorithm) { - return new EncryptedJsonSchemaProperty(targetProperty, algorithm, keyId, iv); + return new EncryptedJsonSchemaProperty(targetProperty, algorithm, keyId); } /** * @param key * @return */ - public EncryptedJsonSchemaProperty keyId(char[] key) { - return new EncryptedJsonSchemaProperty(targetProperty, algorithm, key, iv); - } - - public EncryptedJsonSchemaProperty keyId(String key) { - return keyId(key.toCharArray()); + public EncryptedJsonSchemaProperty keyId(String keyId) { + return new EncryptedJsonSchemaProperty(targetProperty, algorithm, keyId); } /* @@ -1141,7 +1134,7 @@ public Document toDocument() { Document enc = new Document(); if (!ObjectUtils.isEmpty(keyId)) { - enc.append("keyId", new String(keyId)); + enc.append("keyId", keyId); } Type type = extractPropertyType(propertySpecification); diff --git a/src/main/asciidoc/reference/mongo-json-schema.adoc b/src/main/asciidoc/reference/mongo-json-schema.adoc index e4e7f05c53..50e5e430e0 100644 --- a/src/main/asciidoc/reference/mongo-json-schema.adoc +++ b/src/main/asciidoc/reference/mongo-json-schema.adoc @@ -208,7 +208,7 @@ template.find(query(matchingDocumentStructure(schema)), Person.class); [[mongo.jsonSchema.encrypted-fields]] ==== Encrypted Fields -MongoDB 4.2 https://docs.mongodb.com/master/core/security-client-side-encryption/[Field Level Encryption] allows to directly secure certain properties. +MongoDB 4.2 https://docs.mongodb.com/master/core/security-client-side-encryption/[Field Level Encryption] allows to directly encrypt individual properties. Properties can be wrapped within an encrypted property when setting up the JSON Schema as shown in the example below. @@ -225,7 +225,7 @@ MongoJsonSchema schema = MongoJsonSchema.builder() ---- ==== -NOTE: Make sure to set the drivers `com.mongodb.AutoEncryptionSettings` to use client side encryption. +NOTE: Make sure to set the drivers `com.mongodb.AutoEncryptionSettings` to use client-side encryption. [[mongo.jsonSchema.types]] ==== JSON Schema Types From 43c8c434d682e148f8708f93ec85251fc4c33e86 Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Mon, 1 Jul 2019 14:34:25 +0200 Subject: [PATCH 4/4] DATAMONGO-2306 - Parse encryption-settings-ref for MongoClientOptions. We now parse encryption-settings-ref as reference to AutoEncryptionSettings beans. Testing such a setup requires a proper crypto setup with external libraries. --- .../springframework/data/mongodb/config/MongoParsingUtils.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/MongoParsingUtils.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/MongoParsingUtils.java index 63a294f553..36c2544c48 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/MongoParsingUtils.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/MongoParsingUtils.java @@ -35,6 +35,7 @@ * @author Oliver Gierke * @author Thomas Darimont * @author Christoph Strobl + * @author Mark Paluch */ @SuppressWarnings("deprecation") abstract class MongoParsingUtils { @@ -92,6 +93,7 @@ public static boolean parseMongoClientOptions(Element element, BeanDefinitionBui setPropertyValue(clientOptionsDefBuilder, optionsElement, "heartbeat-socket-timeout", "heartbeatSocketTimeout"); setPropertyValue(clientOptionsDefBuilder, optionsElement, "ssl", "ssl"); setPropertyReference(clientOptionsDefBuilder, optionsElement, "ssl-socket-factory-ref", "sslSocketFactory"); + setPropertyReference(clientOptionsDefBuilder, optionsElement, "encryption-settings-ref", "autoEncryptionSettings"); setPropertyValue(clientOptionsDefBuilder, optionsElement, "server-selection-timeout", "serverSelectionTimeout"); mongoClientBuilder.addPropertyValue("mongoClientOptions", clientOptionsDefBuilder.getBeanDefinition());