In the previous article, we learned how to set up LDAP with the spring boot application and how to retrieve the LDAP record using LdapTemplate. In this article, we will learn how to perform CRUD operations on LDAP data with the spring boot application.
Also, we will perform the LDAP CRUD operation with the help of the LdapTemplate.
We have used the Spring boot version: 2.2.0.RELEASE and Java version: 1.8 for this application development.
Table of Contents
- Create Spring boot application with required dependencies
- Configure LDAP related configurations
- Perform the CRUD operation on LDAP records
- Expose RESTful CRUD endpoints
- Test the CRUD operation with Postman
- Conclusion
Create Spring boot application with required dependencies
Create a Spring boot application with required dependencies.
Also, add spring-boot-starter-web, spring-boot-starter-data-ldap, Lombok(to reduce boilerplate code), and unboundid-ldapsdk dependencies to the application.
Finally, the below is the pom.xml with all the required dependencies.
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.2.0.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.asb.example</groupId> <artifactId>spring-embedded-ldap</artifactId> <version>0.0.1-SNAPSHOT</version> <name>spring-embedded-ldap</name> <description>Demo project for Spring Boot</description> <properties> <java.version>1.8</java.version> <maven-jar-plugin.version>3.1.1</maven-jar-plugin.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-ldap</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>com.unboundid</groupId> <artifactId>unboundid-ldapsdk</artifactId> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
Configure LDAP related configurations
Once the Spring boot application is created with the required dependencies, the next step is to configure the application.
Add LDAP configuration properties
Let us add the specified LDAP configuration properties to the Spring boot application’s application.properties file.
#External LDAP directory config: #spring.ldap.urls=ldap://localhost:389 #spring.ldap.base=ou=people,dc=maxcrc,dc=com #spring.ldap.username=cn=Manager,dc=maxcrc,dc=com #spring.ldap.password=secret #Embedded LDAP server config: spring.ldap.embedded.base-dn=dc=asb,dc=com spring.ldap.embedded.credential.username=uid=admin spring.ldap.embedded.credential.password=secret spring.ldap.embedded.ldif=classpath:asb-ldap.ldif spring.ldap.embedded.port=123 spring.ldap.embedded.validation.enabled=false
Add the LDIF file to load initial LDAP data
Create a .ldif file under /src/main/resources/ folder and add the below content.
dn: dc=asb,dc=com objectclass: top objectclass: domain objectclass: extensibleObject dc: asb dn: ou=people,dc=asb,dc=com objectclass: top objectclass: organizationalUnit ou: people dn: uid=ben,ou=people,dc=asb,dc=com objectclass: top objectclass: person objectclass: organizationalPerson objectclass: inetOrgPerson cn: Anne Hathaway sn: Hathaway uid: anne description: Pretty Girl!! dn: uid=bob,ou=people,dc=asb,dc=com objectclass: top objectclass: person objectclass: organizationalPerson objectclass: inetOrgPerson cn: John Hamilton sn: Hamilton uid: john description: Cool guy!! dn: uid=asb,ou=people,dc=asb,dc=com objectclass: top objectclass: person objectclass: organizationalPerson objectclass: inetOrgPerson cn: ASB Notebook sn: Notebook uid: asbnotebook description: Technical blog!.
Perform the CRUD operation on LDAP records
Once the required configurations are ready, we can write code to perform CRUD operation on LDAP data.
Create a DTO class
Create a java class with the name Person. This DTO class will be used to hold the LDAP record during the CRUD operation.
package com.asb.example; import lombok.Getter; import lombok.Setter; import lombok.ToString; @Getter @Setter @ToString public class Person { private String userId; private String fullName; private String lastName; private String description; }
Perform LDAP CRUD operation
The next step is to write a service layer, which performs CRUD operation on LDAP records using the Ldap Template.
Create an interface with the name PersonRepo, and add the required CRUD operation method signatures.
package com.asb.example; import java.util.List; public interface PersonRepo { public List<Person> retrieve(); public String create(Person p); public String update(Person p); public String remove(String userId); }
Create a java implementation class with the name PersonRepoImpl, and implement the methods defined in the PersonRepo interface.
package com.asb.example; import static org.springframework.ldap.query.LdapQueryBuilder.query; import java.util.List; import javax.naming.Name; import javax.naming.NamingException; import javax.naming.directory.Attributes; import javax.naming.directory.BasicAttribute; import javax.naming.directory.BasicAttributes; import javax.naming.directory.SearchControls; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.ldap.core.AttributesMapper; import org.springframework.ldap.core.LdapTemplate; import org.springframework.ldap.support.LdapNameBuilder; import org.springframework.stereotype.Service; @Service public class PersonRepoImpl implements PersonRepo { public static final String BASE_DN = "dc=asb,dc=com"; @Autowired private LdapTemplate ldapTemplate; @Override public String create(Person p) { Name dn = buildDn(p.getUserId()); ldapTemplate.bind(dn, null, buildAttributes(p)); return p.getUserId() + " created successfully"; } @Override public String update(Person p) { Name dn = buildDn(p.getUserId()); ldapTemplate.rebind(dn, null, buildAttributes(p)); return p.getUserId() + " updated successfully"; } @Override public String remove(String userId) { Name dn = buildDn(userId); // ldapTemplate.unbind(dn, true); //Remove recursively all entries ldapTemplate.unbind(dn); return userId + " removed successfully"; } private Attributes buildAttributes(Person p) { BasicAttribute ocattr = new BasicAttribute("objectclass"); ocattr.add("top"); ocattr.add("person"); Attributes attrs = new BasicAttributes(); attrs.put(ocattr); attrs.put("uid", p.getUserId()); attrs.put("cn", p.getFullName()); attrs.put("sn", p.getLastName()); attrs.put("description", p.getDescription()); return attrs; } public Name buildDn(String userId) { return LdapNameBuilder.newInstance(BASE_DN).add("ou", "people").add("uid", userId).build(); } public Name buildBaseDn() { return LdapNameBuilder.newInstance(BASE_DN).add("ou", "people").build(); } @Override public List<Person> retrieve() { SearchControls searchControls = new SearchControls(); searchControls.setSearchScope(SearchControls.SUBTREE_SCOPE); List<Person> people = ldapTemplate.search(query().where("objectclass").is("person"), new PersonAttributeMapper()); return people; } private class PersonAttributeMapper implements AttributesMapper<Person> { @Override public Person mapFromAttributes(Attributes attributes) throws NamingException { Person person = new Person(); person.setUserId(null != attributes.get("uid") ? attributes.get("uid").get().toString() : null); person.setFullName(null != attributes.get("cn") ? attributes.get("cn").get().toString() : null); person.setLastName(null != attributes.get("sn") ? attributes.get("sn").get().toString() : null); person.setDescription( null != attributes.get("description") ? attributes.get("description").get().toString() : null); return person; } } }
This class contains the implementation of all CRUD operations on LDAP data using the LdapTemplate.
We are using bind(), rebind(), and unbind() methods of LdapTemplate to perform create, update and delete operations on LDAP records.
We have also used LdapNameBuilder to build the distinguished name(DN), which is required for the different operations.
Finally, we have created a private attribute mapper class called PersonAttributeMapper to map the LDAP records into Person DTO objects.
Expose RESTful CRUD endpoints
Finally, let us expose the RESTful endpoints for CRUD operation.
Create a Rest controller class called LdapBindController.java as shown below.
This class contains different REST endpoints, that supports CRUD operations.
package com.asb.example; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PutMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; @RestController public class LdapBindController { @Autowired private PersonRepo personRepo; @PostMapping("/add-user") public ResponseEntity<String> bindLdapPerson(@RequestBody Person person) { String result = personRepo.create(person); return new ResponseEntity<>(result, HttpStatus.OK); } @PutMapping("/update-user") public ResponseEntity<String> rebindLdapPerson(@RequestBody Person person) { String result = personRepo.update(person); return new ResponseEntity<>(result, HttpStatus.OK); } @GetMapping("/retrieve-users") public ResponseEntity<List<Person>> retrieve() { return new ResponseEntity<List<Person>>(personRepo.retrieve(), HttpStatus.OK); } @GetMapping("/remove-user") public ResponseEntity<String> unbindLdapPerson(@RequestParam(name = "userId") String userId) { String result = personRepo.remove(userId); return new ResponseEntity<>(result, HttpStatus.OK); } }
Test the CRUD operation with Postman
It’s time to test the application!! 🙂 Launch the spring boot application.
LDAP Search
In the below image, we can observe the LDAP records, imported from the LDIF file.

LDAP binding
The below image shows the create(bind) operation of a new record on the LDAP server.

Once we get the success message, we can verify it by retrieving the records.

LDAP Rebind
The below image shows the update operation.

Retrieve the records to confirm the record update.

LDAP Unbind
The below image shows delete operation by user-id(uid).

Retrieve the records to confirm the record delete operation.

Conclusion
In this article, we learned how to perform CRUD operations on LDAP records using LdapTemplate, while developing the spring boot applications.
We learned the bind(), rebind(), and unbind() methods of the Ldap Template utility and how to use them to perform CRUD operations.
Example code is available on GitHub.