diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/ManagementWebSecurityAutoConfiguration.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/ManagementWebSecurityAutoConfiguration.java index 51507d52af..7eac112ff7 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/ManagementWebSecurityAutoConfiguration.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/ManagementWebSecurityAutoConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2016 the original author or authors. + * Copyright 2012-2017 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. @@ -257,10 +257,11 @@ public class ManagementWebSecurityAutoConfiguration { private void configurePermittedRequests( ExpressionUrlAuthorizationConfigurer.ExpressionInterceptUrlRegistry requests) { + requests.requestMatchers(new LazyEndpointPathRequestMatcher( + this.contextResolver, EndpointPaths.SENSITIVE)).authenticated(); // Permit access to the non-sensitive endpoints requests.requestMatchers(new LazyEndpointPathRequestMatcher( this.contextResolver, EndpointPaths.NON_SENSITIVE)).permitAll(); - requests.anyRequest().authenticated(); } } @@ -276,6 +277,15 @@ public class ManagementWebSecurityAutoConfiguration { return !endpoint.isSensitive(); } + }, + + SENSITIVE { + + @Override + protected boolean isIncluded(MvcEndpoint endpoint) { + return endpoint.isSensitive(); + } + }; public String[] getPaths(EndpointHandlerMapping endpointHandlerMapping) { @@ -289,12 +299,9 @@ public class ManagementWebSecurityAutoConfiguration { String path = endpointHandlerMapping.getPath(endpoint.getPath()); paths.add(path); if (!path.equals("")) { - if (endpoint.isSensitive()) { - // Ensure that nested paths are secured - paths.add(path + "/**"); - // Add Spring MVC-generated additional paths - paths.add(path + ".*"); - } + paths.add(path + "/**"); + // Add Spring MVC-generated additional paths + paths.add(path + ".*"); } paths.add(path + "/"); } diff --git a/spring-boot-autoconfigure/pom.xml b/spring-boot-autoconfigure/pom.xml index 50ba3425b4..9bf8ec354a 100755 --- a/spring-boot-autoconfigure/pom.xml +++ b/spring-boot-autoconfigure/pom.xml @@ -234,6 +234,11 @@ sendgrid-java true + + com.unboundid + unboundid-ldapsdk + true + com.zaxxer HikariCP-java6 @@ -382,6 +387,11 @@ spring-data-cassandra true + + org.springframework.data + spring-data-ldap + true + org.springframework.data spring-data-mongodb diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/ldap/LdapDataAutoConfiguration.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/ldap/LdapDataAutoConfiguration.java new file mode 100644 index 0000000000..9957ef2603 --- /dev/null +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/ldap/LdapDataAutoConfiguration.java @@ -0,0 +1,50 @@ +/* + * Copyright 2012-2017 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 + * + * http://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.boot.autoconfigure.data.ldap; + +import javax.naming.ldap.LdapContext; + +import org.springframework.boot.autoconfigure.AutoConfigureAfter; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.ldap.LdapAutoConfiguration; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.ldap.repository.LdapRepository; +import org.springframework.ldap.core.ContextSource; +import org.springframework.ldap.core.LdapOperations; +import org.springframework.ldap.core.LdapTemplate; + +/** + * {@link EnableAutoConfiguration Auto-configuration} for Spring Data's LDAP support. + * + * @author Eddú Meléndez + * @since 1.5.0 + */ +@Configuration +@ConditionalOnClass({ LdapContext.class, LdapRepository.class }) +@AutoConfigureAfter(LdapAutoConfiguration.class) +public class LdapDataAutoConfiguration { + + @Bean + @ConditionalOnMissingBean(LdapOperations.class) + public LdapTemplate ldapTemplate(ContextSource contextSource) { + return new LdapTemplate(contextSource); + } + +} diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/ldap/LdapRepositoriesAutoConfiguration.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/ldap/LdapRepositoriesAutoConfiguration.java new file mode 100644 index 0000000000..121e719a50 --- /dev/null +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/ldap/LdapRepositoriesAutoConfiguration.java @@ -0,0 +1,44 @@ +/* + * Copyright 2012-2017 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 + * + * http://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.boot.autoconfigure.data.ldap; + +import javax.naming.ldap.LdapContext; + +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; +import org.springframework.data.ldap.repository.LdapRepository; +import org.springframework.data.ldap.repository.support.LdapRepositoryFactoryBean; + +/** + * {@link EnableAutoConfiguration Auto-configuration} for Spring Data's Couchbase + * Repositories. + * + * @author Eddú Meléndez + * @since 1.5.0 + */ +@Configuration +@ConditionalOnClass({ LdapContext.class, LdapRepository.class }) +@ConditionalOnProperty(prefix = "spring.data.ldap.repositories", name = "enabled", havingValue = "true", matchIfMissing = true) +@ConditionalOnMissingBean(LdapRepositoryFactoryBean.class) +@Import(LdapRepositoriesRegistrar.class) +public class LdapRepositoriesAutoConfiguration { + +} diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/ldap/LdapRepositoriesRegistrar.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/ldap/LdapRepositoriesRegistrar.java new file mode 100644 index 0000000000..eb275fa36a --- /dev/null +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/ldap/LdapRepositoriesRegistrar.java @@ -0,0 +1,56 @@ +/* + * Copyright 2012-2017 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 + * + * http://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.boot.autoconfigure.data.ldap; + +import java.lang.annotation.Annotation; + +import org.springframework.boot.autoconfigure.data.AbstractRepositoryConfigurationSourceSupport; +import org.springframework.context.annotation.ImportBeanDefinitionRegistrar; +import org.springframework.data.ldap.repository.config.EnableLdapRepositories; +import org.springframework.data.ldap.repository.config.LdapRepositoryConfigurationExtension; +import org.springframework.data.repository.config.RepositoryConfigurationExtension; + +/** + * {@link ImportBeanDefinitionRegistrar} used to auto-configure Spring Data LDAP + * Repositories. + * + * @author Eddú Meléndez + * @since 1.5.0 + */ +class LdapRepositoriesRegistrar extends AbstractRepositoryConfigurationSourceSupport { + + @Override + protected Class getAnnotation() { + return EnableLdapRepositories.class; + } + + @Override + protected Class getConfiguration() { + return EnableLdapRepositoriesConfiguration.class; + } + + @Override + protected RepositoryConfigurationExtension getRepositoryConfigurationExtension() { + return new LdapRepositoryConfigurationExtension(); + } + + @EnableLdapRepositories + private static class EnableLdapRepositoriesConfiguration { + + } + +} diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/ldap/package-info.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/ldap/package-info.java new file mode 100644 index 0000000000..aac37e601c --- /dev/null +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/ldap/package-info.java @@ -0,0 +1,20 @@ +/* + * Copyright 2012-2017 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 + * + * http://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. + */ + +/** + * Auto-configuration for Spring Data LDAP. + */ +package org.springframework.boot.autoconfigure.data.ldap; diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/ldap/LdapAutoConfiguration.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/ldap/LdapAutoConfiguration.java new file mode 100644 index 0000000000..d8f3acd6e8 --- /dev/null +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/ldap/LdapAutoConfiguration.java @@ -0,0 +1,64 @@ +/* + * Copyright 2012-2017 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 + * + * http://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.boot.autoconfigure.ldap; + +import java.util.Collections; + +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.env.Environment; +import org.springframework.ldap.core.ContextSource; +import org.springframework.ldap.core.support.LdapContextSource; + +/** + * {@link EnableAutoConfiguration Auto-configuration} for LDAP. + * + * @author Eddú Meléndez + * @since 1.5.0 + */ +@Configuration +@ConditionalOnClass(ContextSource.class) +@EnableConfigurationProperties(LdapProperties.class) +public class LdapAutoConfiguration { + + private final LdapProperties properties; + + private final Environment environment; + + public LdapAutoConfiguration(LdapProperties properties, Environment environment) { + this.properties = properties; + this.environment = environment; + } + + @Bean + @ConditionalOnMissingBean + public ContextSource ldapContextSource() { + LdapContextSource source = new LdapContextSource(); + source.setUserDn(this.properties.getUsername()); + source.setPassword(this.properties.getPassword()); + source.setBase(this.properties.getBase()); + source.setUrls(this.properties.determineUrls(this.environment)); + source.setBaseEnvironmentProperties(Collections + .unmodifiableMap(this.properties.getBaseEnvironment())); + return source; + } + +} diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/ldap/LdapProperties.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/ldap/LdapProperties.java new file mode 100644 index 0000000000..35c8ad8b9f --- /dev/null +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/ldap/LdapProperties.java @@ -0,0 +1,120 @@ +/* + * Copyright 2012-2017 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 + * + * http://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.boot.autoconfigure.ldap; + +import java.util.HashMap; +import java.util.Map; + +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.core.env.Environment; +import org.springframework.ldap.core.LdapTemplate; +import org.springframework.util.Assert; +import org.springframework.util.ObjectUtils; + +/** + * Configuration properties to configure {@link LdapTemplate}. + * + * @author Eddú Meléndez + * @since 1.5.0 + */ +@ConfigurationProperties(prefix = "spring.ldap") +public class LdapProperties { + + private static final int DEFAULT_PORT = 389; + + /** + * LDAP urls. + */ + private String[] urls; + + /** + * Base suffix from which all operations should originate. + */ + private String base; + + /** + * Login user of the LDAP. + */ + private String username; + + /** + * Login password of the LDAP. + */ + private String password; + + /** + * LDAP custom environment properties. + */ + private Map baseEnvironment = new HashMap(); + + public String[] getUrls() { + return this.urls; + } + + public void setUrls(String[] urls) { + this.urls = urls; + } + + public String getBase() { + return this.base; + } + + public void setBase(String base) { + this.base = base; + } + + public String getUsername() { + return this.username; + } + + public void setUsername(String username) { + this.username = username; + } + + public String getPassword() { + return this.password; + } + + public void setPassword(String password) { + this.password = password; + } + + public Map getBaseEnvironment() { + return this.baseEnvironment; + } + + public void setBaseEnvironment(Map baseEnvironment) { + this.baseEnvironment = baseEnvironment; + } + + public String[] determineUrls(Environment environment) { + if (ObjectUtils.isEmpty(this.urls)) { + return new String[] { "ldap://localhost:" + determinePort(environment) }; + } + return this.urls; + } + + private int determinePort(Environment environment) { + Assert.state(environment != null, "No local LDAP port configured"); + String localPort = environment.getProperty("local.ldap.port"); + if (localPort != null) { + return Integer.valueOf(localPort); + } + return DEFAULT_PORT; + } + +} 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 new file mode 100644 index 0000000000..3d0670be3c --- /dev/null +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/ldap/embedded/EmbeddedLdapAutoConfiguration.java @@ -0,0 +1,175 @@ +/* + * Copyright 2012-2017 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 + * + * http://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.boot.autoconfigure.ldap.embedded; + +import java.io.InputStream; +import java.util.HashMap; +import java.util.Map; + +import javax.annotation.PreDestroy; + +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.ldif.LDIFReader; + +import org.springframework.boot.autoconfigure.AutoConfigureBefore; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.autoconfigure.ldap.LdapAutoConfiguration; +import org.springframework.boot.autoconfigure.ldap.LdapProperties; +import org.springframework.boot.autoconfigure.ldap.embedded.EmbeddedLdapProperties.Credential; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.DependsOn; +import org.springframework.core.env.Environment; +import org.springframework.core.env.MapPropertySource; +import org.springframework.core.env.MutablePropertySources; +import org.springframework.core.env.PropertySource; +import org.springframework.core.io.Resource; +import org.springframework.ldap.core.ContextSource; +import org.springframework.ldap.core.support.LdapContextSource; +import org.springframework.util.StringUtils; + +/** + * {@link EnableAutoConfiguration Auto-configuration} for Embedded LDAP. + * + * @author Eddú Meléndez + * @since 1.5.0 + */ +@Configuration +@EnableConfigurationProperties({ LdapProperties.class, EmbeddedLdapProperties.class }) +@AutoConfigureBefore(LdapAutoConfiguration.class) +@ConditionalOnClass(InMemoryDirectoryServer.class) +@ConditionalOnProperty(prefix = "spring.ldap.embedded", name = "base-dn") +public class EmbeddedLdapAutoConfiguration { + + private static final String PROPERTY_SOURCE_NAME = "ldap.ports"; + + private final EmbeddedLdapProperties embeddedProperties; + + private final LdapProperties properties; + + private final ConfigurableApplicationContext applicationContext; + + private final Environment environment; + + private InMemoryDirectoryServer server; + + public EmbeddedLdapAutoConfiguration(EmbeddedLdapProperties embeddedProperties, + LdapProperties properties, ConfigurableApplicationContext applicationContext, + Environment environment) { + this.embeddedProperties = embeddedProperties; + this.properties = properties; + this.applicationContext = applicationContext; + this.environment = environment; + } + + @Bean + @DependsOn("directoryServer") + @ConditionalOnMissingBean + public ContextSource ldapContextSource() { + LdapContextSource source = new LdapContextSource(); + if (hasCredentials(this.embeddedProperties.getCredential())) { + source.setUserDn(this.embeddedProperties.getCredential().getUsername()); + source.setPassword(this.embeddedProperties.getCredential().getPassword()); + } + source.setUrls(this.properties.determineUrls(this.environment)); + return source; + } + + @Bean + public InMemoryDirectoryServer directoryServer() throws LDAPException { + InMemoryDirectoryServerConfig config = new InMemoryDirectoryServerConfig( + this.embeddedProperties.getBaseDn()); + if (hasCredentials(this.embeddedProperties.getCredential())) { + config.addAdditionalBindCredentials( + this.embeddedProperties.getCredential().getUsername(), + this.embeddedProperties.getCredential().getPassword()); + } + InMemoryListenerConfig listenerConfig = InMemoryListenerConfig + .createLDAPConfig("LDAP", this.embeddedProperties.getPort()); + config.setListenerConfigs(listenerConfig); + this.server = new InMemoryDirectoryServer(config); + importLdif(); + this.server.startListening(); + setPortProperty(this.applicationContext, this.server.getListenPort()); + return this.server; + } + + private boolean hasCredentials(Credential credential) { + return StringUtils.hasText(credential.getUsername()) + && StringUtils.hasText(credential.getPassword()); + } + + private void importLdif() throws LDAPException { + String location = this.embeddedProperties.getLdif(); + if (StringUtils.hasText(location)) { + try { + Resource resource = this.applicationContext.getResource(location); + if (resource.exists()) { + InputStream inputStream = resource.getInputStream(); + try { + this.server.importFromLDIF(true, new LDIFReader(inputStream)); + } + finally { + inputStream.close(); + } + } + } + catch (Exception ex) { + throw new IllegalStateException("Unable to load LDIF " + location, ex); + } + } + } + + private void setPortProperty(ApplicationContext context, int port) { + if (context instanceof ConfigurableApplicationContext) { + MutablePropertySources sources = ((ConfigurableApplicationContext) context) + .getEnvironment().getPropertySources(); + getLdapPorts(sources).put("local.ldap.port", port); + } + if (context.getParent() != null) { + setPortProperty(context.getParent(), port); + } + } + + @SuppressWarnings("unchecked") + private Map getLdapPorts(MutablePropertySources sources) { + PropertySource propertySource = sources.get(PROPERTY_SOURCE_NAME); + if (propertySource == null) { + propertySource = new MapPropertySource(PROPERTY_SOURCE_NAME, + new HashMap()); + sources.addFirst(propertySource); + } + return (Map) propertySource.getSource(); + } + + @PreDestroy + public void close() { + if (this.server != null) { + this.server.shutDown(true); + } + } + +} 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 new file mode 100644 index 0000000000..1a4ac083ed --- /dev/null +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/ldap/embedded/EmbeddedLdapProperties.java @@ -0,0 +1,112 @@ +/* + * Copyright 2012-2017 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 + * + * http://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.boot.autoconfigure.ldap.embedded; + +import org.springframework.boot.context.properties.ConfigurationProperties; + +/** + * Configuration properties for Embedded LDAP. + * + * @author Eddú Meléndez + * @since 1.5.0 + */ +@ConfigurationProperties(prefix = "spring.ldap.embedded") +public class EmbeddedLdapProperties { + + /** + * Embedded LDAP port. + */ + private int port = 0; + + /** + * Embedded LDAP credentials. + */ + private Credential credential = new Credential(); + + /** + * Base DNs. + */ + private String baseDn; + + /** + * Schema (LDIF) script resource reference. + */ + private String ldif = "classpath:schema.ldif"; + + public int getPort() { + return this.port; + } + + public void setPort(int port) { + this.port = port; + } + + public Credential getCredential() { + return this.credential; + } + + public void setCredential(Credential credential) { + this.credential = credential; + } + + public String getBaseDn() { + return this.baseDn; + } + + public void setBaseDn(String baseDn) { + this.baseDn = baseDn; + } + + public String getLdif() { + return this.ldif; + } + + public void setLdif(String ldif) { + this.ldif = ldif; + } + + static class Credential { + + /** + * Embedded LDAP username. + */ + private String username; + + /** + * Embedded LDAP password. + */ + private String password; + + public String getUsername() { + return this.username; + } + + public void setUsername(String username) { + this.username = username; + } + + public String getPassword() { + return this.password; + } + + public void setPassword(String password) { + this.password = password; + } + + } + +} diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/ldap/package-info.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/ldap/package-info.java new file mode 100644 index 0000000000..11f9a8a5c4 --- /dev/null +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/ldap/package-info.java @@ -0,0 +1,20 @@ +/* + * Copyright 2012-2017 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 + * + * http://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. + */ + +/** + * Auto-configuration for LDAP. + */ +package org.springframework.boot.autoconfigure.ldap; diff --git a/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories b/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories index 531c28c38c..40f08a2073 100644 --- a/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories +++ b/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories @@ -29,6 +29,8 @@ org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchAutoConfi org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchDataAutoConfiguration,\ org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchRepositoriesAutoConfiguration,\ org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration,\ +org.springframework.boot.autoconfigure.data.ldap.LdapDataAutoConfiguration,\ +org.springframework.boot.autoconfigure.data.ldap.LdapRepositoriesAutoConfiguration,\ org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration,\ org.springframework.boot.autoconfigure.data.mongo.MongoRepositoriesAutoConfiguration,\ org.springframework.boot.autoconfigure.data.neo4j.Neo4jDataAutoConfiguration,\ @@ -63,6 +65,8 @@ org.springframework.boot.autoconfigure.groovy.template.GroovyTemplateAutoConfigu org.springframework.boot.autoconfigure.jersey.JerseyAutoConfiguration,\ org.springframework.boot.autoconfigure.jooq.JooqAutoConfiguration,\ org.springframework.boot.autoconfigure.kafka.KafkaAutoConfiguration,\ +org.springframework.boot.autoconfigure.ldap.embedded.EmbeddedLdapAutoConfiguration,\ +org.springframework.boot.autoconfigure.ldap.LdapAutoConfiguration,\ org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration,\ org.springframework.boot.autoconfigure.mail.MailSenderAutoConfiguration,\ org.springframework.boot.autoconfigure.mail.MailSenderValidatorAutoConfiguration,\ diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/alt/ldap/PersonLdapRepository.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/alt/ldap/PersonLdapRepository.java new file mode 100644 index 0000000000..baa9fcbf64 --- /dev/null +++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/alt/ldap/PersonLdapRepository.java @@ -0,0 +1,26 @@ +/* + * Copyright 2012-2017 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 + * + * http://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.boot.autoconfigure.data.alt.ldap; + +import javax.naming.Name; + +import org.springframework.boot.autoconfigure.data.ldap.person.Person; +import org.springframework.data.repository.Repository; + +public interface PersonLdapRepository extends Repository { + +} diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/ldap/LdapDataAutoConfigurationTests.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/ldap/LdapDataAutoConfigurationTests.java new file mode 100644 index 0000000000..1301db97c9 --- /dev/null +++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/ldap/LdapDataAutoConfigurationTests.java @@ -0,0 +1,55 @@ +/* + * Copyright 2012-2017 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 + * + * http://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.boot.autoconfigure.data.ldap; + +import org.junit.After; +import org.junit.Test; + +import org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration; +import org.springframework.boot.autoconfigure.ldap.LdapAutoConfiguration; +import org.springframework.boot.test.util.EnvironmentTestUtils; +import org.springframework.context.annotation.AnnotationConfigApplicationContext; +import org.springframework.ldap.core.LdapTemplate; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link LdapDataAutoConfiguration} + * + * @author Eddú Meléndez + */ +public class LdapDataAutoConfigurationTests { + + private AnnotationConfigApplicationContext context; + + @After + public void close() { + this.context.close(); + } + + @Test + public void templateExists() { + this.context = new AnnotationConfigApplicationContext(); + EnvironmentTestUtils.addEnvironment(this.context, + "spring.ldap.urls:ldap://localhost:389"); + this.context.register(PropertyPlaceholderAutoConfiguration.class, + LdapAutoConfiguration.class, LdapDataAutoConfiguration.class); + this.context.refresh(); + assertThat(this.context.getBeanNamesForType(LdapTemplate.class)).hasSize(1); + } + +} diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/ldap/LdapRepositoriesAutoConfigurationTests.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/ldap/LdapRepositoriesAutoConfigurationTests.java new file mode 100644 index 0000000000..6ebb70597a --- /dev/null +++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/ldap/LdapRepositoriesAutoConfigurationTests.java @@ -0,0 +1,100 @@ +/* + * Copyright 2012-2017 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 + * + * http://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.boot.autoconfigure.data.ldap; + +import org.junit.After; +import org.junit.Test; + +import org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration; +import org.springframework.boot.autoconfigure.TestAutoConfigurationPackage; +import org.springframework.boot.autoconfigure.data.alt.ldap.PersonLdapRepository; +import org.springframework.boot.autoconfigure.data.empty.EmptyDataPackage; +import org.springframework.boot.autoconfigure.data.ldap.person.Person; +import org.springframework.boot.autoconfigure.data.ldap.person.PersonRepository; +import org.springframework.boot.autoconfigure.ldap.LdapAutoConfiguration; +import org.springframework.boot.test.util.EnvironmentTestUtils; +import org.springframework.context.annotation.AnnotationConfigApplicationContext; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.ldap.repository.config.EnableLdapRepositories; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link LdapRepositoriesAutoConfiguration} + * + * @author Eddú Meléndez + */ +public class LdapRepositoriesAutoConfigurationTests { + + private AnnotationConfigApplicationContext context; + + @After + public void close() { + if (this.context != null) { + this.context.close(); + } + } + + @Test + public void testDefaultRepositoryConfiguration() throws Exception { + load(TestConfiguration.class); + assertThat(this.context.getBean(PersonRepository.class)).isNotNull(); + } + + @Test + public void testNoRepositoryConfiguration() throws Exception { + load(EmptyConfiguration.class); + assertThat(this.context.getBeanNamesForType(PersonRepository.class)).isEmpty(); + } + + @Test + public void doesNotTriggerDefaultRepositoryDetectionIfCustomized() { + load(CustomizedConfiguration.class); + assertThat(this.context.getBean(PersonLdapRepository.class)).isNotNull(); + } + + private void load(Class... configurationClasses) { + this.context = new AnnotationConfigApplicationContext(); + EnvironmentTestUtils.addEnvironment(this.context, + "spring.ldap.urls:ldap://localhost:389"); + this.context.register(configurationClasses); + this.context.register(LdapAutoConfiguration.class, + LdapDataAutoConfiguration.class, LdapRepositoriesAutoConfiguration.class, + PropertyPlaceholderAutoConfiguration.class); + this.context.refresh(); + } + + @Configuration + @TestAutoConfigurationPackage(Person.class) + protected static class TestConfiguration { + + } + + @Configuration + @TestAutoConfigurationPackage(EmptyDataPackage.class) + protected static class EmptyConfiguration { + + } + + @Configuration + @TestAutoConfigurationPackage(LdapRepositoriesAutoConfigurationTests.class) + @EnableLdapRepositories(basePackageClasses = PersonLdapRepository.class) + protected static class CustomizedConfiguration { + + } + +} diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/ldap/person/Person.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/ldap/person/Person.java new file mode 100644 index 0000000000..02bb4600c3 --- /dev/null +++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/ldap/person/Person.java @@ -0,0 +1,36 @@ +/* + * Copyright 2012-2017 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 + * + * http://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.boot.autoconfigure.data.ldap.person; + +import javax.naming.Name; + +import org.springframework.ldap.odm.annotations.Attribute; +import org.springframework.ldap.odm.annotations.DnAttribute; +import org.springframework.ldap.odm.annotations.Entry; +import org.springframework.ldap.odm.annotations.Id; + +@Entry(objectClasses = { "person", "top" }, base = "ou=someOu") +public class Person { + + @Id + private Name dn; + + @Attribute(name = "cn") + @DnAttribute(value = "cn", index = 1) + private String fullName; + +} diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/ldap/person/PersonRepository.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/ldap/person/PersonRepository.java new file mode 100644 index 0000000000..4f0714ac01 --- /dev/null +++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/ldap/person/PersonRepository.java @@ -0,0 +1,25 @@ +/* + * Copyright 2012-2017 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 + * + * http://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.boot.autoconfigure.data.ldap.person; + +import javax.naming.Name; + +import org.springframework.data.repository.Repository; + +public interface PersonRepository extends Repository { + +} diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/ldap/LdapAutoConfigurationTests.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/ldap/LdapAutoConfigurationTests.java new file mode 100644 index 0000000000..102e205a6b --- /dev/null +++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/ldap/LdapAutoConfigurationTests.java @@ -0,0 +1,96 @@ +/* + * Copyright 2012-2017 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 + * + * http://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.boot.autoconfigure.ldap; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration; +import org.springframework.boot.test.util.EnvironmentTestUtils; +import org.springframework.context.annotation.AnnotationConfigApplicationContext; +import org.springframework.ldap.core.ContextSource; +import org.springframework.test.util.ReflectionTestUtils; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link LdapAutoConfiguration}. + * + * @author Eddú Meléndez + */ +public class LdapAutoConfigurationTests { + + private AnnotationConfigApplicationContext context; + + @Before + public void setup() { + this.context = new AnnotationConfigApplicationContext(); + } + + @After + public void close() { + if (this.context != null) { + this.context.close(); + } + } + + @Test + public void testDefaultUrl() { + load(); + ContextSource contextSource = this.context.getBean(ContextSource.class); + String[] urls = (String[]) ReflectionTestUtils.getField(contextSource, "urls"); + assertThat(urls).containsExactly("ldap://localhost:389"); + } + + @Test + public void testContextSourceSetOneUrl() { + load("spring.ldap.urls:ldap://localhost:123"); + ContextSource contextSource = this.context.getBean(ContextSource.class); + String[] urls = (String[]) ReflectionTestUtils.getField(contextSource, "urls"); + assertThat(urls).containsExactly("ldap://localhost:123"); + } + + @Test + public void testContextSourceSetTwoUrls() { + load("spring.ldap.urls:ldap://localhost:123,ldap://mycompany:123"); + ContextSource contextSource = this.context.getBean(ContextSource.class); + LdapProperties ldapProperties = this.context.getBean(LdapProperties.class); + String[] urls = (String[]) ReflectionTestUtils.getField(contextSource, "urls"); + assertThat(urls).containsExactly("ldap://localhost:123", "ldap://mycompany:123"); + assertThat(ldapProperties.getUrls()).hasSize(2); + } + + @Test + public void testContextSourceWithMoreProperties() { + load("spring.ldap.urls:ldap://localhost:123", "spring.ldap.username:root", + "spring.ldap.password:root", "spring.ldap.base:cn=SpringDevelopers", + "spring.ldap.baseEnvironment.java.naming.security" + + ".authentication:DIGEST-MD5"); + LdapProperties ldapProperties = this.context.getBean(LdapProperties.class); + assertThat(ldapProperties.getBaseEnvironment()) + .containsEntry("java.naming.security.authentication", "DIGEST-MD5"); + } + + private void load(String... properties) { + EnvironmentTestUtils.addEnvironment(this.context, properties); + this.context.register(LdapAutoConfiguration.class, + PropertyPlaceholderAutoConfiguration.class); + this.context.refresh(); + } + +} 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 new file mode 100644 index 0000000000..c425850826 --- /dev/null +++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/ldap/embedded/EmbeddedLdapAutoConfigurationTests.java @@ -0,0 +1,154 @@ +/* + * Copyright 2012-2017 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 + * + * http://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.boot.autoconfigure.ldap.embedded; + +import com.unboundid.ldap.listener.InMemoryDirectoryServer; +import com.unboundid.ldap.sdk.BindResult; +import com.unboundid.ldap.sdk.DN; +import com.unboundid.ldap.sdk.LDAPConnection; +import com.unboundid.ldap.sdk.LDAPException; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration; +import org.springframework.boot.autoconfigure.data.ldap.LdapDataAutoConfiguration; +import org.springframework.boot.autoconfigure.ldap.LdapAutoConfiguration; +import org.springframework.boot.test.util.EnvironmentTestUtils; +import org.springframework.context.annotation.AnnotationConfigApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.ldap.core.LdapTemplate; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link EmbeddedLdapAutoConfiguration} + * + * @author Eddú Meléndez + */ +public class EmbeddedLdapAutoConfigurationTests { + + private AnnotationConfigApplicationContext context; + + @Before + public void setup() { + this.context = new AnnotationConfigApplicationContext(); + } + + @After + public void close() { + if (this.context != null) { + this.context.close(); + } + } + + @Test + public void testSetDefaultPort() throws LDAPException { + load("spring.ldap.embedded.port:1234", + "spring.ldap.embedded.base-dn:dc=spring,dc=org"); + InMemoryDirectoryServer server = this.context + .getBean(InMemoryDirectoryServer.class); + assertThat(server.getListenPort()).isEqualTo(1234); + } + + @Test + public void testRandomPortWithEnvironment() throws LDAPException { + load("spring.ldap.embedded.base-dn:dc=spring,dc=org"); + InMemoryDirectoryServer server = this.context + .getBean(InMemoryDirectoryServer.class); + assertThat(server.getListenPort()).isEqualTo(this.context.getEnvironment() + .getProperty("local.ldap.port", Integer.class)); + } + + @Test + public void testRandomPortWithValueAnnotation() throws LDAPException { + EnvironmentTestUtils.addEnvironment(this.context, + "spring.ldap.embedded.base-dn:dc=spring,dc=org"); + this.context.register(EmbeddedLdapAutoConfiguration.class, + LdapClientConfiguration.class, + PropertyPlaceholderAutoConfiguration.class); + this.context.refresh(); + LDAPConnection connection = this.context.getBean(LDAPConnection.class); + assertThat(connection.getConnectedPort()).isEqualTo(this.context.getEnvironment() + .getProperty("local.ldap.port", Integer.class)); + } + + @Test + public void testSetCredentials() throws LDAPException { + load("spring.ldap.embedded.base-dn:dc=spring,dc=org", + "spring.ldap.embedded.credential.username:uid=root", + "spring.ldap.embedded.credential.password:boot"); + InMemoryDirectoryServer server = this.context + .getBean(InMemoryDirectoryServer.class); + BindResult result = server.bind("uid=root", "boot"); + assertThat(result).isNotNull(); + } + + @Test + public void testSetPartitionSuffix() throws LDAPException { + load("spring.ldap.embedded.base-dn:dc=spring,dc=org"); + InMemoryDirectoryServer server = this.context + .getBean(InMemoryDirectoryServer.class); + assertThat(server.getBaseDNs()).containsExactly(new DN("dc=spring,dc=org")); + } + + @Test + public void testSetLdifFile() throws LDAPException { + load("spring.ldap.embedded.base-dn:dc=spring,dc=org"); + InMemoryDirectoryServer server = this.context + .getBean(InMemoryDirectoryServer.class); + assertThat(server.countEntriesBelow("ou=company1,c=Sweden,dc=spring,dc=org")) + .isEqualTo(5); + } + + @Test + public void testQueryEmbeddedLdap() throws LDAPException { + EnvironmentTestUtils.addEnvironment(this.context, + "spring.ldap.embedded.base-dn:dc=spring,dc=org"); + this.context.register(EmbeddedLdapAutoConfiguration.class, + LdapAutoConfiguration.class, LdapDataAutoConfiguration.class, + PropertyPlaceholderAutoConfiguration.class); + this.context.refresh(); + assertThat(this.context.getBeanNamesForType(LdapTemplate.class).length) + .isEqualTo(1); + LdapTemplate ldapTemplate = this.context.getBean(LdapTemplate.class); + assertThat(ldapTemplate.list("ou=company1,c=Sweden,dc=spring,dc=org")).hasSize(4); + } + + private void load(String... properties) { + EnvironmentTestUtils.addEnvironment(this.context, properties); + this.context.register(EmbeddedLdapAutoConfiguration.class, + PropertyPlaceholderAutoConfiguration.class); + this.context.refresh(); + } + + @Configuration + static class LdapClientConfiguration { + + @Bean + public LDAPConnection ldapConnection(@Value("${local.ldap.port}") int port) + throws LDAPException { + LDAPConnection con = new LDAPConnection(); + con.connect("localhost", port); + return con; + } + + } + +} diff --git a/spring-boot-autoconfigure/src/test/resources/schema.ldif b/spring-boot-autoconfigure/src/test/resources/schema.ldif new file mode 100644 index 0000000000..df76aace51 --- /dev/null +++ b/spring-boot-autoconfigure/src/test/resources/schema.ldif @@ -0,0 +1,85 @@ +dn: dc=spring,dc=org +objectclass: top +objectclass: domain +objectclass: extensibleObject +dc: spring + +dn: ou=groups,dc=spring,dc=org +objectclass: top +objectclass: organizationalUnit +ou: groups + +dn: cn=ROLE_USER,ou=groups,dc=spring,dc=org +objectclass: top +objectclass: groupOfUniqueNames +cn: ROLE_USER +uniqueMember: cn=Some Person,ou=company1,c=Sweden,dc=spring,dc=org +uniqueMember: cn=Some Person2,ou=company1,c=Sweden,dc=spring,dc=org +uniqueMember: cn=Some Person,ou=company1,c=Sweden,dc=spring,dc=org +uniqueMember: cn=Some Person3,ou=company1,c=Sweden,dc=spring,dc=org + +dn: cn=ROLE_ADMIN,ou=groups,dc=spring,dc=org +objectclass: top +objectclass: groupOfUniqueNames +cn: ROLE_ADMIN +uniqueMember: cn=Some Person2,ou=company1,c=Sweden,dc=spring,dc=org + +dn: c=Sweden,dc=spring,dc=org +objectclass: top +objectclass: country +c: Sweden +description: The country of Sweden + +dn: ou=company1,c=Sweden,dc=spring,dc=org +objectclass: top +objectclass: organizationalUnit +ou: company1 +description: First company in Sweden + +dn: cn=Some Person,ou=company1,c=Sweden,dc=spring,dc=org +objectclass: top +objectclass: person +objectclass: organizationalPerson +objectclass: inetOrgPerson +uid: some.person +userPassword: password +cn: Some Person +sn: Person +description: Sweden, Company1, Some Person +telephoneNumber: +46 555-123456 + +dn: cn=Some Person2,ou=company1,c=Sweden,dc=spring,dc=org +objectclass: top +objectclass: person +objectclass: organizationalPerson +objectclass: inetOrgPerson +uid: some.person2 +userPassword: password +cn: Some Person2 +sn: Person2 +description: Sweden, Company1, Some Person2 +telephoneNumber: +46 555-654321 + +dn: cn=Some Person3,ou=company1,c=Sweden,dc=spring,dc=org +objectclass: top +objectclass: person +objectclass: organizationalPerson +objectclass: inetOrgPerson +uid: some.person3 +userPassword: password +cn: Some Person3 +sn: Person3 +description: Sweden, Company1, Some Person3 +telephoneNumber: +46 555-123654 + +dn: cn=Some Person4,ou=company1,c=Sweden,dc=spring,dc=org +objectclass: top +objectclass: person +objectclass: organizationalPerson +objectclass: inetOrgPerson +uid: some.person4 +userPassword: password +cn: Some Person +sn: Person +description: Sweden, Company1, Some Person +telephoneNumber: +46 555-456321 diff --git a/spring-boot-dependencies/pom.xml b/spring-boot-dependencies/pom.xml index 821a73a217..26f1934270 100644 --- a/spring-boot-dependencies/pom.xml +++ b/spring-boot-dependencies/pom.xml @@ -181,6 +181,7 @@ 2.1.0.RELEASE 8.5.6 1.4.8.Final + 3.2.0 9f96c74 0.32 1.6.3 @@ -335,6 +336,11 @@ spring-boot-starter-data-jpa 2.0.0.BUILD-SNAPSHOT + + org.springframework.boot + spring-boot-starter-data-ldap + 1.5.0.BUILD-SNAPSHOT + org.springframework.boot spring-boot-starter-data-mongodb @@ -784,6 +790,11 @@ java-statsd-client ${statsd-client.version} + + com.unboundid + unboundid-ldapsdk + ${unboundid-ldapsdk.version} + com.zaxxer HikariCP 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 ed291ef1df..dcec82c9aa 100644 --- a/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc +++ b/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc @@ -314,6 +314,20 @@ content into your application; rather pick only the properties that you need. spring.jersey.servlet.load-on-startup=-1 # Load on startup priority of the Jersey servlet. spring.jersey.type=servlet # Jersey integration type. + # SPRING LDAP ({sc-spring-boot-autoconfigure}/ldap/LdapProperties.{sc-ext}[LdapProperties]) + spring.ldap.urls= # LDAP url of the server. + spring.ldap.base= # Base suffix from which all operations should originate. + spring.ldap.username= # Login user of the server. + spring.ldap.password= # Login password of the server. + 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.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= # Schema (LDIF) script resource reference. + # SPRING MOBILE DEVICE VIEWS ({sc-spring-boot-autoconfigure}/mobile/DeviceDelegatingViewResolverAutoConfiguration.{sc-ext}[DeviceDelegatingViewResolverAutoConfiguration]) spring.mobile.devicedelegatingviewresolver.enable-fallback=false # Enable support for fallback resolution. spring.mobile.devicedelegatingviewresolver.enabled=false # Enable device view resolver. 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 8b48cbc459..8ce2cee5f4 100644 --- a/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc +++ b/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc @@ -3203,11 +3203,12 @@ https://github.com/spring-projects/spring-data-elasticsearch/[Elasticsearch], http://projects.spring.io/spring-data-solr/[Solr], http://projects.spring.io/spring-data-redis/[Redis], http://projects.spring.io/spring-data-gemfire/[Gemfire], +http://projects.spring.io/spring-data-cassandra/[Cassandra], http://projects.spring.io/spring-data-couchbase/[Couchbase] and -http://projects.spring.io/spring-data-cassandra/[Cassandra]. +http://projects.spring.io/spring-data-ldap/[LDAP]. Spring Boot provides auto-configuration for Redis, MongoDB, Neo4j, Elasticsearch, Solr -and Cassandra; you can make use of the other projects, but you will need to configure -them yourself. Refer to the appropriate reference documentation at +Cassandra, Couchbase and LDAP; you can make use of the other projects, but you will need +to configure them yourself. Refer to the appropriate reference documentation at http://projects.spring.io/spring-data[projects.spring.io/spring-data]. @@ -3746,6 +3747,7 @@ TIP: For complete details of Spring Data Cassandra, refer to their http://docs.spring.io/spring-data/cassandra/docs/[reference documentation]. + [[boot-features-couchbase]] === Couchbase http://www.couchbase.com/[Couchbase] is an open-source, distributed multi-model NoSQL @@ -3853,6 +3855,89 @@ implementation. +[[boot-features-ldap]] +=== LDAP +https://en.wikipedia.org/wiki/Lightweight_Directory_Access_Protocol[LDAP] (Lightweight +Directory Access Protocol) is an is an open, vendor-neutral, industry standard application +protocol for accessing and maintaining distributed directory information services over an +IP network. Spring Boot offers auto-configuration for any compliant LDAP server as well +as support for the embedded in-memory LDAP server from +https://www.ldap.com/unboundid-ldap-sdk-for-java[Unbounded]. + +LDAP abstractions are provided by +https://github.com/spring-projects/spring-data-ldap[Spring Data LDAP]. +There is a `spring-boot-starter-data-ldap` '`Starter`' for collecting the dependencies in +a convenient way. + + + +[[boot-features-ldap-connecting]] +==== Connecting to an LDAP server +To connect to an LDAP server make sure you declare a dependency on the +`spring-boot-starter-data-ldap` '`Starter`' or `spring-ldap-core` then declare the +URLs of your server in your application.properties: + +[source,properties,indent=0] +---- + spring.ldap.urls=ldap://myserver:1235 + spring.ldap.username=admin + spring.ldap.password=secret +---- + +If you need to customize connection settings you can use the `spring.ldap.base` and +`spring.ldap.base-environment` properties. + + + +[[boot-features-ldap-spring-data-repositories]] +==== Spring Data LDAP repositories +Spring Data includes repository support for LDAP. For complete details of Spring +Data LDAP, refer to their +http://docs.spring.io/spring-data/ldap/docs/1.0.x/reference/html/[reference documentation]. + +You can also inject an auto-configured `LdapTemplate` instance as you would with any +other Spring Bean. + + +[source,java,indent=0] +---- + @Component + public class MyBean { + + private final LdapTemplate template; + + @Autowired + public MyBean(LdapTemplate template) { + this.template = template; + } + + // ... + + } +---- + + + +[[boot-features-ldap-embedded]] +==== Embedded in-memory LDAP server +For testing purposes Spring Boot supports auto-configuration of an in-memory LDAP server +from https://www.ldap.com/unboundid-ldap-sdk-for-java[Unbounded]. To configure the server +add a dependency to `com.unboundid:unboundid-ldapsdk` and declare a `base-dn` property: + +[source,properties,indent=0] +---- + spring.ldap.embedded.base-dn=dc=spring,dc=io +---- + +By default the server will start on a random port and the trigger the regular LDAP support +(there is not need to specify a `spring.ldap.urls` property). + +If there is a `schema.ldif` file on your classpath it will be used to initialize the +server. You can also use the `spring.ldap.embedded.ldif` property if you want to load +the initialization script from a different resource. + + + [[boot-features-caching]] == Caching The Spring Framework provides support for transparently adding caching to an application. diff --git a/spring-boot-samples/pom.xml b/spring-boot-samples/pom.xml index 6a07c18533..14e2069f7e 100644 --- a/spring-boot-samples/pom.xml +++ b/spring-boot-samples/pom.xml @@ -37,6 +37,7 @@ spring-boot-sample-data-couchbase spring-boot-sample-data-elasticsearch spring-boot-sample-data-jpa + spring-boot-sample-data-ldap spring-boot-sample-data-mongodb spring-boot-sample-data-neo4j spring-boot-sample-data-redis @@ -112,6 +113,7 @@ spring-boot-sample-websocket-undertow spring-boot-sample-webservices spring-boot-sample-xml + spring-boot-sample-hypermedia-ui-secure diff --git a/spring-boot-samples/spring-boot-sample-data-ldap/pom.xml b/spring-boot-samples/spring-boot-sample-data-ldap/pom.xml new file mode 100644 index 0000000000..7c5e939c8d --- /dev/null +++ b/spring-boot-samples/spring-boot-sample-data-ldap/pom.xml @@ -0,0 +1,50 @@ + + + 4.0.0 + + + org.springframework.boot + spring-boot-samples + 2.0.0.BUILD-SNAPSHOT + + spring-boot-sample-data-ldap + Spring Boot Data LDAP Sample + Spring Boot Data LDAP Sample + http://projects.spring.io/spring-boot/ + + Pivotal Software, Inc. + http://www.spring.io + + + ${basedir}/../.. + + + + + com.unboundid + unboundid-ldapsdk + + + org.springframework.boot + spring-boot-starter + + + org.springframework.boot + spring-boot-starter-data-ldap + + + + org.springframework.boot + spring-boot-starter-test + test + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + diff --git a/spring-boot-samples/spring-boot-sample-data-ldap/src/main/java/sample/data/ldap/Person.java b/spring-boot-samples/spring-boot-sample-data-ldap/src/main/java/sample/data/ldap/Person.java new file mode 100644 index 0000000000..93ef7b3a92 --- /dev/null +++ b/spring-boot-samples/spring-boot-sample-data-ldap/src/main/java/sample/data/ldap/Person.java @@ -0,0 +1,39 @@ +/* + * Copyright 2012-2017 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 + * + * http://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 sample.data.ldap; + +import javax.naming.Name; + +import org.springframework.ldap.odm.annotations.Attribute; +import org.springframework.ldap.odm.annotations.Entry; +import org.springframework.ldap.odm.annotations.Id; + +@Entry(objectClasses = { "person", "top" }) +public class Person { + + @Id + private Name dn; + + @Attribute(name = "telephoneNumber") + private String phone; + + @Override + public String toString() { + return String.format("Customer[dn=%s, phone='%s']", this.dn, this.phone); + } + +} diff --git a/spring-boot-samples/spring-boot-sample-data-ldap/src/main/java/sample/data/ldap/PersonRepository.java b/spring-boot-samples/spring-boot-sample-data-ldap/src/main/java/sample/data/ldap/PersonRepository.java new file mode 100644 index 0000000000..526f379d96 --- /dev/null +++ b/spring-boot-samples/spring-boot-sample-data-ldap/src/main/java/sample/data/ldap/PersonRepository.java @@ -0,0 +1,25 @@ +/* + * Copyright 2012-2017 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 + * + * http://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 sample.data.ldap; + +import org.springframework.data.ldap.repository.LdapRepository; + +public interface PersonRepository extends LdapRepository { + + Person findByPhone(String phone); + +} diff --git a/spring-boot-samples/spring-boot-sample-data-ldap/src/main/java/sample/data/ldap/SampleLdapApplication.java b/spring-boot-samples/spring-boot-sample-data-ldap/src/main/java/sample/data/ldap/SampleLdapApplication.java new file mode 100644 index 0000000000..294f08954f --- /dev/null +++ b/spring-boot-samples/spring-boot-sample-data-ldap/src/main/java/sample/data/ldap/SampleLdapApplication.java @@ -0,0 +1,59 @@ +/* + * Copyright 2012-2017 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 + * + * http://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 sample.data.ldap; + +import org.springframework.boot.CommandLineRunner; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class SampleLdapApplication implements CommandLineRunner { + + private final PersonRepository repository; + + public SampleLdapApplication(PersonRepository repository) { + this.repository = repository; + } + + @Override + public void run(String... args) throws Exception { + + // fetch all people + System.out.println("People found with findAll():"); + System.out.println("-------------------------------"); + for (Person person : this.repository.findAll()) { + System.out.println(person); + } + System.out.println(); + + // fetch an individual person + System.out.println("Person found with findByPhone('+46 555-123456'):"); + System.out.println("--------------------------------"); + System.out.println(this.repository.findByPhone("+46 555-123456")); + // + // System.out.println("Customers found with findByLastName('Smith'):"); + // System.out.println("--------------------------------"); + // for (Customer customer : this.repository.findByLastName("Smith")) { + // System.out.println(customer); + // } + } + + public static void main(String[] args) throws Exception { + SpringApplication.run(SampleLdapApplication.class, args).close(); + } + +} diff --git a/spring-boot-samples/spring-boot-sample-data-ldap/src/main/resources/application.properties b/spring-boot-samples/spring-boot-sample-data-ldap/src/main/resources/application.properties new file mode 100644 index 0000000000..b574703f0f --- /dev/null +++ b/spring-boot-samples/spring-boot-sample-data-ldap/src/main/resources/application.properties @@ -0,0 +1 @@ +spring.ldap.embedded.base-dn=dc=spring,dc=org diff --git a/spring-boot-samples/spring-boot-sample-data-ldap/src/main/resources/schema.ldif b/spring-boot-samples/spring-boot-sample-data-ldap/src/main/resources/schema.ldif new file mode 100644 index 0000000000..bb97e4a3c5 --- /dev/null +++ b/spring-boot-samples/spring-boot-sample-data-ldap/src/main/resources/schema.ldif @@ -0,0 +1,62 @@ +dn: dc=spring,dc=org +objectclass: top +objectclass: domain +objectclass: extensibleObject +dc: spring + +dn: ou=groups,dc=spring,dc=org +objectclass: top +objectclass: organizationalUnit +ou: groups + +dn: cn=ROLE_USER,ou=groups,dc=spring,dc=org +objectclass: top +objectclass: groupOfUniqueNames +cn: ROLE_USER +uniqueMember: cn=Some Person,ou=company1,c=Sweden,dc=spring,dc=org +uniqueMember: cn=Some Person2,ou=company1,c=Sweden,dc=spring,dc=org +uniqueMember: cn=Some Person,ou=company1,c=Sweden,dc=spring,dc=org +uniqueMember: cn=Some Person3,ou=company1,c=Sweden,dc=spring,dc=org + +dn: cn=ROLE_ADMIN,ou=groups,dc=spring,dc=org +objectclass: top +objectclass: groupOfUniqueNames +cn: ROLE_ADMIN +uniqueMember: cn=Some Person2,ou=company1,c=Sweden,dc=spring,dc=org + +dn: c=Sweden,dc=spring,dc=org +objectclass: top +objectclass: country +c: Sweden +description: The country of Sweden + +dn: ou=company1,c=Sweden,dc=spring,dc=org +objectclass: top +objectclass: organizationalUnit +ou: company1 +description: First company in Sweden + +dn: cn=Alice Smith,ou=company1,c=Sweden,dc=spring,dc=org +objectclass: top +objectclass: person +objectclass: organizationalPerson +objectclass: inetOrgPerson +uid: alice.smith +userPassword: password +cn: Alice Smith +sn: Alice Smith +description: Sweden, Company1, Alice Smith +telephoneNumber: +46 555-123456 + +dn: cn=Bob Smith,ou=company1,c=Sweden,dc=spring,dc=org +objectclass: top +objectclass: person +objectclass: organizationalPerson +objectclass: inetOrgPerson +uid: bob.smith +userPassword: password +cn: Bob Smith +sn: Bob Smith +description: Sweden, Company1, Some Person2 +telephoneNumber: +46 555-654321 + diff --git a/spring-boot-samples/spring-boot-sample-data-ldap/src/test/java/sample/data/ldap/SampleLdapApplicationTests.java b/spring-boot-samples/spring-boot-sample-data-ldap/src/test/java/sample/data/ldap/SampleLdapApplicationTests.java new file mode 100644 index 0000000000..4ab05c0670 --- /dev/null +++ b/spring-boot-samples/spring-boot-sample-data-ldap/src/test/java/sample/data/ldap/SampleLdapApplicationTests.java @@ -0,0 +1,47 @@ +/* + * Copyright 2012-2017 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 + * + * http://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 sample.data.ldap; + +import org.junit.ClassRule; +import org.junit.Test; +import org.junit.runner.RunWith; + +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.rule.OutputCapture; +import org.springframework.test.context.junit4.SpringRunner; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link SampleLdapApplication}. + * + * @author Phillip Webb + */ +@RunWith(SpringRunner.class) +@SpringBootTest +public class SampleLdapApplicationTests { + + @ClassRule + public static OutputCapture outputCapture = new OutputCapture(); + + @Test + public void testDefaultSettings() throws Exception { + String output = outputCapture.toString(); + assertThat(output).contains("cn=Alice Smith"); + } + +} diff --git a/spring-boot-samples/spring-boot-sample-devtools/src/test/java/sample/devtools/SampleDevToolsApplicationIntegrationTests.java b/spring-boot-samples/spring-boot-sample-devtools/src/test/java/sample/devtools/SampleDevToolsApplicationIntegrationTests.java index 8e5937b4fe..997e74020b 100644 --- a/spring-boot-samples/spring-boot-sample-devtools/src/test/java/sample/devtools/SampleDevToolsApplicationIntegrationTests.java +++ b/spring-boot-samples/spring-boot-sample-devtools/src/test/java/sample/devtools/SampleDevToolsApplicationIntegrationTests.java @@ -60,4 +60,11 @@ public class SampleDevToolsApplicationIntegrationTests { assertThat(entity.getBody()).contains("public file"); } + @Test + public void testClassResource() throws Exception { + ResponseEntity entity = this.restTemplate + .getForEntity("/application.properties", String.class); + assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.NOT_FOUND); + } + } diff --git a/spring-boot-samples/spring-boot-sample-hypermedia-ui-secure/pom.xml b/spring-boot-samples/spring-boot-sample-hypermedia-ui-secure/pom.xml new file mode 100644 index 0000000000..2e53dc4b89 --- /dev/null +++ b/spring-boot-samples/spring-boot-sample-hypermedia-ui-secure/pom.xml @@ -0,0 +1,53 @@ + + + + spring-boot-samples + org.springframework.boot + 1.5.0.BUILD-SNAPSHOT + + 4.0.0 + spring-boot-sample-hypermedia-ui-secure + Spring Boot Hypermedia UI Secure Sample + Spring Boot Hypermedia UI Secure Sample + + ${basedir}/../.. + + + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-actuator + + + org.springframework.boot + spring-boot-starter-security + + + org.springframework.boot + spring-boot-starter-hateoas + + + org.springframework.boot + spring-boot-actuator-docs + + + + org.springframework.boot + spring-boot-starter-test + test + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + diff --git a/spring-boot-samples/spring-boot-sample-hypermedia-ui-secure/src/main/java/sample/hypermedia/ui/secure/SampleHypermediaUiSecureApplication.java b/spring-boot-samples/spring-boot-sample-hypermedia-ui-secure/src/main/java/sample/hypermedia/ui/secure/SampleHypermediaUiSecureApplication.java new file mode 100644 index 0000000000..476bf446af --- /dev/null +++ b/spring-boot-samples/spring-boot-sample-hypermedia-ui-secure/src/main/java/sample/hypermedia/ui/secure/SampleHypermediaUiSecureApplication.java @@ -0,0 +1,29 @@ +/* + * Copyright 2012-2017 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 + * + * http://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 sample.hypermedia.ui.secure; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class SampleHypermediaUiSecureApplication { + + public static void main(String[] args) { + SpringApplication.run(SampleHypermediaUiSecureApplication.class, args); + } + +} diff --git a/spring-boot-samples/spring-boot-sample-hypermedia-ui-secure/src/main/resources/static/index.html b/spring-boot-samples/spring-boot-sample-hypermedia-ui-secure/src/main/resources/static/index.html new file mode 100644 index 0000000000..66a41f708c --- /dev/null +++ b/spring-boot-samples/spring-boot-sample-hypermedia-ui-secure/src/main/resources/static/index.html @@ -0,0 +1,5 @@ + + +

Hello World!

+ + \ No newline at end of file diff --git a/spring-boot-samples/spring-boot-sample-hypermedia-ui-secure/src/test/java/sample/hypermedia/ui/secure/SampleHypermediaUiSecureApplicationTests.java b/spring-boot-samples/spring-boot-sample-hypermedia-ui-secure/src/test/java/sample/hypermedia/ui/secure/SampleHypermediaUiSecureApplicationTests.java new file mode 100644 index 0000000000..3c043ff8ae --- /dev/null +++ b/spring-boot-samples/spring-boot-sample-hypermedia-ui-secure/src/test/java/sample/hypermedia/ui/secure/SampleHypermediaUiSecureApplicationTests.java @@ -0,0 +1,62 @@ +/* + * Copyright 2012-2017 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 + * + * http://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 sample.hypermedia.ui.secure; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.web.client.TestRestTemplate; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.test.context.junit4.SpringRunner; + +import static org.assertj.core.api.Assertions.assertThat; + +@RunWith(SpringRunner.class) +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, properties = { + "endpoints.env.sensitive=false" }) +public class SampleHypermediaUiSecureApplicationTests { + + @Autowired + private TestRestTemplate restTemplate; + + @Test + public void links() { + String response = this.restTemplate.getForObject("/actuator", String.class); + assertThat(response).contains("\"_links\":"); + } + + @Test + public void testInSecureNestedPath() throws Exception { + ResponseEntity entity = this.restTemplate.getForEntity("/env", + String.class); + assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK); + ResponseEntity user = this.restTemplate.getForEntity("/env/user", + String.class); + assertThat(user.getStatusCode()).isEqualTo(HttpStatus.OK); + assertThat(user.getBody()).contains("{\"user\":"); + } + + @Test + public void testSecurePath() throws Exception { + ResponseEntity entity = this.restTemplate.getForEntity("/metrics", + String.class); + assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.UNAUTHORIZED); + } +} diff --git a/spring-boot-samples/spring-boot-sample-hypermedia-ui-secure/src/test/java/sample/hypermedia/ui/secure/SampleHypermediaUiSecureApplicationWithContextPathTests.java b/spring-boot-samples/spring-boot-sample-hypermedia-ui-secure/src/test/java/sample/hypermedia/ui/secure/SampleHypermediaUiSecureApplicationWithContextPathTests.java new file mode 100644 index 0000000000..cd921fe209 --- /dev/null +++ b/spring-boot-samples/spring-boot-sample-hypermedia-ui-secure/src/test/java/sample/hypermedia/ui/secure/SampleHypermediaUiSecureApplicationWithContextPathTests.java @@ -0,0 +1,52 @@ +/* + * Copyright 2012-2017 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 + * + * http://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 sample.hypermedia.ui.secure; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.web.client.TestRestTemplate; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.test.context.junit4.SpringRunner; + +import static org.assertj.core.api.Assertions.assertThat; + +@RunWith(SpringRunner.class) +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, properties = { + "management.context-path=/admin" }) +public class SampleHypermediaUiSecureApplicationWithContextPathTests { + + @Autowired + private TestRestTemplate restTemplate; + + @Test + public void links() { + String response = this.restTemplate.getForObject("/admin", String.class); + assertThat(response).contains("\"_links\":"); + } + + @Test + public void testSecurePath() throws Exception { + ResponseEntity entity = this.restTemplate.getForEntity("/admin/metrics", + String.class); + assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.UNAUTHORIZED); + } + +} diff --git a/spring-boot-starters/pom.xml b/spring-boot-starters/pom.xml index bf3177c937..1cd0f43dfd 100644 --- a/spring-boot-starters/pom.xml +++ b/spring-boot-starters/pom.xml @@ -32,6 +32,7 @@ spring-boot-starter-data-couchbase spring-boot-starter-data-elasticsearch spring-boot-starter-data-jpa + spring-boot-starter-data-ldap spring-boot-starter-data-mongodb spring-boot-starter-data-neo4j spring-boot-starter-data-redis diff --git a/spring-boot-starters/spring-boot-starter-data-ldap/pom.xml b/spring-boot-starters/spring-boot-starter-data-ldap/pom.xml new file mode 100644 index 0000000000..6bd40e5e42 --- /dev/null +++ b/spring-boot-starters/spring-boot-starter-data-ldap/pom.xml @@ -0,0 +1,53 @@ + + + 4.0.0 + + spring-boot-starters + org.springframework.boot + 2.0.0.BUILD-SNAPSHOT + + spring-boot-starter-data-ldap + Spring Boot Data LDAP Starter + Starter for using Spring Data LDAP + http://projects.spring.io/spring-boot/ + + Pivotal Software, Inc. + http://www.spring.io + + + ${basedir}/../.. + + + + org.springframework.boot + spring-boot-starter + + + org.springframework.data + spring-data-ldap + + + + + + org.basepom.maven + duplicate-finder-maven-plugin + + + duplicate-dependencies + validate + + check + + + + changelog.txt + + + + + + + + diff --git a/spring-boot-starters/spring-boot-starter-data-ldap/src/main/resources/META-INF/spring.provides b/spring-boot-starters/spring-boot-starter-data-ldap/src/main/resources/META-INF/spring.provides new file mode 100644 index 0000000000..510e85a80c --- /dev/null +++ b/spring-boot-starters/spring-boot-starter-data-ldap/src/main/resources/META-INF/spring.provides @@ -0,0 +1 @@ +provides: spring-ldap-core \ No newline at end of file