Spring LDAP Object Directory Mapping (ODM) Configuration Example
In the following tutorial we demonstrate how to use Spring LDAP Object Directory Mapping (ODM). ODM offers developers the ability to use annotations to map LDAP directories to Java objects.
Maven Dependencies
We use Apache Maven to manage our project dependencies. Add the following dependencies to your project.
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.memorynotfound.ldap</groupId> <artifactId>attributes-mapper</artifactId> <version>1.0.0-SNAPSHOT</version> <url>https://memorynotfound.com</url> <name>Spring LDAP - ${project.artifactId}</name> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.5.7.RELEASE</version> </parent> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-ldap</artifactId> </dependency> <dependency> <groupId>com.unboundid</groupId> <artifactId>unboundid-ldapsdk</artifactId> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> <plugin> <artifactId>maven-compiler-plugin</artifactId> <version>3.5.1</version> <configuration> <source>1.8</source> <target>1.8</target> </configuration> </plugin> </plugins> </build> </project>
Configure Embedded LDAP Server using application.yml
We use spring boot to create and configure our embedded LDAP server. The following properties create an LDAP server running on port 12345 and populates the LDAP server using the schema.ldif which resides on the class-path.
# Spring LDAP CRUD Operations Binding and Unbinding Example spring: ldap: # Spring LDAP # # In this example we use an embedded ldap server. When using a real one, # you can configure the settings here. # # urls: ldap://localhost:12345 # base: dc=memorynotfound,dc=com # username: uid=admin # password: secret # Embedded Spring LDAP embedded: base-dn: dc=memorynotfound,dc=com credential: username: uid=admin password: secret ldif: classpath:schema.ldif port: 12345 validation: enabled: false
Populate LDAP Server
The LDAP servers gets populated using the following schema.ldif file.
dn: dc=memorynotfound,dc=com objectclass: top objectclass: domain objectclass: extensibleObject dc: memorynotfound # Organizational Units dn: ou=groups,dc=memorynotfound,dc=com objectclass: top objectclass: organizationalUnit ou: groups dn: ou=people,dc=memorynotfound,dc=com objectclass: top objectclass: organizationalUnit ou: people # Create People dn: uid=john,ou=people,dc=memorynotfound,dc=com objectclass: top objectclass: person objectclass: organizationalPerson objectclass: inetOrgPerson cn: John Doe sn: John uid: john password: secret dn: uid=jihn,ou=people,dc=memorynotfound,dc=com objectclass: top objectclass: person objectclass: organizationalPerson objectclass: inetOrgPerson cn: Jihn Die sn: Jihn uid: jihn password: secret dn: uid=jahn,ou=people,dc=memorynotfound,dc=com objectclass: top objectclass: person objectclass: organizationalPerson objectclass: inetOrgPerson cn: Jahn Dae sn: Jahn uid: jahn password: secret # Create Groups dn: cn=developers,ou=groups,dc=memorynotfound,dc=com objectclass: top objectclass: groupOfUniqueNames cn: developers ou: developer uniqueMember: uid=john,ou=people,dc=memorynotfound,dc=com uniqueMember: uid=jihn,ou=people,dc=memorynotfound,dc=com dn: cn=managers,ou=groups,dc=memorynotfound,dc=com objectclass: top objectclass: groupOfUniqueNames cn: managers ou: manager uniqueMember: uid=jahn,ou=people,dc=memorynotfound,dc=com
Annotations
- @Entry – Class level annotation indicating the objectClass definitions to which the entity maps. (required)
- @Id – Indicates that entity distinguished name (DN); the field declaring this attribute must be a derivative of the javax.naming.Name class. (required)
- @Attribute – Indicates the mapping of a directory attribute to the object class field.
- @DnAttribute – Indicates the mapping of a dn attribute to the object class field.
- @Transient – Indicates the field is not persistent and should be ignored by the OdmManager.
The @Entry and @Id annotations are required to be declared on managed classes. @Entry is used to specify which object classes the entity maps to and (optionally) the directory root of the LDAP entries represented by the class. All object classes for which fields are mapped are required to be declared. Note that when creating new entries of the managed class, only the declared objectlasses will be used.
In order for a directory entry to be considered a match to the managed entity, all object classes declared by the directory entry must match be declared by in the @Entry annotation. For example: let’s assume that you have entries in your LDAP tree that have the objectclasses inetOrgPerson,organizationalPerson,person,top. If you are only interested in changing the attributes defined in the person objectclass, your @Entry annotation can be @Entry(objectClasses = { "person", "top"}). However, if you want to manage attributes defined in the inetOrgPerson objectclass you’ll need to use the full monty: @Entry(objectClasses = { "inetOrgPerson", "organizationalPerson", "person", "top" }).
Managing LDAP Users
First, lets look at how to create, update and delete some users. We use the Person class to represent a person LDAP entry. This object is mapped with specific ODM annotations, mapping the object to the LDAP counterpart.
package com.memorynotfound.ldap; import org.springframework.ldap.odm.annotations.*; import org.springframework.ldap.support.LdapNameBuilder; import javax.naming.Name; @Entry(objectClasses = { "person", "top" }) public final class Person { private static final String BASE_DN = "dc=memorynotfound,dc=com"; @Id private Name dn; @DnAttribute(value="uid") private String uid; @Attribute(name="cn") private String fullName; @Attribute(name="sn") private String lastName; @DnAttribute(value="ou") @Transient private String group; public Person() { } public Person(String fullName, String lastName) { Name dn = LdapNameBuilder.newInstance(BASE_DN) .add("ou", "people") .add("uid", fullName) .build(); this.dn = dn; this.fullName = fullName; this.lastName = lastName; } public String getUid() { return uid; } public Name getDn() { return dn; } public void setDn(Name dn) { this.dn = dn; } public String getFullName() { return fullName; } public void setFullName(String fullName) { this.fullName = fullName; } public String getLastName() { return lastName; } public void setLastName(String lastName) { this.lastName = lastName; } public String getGroup() { return group; } public void setGroup(String group) { this.group = group; } @Override public String toString() { return "Person{" + "dn=" + dn + ", uid='" + uid + '\'' + ", fullName='" + fullName + '\'' + ", lastName='" + lastName + '\'' + ", group='" + group + '\'' + '}'; } }
By using annotations, our queries are simplified a lot. The following PersonRepository manages the basic CRUD operations performed on the LDAP server. These operations include but are not limited to: Create, Read, Update and Delete.
package com.memorynotfound.ldap; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.ldap.core.LdapTemplate; import org.springframework.stereotype.Service; import java.util.List; import static org.springframework.ldap.query.LdapQueryBuilder.query; @Service public class PersonRepository { @Autowired private LdapTemplate ldapTemplate; public Person create(Person person) { ldapTemplate.create(person); return person; } public Person findByUid(String uid) { return ldapTemplate.findOne(query().where("uid").is(uid), Person.class); } public void update(Person person) { ldapTemplate.update(person); } public void delete(Person person) { ldapTemplate.delete(person); } public List<Person> findAll() { return ldapTemplate.findAll(Person.class); } public List<Person> findByLastName(String lastName) { return ldapTemplate.find(query().where("sn").is(lastName), Person.class); } }
Managing LDAP Groups
Now we are looking into managing our groups. We can map the Group object to the LDAP counterpart using Spring ODM Annotations.
package com.memorynotfound.ldap; 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; import org.springframework.ldap.support.LdapNameBuilder; import javax.naming.Name; import java.util.HashSet; import java.util.Set; @Entry(objectClasses = {"top", "groupOfUniqueNames"}, base = "cn=groups") public final class Group { private static final String BASE_DN = "dc=memorynotfound,dc=com"; @Id private Name dn; @Attribute(name="cn") @DnAttribute("cn") private String name; @Attribute(name="uniqueMember") private Setmembers; public Group() { } public Group(String name, Set members) { Name dn = LdapNameBuilder.newInstance(BASE_DN) .add("ou", "groups") .add("cn", name) .build(); this.dn = dn; this.name = name; this.members = members; } public Group(Name dn, String name, Set members) { this.dn = dn; this.name = name; this.members = members; } public Name getDn() { return dn; } public void setDn(Name dn) { this.dn = dn; } public Set getMembers() { return members; } public void setMembers(Set members) { this.members = members; } public String getName() { return name; } public void setName(String name) { this.name = name; } public void addMember(Name member) { if (this.members == null){ this.members = new HashSet<>(); } members.add(member); } public void removeMember(Name member) { members.remove(member); } @Override public String toString() { return "Group{" + "dn=" + dn + ", name='" + name + '\'' + ", members=" + members + '}'; } }
By using annotations, our queries are simplified a lot. The following GroupRepository manages the basic CRUD operations performed on the LDAP server. These operations include but are not limited to: Create, Read, Update and Delete.
package com.memorynotfound.ldap; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.ldap.core.LdapTemplate; import org.springframework.stereotype.Service; import java.util.List; import static org.springframework.ldap.query.LdapQueryBuilder.query; @Service public class GroupRepository { @Autowired private LdapTemplate ldapTemplate; public Group create(Group group) { ldapTemplate.create(group); return group; } public Group findBy(String attr, String value) { return ldapTemplate.findOne(query().where(attr).is(value), Group.class); } public void update(Group group) { ldapTemplate.update(group); } public void delete(Group group) { ldapTemplate.delete(group); } public List<Group> findAll() { return ldapTemplate.findAll(Group.class); } }
Spring LDAP Object Directory Mapping (ODM) Configuration Example
We bootstrap our application using spring boot. After the application is initialized, we execute some operations on the LDAP server to demonstrate our previous code.
package com.memorynotfound.ldap; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import javax.annotation.PostConstruct; import java.util.List; @SpringBootApplication public class Application { private static Logger log = LoggerFactory.getLogger(Application.class); @Autowired private PersonRepository personRepository; @Autowired private GroupRepository groupRepository; public static void main(String[] args) throws Exception { SpringApplication.run(Application.class, args); } @PostConstruct public void init() { log.info("Spring LDAP Object Directory Mapping (ODM) Configuration Example"); log.info("- - - - - Managing LDAP persons using Spring LDAP ODM"); List<Person> persons = personRepository.findAll(); log.info("persons: " + persons); Person olivier = new Person("Olivier Sips", "Sips"); personRepository.create(olivier); Person john = personRepository.findByUid("john"); personRepository.delete(john); Person jahn = personRepository.findByUid("jahn"); jahn.setLastName("custom last name"); personRepository.update(jahn); List<Person> result = personRepository.findByLastName("custom last name"); log.info("result: " + result); persons = personRepository.findAll(); log.info("persons: " + persons); log.info("- - - - - Managing LDAP groups using Spring LDAP ODM"); List<Group> groups = groupRepository.findAll(); log.info("groups: " + groups); Group otherEmployees = new Group("other employees", null); otherEmployees.addMember(jahn.getDn()); groupRepository.create(otherEmployees); Group developers = groupRepository.findBy("cn", "developers"); developers.removeMember(john.getDn()); groupRepository.update(developers); Group managers = groupRepository.findBy("cn", "managers"); groupRepository.delete(managers); groups = groupRepository.findAll(); log.info("groups: " + groups); System.exit(-1); } }
Output
The previous application will print the following output to the console.
. ____ _ __ _ _ /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ \\/ ___)| |_)| | | | | || (_| | ) ) ) ) ' |____| .__|_| |_|_| |_\__, | / / / / =========|_|==============|___/=/_/_/_/ :: Spring Boot :: (v1.5.7.RELEASE) 2017-10-02 15:55:52.115 INFO 17488 --- [ main] com.memorynotfound.ldap.Application : Spring LDAP Object Directory Mapping (ODM) Configuration Example 2017-10-02 15:55:52.115 INFO 17488 --- [ main] com.memorynotfound.ldap.Application : - - - - - Managing LDAP persons using Spring LDAP ODM 2017-10-02 15:55:52.190 INFO 17488 --- [ main] com.memorynotfound.ldap.Application : persons: [Person{dn=uid=jahn,ou=people,dc=memorynotfound,dc=com, uid='jahn', fullName='Jahn Dae', lastName='Jahn', group='people'}, Person{dn=uid=jihn,ou=people,dc=memorynotfound,dc=com, uid='jihn', fullName='Jihn Die', lastName='Jihn', group='people'}, Person{dn=uid=john,ou=people,dc=memorynotfound,dc=com, uid='john', fullName='John Doe', lastName='John', group='people'}] 2017-10-02 15:55:52.213 INFO 17488 --- [ main] com.memorynotfound.ldap.Application : result: [Person{dn=uid=jahn,ou=people,dc=memorynotfound,dc=com, uid='jahn', fullName='Jahn Dae', lastName='custom last name', group='people'}] 2017-10-02 15:55:52.216 INFO 17488 --- [ main] com.memorynotfound.ldap.Application : persons: [Person{dn=uid=jahn,ou=people,dc=memorynotfound,dc=com, uid='jahn', fullName='Jahn Dae', lastName='custom last name', group='people'}, Person{dn=uid=jihn,ou=people,dc=memorynotfound,dc=com, uid='jihn', fullName='Jihn Die', lastName='Jihn', group='people'}, Person{dn=uid=Olivier Sips,ou=people,dc=memorynotfound,dc=com, uid='Olivier Sips', fullName='Olivier Sips', lastName='Sips', group='people'}] 2017-10-02 15:55:52.217 INFO 17488 --- [ main] com.memorynotfound.ldap.Application : - - - - - Managing LDAP groups using Spring LDAP ODM 2017-10-02 15:55:52.223 INFO 17488 --- [ main] com.memorynotfound.ldap.Application : groups: [Group{dn=cn=developers,ou=groups,dc=memorynotfound,dc=com, name='developers', members=[uid=john,ou=people,dc=memorynotfound,dc=com, uid=jihn,ou=people,dc=memorynotfound,dc=com]}, Group{dn=cn=managers,ou=groups,dc=memorynotfound,dc=com, name='managers', members=[uid=jahn,ou=people,dc=memorynotfound,dc=com]}] 2017-10-02 15:55:52.236 INFO 17488 --- [ main] com.memorynotfound.ldap.Application : groups: [Group{dn=cn=developers,ou=groups,dc=memorynotfound,dc=com, name='developers', members=[uid=jihn,ou=people,dc=memorynotfound,dc=com]}, Group{dn=cn=other employees,ou=groups,dc=memorynotfound,dc=com, name='other employees', members=[uid=jahn,ou=people,dc=memorynotfound,dc=com]}]
Download
From:一号门
COMMENTS