diff --git a/pom.xml b/pom.xml
index 5adbbcb7e3..9243770060 100644
--- a/pom.xml
+++ b/pom.xml
@@ -137,6 +137,7 @@
spring-jooq
spring-jpa
spring-katharsis
+ spring-ldap
spring-mockito
spring-mvc-email
spring-mvc-forms
diff --git a/spring-ldap/.gitignore b/spring-ldap/.gitignore
new file mode 100644
index 0000000000..83c05e60c8
--- /dev/null
+++ b/spring-ldap/.gitignore
@@ -0,0 +1,13 @@
+*.class
+
+#folders#
+/target
+/neoDb*
+/data
+/src/main/webapp/WEB-INF/classes
+*/META-INF/*
+
+# Packaged files #
+*.jar
+*.war
+*.ear
\ No newline at end of file
diff --git a/spring-ldap/README.md b/spring-ldap/README.md
new file mode 100644
index 0000000000..56ffdee617
--- /dev/null
+++ b/spring-ldap/README.md
@@ -0,0 +1,5 @@
+=========
+
+## Spring LDAP Example Project
+- (http://www.baeldung.com/spring-ldap-overview/)
+
diff --git a/spring-ldap/pom.xml b/spring-ldap/pom.xml
new file mode 100644
index 0000000000..55014897c4
--- /dev/null
+++ b/spring-ldap/pom.xml
@@ -0,0 +1,181 @@
+
+
+ 4.0.0
+
+ com.baeldung
+ spring-ldap
+ 0.1-SNAPSHOT
+ jar
+
+
+ 4.12
+ 2.19.1
+ 3.6.1
+ 2.3.1.RELEASE
+ 1.7.22
+ 1.1.8
+ 4.3.6.RELEASE
+ 1.5.5
+ 0.9.15
+ 1.3
+
+
+
+ spring-ldap
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+ ${maven-compiler-plugin.version}
+
+
+ 1.8
+
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+ ${maven-surefire-plugin.version}
+
+
+ **/*IntegrationTest.java
+ **/*LiveTest.java
+
+
+
+
+
+
+
+
+
+ org.springframework.ldap
+ spring-ldap-core
+ ${spring-ldap.version}
+
+
+ commons-logging
+ commons-logging
+
+
+
+
+
+ org.slf4j
+ jcl-over-slf4j
+ ${jcl.slf4j.version}
+
+
+
+ ch.qos.logback
+ logback-classic
+ ${logback.version}
+
+
+ org.springframework
+ spring-context
+ ${spring-context.version}
+
+
+
+
+
+
+ junit
+ junit
+ ${junit.version}
+ test
+
+
+
+ org.hamcrest
+ hamcrest-core
+ ${org.hamcrest.version}
+ test
+
+
+ org.hamcrest
+ hamcrest-library
+ ${org.hamcrest.version}
+ test
+
+
+
+
+ org.springframework.ldap
+ spring-ldap-test
+ ${spring-ldap.version}
+ test
+
+
+
+
+ org.apache.directory.server
+ apacheds-core
+ ${apacheds.version}
+ test
+
+
+ org.apache.directory.server
+ apacheds-core-entry
+ ${apacheds.version}
+ test
+
+
+ org.apache.directory.server
+ apacheds-protocol-shared
+ ${apacheds.version}
+ test
+
+
+ org.apache.directory.server
+ apacheds-protocol-ldap
+ ${apacheds.version}
+ test
+
+
+ org.apache.directory.server
+ apacheds-server-jndi
+ ${apacheds.version}
+ test
+
+
+ org.apache.directory.shared
+ shared-ldap
+ ${shared-ldap.version}
+ test
+
+
+
+
+
+
+ live
+
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+
+
+ integration-test
+
+ test
+
+
+
+ **/*IntegrationTest.java
+
+
+ **/*LiveTest.java
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/spring-ldap/src/main/java/com/baeldung/ldap/client/LdapClient.java b/spring-ldap/src/main/java/com/baeldung/ldap/client/LdapClient.java
new file mode 100644
index 0000000000..8c71007b27
--- /dev/null
+++ b/spring-ldap/src/main/java/com/baeldung/ldap/client/LdapClient.java
@@ -0,0 +1,80 @@
+package com.baeldung.ldap.client;
+
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.Base64;
+import java.util.List;
+
+import javax.naming.Name;
+import javax.naming.NamingException;
+import javax.naming.directory.Attributes;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.core.env.Environment;
+import org.springframework.ldap.core.AttributesMapper;
+import org.springframework.ldap.core.ContextSource;
+import org.springframework.ldap.core.DirContextAdapter;
+import org.springframework.ldap.core.DirContextOperations;
+import org.springframework.ldap.core.LdapTemplate;
+import org.springframework.ldap.support.LdapNameBuilder;
+
+public class LdapClient {
+
+ @Autowired
+ private Environment env;
+
+ @Autowired
+ private ContextSource contextSource;
+
+ @Autowired
+ private LdapTemplate ldapTemplate;
+
+ public void authenticate(final String username, final String password) {
+ contextSource.getContext("cn=" + username + ",ou=users," + env.getRequiredProperty("ldap.partitionSuffix"), password);
+ }
+
+ public List search(final String username) {
+ List users = ldapTemplate.search("ou=users", "cn=" + username, new AttributesMapper() {
+ public String mapFromAttributes(Attributes attrs) throws NamingException {
+ return (String) attrs.get("cn").get();
+ }
+ });
+ return users;
+ }
+
+ public void create(final String username, final String password) {
+ Name dn = LdapNameBuilder.newInstance().add("ou", "users").add("cn", username).build();
+ DirContextAdapter context = new DirContextAdapter(dn);
+
+ context.setAttributeValues("objectclass", new String[] { "top", "person", "organizationalPerson", "inetOrgPerson" });
+ context.setAttributeValue("cn", username);
+ context.setAttributeValue("sn", username);
+ context.setAttributeValue("userPassword", digestSHA(password));
+
+ ldapTemplate.bind(context);
+ }
+
+ public void modify(final String username, final String password) {
+ Name dn = LdapNameBuilder.newInstance().add("ou", "users").add("cn", username).build();
+ DirContextOperations context = ldapTemplate.lookupContext(dn);
+
+ context.setAttributeValues("objectclass", new String[] { "top", "person", "organizationalPerson", "inetOrgPerson" });
+ context.setAttributeValue("cn", username);
+ context.setAttributeValue("sn", username);
+ context.setAttributeValue("userPassword", digestSHA(password));
+
+ ldapTemplate.modifyAttributes(context);
+ }
+
+ private String digestSHA(final String password) {
+ String base64;
+ try {
+ MessageDigest digest = MessageDigest.getInstance("SHA");
+ digest.update(password.getBytes());
+ base64 = Base64.getEncoder().encodeToString(digest.digest());
+ } catch (NoSuchAlgorithmException e) {
+ throw new RuntimeException(e);
+ }
+ return "{SHA}" + base64;
+ }
+}
diff --git a/spring-ldap/src/main/java/com/baeldung/ldap/javaconfig/AppConfig.java b/spring-ldap/src/main/java/com/baeldung/ldap/javaconfig/AppConfig.java
new file mode 100644
index 0000000000..8572e5d1be
--- /dev/null
+++ b/spring-ldap/src/main/java/com/baeldung/ldap/javaconfig/AppConfig.java
@@ -0,0 +1,44 @@
+package com.baeldung.ldap.javaconfig;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Profile;
+import org.springframework.context.annotation.PropertySource;
+import org.springframework.core.env.Environment;
+import org.springframework.ldap.core.LdapTemplate;
+import org.springframework.ldap.core.support.LdapContextSource;
+
+import com.baeldung.ldap.client.LdapClient;
+
+@Configuration
+@PropertySource("classpath:application.properties")
+@ComponentScan(basePackages = { "com.baeldung.ldap.*" })
+@Profile("default")
+public class AppConfig {
+
+ @Autowired
+ private Environment env;
+
+ @Bean
+ public LdapContextSource contextSource() {
+ LdapContextSource contextSource = new LdapContextSource();
+ contextSource.setUrl(env.getRequiredProperty("ldap.url"));
+ contextSource.setBase(env.getRequiredProperty("ldap.partitionSuffix"));
+ contextSource.setUserDn(env.getRequiredProperty("ldap.principal"));
+ contextSource.setPassword(env.getRequiredProperty("ldap.password"));
+ return contextSource;
+ }
+
+ @Bean
+ public LdapTemplate ldapTemplate() {
+ return new LdapTemplate(contextSource());
+ }
+
+ @Bean
+ public LdapClient ldapClient() {
+ return new LdapClient();
+ }
+
+}
diff --git a/spring-ldap/src/main/resources/application.properties b/spring-ldap/src/main/resources/application.properties
new file mode 100644
index 0000000000..670fb79234
--- /dev/null
+++ b/spring-ldap/src/main/resources/application.properties
@@ -0,0 +1,6 @@
+ldap.partitionSuffix=dc=example,dc=com
+ldap.partition=example
+ldap.principal=uid=admin,ou=system
+ldap.password=secret
+ldap.port=18889
+ldap.url=ldap://localhost:18889
\ No newline at end of file
diff --git a/spring-ldap/src/main/resources/logback.xml b/spring-ldap/src/main/resources/logback.xml
new file mode 100644
index 0000000000..788096686a
--- /dev/null
+++ b/spring-ldap/src/main/resources/logback.xml
@@ -0,0 +1,15 @@
+
+
+
+
+ web - %date [%thread] %-5level %logger{36} -
+ %message%n
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/spring-ldap/src/test/java/com/baeldung/ldap/client/LdapClientLiveTest.java b/spring-ldap/src/test/java/com/baeldung/ldap/client/LdapClientLiveTest.java
new file mode 100644
index 0000000000..b65588dc38
--- /dev/null
+++ b/spring-ldap/src/test/java/com/baeldung/ldap/client/LdapClientLiveTest.java
@@ -0,0 +1,63 @@
+package com.baeldung.ldap.client;
+
+import java.util.List;
+
+import org.hamcrest.Matchers;
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.ldap.AuthenticationException;
+import org.springframework.test.context.ActiveProfiles;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+import org.springframework.test.context.support.AnnotationConfigContextLoader;
+
+import com.baeldung.ldap.javaconfig.TestConfig;
+
+@RunWith(SpringJUnit4ClassRunner.class)
+@ActiveProfiles("testlive")
+@ContextConfiguration(classes = { TestConfig.class }, loader = AnnotationConfigContextLoader.class)
+public class LdapClientLiveTest {
+
+ private static final String USER2 = "TEST02";
+ private static final String USER3 = "TEST03";
+ private static final String USER4 = "TEST04";
+
+ private static final String USER2_PWD = "TEST02";
+ private static final String USER3_PWD = "TEST03";
+ private static final String USER4_PWD = "TEST04";
+
+ private static final String SEARCH_STRING = "TEST*";
+
+ @Autowired
+ private LdapClient ldapClient;
+
+ @Test
+ public void givenLdapClient_whenCorrectCredentials_thenSuccessfulLogin() {
+ ldapClient.authenticate(USER3, USER3_PWD);
+ }
+
+ @Test(expected = AuthenticationException.class)
+ public void givenLdapClient_whenIncorrectCredentials_thenFailedLogin() {
+ ldapClient.authenticate(USER3, USER2_PWD);
+ }
+
+ @Test
+ public void givenLdapClient_whenCorrectSearchFilter_thenEntriesReturned() {
+ List users = ldapClient.search(SEARCH_STRING);
+ Assert.assertThat(users, Matchers.containsInAnyOrder(USER2, USER3));
+ }
+
+ @Test
+ public void givenLdapClientNotExists_whenDataProvided_thenNewUserCreated() {
+ ldapClient.create(USER4, USER4_PWD);
+ ldapClient.authenticate(USER4, USER4_PWD);
+ }
+
+ @Test
+ public void givenLdapClientExists_whenDataProvided_thenExistingUserModified() {
+ ldapClient.modify(USER2, USER3_PWD);
+ ldapClient.authenticate(USER2, USER3_PWD);
+ }
+}
diff --git a/spring-ldap/src/test/java/com/baeldung/ldap/javaconfig/TestConfig.java b/spring-ldap/src/test/java/com/baeldung/ldap/javaconfig/TestConfig.java
new file mode 100644
index 0000000000..e2968e977c
--- /dev/null
+++ b/spring-ldap/src/test/java/com/baeldung/ldap/javaconfig/TestConfig.java
@@ -0,0 +1,59 @@
+package com.baeldung.ldap.javaconfig;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Profile;
+import org.springframework.context.annotation.PropertySource;
+import org.springframework.core.env.Environment;
+import org.springframework.core.io.ResourceLoader;
+import org.springframework.ldap.core.LdapTemplate;
+import org.springframework.ldap.core.support.LdapContextSource;
+import org.springframework.ldap.test.TestContextSourceFactoryBean;
+
+import com.baeldung.ldap.client.LdapClient;
+
+@Configuration
+@PropertySource("classpath:test_application.properties")
+@ComponentScan(basePackages = { "com.baeldung.ldap.*" })
+@Profile("testlive")
+public class TestConfig {
+ @Autowired
+ private Environment env;
+
+ @Autowired
+ private ResourceLoader resourceLoader;
+
+ @Bean
+ public TestContextSourceFactoryBean testContextSource() {
+ TestContextSourceFactoryBean contextSource = new TestContextSourceFactoryBean();
+ contextSource.setDefaultPartitionName(env.getRequiredProperty("ldap.partition"));
+ contextSource.setDefaultPartitionSuffix(env.getRequiredProperty("ldap.partitionSuffix"));
+ contextSource.setPrincipal(env.getRequiredProperty("ldap.principal"));
+ contextSource.setPassword(env.getRequiredProperty("ldap.password"));
+ contextSource.setLdifFile(resourceLoader.getResource(env.getRequiredProperty("ldap.ldiffile")));
+ contextSource.setPort(Integer.valueOf(env.getRequiredProperty("ldap.port")));
+ return contextSource;
+ }
+
+ @Bean
+ public LdapContextSource contextSource() {
+ LdapContextSource contextSource = new LdapContextSource();
+ contextSource.setUrl(env.getRequiredProperty("ldap.url"));
+ contextSource.setBase(env.getRequiredProperty("ldap.partitionSuffix"));
+ contextSource.setUserDn(env.getRequiredProperty("ldap.principal"));
+ contextSource.setPassword(env.getRequiredProperty("ldap.password"));
+ return contextSource;
+ }
+
+ @Bean
+ public LdapTemplate ldapTemplate() {
+ return new LdapTemplate(contextSource());
+ }
+
+ @Bean
+ public LdapClient ldapClient() {
+ return new LdapClient();
+ }
+}
diff --git a/spring-ldap/src/test/resources/test.ldif b/spring-ldap/src/test/resources/test.ldif
new file mode 100644
index 0000000000..2344630204
--- /dev/null
+++ b/spring-ldap/src/test/resources/test.ldif
@@ -0,0 +1,24 @@
+version: 1
+dn: ou=users,dc=example,dc=com
+objectClass: organizationalUnit
+objectClass: top
+ou: users
+
+dn: cn=TEST03,ou=users,dc=example,dc=com
+objectClass: inetOrgPerson
+objectClass: organizationalPerson
+objectClass: person
+objectClass: top
+cn: TEST03
+sn: TEST03
+userPassword:: e1NIQX1JbktFOFY2enBpWWdMY0RYQTYzdXZVNjRGZXc9
+
+dn: cn=TEST02,ou=users,dc=example,dc=com
+objectClass: inetOrgPerson
+objectClass: organizationalPerson
+objectClass: person
+objectClass: top
+cn: TEST02
+sn: TEST02
+userPassword:: e1NIQX1uZERKdWNNYnl5a3hWdEkyQzgyRUFlalN1WTQ9
+
diff --git a/spring-ldap/src/test/resources/test_application.properties b/spring-ldap/src/test/resources/test_application.properties
new file mode 100644
index 0000000000..40b90cfdcf
--- /dev/null
+++ b/spring-ldap/src/test/resources/test_application.properties
@@ -0,0 +1,7 @@
+ldap.partitionSuffix=dc=example,dc=com
+ldap.partition=example
+ldap.principal=uid=admin,ou=system
+ldap.password=secret
+ldap.ldiffile=classpath:/test.ldif
+ldap.port=18888
+ldap.url=ldap://localhost:18888
\ No newline at end of file