From fa8f0a61364127dc6dc2455642f66c8f5de33f3d Mon Sep 17 00:00:00 2001 From: Mathieu Ouellet Date: Sat, 4 Feb 2017 10:54:09 -0500 Subject: [PATCH 1/2] Add schema validation options for embedded LDAP See gh-8195 --- .../EmbeddedLdapAutoConfiguration.java | 18 ++++++++ .../ldap/embedded/EmbeddedLdapProperties.java | 41 +++++++++++++++++++ .../EmbeddedLdapAutoConfigurationTests.java | 23 +++++++++++ .../test/resources/custom-schema-sample.ldif | 7 ++++ .../src/test/resources/custom-schema.ldif | 17 ++++++++ 5 files changed, 106 insertions(+) create mode 100644 spring-boot-autoconfigure/src/test/resources/custom-schema-sample.ldif create mode 100644 spring-boot-autoconfigure/src/test/resources/custom-schema.ldif diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/ldap/embedded/EmbeddedLdapAutoConfiguration.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/ldap/embedded/EmbeddedLdapAutoConfiguration.java index 3d0670be3c..c7805d123e 100644 --- a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/ldap/embedded/EmbeddedLdapAutoConfiguration.java +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/ldap/embedded/EmbeddedLdapAutoConfiguration.java @@ -26,6 +26,7 @@ import com.unboundid.ldap.listener.InMemoryDirectoryServer; import com.unboundid.ldap.listener.InMemoryDirectoryServerConfig; import com.unboundid.ldap.listener.InMemoryListenerConfig; import com.unboundid.ldap.sdk.LDAPException; +import com.unboundid.ldap.sdk.schema.Schema; import com.unboundid.ldif.LDIFReader; import org.springframework.boot.autoconfigure.AutoConfigureBefore; @@ -55,6 +56,7 @@ import org.springframework.util.StringUtils; * {@link EnableAutoConfiguration Auto-configuration} for Embedded LDAP. * * @author Eddú Meléndez + * @author Mathieu Ouellet * @since 1.5.0 */ @Configuration @@ -107,6 +109,22 @@ public class EmbeddedLdapAutoConfiguration { this.embeddedProperties.getCredential().getUsername(), this.embeddedProperties.getCredential().getPassword()); } + + if (!this.embeddedProperties.getValidation().isEnabled()) { + config.setSchema(null); + } + else if (this.embeddedProperties.getValidation().getSchema() != null) { + Resource schemaLocation = this.embeddedProperties.getValidation().getSchema(); + try { + config.setSchema(Schema.mergeSchemas(Schema.getDefaultStandardSchema(), + Schema.getSchema(schemaLocation.getFile()))); + } + catch (Exception ex) { + throw new IllegalStateException( + "Unable to load schema " + schemaLocation.getDescription(), ex); + } + } + InMemoryListenerConfig listenerConfig = InMemoryListenerConfig .createLDAPConfig("LDAP", this.embeddedProperties.getPort()); config.setListenerConfigs(listenerConfig); diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/ldap/embedded/EmbeddedLdapProperties.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/ldap/embedded/EmbeddedLdapProperties.java index 1a4ac083ed..8e4d0b6927 100644 --- a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/ldap/embedded/EmbeddedLdapProperties.java +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/ldap/embedded/EmbeddedLdapProperties.java @@ -17,11 +17,13 @@ package org.springframework.boot.autoconfigure.ldap.embedded; import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.core.io.Resource; /** * Configuration properties for Embedded LDAP. * * @author Eddú Meléndez + * @author Mathieu Ouellet * @since 1.5.0 */ @ConfigurationProperties(prefix = "spring.ldap.embedded") @@ -47,6 +49,11 @@ public class EmbeddedLdapProperties { */ private String ldif = "classpath:schema.ldif"; + /** + * Schema validation + */ + private Validation validation = new Validation(); + public int getPort() { return this.port; } @@ -79,6 +86,10 @@ public class EmbeddedLdapProperties { this.ldif = ldif; } + public Validation getValidation() { + return this.validation; + } + static class Credential { /** @@ -109,4 +120,34 @@ public class EmbeddedLdapProperties { } + static class Validation { + + /** + * Enable LDAP schema validation + */ + private boolean enabled = true; + + /** + * Path to the custom schema file + */ + private Resource schema; + + public boolean isEnabled() { + return this.enabled; + } + + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } + + public Resource getSchema() { + return this.schema; + } + + public void setSchema(Resource schema) { + this.schema = schema; + } + + } + } diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/ldap/embedded/EmbeddedLdapAutoConfigurationTests.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/ldap/embedded/EmbeddedLdapAutoConfigurationTests.java index d5d5e54dae..5643eda946 100644 --- a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/ldap/embedded/EmbeddedLdapAutoConfigurationTests.java +++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/ldap/embedded/EmbeddedLdapAutoConfigurationTests.java @@ -131,6 +131,29 @@ public class EmbeddedLdapAutoConfigurationTests { assertThat(ldapTemplate.list("ou=company1,c=Sweden,dc=spring,dc=org")).hasSize(4); } + @Test + public void testDisableSchemaValidation() throws LDAPException { + load("spring.ldap.embedded.validation.enabled:false", + "spring.ldap.embedded.base-dn:dc=spring,dc=org"); + InMemoryDirectoryServer server = this.context + .getBean(InMemoryDirectoryServer.class); + assertThat(server.getSchema()).isNull(); + } + + @Test + public void testCustomSchemaValidation() throws LDAPException { + load("spring.ldap.embedded.validation.schema:classpath:custom-schema.ldif", + "spring.ldap.embedded.ldif:classpath:custom-schema-sample.ldif", + "spring.ldap.embedded.base-dn:dc=spring,dc=org"); + InMemoryDirectoryServer server = this.context + .getBean(InMemoryDirectoryServer.class); + + assertThat(server.getSchema().getObjectClass("exampleAuxiliaryClass")) + .isNotNull(); + assertThat(server.getSchema().getAttributeType("exampleAttributeName")) + .isNotNull(); + } + private void load(String... properties) { EnvironmentTestUtils.addEnvironment(this.context, properties); this.context.register(EmbeddedLdapAutoConfiguration.class, diff --git a/spring-boot-autoconfigure/src/test/resources/custom-schema-sample.ldif b/spring-boot-autoconfigure/src/test/resources/custom-schema-sample.ldif new file mode 100644 index 0000000000..c5b81e84ce --- /dev/null +++ b/spring-boot-autoconfigure/src/test/resources/custom-schema-sample.ldif @@ -0,0 +1,7 @@ +dn: dc=spring,dc=org +objectclass: top +objectclass: domain +objectclass: extensibleObject +objectClass: exampleAuxiliaryClass +dc: spring +exampleAttributeName: exampleAttributeName diff --git a/spring-boot-autoconfigure/src/test/resources/custom-schema.ldif b/spring-boot-autoconfigure/src/test/resources/custom-schema.ldif new file mode 100644 index 0000000000..a561a201cb --- /dev/null +++ b/spring-boot-autoconfigure/src/test/resources/custom-schema.ldif @@ -0,0 +1,17 @@ +dn: cn=schema +attributeTypes: ( 1.3.6.1.4.1.32473.1.1.1 + NAME 'exampleAttributeName' + DESC 'An example attribute type definition' + EQUALITY caseIgnoreMatch + ORDERING caseIgnoreOrderingMatch + SUBSTR caseIgnoreSubstringsMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 + SINGLE-VALUE + X-ORIGIN 'Managing Schema Document' ) +objectClasses: ( 1.3.6.1.4.1.32473.1.2.2 + NAME 'exampleAuxiliaryClass' + DESC 'An example auxiliary object class definition' + SUP top + AUXILIARY + MAY exampleAttributeName + X-ORIGIN 'Managing Schema Document' ) \ No newline at end of file From 43a534f4ca67a70446584eee21765ea34e7e549a Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Mon, 20 Feb 2017 14:03:07 +0100 Subject: [PATCH 2/2] Polish contribution Closes gh-8195 --- .../EmbeddedLdapAutoConfiguration.java | 20 ++++++++++--------- .../ldap/embedded/EmbeddedLdapProperties.java | 10 +++++----- .../appendix-application-properties.adoc | 6 ++++-- .../main/asciidoc/spring-boot-features.adoc | 4 ++++ 4 files changed, 24 insertions(+), 16 deletions(-) diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/ldap/embedded/EmbeddedLdapAutoConfiguration.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/ldap/embedded/EmbeddedLdapAutoConfiguration.java index c7805d123e..54e5ae5724 100644 --- a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/ldap/embedded/EmbeddedLdapAutoConfiguration.java +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/ldap/embedded/EmbeddedLdapAutoConfiguration.java @@ -113,15 +113,17 @@ public class EmbeddedLdapAutoConfiguration { if (!this.embeddedProperties.getValidation().isEnabled()) { config.setSchema(null); } - else if (this.embeddedProperties.getValidation().getSchema() != null) { - Resource schemaLocation = this.embeddedProperties.getValidation().getSchema(); - try { - config.setSchema(Schema.mergeSchemas(Schema.getDefaultStandardSchema(), - Schema.getSchema(schemaLocation.getFile()))); - } - catch (Exception ex) { - throw new IllegalStateException( - "Unable to load schema " + schemaLocation.getDescription(), ex); + else { + Resource schema = this.embeddedProperties.getValidation().getSchema(); + if (schema != null) { + try { + config.setSchema(Schema.mergeSchemas(Schema.getDefaultStandardSchema(), + Schema.getSchema(schema.getInputStream()))); + } + catch (Exception ex) { + throw new IllegalStateException( + "Unable to load schema " + schema.getDescription(), ex); + } } } diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/ldap/embedded/EmbeddedLdapProperties.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/ldap/embedded/EmbeddedLdapProperties.java index 8e4d0b6927..bd4de81fa3 100644 --- a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/ldap/embedded/EmbeddedLdapProperties.java +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/ldap/embedded/EmbeddedLdapProperties.java @@ -50,7 +50,7 @@ public class EmbeddedLdapProperties { private String ldif = "classpath:schema.ldif"; /** - * Schema validation + * Schema validation. */ private Validation validation = new Validation(); @@ -90,7 +90,7 @@ public class EmbeddedLdapProperties { return this.validation; } - static class Credential { + public static class Credential { /** * Embedded LDAP username. @@ -120,15 +120,15 @@ public class EmbeddedLdapProperties { } - static class Validation { + public static class Validation { /** - * Enable LDAP schema validation + * Enable LDAP schema validation. */ private boolean enabled = true; /** - * Path to the custom schema file + * Path to the custom schema. */ private Resource schema; diff --git a/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc b/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc index 069b24e757..9adba7f721 100644 --- a/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc +++ b/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc @@ -323,11 +323,13 @@ content into your application; rather pick only the properties that you need. spring.ldap.base-environment.*= # LDAP specification settings. # EMBEDDED LDAP ({sc-spring-boot-autoconfigure}/ldap/embedded/EmbeddedLdapProperties.{sc-ext}[EmbeddedLdapProperties]) - spring.ldap.embedded.port= # Embedded LDAP port. + spring.ldap.embedded.base-dn= # The base DN spring.ldap.embedded.credential.username= # Embedded LDAP username. spring.ldap.embedded.credential.password= # Embedded LDAP password. - spring.ldap.embedded.base-dn= # The base DN spring.ldap.embedded.ldif=classpath:schema.ldif # Schema (LDIF) script resource reference. + spring.ldap.embedded.port= # Embedded LDAP port. + spring.ldap.embedded.validation.enabled=true # Enable LDAP schema validation. + spring.ldap.embedded.validation.schema= # Path to the custom schema. # SPRING MOBILE DEVICE VIEWS ({sc-spring-boot-autoconfigure}/mobile/DeviceDelegatingViewResolverAutoConfiguration.{sc-ext}[DeviceDelegatingViewResolverAutoConfiguration]) spring.mobile.devicedelegatingviewresolver.enable-fallback=false # Enable support for fallback resolution. diff --git a/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc b/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc index 561eafb7ee..ed1c8f6e26 100644 --- a/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc +++ b/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc @@ -3991,6 +3991,10 @@ If there is a `schema.ldif` file on your classpath it will be used to initialize server. You can also use the `spring.ldap.embedded.ldif` property if you want to load the initialization script from a different resource. +By default, a standard schema will be used to validate `LDIF` files, you can turn off +validation altogether using the `spring.ldap.embedded.validation.enabled` property. If +you have custom attributes, you can use `spring.ldap.embedded.validation.schema` to define +your custom attribute types or object classes. [[boot-features-caching]]