Spring Boot + Spring LDAP Advanced LDAP Queries Example

摘要: This tutorial demonstrates how to write advanced LDAP queries using Spring LDAP. We can write advanced queries using the LdapQueryBuilder or by using custom filters, either by using clear text or custom logical filters.

This tutorial demonstrates how to write advanced LDAP queries using Spring LDAP. We can write advanced queries using the LdapQueryBuilder or by using custom filters, either by using clear text or custom logical filters.

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>advanced-ldap-queries</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 Boot + Spring LDAP Advanced LDAP Queries 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

Person Object

We are using this Person object to map our LDAP entries to.

package com.memorynotfound.ldap;

public class Person {

    private String fullName;
    private String lastName;

    public Person() {
    }

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

    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 + '\'' +
                '}';
    }
}

LDAP Query Builder Parameters

The LdapQueryBuilder and its associated classes are intended to support all parameters that can be supplied to an LDAP search. The following parameters are supported:

  • base – specifies the root DN in the LDAP tree where the search should start.
  • searchScope – specifies how deep into the LDAP tree the search should traverse.
  • attributes – specifies the attributes to return from the search. Default is all.
  • countLimit – specifies the maximum number of entries to return from the search.
  • timeLimit – specifies the maximum time that the search may take.
  • Search Filter – the conditions that the entries we are looking for must meet.

An LdapQueryBuilder is created with a call to the query method of LdapQueryBuilder. It’s intended as a fluent builder API, where the base parameters are defined first, followed by the filter specification calls. Once filter conditions have been started to be defined with a call to the where method of LdapQueryBuilder, later attempts to call e.g. base will be rejected. The base search parameters are optional, but at least one filter specification call is required.

Filter Criteria

The LDAP query builder has support for the following criteria types:

  • is – specifies an equal condition (=).
  • gte – specifies a greater than or equals condition (>=).
  • lte – specifies a less than or equals condition (<=).
  • like – specifies a ‘like’ condition where wildcards can be included in the query, e.g. where("cn").like("J*hn") will result in the filter (cn=J*hn).
  • whitespaceWildcardsLike – specifies a condition where all whitespace is replaced with wildcards, e.g. where("cn").like("John Doe") will result in the filter (cn=John*Doe).
  • isPresent – specifies condition that checks for the presence of an attribute, e.g. where("cn").isPresent() will result in the filter (cn=*).
  • not – specifies that the current condition should be negated, e.g. where("sn").not().is("Doe") will result in the filter (!(sn=Doe)).

Writing Advanced LDAP Queries using LdapTemplate

In the following example we demonstrate a couple of different example use cases. First, we are building advanced LDAP queries using the builder API. Second, we are building advanced queries using hardcoded filters. Last, we are building advanced ldap queries using conditional filters. Each method maps the attributes with the same custom AttributesMapper which as the name implies, maps the attributes to the Person object.

package com.memorynotfound.ldap;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.ldap.core.AttributesMapper;
import org.springframework.ldap.core.LdapTemplate;
import org.springframework.ldap.filter.AndFilter;
import org.springframework.ldap.filter.EqualsFilter;
import org.springframework.ldap.query.LdapQuery;
import org.springframework.ldap.query.SearchScope;
import org.springframework.ldap.support.LdapUtils;
import org.springframework.stereotype.Service;
import javax.naming.NamingException;
import javax.naming.directory.Attribute;
import javax.naming.directory.Attributes;
import javax.naming.directory.SearchControls;
import java.util.List;
import static org.springframework.ldap.query.LdapQueryBuilder.query;

@Service
public class PersonRepository {

    private static final Integer THREE_SECONDS = 3000;

    @Autowired
    private LdapTemplate ldapTemplate;

    public List<Person> getPersonNamesByLastName(String lastName) {

        LdapQuery query = query()
                .searchScope(SearchScope.SUBTREE)
                .timeLimit(THREE_SECONDS)
                .countLimit(10)
                .attributes("cn")
                .base(LdapUtils.emptyLdapName())
                .where("objectclass").is("person")
                .and("sn").not().is(lastName)
                .and("sn").like("j*hn")
                .and("uid").isPresent();

        return ldapTemplate.search(query, new PersonAttributesMapper());
    }

    public List<Person> getPersonNamesByLastName2(String lastName) {

        SearchControls sc = new SearchControls();
        sc.setSearchScope(SearchControls.SUBTREE_SCOPE);
        sc.setTimeLimit(THREE_SECONDS);
        sc.setCountLimit(10);
        sc.setReturningAttributes(new String[]{"cn"});

        String filter = "(&(objectclass=person)(sn=" + lastName + "))";
        return ldapTemplate.search(LdapUtils.emptyLdapName(), filter, sc, new PersonAttributesMapper());
    }

    public List<Person> getPersonNamesByLastName3(String lastName) {

        SearchControls sc = new SearchControls();
        sc.setSearchScope(SearchControls.SUBTREE_SCOPE);
        sc.setTimeLimit(THREE_SECONDS);
        sc.setCountLimit(10);
        sc.setReturningAttributes(new String[]{"cn"});

        AndFilter filter = new AndFilter();
        filter.and(new EqualsFilter("objectclass", "person"));
        filter.and(new EqualsFilter("sn", lastName));

        return ldapTemplate.search(LdapUtils.emptyLdapName(), filter.encode(), sc, new PersonAttributesMapper());
    }

    /**
     * Custom person attributes mapper, maps the attributes to the person POJO
     */
    private class PersonAttributesMapper implements AttributesMapper<Person> {
        public Person mapFromAttributes(Attributes attrs) throws NamingException {
            Person person = new Person();
            person.setFullName((String)attrs.get("cn").get());

            Attribute sn = attrs.get("sn");
            if (sn != null){
                person.setLastName((String)sn.get());
            }
            return person;
        }
    }
}

Spring Boot + Spring LDAP Advanced LDAP Queries 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;

    public static void main(String[] args) throws Exception {
        SpringApplication.run(Application.class, args);
    }

    @PostConstruct
    public void setup(){
        log.info("Spring Boot + Spring LDAP Advanced LDAP Queries Example");

        List<Person> names = personRepository.getPersonNamesByLastName("John");
        log.info("names: " + names);

        names = personRepository.getPersonNamesByLastName2("Jihn");
        log.info("names: " + names);

        names = personRepository.getPersonNamesByLastName3("Jahn");
        log.info("names: " + names);

        System.exit(-1);
    }

}

Output

The previous application will print the following output to the console.

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v1.5.7.RELEASE)

2017-10-03 14:17:12.653  INFO 30067 --- [main] com.memorynotfound.ldap.Application: Spring Boot + Spring LDAP Advanced LDAP Queries Example
2017-10-03 14:17:12.697  INFO 30067 --- [main] com.memorynotfound.ldap.Application: names: [Person{fullName='Jahn Dae', lastName='null'}, Person{fullName='Jihn Die', lastName='null'}]
2017-10-03 14:17:12.699  INFO 30067 --- [main] com.memorynotfound.ldap.Application: names: [Person{fullName='Jihn Die', lastName='null'}]
2017-10-03 14:17:12.701  INFO 30067 --- [main] com.memorynotfound.ldap.Application: names: [Person{fullName='Jahn Dae', lastName='null'}]

Download

上一篇: Spring Boot + Spring LDAP Integration Testing Example
下一篇: Spring LDAP Object Directory Mapping (ODM) Configuration Example
 评论 ( What Do You Think )
名称
邮箱
网址
评论
验证
   
 

 


  • 微信公众号

  • 我的微信

站点声明:

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

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

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