diff --git a/core-java-modules/core-java-jndi/pom.xml b/core-java-modules/core-java-jndi/pom.xml
index 1728c0b5d9..6b7c4e1359 100644
--- a/core-java-modules/core-java-jndi/pom.xml
+++ b/core-java-modules/core-java-jndi/pom.xml
@@ -41,6 +41,18 @@
h2
${h2.version}
+
+ org.apache.directory.server
+ apacheds-test-framework
+ ${apacheds.version}
+ test
+
+
+ org.assertj
+ assertj-core
+ 3.21.0
+ test
+
@@ -59,6 +71,7 @@
5.0.9.RELEASE
1.4.199
+ 2.0.0.AM26
1.8
1.8
diff --git a/core-java-modules/core-java-jndi/src/test/java/com/baeldung/jndi/ldap/auth/JndiLdapAuthManualTest.java b/core-java-modules/core-java-jndi/src/test/java/com/baeldung/jndi/ldap/auth/JndiLdapAuthManualTest.java
new file mode 100644
index 0000000000..5a675c62c9
--- /dev/null
+++ b/core-java-modules/core-java-jndi/src/test/java/com/baeldung/jndi/ldap/auth/JndiLdapAuthManualTest.java
@@ -0,0 +1,165 @@
+package com.baeldung.jndi.ldap.auth;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatCode;
+import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
+
+import java.util.Hashtable;
+
+import javax.naming.AuthenticationException;
+import javax.naming.Context;
+import javax.naming.NamingEnumeration;
+import javax.naming.directory.Attributes;
+import javax.naming.directory.DirContext;
+import javax.naming.directory.InitialDirContext;
+import javax.naming.directory.SearchControls;
+import javax.naming.directory.SearchResult;
+
+import org.apache.directory.server.annotations.CreateLdapServer;
+import org.apache.directory.server.annotations.CreateTransport;
+import org.apache.directory.server.core.annotations.ApplyLdifFiles;
+import org.apache.directory.server.core.annotations.CreateDS;
+import org.apache.directory.server.core.annotations.CreatePartition;
+import org.apache.directory.server.core.integ.AbstractLdapTestUnit;
+import org.apache.directory.server.core.integ.FrameworkRunner;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(FrameworkRunner.class)
+@CreateLdapServer(transports = { @CreateTransport(protocol = "LDAP", address = "localhost", port = 10390)})
+@CreateDS(
+ allowAnonAccess = false, partitions = {@CreatePartition(name = "TestPartition", suffix = "dc=baeldung,dc=com")})
+@ApplyLdifFiles({"users.ldif"})
+// class marked as manual test, as it has to run independently from the other unit tests in the module
+public class JndiLdapAuthManualTest extends AbstractLdapTestUnit {
+
+ private static void authenticateUser(Hashtable environment) throws Exception {
+ DirContext context = new InitialDirContext(environment);
+ context.close();
+ }
+
+ @Test
+ public void givenPreloadedLDAPUserJoe_whenAuthUserWithCorrectPW_thenAuthSucceeds() throws Exception {
+
+ Hashtable environment = new Hashtable();
+ environment.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
+ environment.put(Context.PROVIDER_URL, "ldap://localhost:10390");
+ environment.put(Context.SECURITY_AUTHENTICATION, "simple");
+
+ environment.put(Context.SECURITY_PRINCIPAL, "cn=Joe Simms,ou=Users,dc=baeldung,dc=com");
+ environment.put(Context.SECURITY_CREDENTIALS, "12345");
+
+ assertThatCode(() -> authenticateUser(environment)).doesNotThrowAnyException();
+ }
+
+ @Test
+ public void givenPreloadedLDAPUserJoe_whenAuthUserWithWrongPW_thenAuthFails() throws Exception {
+
+ Hashtable environment = new Hashtable();
+ environment.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
+ environment.put(Context.PROVIDER_URL, "ldap://localhost:10390");
+ environment.put(Context.SECURITY_AUTHENTICATION, "simple");
+
+ environment.put(Context.SECURITY_PRINCIPAL, "cn=Joe Simms,ou=Users,dc=baeldung,dc=com");
+ environment.put(Context.SECURITY_CREDENTIALS, "wronguserpw");
+
+ assertThatExceptionOfType(AuthenticationException.class).isThrownBy(() -> authenticateUser(environment));
+ }
+
+ @Test
+ public void givenPreloadedLDAPUserJoe_whenSearchAndAuthUserWithCorrectPW_thenAuthSucceeds() throws Exception {
+
+ // first authenticate against LDAP as admin to search up DN of user : Joe Simms
+
+ Hashtable environment = new Hashtable();
+ environment.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
+ environment.put(Context.PROVIDER_URL, "ldap://localhost:10390");
+ environment.put(Context.SECURITY_AUTHENTICATION, "simple");
+ environment.put(Context.SECURITY_PRINCIPAL, "uid=admin,ou=system");
+ environment.put(Context.SECURITY_CREDENTIALS, "secret");
+
+ DirContext adminContext = new InitialDirContext(environment);
+
+ // define the search filter to find the person with CN : Joe Simms
+ String filter = "(&(objectClass=person)(cn=Joe Simms))";
+
+ // declare the attributes we want returned for the object being searched
+ String[] attrIDs = { "cn" };
+
+ // define the search controls
+ SearchControls searchControls = new SearchControls();
+ searchControls.setReturningAttributes(attrIDs);
+ searchControls.setSearchScope(SearchControls.SUBTREE_SCOPE);
+
+ // search for User with filter cn=Joe Simms
+ NamingEnumeration searchResults = adminContext.search("dc=baeldung,dc=com", filter, searchControls);
+ if (searchResults.hasMore()) {
+
+ SearchResult result = (SearchResult) searchResults.next();
+ Attributes attrs = result.getAttributes();
+
+ String distinguishedName = result.getNameInNamespace();
+ assertThat(distinguishedName).isEqualTo("cn=Joe Simms,ou=Users,dc=baeldung,dc=com");
+
+ String commonName = attrs.get("cn").toString();
+ assertThat(commonName).isEqualTo("cn: Joe Simms");
+
+ // authenticate new context with DN for user Joe Simms, using correct password
+
+ environment.put(Context.SECURITY_PRINCIPAL, distinguishedName);
+ environment.put(Context.SECURITY_CREDENTIALS, "12345");
+
+ assertThatCode(() -> authenticateUser(environment)).doesNotThrowAnyException();
+ }
+
+ adminContext.close();
+ }
+
+ @Test
+ public void givenPreloadedLDAPUserJoe_whenSearchAndAuthUserWithWrongPW_thenAuthFails() throws Exception {
+
+ // first authenticate against LDAP as admin to search up DN of user : Joe Simms
+
+ Hashtable environment = new Hashtable();
+ environment.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
+ environment.put(Context.PROVIDER_URL, "ldap://localhost:10390");
+ environment.put(Context.SECURITY_AUTHENTICATION, "simple");
+ environment.put(Context.SECURITY_PRINCIPAL, "uid=admin,ou=system");
+ environment.put(Context.SECURITY_CREDENTIALS, "secret");
+ DirContext adminContext = new InitialDirContext(environment);
+
+ // define the search filter to find the person with CN : Joe Simms
+ String filter = "(&(objectClass=person)(cn=Joe Simms))";
+
+ // declare the attributes we want returned for the object being searched
+ String[] attrIDs = { "cn" };
+
+ // define the search controls
+ SearchControls searchControls = new SearchControls();
+ searchControls.setReturningAttributes(attrIDs);
+ searchControls.setSearchScope(SearchControls.SUBTREE_SCOPE);
+
+ // search for User with filter cn=Joe Simms
+ NamingEnumeration searchResults = adminContext.search("dc=baeldung,dc=com", filter, searchControls);
+ if (searchResults.hasMore()) {
+
+ SearchResult result = (SearchResult) searchResults.next();
+ Attributes attrs = result.getAttributes();
+
+ String distinguishedName = result.getNameInNamespace();
+ assertThat(distinguishedName).isEqualTo("cn=Joe Simms,ou=Users,dc=baeldung,dc=com");
+
+ String commonName = attrs.get("cn").toString();
+ assertThat(commonName).isEqualTo("cn: Joe Simms");
+
+ // authenticate new context with DN for user Joe Simms, using wrong password
+
+ environment.put(Context.SECURITY_PRINCIPAL, distinguishedName);
+ environment.put(Context.SECURITY_CREDENTIALS, "wronguserpassword");
+
+ assertThatExceptionOfType(AuthenticationException.class).isThrownBy(() -> authenticateUser(environment));
+ }
+
+ adminContext.close();
+ }
+}
diff --git a/core-java-modules/core-java-jndi/src/test/resources/logback.xml b/core-java-modules/core-java-jndi/src/test/resources/logback.xml
new file mode 100644
index 0000000000..e55b365ba4
--- /dev/null
+++ b/core-java-modules/core-java-jndi/src/test/resources/logback.xml
@@ -0,0 +1,13 @@
+
+
+
+
+ %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
+
+
+
+
+
+
+
+
diff --git a/core-java-modules/core-java-jndi/src/test/resources/users.ldif b/core-java-modules/core-java-jndi/src/test/resources/users.ldif
new file mode 100644
index 0000000000..c1996586d5
--- /dev/null
+++ b/core-java-modules/core-java-jndi/src/test/resources/users.ldif
@@ -0,0 +1,20 @@
+version: 1
+dn: dc=baeldung,dc=com
+objectClass: domain
+objectClass: top
+dc: baeldung
+
+dn: ou=Users,dc=baeldung,dc=com
+objectClass: organizationalUnit
+objectClass: top
+ou: Users
+
+dn: cn=Joe Simms,ou=Users,dc=baeldung,dc=com
+objectClass: inetOrgPerson
+objectClass: organizationalPerson
+objectClass: person
+objectClass: top
+cn: Joe Simms
+sn: Simms
+uid: user1
+userPassword: 12345