Spring LDAP CRUD Operations Binding and Unbinding Example

摘要: In this tutorial we use spring ldap to demonstrate CRUD (Create, Read, Update Delete) operations performed on an LDAP server.

In this tutorial we use spring ldap to demonstrate CRUD (Create, Read, Update Delete) operations performed on an LDAP server.

Inserting data in Java LDAP is called binding. This is somewhat confusing, because in LDAP terminology ‘bind’ means something completely different. A JNDI bind performs an LDAP Add operation, associating a new entry with a specified distinguished name with a set of attributes. The following example shows how data is created, read, updated and deleted using LdapTemplate.

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

Managing Persons

Lets start by managing persons in the LDAP server. The following object represents a Person. This person has some basic attributes like fullname and lastName you can easily add new attributes..

package com.memorynotfound.ldap;

public class Person {

    private String uid;
    private String fullName;
    private String lastName;

    public Person() {
    }

    public Person(String fullName, String lastName) {
        this.fullName = fullName;
        this.lastName = lastName;
    }

    public Person(String uid, String fullName, String lastName) {
        this.uid = uid;
        this.fullName = fullName;
        this.lastName = lastName;
    }

    public String getUid() {
        return uid;
    }

    public void setUid(String uid) {
        this.uid = uid;
    }

    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;
    }

    @Override
    public String toString() {
        return "Person{" +
                "fullName='" + fullName + '\'' +
                ", lastName='" + lastName + '\'' +
                '}';
    }
}

We are managing our person objects using the following PersonRepository. First thing to notice is that we implement the BaseLdapNameAware interface, in order to get hold of the base LDAP path. This is necessary because distinguished names as member attribute values must always be absolute form the directory root.

  • Create: using the ldapTemplate.bind() method you can insert data in the LDAP server.
  • Read: you can read data using multiple methods.
    • ldapTemplate.search() you can use ldap queries to filter your search.
    • ldapTemplate.lookup() you can do a lookup by a distinguished name.
  • Update: in Java LDAP, data can be modified in two ways: either using rebind or modifyAttributes.
    • ldapTemplate.rebind() is a very crude way to modify data. It’s basically an unbind followed by a bind.
    • ldapTemplate.modifyAttributes() is a more sophisticated way of modifying data. This operation takes an array of explicit attribute modifications and performs these on a specific entry.
  • Delete: using the ldapTemplate.unbind() method you can delete data from the LDAP server.
package com.memorynotfound.ldap;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.ldap.core.DirContextOperations;
import org.springframework.ldap.core.LdapTemplate;
import org.springframework.ldap.core.support.AbstractContextMapper;
import org.springframework.ldap.core.support.BaseLdapNameAware;
import org.springframework.ldap.filter.EqualsFilter;
import org.springframework.ldap.query.LdapQuery;
import org.springframework.ldap.support.LdapNameBuilder;
import org.springframework.ldap.support.LdapUtils;
import org.springframework.stereotype.Service;

import javax.naming.Name;
import javax.naming.directory.*;
import javax.naming.ldap.LdapName;
import java.util.List;

import static org.springframework.ldap.query.LdapQueryBuilder.query;

@Service
public class PersonRepository implements BaseLdapNameAware {

    @Autowired
    private LdapTemplate ldapTemplate;
    private LdapName baseLdapPath;

    public void setBaseLdapPath(LdapName baseLdapPath) {
        this.baseLdapPath = baseLdapPath;
    }


    public void create(Person p) {
        Name dn = buildDn(p);
        ldapTemplate.bind(dn, null, buildAttributes(p));
    }

    public List<Person> findAll() {
        EqualsFilter filter = new EqualsFilter("objectclass", "person");
        return ldapTemplate.search(LdapUtils.emptyLdapName(), filter.encode(), new PersonContextMapper());
    }

    public Person findOne(String uid) {
        Name dn = LdapNameBuilder.newInstance(baseLdapPath)
                .add("ou", "people")
                .add("uid", uid)
                .build();
        return ldapTemplate.lookup(dn, new PersonContextMapper());
    }

    public List<Person> findByName(String name) {
        LdapQuery q = query()
                .where("objectclass").is("person")
                .and("cn").whitespaceWildcardsLike(name);
        return ldapTemplate.search(q, new PersonContextMapper());
    }

    public void update(Person p) {
        ldapTemplate.rebind(buildDn(p), null, buildAttributes(p));
    }

    public void updateLastName(Person p) {
        Attribute attr = new BasicAttribute("sn", p.getLastName());
        ModificationItem item = new ModificationItem(DirContext.REPLACE_ATTRIBUTE, attr);
        ldapTemplate.modifyAttributes(buildDn(p), new ModificationItem[] {item});
    }

    public void delete(Person p) {
        ldapTemplate.unbind(buildDn(p));
    }

    private Name buildDn(Person p) {
        return LdapNameBuilder.newInstance(baseLdapPath)
                .add("ou", "people")
                .add("uid", p.getUid())
                .build();
    }

    private Attributes buildAttributes(Person p) {
        Attributes attrs = new BasicAttributes();
        BasicAttribute ocAttr = new BasicAttribute("objectclass");
        ocAttr.add("top");
        ocAttr.add("person");
        attrs.put(ocAttr);
        attrs.put("ou", "people");
        attrs.put("uid", p.getUid());
        attrs.put("cn", p.getFullName());
        attrs.put("sn", p.getLastName());
        return attrs;
    }


    private static class PersonContextMapper extends AbstractContextMapper<Person> {
        public Person doMapFromContext(DirContextOperations context) {
            Person person = new Person();
            person.setFullName(context.getStringAttribute("cn"));
            person.setLastName(context.getStringAttribute("sn"));
            person.setUid(context.getStringAttribute("uid"));
            return person;
        }
    }
}

Managing Groups

Next we look at how to manage groups in the LDAP server. The following object represents a Group. This group has some basic attributes like name and members you can easily add new attributes..

package com.memorynotfound.ldap;

import javax.naming.Name;
import java.util.HashSet;
import java.util.Set;

public class Group {

    private String name;
    private Set<Name> members;

    public Group() {
    }

    public Group(String name, Set<Name> members) {
        this.name = name;
        this.members = members;
    }

    public Group(Name dn, String name, Set<Name> members) {
        this.name = name;
        this.members = members;
    }

    public Set<Name> getMembers() {
        return members;
    }

    public void setMembers(Set<Name> 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{" +
                "name='" + name + '\'' +
                ", members=" + members +
                '}';
    }
}

In the GroupRepository we demonstrate how to add a user to an LDAP group. We also show how you can remove a user from an LDAP group.

package com.memorynotfound.ldap;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.ldap.core.DirContextOperations;
import org.springframework.ldap.core.LdapTemplate;
import org.springframework.ldap.core.support.AbstractContextMapper;
import org.springframework.ldap.core.support.BaseLdapNameAware;
import org.springframework.ldap.support.LdapNameBuilder;
import org.springframework.stereotype.Service;

import javax.naming.Name;
import javax.naming.ldap.LdapName;
import java.util.List;

import static org.springframework.ldap.query.LdapQueryBuilder.query;

@Service
public class GroupRepository implements BaseLdapNameAware {

    @Autowired
    private LdapTemplate ldapTemplate;
    private LdapName baseLdapPath;

    public void setBaseLdapPath(LdapName baseLdapPath) {
        this.baseLdapPath = baseLdapPath;
    }

    public List<Group> findAll(){
        return ldapTemplate.search(
                query().where("objectclass").is("groupOfUniqueNames"),
                new GroupContextMapper());
    }

    public void addMemberToGroup(String groupName, Person p) {
        Name groupDn = buildGroupDn(groupName);
        Name personDn = buildPersonDn(p);

        DirContextOperations ctx = ldapTemplate.lookupContext(groupDn);
        ctx.addAttributeValue("uniqueMember", personDn);

        ldapTemplate.modifyAttributes(ctx);
    }

    public void removeMemberFromGroup(String groupName, Person p) {
        Name groupDn = buildGroupDn(groupName);
        Name personDn = buildPersonDn(p);

        DirContextOperations ctx = ldapTemplate.lookupContext(groupDn);
        ctx.removeAttributeValue("uniqueMember", personDn);

        ldapTemplate.modifyAttributes(ctx);
    }

    private Name buildGroupDn(String groupName) {
        return LdapNameBuilder.newInstance(baseLdapPath)
                .add("ou", "groups")
                .add("cn", groupName)
                .build();
    }

    private Name buildPersonDn(Person person) {
        return LdapNameBuilder.newInstance(baseLdapPath)
                .add("ou", "people")
                .add("uid", person.getUid())
                .build();
    }

    private static class GroupContextMapper extends AbstractContextMapper<Group> {
        public Group doMapFromContext(DirContextOperations context) {
            Group group = new Group();
            group.setName(context.getStringAttribute("cn"));
            Object[] members = context.getObjectAttributes("uniqueMember");
            for (Object member : members){
                Name memberDn = LdapNameBuilder.newInstance(String.valueOf(member)).build();
                group.addMember(memberDn);
            }
            return group;
        }
    }
}

Spring LDAP Configuration

Earlier we saw that both PersonRepository and GroupRepository implements the BaseLdapNameAware interface to get hold of the LDAP base path. Implementing this interface alone isn’t enough to get hold of the base path. You need to register a bean called BaseLdapPathBeanPostProcessor. The BaseLdapPathBeanPostProcessor checks each bean if it implements BaseLdapNameAware or BaseLdapPathAware. If it does, the default context base LDAP path will be determined and that value will be injected to the setBaseLdapPath method of the processed bean.

package com.memorynotfound.ldap;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.ldap.core.support.BaseLdapPathBeanPostProcessor;

@Configuration
public class LdapConfig {

    @Value("${spring.ldap.embedded.base-dn}")
    private String baseDn;

    @Bean
    public BaseLdapPathBeanPostProcessor ldapPathBeanPostProcessor(){
        BaseLdapPathBeanPostProcessor baseLdapPathBeanPostProcessor = new BaseLdapPathBeanPostProcessor();
        baseLdapPathBeanPostProcessor.setBasePath(baseDn);
        return baseLdapPathBeanPostProcessor;
    }
}

Spring LDAP CRUD Operations Binding and Unbinding Example

In the following application we demonstrate some methods of the PersonRepository and GroupRepository. We create, read, update and delete persons. Afterwards, we add and remove some persons from particular groups.

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 setup(){
        log.info("Spring LDAP CRUD Operations Binding and Unbinding Example");

        log.info("- - - - - - Managing persons");

        List<Person> persons = personRepository.findAll();
        log.info("persons: " + persons);

        Person john = personRepository.findOne("john");
        john.setLastName("custom last name");
        personRepository.updateLastName(john);

        Person jahn = personRepository.findOne("jahn");
        jahn.setLastName("custom last name");
        personRepository.update(jahn);

        Person person = new Person("uid", "new", "person");
        personRepository.create(person);

        Person jihn = personRepository.findOne("jihn");
        personRepository.delete(jihn);

        persons = personRepository.findAll();
        log.info("persons: " + persons);

        log.info("- - - - - - Managing groups");

        List<Group> groups = groupRepository.findAll();
        log.info("groups: " + groups);

        groupRepository.removeMemberFromGroup("developers", jihn);

        groupRepository.addMemberToGroup("managers", jihn);

        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 14:05:57.039  INFO 14509 --- [main] com.memorynotfound.ldap.Application: 
Spring LDAP CRUD Operations Binding and Unbinding Example
2017-10-02 14:05:57.039  INFO 14509 --- [main] com.memorynotfound.ldap.Application: 
- - - - - - Managing persons
2017-10-02 14:05:57.079  INFO 14509 --- [main] com.memorynotfound.ldap.Application: 
persons: [Person{fullName='Jahn Dae', lastName='Jahn'}, Person{fullName='Jihn Die', lastName='Jihn'}, Person{fullName='John Doe', lastName='John'}]
2017-10-02 14:05:57.097  INFO 14509 --- [main] com.memorynotfound.ldap.Application: 
persons: [Person{fullName='Jahn Dae', lastName='custom last name'}, Person{fullName='John Doe', lastName='custom last name'}, Person{fullName='new', lastName='person'}]
2017-10-02 14:05:57.097  INFO 14509 --- [main] com.memorynotfound.ldap.Application: 
- - - - - - Managing groups
2017-10-02 14:05:57.103  INFO 14509 --- [main] com.memorynotfound.ldap.Application: 
groups: [Group{name='developers', members=[uid=jihn,ou=people,dc=memorynotfound,dc=com, uid=john,ou=people,dc=memorynotfound,dc=com]}, Group{name='managers', members=[uid=jahn,ou=people,dc=memorynotfound,dc=com]}]
2017-10-02 14:05:57.111  INFO 14509 --- [main] com.memorynotfound.ldap.Application: 
groups: [Group{name='developers', members=[uid=john,ou=people,dc=memorynotfound,dc=com]}, Group{name='managers', members=[uid=jahn,ou=people,dc=memorynotfound,dc=com, uid=jihn,ou=people,dc=memorynotfound,dc=com]}]

Download

上一篇: Spring LDAP Object Directory Mapping (ODM) Configuration Example
下一篇: Spring LDAP Mapping Attributes to POJO with AttributesMapper Example
 评论 ( What Do You Think )
名称
邮箱
网址
评论
验证
   
 

 


  • 微信公众号

  • 我的微信

站点声明:

1、一号门博客CMS,由Python, MySQL, Nginx, Wsgi 强力驱动

2、部分文章或者资源来源于互联网, 有时候很难判断是否侵权, 若有侵权, 请联系邮箱:summer@yihaomen.com, 同时欢迎大家注册用户,主动发布无版权争议的 文章/资源.

3、鄂ICP备14001754号-3, 鄂公网安备 42280202422812号