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 + 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