CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-org-springframework-security--spring-security-ldap

Spring Security LDAP module providing comprehensive LDAP authentication and authorization capabilities for enterprise applications

Pending
Overview
Eval results
Files

embedded-server.mddocs/

Embedded Server Support

Embedded LDAP server containers for testing and development environments with support for Apache Directory Server and UnboundID implementations.

Capabilities

EmbeddedLdapServerContainer

Base interface for embedded LDAP server containers.

/**
 * Base interface for embedded LDAP server containers providing common lifecycle operations
 */
public interface EmbeddedLdapServerContainer {
    /**
     * Gets the port number the embedded server is listening on
     * @return the LDAP port number
     */
    int getPort();
    
    /**
     * Sets the port number for the embedded LDAP server
     * @param port the port number to use
     */
    void setPort(int port);
    
    /**
     * Starts the embedded LDAP server
     * @throws Exception if server startup fails
     */
    void start() throws Exception;
    
    /**
     * Stops the embedded LDAP server
     * @throws Exception if server shutdown fails
     */
    void stop() throws Exception;
    
    /**
     * Checks if the embedded server is currently running
     * @return true if the server is running
     */
    boolean isRunning();
}

ApacheDSContainer

Embedded Apache Directory Server container for testing and development with Spring Security LDAP.

/**
 * Embedded Apache Directory Server container providing LDAP server functionality
 * for testing and development environments
 */
public class ApacheDSContainer implements InitializingBean, DisposableBean, Lifecycle {
    /**
     * Creates an Apache DS container with root DN and LDIF data
     * @param root the root DN for the directory (e.g., "dc=springframework,dc=org")
     * @param ldifs comma-separated list of LDIF file paths to load
     */
    public ApacheDSContainer(String root, String ldifs);
    
    /**
     * Starts the embedded Apache Directory Server
     * @throws Exception if server startup fails
     */
    public void start() throws Exception;
    
    /**
     * Stops the embedded Apache Directory Server
     * @throws Exception if server shutdown fails
     */
    public void stop() throws Exception;
    
    /**
     * Checks if the server is currently running
     * @return true if server is running
     */
    public boolean isRunning();
    
    /**
     * Gets the port number the server is listening on
     * @return the LDAP port number
     */
    public int getPort();
    
    /**
     * Sets the port number for the LDAP server
     * @param port the port number (default: random available port)
     */
    public void setPort(int port);
    
    /**
     * Sets additional Apache DS configuration
     * @param ldifFile path to LDIF file containing additional configuration
     */
    public void setLdifFile(String ldifFile);
    
    /**
     * Sets the working directory for the server
     * @param workingDirectory the working directory path
     */
    public void setWorkingDirectory(String workingDirectory);
    
    /**
     * Performs initialization after properties are set
     */
    public void afterPropertiesSet() throws Exception;
    
    /**
     * Cleanup resources when bean is destroyed
     */
    public void destroy() throws Exception;
}

Usage Examples:

// Basic Apache DS container setup
ApacheDSContainer container = new ApacheDSContainer("dc=springframework,dc=org", 
    "classpath:test-data.ldif");
container.setPort(33389);
container.start();

// With custom working directory
container.setWorkingDirectory("target/apacheds-work");

// Lifecycle management
container.afterPropertiesSet();
// ... use the server for testing
container.destroy();

UnboundIdContainer

Embedded UnboundID LDAP server container offering high performance for testing scenarios.

/**
 * Embedded UnboundID LDAP server container providing high-performance LDAP server
 * functionality for testing and development environments
 */
public class UnboundIdContainer implements InitializingBean, DisposableBean, Lifecycle {
    /**
     * Creates an UnboundID container with root DN and LDIF data
     * @param root the root DN for the directory
     * @param ldif path to LDIF file containing initial data
     */
    public UnboundIdContainer(String root, String ldif);
    
    /**
     * Starts the embedded UnboundID LDAP server
     * @throws Exception if server startup fails
     */
    public void start() throws Exception;
    
    /**
     * Stops the embedded UnboundID LDAP server
     * @throws Exception if server shutdown fails
     */
    public void stop() throws Exception;
    
    /**
     * Checks if the server is currently running
     * @return true if server is running
     */
    public boolean isRunning();
    
    /**
     * Gets the port number the server is listening on
     * @return the LDAP port number
     */
    public int getPort();
    
    /**
     * Sets the port number for the LDAP server
     * @param port the port number (default: random available port)
     */
    public void setPort(int port);
    
    /**
     * Sets the manager distinguished name for administrative operations
     * @param managerDn the manager DN (e.g., "cn=Directory Manager")
     */
    public void setManagerDn(String managerDn);
    
    /**
     * Sets the manager password for administrative operations
     * @param managerPassword the manager password
     */
    public void setManagerPassword(String managerPassword);
    
    /**
     * Performs initialization after properties are set
     */
    public void afterPropertiesSet() throws Exception;
    
    /**
     * Cleanup resources when bean is destroyed
     */
    public void destroy() throws Exception;
}

Usage Examples:

// Basic UnboundID container setup
UnboundIdContainer container = new UnboundIdContainer("dc=springframework,dc=org", 
    "classpath:test-users.ldif");
container.setPort(33389);
container.setManagerDn("cn=Directory Manager");
container.setManagerPassword("password");
container.start();

// Lifecycle management in tests
@BeforeEach
void setUp() throws Exception {
    container.afterPropertiesSet();
    container.start();
}

@AfterEach
void tearDown() throws Exception {
    container.stop();
    container.destroy();
}

Test Configuration Examples

Spring Test Configuration with Embedded Server

@TestConfiguration
@Profile("embedded-ldap")
public class EmbeddedLdapConfig {
    
    @Bean
    @Primary
    public UnboundIdContainer embeddedLdapServer() {
        UnboundIdContainer container = new UnboundIdContainer(
            "dc=springframework,dc=org", 
            "classpath:test-ldap-data.ldif"
        );
        container.setPort(0); // Use random available port
        container.setManagerDn("cn=Directory Manager");
        container.setManagerPassword("password");
        return container;
    }
    
    @Bean
    @Primary
    @DependsOn("embeddedLdapServer")
    public DefaultSpringSecurityContextSource embeddedContextSource() {
        int port = embeddedLdapServer().getPort();
        DefaultSpringSecurityContextSource contextSource = 
            new DefaultSpringSecurityContextSource("ldap://localhost:" + port + "/dc=springframework,dc=org");
        contextSource.setUserDn("cn=Directory Manager");
        contextSource.setPassword("password");
        return contextSource;
    }
}

JUnit 5 Test with Embedded LDAP

@SpringBootTest
@ActiveProfiles("embedded-ldap")
class LdapAuthenticationTest {
    
    @Autowired
    private UnboundIdContainer embeddedLdapServer;
    
    @Autowired
    private LdapAuthenticationProvider authenticationProvider;
    
    @Test
    void shouldAuthenticateValidUser() {
        // Given
        UsernamePasswordAuthenticationToken token = 
            new UsernamePasswordAuthenticationToken("john", "password");
        
        // When
        Authentication result = authenticationProvider.authenticate(token);
        
        // Then
        assertThat(result.isAuthenticated()).isTrue();
        assertThat(result.getName()).isEqualTo("john");
        assertThat(result.getAuthorities()).hasSize(2);
    }
}

Integration Test Setup

@ExtendWith(SpringExtension.class)
@ContextConfiguration(classes = {EmbeddedLdapConfig.class, LdapSecurityConfig.class})
class LdapIntegrationTest {
    
    @Autowired
    private ApacheDSContainer ldapServer;
    
    @Autowired
    private LdapUserDetailsService userDetailsService;
    
    @BeforeEach
    void startLdapServer() throws Exception {
        if (!ldapServer.isRunning()) {
            ldapServer.start();
        }
    }
    
    @AfterEach
    void stopLdapServer() throws Exception {
        if (ldapServer.isRunning()) {
            ldapServer.stop();
        }
    }
    
    @Test
    void shouldLoadUserDetails() {
        UserDetails user = userDetailsService.loadUserByUsername("alice");
        
        assertThat(user).isNotNull();
        assertThat(user.getUsername()).isEqualTo("alice");
        assertThat(user.getAuthorities()).isNotEmpty();
    }
}

LDIF Data Examples

Sample LDIF for Testing

# test-ldap-data.ldif
dn: dc=springframework,dc=org
objectClass: top
objectClass: domain
objectClass: extensibleObject
dc: springframework

dn: ou=people,dc=springframework,dc=org
objectClass: top
objectClass: organizationalUnit
ou: people

dn: ou=groups,dc=springframework,dc=org
objectClass: top
objectClass: organizationalUnit
ou: groups

# Users
dn: uid=john,ou=people,dc=springframework,dc=org
objectClass: top
objectClass: person
objectClass: organizationalPerson
objectClass: inetOrgPerson
uid: john
cn: John Smith
sn: Smith
mail: john@springframework.org
userPassword: password

dn: uid=alice,ou=people,dc=springframework,dc=org
objectClass: top
objectClass: person
objectClass: organizationalPerson
objectClass: inetOrgPerson
uid: alice
cn: Alice Johnson
sn: Johnson
mail: alice@springframework.org
userPassword: secret

# Groups
dn: cn=users,ou=groups,dc=springframework,dc=org
objectClass: top
objectClass: groupOfNames
cn: users
member: uid=john,ou=people,dc=springframework,dc=org
member: uid=alice,ou=people,dc=springframework,dc=org

dn: cn=admins,ou=groups,dc=springframework,dc=org
objectClass: top
objectClass: groupOfNames
cn: admins
member: uid=alice,ou=people,dc=springframework,dc=org

Complex Test Data Structure

@TestConfiguration
public class LdapTestDataConfig {
    
    @Bean
    public UnboundIdContainer ldapServerWithComplexData() {
        UnboundIdContainer container = new UnboundIdContainer(
            "dc=example,dc=com", 
            "classpath:complex-ldap-structure.ldif"
        );
        
        // Configure for complex scenarios
        container.setPort(0);
        container.setManagerDn("cn=Directory Manager");
        container.setManagerPassword("admin123");
        
        return container;
    }
    
    // Bean that loads additional test data after server start
    @Bean
    @DependsOn("ldapServerWithComplexData")
    public LdapTestDataLoader testDataLoader() {
        return new LdapTestDataLoader(embeddedContextSource());
    }
}

@Component
public class LdapTestDataLoader {
    
    private final SpringSecurityLdapTemplate ldapTemplate;
    
    public LdapTestDataLoader(ContextSource contextSource) {
        this.ldapTemplate = new SpringSecurityLdapTemplate(contextSource);
    }
    
    @PostConstruct
    public void loadAdditionalTestData() {
        // Add test data programmatically
        createTestOrganizationalUnits();
        createTestUsers();
        createTestGroups();
    }
    
    private void createTestOrganizationalUnits() {
        // Create additional OUs for testing
        DirContextAdapter context = new DirContextAdapter("ou=departments,dc=example,dc=com");
        context.setAttributeValues("objectClass", new String[]{"top", "organizationalUnit"});
        context.setAttributeValue("ou", "departments");
        ldapTemplate.bind(context);
    }
    
    // Additional helper methods for test data creation...
}

Performance Testing Configuration

@TestConfiguration
@Profile("performance-test")
public class PerformanceLdapConfig {
    
    @Bean
    public UnboundIdContainer performanceTestLdapServer() {
        UnboundIdContainer container = new UnboundIdContainer(
            "dc=perf,dc=test", 
            "classpath:large-dataset.ldif"
        );
        
        // Optimize for performance testing
        container.setPort(33389); // Fixed port for consistency
        container.setManagerDn("cn=Directory Manager");
        container.setManagerPassword("admin");
        
        return container;
    }
    
    @Bean
    @Primary
    public DefaultSpringSecurityContextSource performanceContextSource() {
        DefaultSpringSecurityContextSource contextSource = 
            new DefaultSpringSecurityContextSource("ldap://localhost:33389/dc=perf,dc=test");
        
        // Connection pool settings for performance
        contextSource.setPooled(true);
        
        Map<String, Object> baseEnv = new HashMap<>();
        baseEnv.put("com.sun.jndi.ldap.connect.pool.maxsize", "20");
        baseEnv.put("com.sun.jndi.ldap.connect.pool.prefsize", "10");
        baseEnv.put("com.sun.jndi.ldap.connect.pool.timeout", "300000");
        contextSource.setBaseEnvironmentProperties(baseEnv);
        
        return contextSource;
    }
}

Docker-based Testing Alternative

@Testcontainers
@SpringBootTest
class DockerLdapTest {
    
    @Container
    static final GenericContainer<?> ldapContainer = new GenericContainer<>("osixia/openldap:1.5.0")
            .withExposedPorts(389)
            .withEnv("LDAP_ORGANISATION", "Test Org")
            .withEnv("LDAP_DOMAIN", "test.org")
            .withEnv("LDAP_ADMIN_PASSWORD", "admin")
            .withClasspathResourceMapping("test-data.ldif", "/container/service/slapd/assets/config/bootstrap/ldif/50-bootstrap.ldif", BindMode.READ_ONLY);
    
    @DynamicPropertySource
    static void configureProperties(DynamicPropertyRegistry registry) {
        registry.add("ldap.url", () -> "ldap://localhost:" + ldapContainer.getMappedPort(389));
        registry.add("ldap.base", () -> "dc=test,dc=org");
        registry.add("ldap.username", () -> "cn=admin,dc=test,dc=org");
        registry.add("ldap.password", () -> "admin");
    }
    
    @Test
    void shouldConnectToDockerLdap() {
        // Test LDAP connectivity and operations
        assertThat(ldapContainer.isRunning()).isTrue();
    }
}

Install with Tessl CLI

npx tessl i tessl/maven-org-springframework-security--spring-security-ldap

docs

authentication.md

authorities.md

context-management.md

embedded-server.md

index.md

json-serialization.md

password-policy.md

user-details.md

tile.json