Spring LDAP

repository·main·Indexed 18 days ago

https://github.com/spring-projects/spring-ldap

A Java library that simplifies LDAP programming by providing high-level abstractions like LdapTemplate and LdapClient. It reduces boilerplate for connection management, exception handling, and data mapping, and includes support for Object-to-Directory Mapping (ODM) via the @Entry annotation.

Tokens
29.4K
Snippets
58
Records
100
Agent score
61%

What's inside Spring LDAP

  1. Overview of Spring LDAP

    main

    Spring LDAP is a Java library designed to simplify LDAP programming by following the same principles as Spring Jdbc. It provides the LdapTemplate class to encapsulate the boilerplate code associated with traditional LDAP operations, such as:

    • Creating and managing connections.
    • Looping through NamingEnumerations.
    • Handling LDAP-specific exceptions.
    • Cleaning up resources.

    By using Spring LDAP, developers can focus on high-level logic like defining Distinguished Names (DNs) and Filters, and mapping LDAP data to domain objects, rather than managing the underlying plumbing.

  2. Overview of Spring LDAP features

    main

    Spring LDAP simplifies LDAP programming in Java by providing several high-level abstractions and utilities. Key features include:

    • Template Simplification: JdbcTemplate-style templates to reduce boilerplate when interacting with LDAP.
    • Object Mapping: JPA- or Hibernate-style annotation-based mapping for objects and directory entries.
    • Spring Data Support: Integration with Spring Data repositories, including QueryDSL support.
    • Query Utilities: Tools to simplify the construction of LDAP queries and Distinguished Names (DNs).
    • Connection Management: Built-in support for proper LDAP connection pooling.
    • Transaction Support: Client-side LDAP compensating transaction support.
  3. Use Object-Directory Mapping (ODM) with LdapOperations

    main

    Spring LDAP provides Object-Directory Mapping (ODM) to map LDAP directory entries to Java objects using annotations, similar to JPA/Hibernate. You can perform CRUD operations and searches using the following LdapOperations methods:

    • <T> T findByDn(Name dn, Class<T> clazz)
    • <T> T findOne(LdapQuery query, Class<T> clazz)
    • <T> List<T> find(LdapQuery query, Class<T> clazz)
    • <T> List<T> findAll(Class<T> clazz)
    • <T> List<T> findAll(Name base, SearchControls searchControls, Class<T> clazz)
    • <T> List<T> findAll(Name base, Filter filter, SearchControls searchControls, Class<T> clazz)
    • void create(Object entry)
    • void update(Object entry)
    • void delete(Object entry)
  4. Understand Spring LDAP module structure

    main

    Spring LDAP is distributed as several specialized modules. Depending on your needs, you may only need to include specific artifacts in your project:

    • spring-ldap-core: The primary Spring LDAP library. It includes the core LDAP functionality and the Object-Directory Mapping (ODM) framework.
    • spring-ldap-test: Provides support classes specifically designed to assist with LDAP integration testing.
    • spring-ldap-ldif-core: A library dedicated to parsing LDIF (LDAP Data Interchange Format) files.
    • spring-ldap-ldif-batch: An integration layer that connects the LDIF parsing library with Spring Batch.

    If you are looking for Spring Data's specific integration with LDAP, you should refer to the spring-data-ldap project instead.

  5. How LdapTemplate simplifies LDAP programming

    main

    Spring LDAP uses the LdapTemplate to abstract away the complexities of the LDAP protocol. It provides:

    1. Exception Translation: Converts standard NamingExceptions into a more manageable hierarchy of unchecked exceptions.
    2. Plumbing Abstraction: Handles the lifecycle of LDAP operations, similar to how JdbcTemplate handles SQL.
    3. Utilities: Provides helper tools for working with LDAP paths, attributes, and filters.

    This allows the programmer to focus on:

    • Where to find data: Using DNs and Filters.
    • What to do with data: Binding, modifying, unbinding, and mapping to/from domain objects.
  6. How LdapQueryBuilder works

    main

    The LdapQueryBuilder provides a fluent API for constructing LDAP searches. It is initialized via the query() method of LdapQueryBuilder.

    Usage Pattern:

    1. Base Parameters: Define search parameters like base, searchScope, attributes, countLimit, and timeLimit first.
    2. Filter Specification: Use the where() method to start defining filter conditions.

    Constraint: Once you call where() to begin defining filter conditions, you can no longer call base parameter methods (like base()). You must define the search scope and base DN before defining the filter logic. At least one filter specification call is required.

  7. Transform LDAP entries using ContextMapper

    main

    When performing searches or lookups, Spring LDAP can return DirContextAdapter instances. You can use a ContextMapper to transform these adapters into your domain objects. This is more convenient than using AttributesMapper because you can access attributes directly by name via the DirContextAdapter without manually iterating through NamingEnumeration objects.

    private static class PersonContextMapper implements ContextMapper {
       public Object mapFromContext(Object ctx) {
          DirContextAdapter context = (DirContextAdapter)ctx;
          Person p = new Person();
          p.setFullName(context.getStringAttribute("cn"));
          p.setLastName(context.getStringAttribute("sn"));
          p.setDescription(context.getStringAttribute("description"));
          return p;
       }
    }
    
    // Usage in a repository
    public Person findByPrimaryKey(String name, String company, String country) {
       Name dn = buildDn(name, company, country);
       return ldapClient.search().name(dn).map(new PersonContextMapper()).single();
    }
  8. Custom `DirContext` Authentication Processing

    main

    By default, Spring LDAP uses SIMPLE authentication. If you need to use TLS, LDAP Proxy Auth, or other mechanisms, you can provide a custom DirContextAuthenticationStrategy by setting the authentication-strategy-ref attribute on the <ldap:context-source>.

    TLS Configuration

    Spring LDAP provides two strategies for TLS:

    • DefaultTlsDirContextAuthenticationStrategy: Applies SIMPLE authentication over a secure TLS channel.
    • ExternalTlsDirContextAuthenticationStrategy: Uses EXTERNAL SASL authentication with a client certificate configured via system properties.

    Both support the shutdownTlsGracefully parameter (defaults to false). If set to true, Spring LDAP attempts a graceful TLS shutdown.

    Note: When using TLS, ensure native-pooling is disabled. For performance, use Spring LDAP's own pooling support instead.

  9. Understand Spring LDAP observation metrics and names

    main

    When observability is enabled, LDAP operations are recorded as observations.

    • Observation Name: spring.ldap.dir.context.operations
    • Contextual Name: perform _operation_ (where _operation_ is the specific LDAP action being performed).

    Observation Metadata

    Observations include various key-value pairs for filtering and analysis:

    Low Cardinality Keys (Commonly used for grouping/filtering):

    • base: The LDAP base DN.
    • operation: The type of operation (e.g., get.attributes).
    • urls: The LDAP URLs being used.

    High Cardinality Keys (Specific to individual requests):

    • attribute.ids: The IDs of the attributes being accessed.
    • name: The specific DN being targeted (e.g., uid=user,ou=people).
  10. Understand LDAP compensating operations

    main

    Spring LDAP manages rollbacks by splitting modifying operations into four phases: Recording, Preparation, Commit, and Rollback. This ensures that even complex operations like unbind or rebind can be reversed by temporarily renaming entries or calculating compensating modifications.

    | LDAP Operation | Recording | Preparation | Commit | Rollback | | :--- | :--- | :--- | :--- | : | | bind | Record DN | Bind entry | No operation | Unbind using recorded DN | | rename | Record original & target DN | Rename entry | No operation | Rename back to original DN | | unbind | Record original DN & calculate temp DN | Rename to temp DN | Unbind temp entry | Rename from temp DN back to original | | rebind | Record original DN, new Attributes & temp DN | Rename to temp DN | Bind new Attributes at original DN & unbind temp entry | Rename from temp DN back to original | | modifyAttributes | Record DN & calculate compensating ModificationItems | Perform modifyAttributes | No operation | Perform modifyAttributes using compensating items |

  11. Represent LDIF data using LdapAttribute and LdapAttributes

    main

    To represent LDIF data in your code, use the following classes from the org.springframework.ldap.core package:

    • LdapAttribute: Extends javax.naming.directory.BasicAttribute. It adds support for LDIF options as defined in RFC 2849, representing options as a Set<String>.
    • LdapAttributes: Extends javax.naming.directory.BasicAttributes. It adds specialized support for Distinguished Names (DNs) using the javax.naming.ldap.LdapName class.
  12. Handle Distinguished Names as Attribute Values in ODM

    main

    ODM supports using javax.naming.Name as attribute values. This is particularly useful for LDAP security groups where a multi-value attribute contains the DNs of users.

    When using ldapTemplate.update() to modify collections of Name objects, Spring LDAP calculates modifications based on distinguished name equality, disregarding text formatting differences.

    @Entry(objectClasses = {"top", "groupOfUniqueNames"}, base = "cn=groups")
    public class Group {
    
        @Id
        private Name dn;
    
        @Attribute(name="cn")
        @DnAttribute("cn")
        private String name;
    
        @Attribute(name="uniqueMember")
        private Set<Name> members;
    
        public Name getDn() { return dn; }
        public void setDn(Name dn) { this.dn = dn; }
        public Set<Name> getMembers() { return members; }
        public void setMembers(Set<Name> members) { this.members = members; }
        public void addMember(Name member) { members.add(member); }
        public void removeMember(Name member) { members.remove(member); }
        public String getName() { return name; }
        public void setName(String name) { this.name = name; }
    }