Browse Source

Update documentation

feature/fle-derivation
Christoph Strobl 4 years ago
parent
commit
e8d0492520
  1. 36
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoJsonSchemaCreator.java
  2. 20
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/Encrypted.java
  3. 1
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/schema/MongoJsonSchema.java
  4. 104
      src/main/asciidoc/reference/mongo-json-schema.adoc

36
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoJsonSchemaCreator.java

@ -19,6 +19,7 @@ import java.util.HashSet; @@ -19,6 +19,7 @@ import java.util.HashSet;
import java.util.Set;
import java.util.function.Predicate;
import org.springframework.data.mapping.PersistentProperty;
import org.springframework.data.mapping.context.MappingContext;
import org.springframework.data.mongodb.core.convert.MappingMongoConverter;
import org.springframework.data.mongodb.core.convert.MongoConverter;
@ -29,6 +30,7 @@ import org.springframework.data.mongodb.core.mapping.MongoMappingContext; @@ -29,6 +30,7 @@ import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
import org.springframework.data.mongodb.core.mapping.MongoPersistentEntity;
import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty;
import org.springframework.data.mongodb.core.mapping.MongoSimpleTypes;
import org.springframework.data.mongodb.core.mapping.Unwrapped.Nullable;
import org.springframework.data.mongodb.core.schema.JsonSchemaProperty;
import org.springframework.data.mongodb.core.schema.MongoJsonSchema;
import org.springframework.util.Assert;
@ -60,6 +62,7 @@ import org.springframework.util.Assert; @@ -60,6 +62,7 @@ import org.springframework.util.Assert;
* {@link org.bson.types.ObjectId} like {@link String} will be mapped to {@code type : 'object'} unless there is more
* specific information available via the {@link org.springframework.data.mongodb.core.mapping.MongoId} annotation.
* </p>
* {@link Encrypted} properties will contain {@literal encrypt} information.
*
* @author Christoph Strobl
* @since 2.2
@ -83,21 +86,43 @@ public interface MongoJsonSchemaCreator { @@ -83,21 +86,43 @@ public interface MongoJsonSchemaCreator {
*/
MongoJsonSchemaCreator filter(Predicate<JsonSchemaPropertyContext> filter);
/**
* The context in which a specific {@link #getProperty()} is encountered during schema creation.
*
* @since 3.3
*/
interface JsonSchemaPropertyContext {
/**
* The path to a given field/property in dot notation.
*
* @return never {@literal null}.
*/
String getPath();
/**
* The current property.
*
* @return never {@literal null}.
*/
MongoPersistentProperty getProperty();
/**
* Obtain the {@link MongoPersistentEntity} for a given property.
*
* @param property must not be {@literal null}.
* @param <T>
* @return {@literal null} if the property is not an entity. It is nevertheless recommend to check
* {@link PersistentProperty#isEntity()} first.
*/
@Nullable
<T> MongoPersistentEntity<T> resolveEntity(MongoPersistentProperty property);
}
/**
* A filter {@link Predicate} that matches
* {@link org.springframework.data.mongodb.core.schema.IdentifiableJsonSchemaProperty.EncryptedJsonSchemaProperty
* encrypted properties} and those having nested ones.
*
* A filter {@link Predicate} that matches {@link Encrypted encrypted properties} and those having nested ones.
*
* @return new instance of {@link Predicate}.
* @since 3.3
*/
@ -105,7 +130,8 @@ public interface MongoJsonSchemaCreator { @@ -105,7 +130,8 @@ public interface MongoJsonSchemaCreator {
return new Predicate<JsonSchemaPropertyContext>() {
Set<MongoPersistentProperty> seen = new HashSet<>();
// cycle guard
private final Set<MongoPersistentProperty> seen = new HashSet<>();
@Override
public boolean test(JsonSchemaPropertyContext context) {

20
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/Encrypted.java

@ -27,6 +27,7 @@ import java.lang.annotation.Target; @@ -27,6 +27,7 @@ import java.lang.annotation.Target;
* {@literal encryptMetadata}.
*
* <pre class="code">
* &#64;Document
* &#64;Encrypted(keyId = "4fPYFM9qSgyRAjgQ2u+IMQ==")
* public class Patient {
* private ObjectId id;
@ -85,12 +86,27 @@ import java.lang.annotation.Target; @@ -85,12 +86,27 @@ import java.lang.annotation.Target;
public @interface Encrypted {
/**
* @return the key id to use. May contain a parsable {@link org.springframework.expression.Expression expression}.
* Get the {@code keyId} to use. The value must resolve to either the UUID representation of the key or a base64
* encoded value representing the UUID value.
* <p />
* On {@link ElementType#TYPE} level the {@link #keyId()} can be left empty if explicitly set for fields. <br />
* On {@link ElementType#FIELD} level the {@link #keyId()} can be left empty if inherited from
* {@literal encryptMetadata}.
*
* @return the key id to use. May contain a parsable {@link org.springframework.expression.Expression expression}. In
* this case the {@code #target} variable will hold the target element name.
*/
String[] keyId() default {};
/**
* @return the algorithm.
* Set the algorithm to use.
* <p />
* On {@link ElementType#TYPE} level the {@link #algorithm()} can be left empty if explicitly set for fields. <br />
* On {@link ElementType#FIELD} level the {@link #algorithm()} can be left empty if inherited from
* {@literal encryptMetadata}.
*
* @return the encryption algorithm.
* @see org.springframework.data.mongodb.core.EncryptionAlgorithms
*/
String algorithm() default "";
}

1
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/schema/MongoJsonSchema.java

@ -79,6 +79,7 @@ public interface MongoJsonSchema { @@ -79,6 +79,7 @@ public interface MongoJsonSchema {
* {@link org.springframework.data.mongodb.core.convert.JsonSchemaMapper} to apply field name customization.
*
* @return never {@literal null}.
* @since 3.3
*/
Document schemaDocument();

104
src/main/asciidoc/reference/mongo-json-schema.adoc

@ -225,6 +225,110 @@ MongoJsonSchema schema = MongoJsonSchema.builder() @@ -225,6 +225,110 @@ MongoJsonSchema schema = MongoJsonSchema.builder()
----
====
Instead of defining encrypted fields manually it is possible leverage the `@Encrypted` annotation as shown in the snippet below.
.Client-Side Field Level Encryption via Json Schema
====
[source,java]
----
@Document
@Encrypted(keyId = "xKVup8B1Q+CkHaVRx+qa+g==", algorithm = "AEAD_AES_256_CBC_HMAC_SHA_512-Random") <1>
static class Patient {
@Id String id;
String name;
@Encrypted <2>
String bloodType;
@Encrypted(algorithm = "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic") <3>
Integer ssn;
}
----
<1> Default encryption settings that will be set for `encryptMetadata`.
<2> Encrypted field using default encryption settings.
<3> Encrypted field overriding the default encryption algorithm.
====
[TIP]
====
The `@EncryptedAnnoation` supports resolving keyIds via SpEL Expressions.
To do so additional environment metadata (via the `MappingContext`) is required and must be provided.
[source,java]
----
@Document
@Encrypted(keyId = "#{mongocrypt.keyId(#target)}")
static class Patient {
@Id String id;
String name;
@Encrypted(algorithm = "AEAD_AES_256_CBC_HMAC_SHA_512-Random")
String bloodType;
@Encrypted(algorithm = "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic")
Integer ssn;
}
MongoJsonSchemaCreator schemaCreator = MongoJsonSchemaCreator.create(mappingContext);
MongoJsonSchema personSchema = schemaCreator
.filter(MongoJsonSchemaCreator.encryptedOnly())
.createSchemaFor(Patient.class);
----
The `mongocrypt.keyId` function is defined via an `EvaluationContextExtension` as shown in the snippet below.
Providing a custom extension provides the most flexible way of computing keyIds.
[source,java]
----
public class EncryptionExtension implements EvaluationContextExtension {
@Override
public String getExtensionId() {
return "mongocrypt";
}
@Override
public Map<String, Function> getFunctions() {
return Collections.singletonMap("keyId", new Function(getMethod("computeKeyId", String.class), this));
}
public String computeKeyId(String target) {
// ... lookup via target element name
}
}
----
To combine derived encryption settings with `AutoEncryptionSettings` in a Spring Boot application use the `MongoClientSettingsBuilderCustomizer`.
[source,java]
----
@Bean
MongoClientSettingsBuilderCustomizer customizer(MappingContext mappingContext) {
return (builder) -> {
// ... keyVaultCollection, kmsProvider, ...
MongoJsonSchemaCreator schemaCreator = MongoJsonSchemaCreator.create(mappingContext);
MongoJsonSchema patientSchema = schemaCreator
.filter(MongoJsonSchemaCreator.encryptedOnly())
.createSchemaFor(Patient.class);
AutoEncryptionSettings autoEncryptionSettings = AutoEncryptionSettings.builder()
.keyVaultNamespace(keyVaultCollection)
.kmsProviders(kmsProviders)
.extraOptions(extraOpts)
.schemaMap(Collections.singletonMap("db.patient", patientSchema.schemaDocument().toBsonDocument()))
.build();
builder.autoEncryptionSettings(autoEncryptionSettings);
};
}
----
====
NOTE: Make sure to set the drivers `com.mongodb.AutoEncryptionSettings` to use client-side encryption. MongoDB does not support encryption for all field types. Specific data types require deterministic encryption to preserve equality comparison functionality.
[[mongo.jsonSchema.types]]

Loading…
Cancel
Save