Spring Security + Spring LDAP Authentication Configuration Example

摘要: In this tutorial we demonstrate how to Configure Spring Security + Spring LDAP authentication application. We show how to configure spring security and spring LDAP using Java And XML Configuration.

In this tutorial we demonstrate how to Configure Spring Security + Spring LDAP authentication application. We show how to configure spring security and spring LDAP using Java And XML Configuration.

LDAP is often used by organisations as a central repository for user information and as an authentication service. It can also be used to store the role information for application users.

Project Structure

Let’s start by looking at our project structure.

Maven Dependencies

We use Apache Maven to manage our project dependencies. Make sure the following dependencies reside on your class-path.

<?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.spring.security</groupId>
    <artifactId>ldap-auth</artifactId>
    <version>1.0.0-SNAPSHOT</version>
    <url>https://memorynotfound.com</url>
    <name>Spring SECURITY - ${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-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.ldap</groupId>
            <artifactId>spring-ldap-core</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-ldap</artifactId>
        </dependency>
        <dependency>
            <groupId>com.unboundid</groupId>
            <artifactId>unboundid-ldapsdk</artifactId>
        </dependency>

        <!-- testing -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-test</artifactId>
            <scope>test</scope>
        </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>

Spring LDAP + Spring Boot Embedded LDAP Configuration

In this example we configure an embedded ldap server. We can configure the LDAP server using the application.yml file located in the src/main/resources folder.

# application.yml

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 with LDIF

We can populate the embedded LDAP server using a .ldif file. The following file populates the embedded LDAP server with organizational units, persons and groups. Passwords are hashed using SHA. You can generate your password hash and place it in the userPassword field.

dn: dc=memorynotfound,dc=com
objectclass: top
objectclass: domain
objectclass: extensibleObject
dc: memorynotfound

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


dn: uid=john,ou=people,dc=memorynotfound,dc=com
objectclass: top
objectclass: person
objectclass: organizationalPerson
objectclass: inetOrgPerson
cn: John Doe
uid: john
userPassword: {SHA}5en6G6MezRroT3XKqkdPOmY/BfQ=


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

dn: cn=managers,ou=groups,dc=memorynotfound,dc=com
objectclass: top
objectclass: groupOfUniqueNames
cn: managers
ou: manager
uniqueMember: uid=john,ou=people,dc=memorynotfound,dc=com

Spring Security + Spring LDAP Java Configuration

The @EnableWebSecurity turns on a variety of beans needed to use Spring Security.

Using the ldapAuthentication() method, we can configure where spring security can pull the user information from. In this case we set the userDnPatterns() to uid={0},ou=people which translates in an LDAP lookup uid={0},ou=people,dc=memorynotfound,dc=com in the LDAP server. The groupSearchBase() method is used to map the LDAP groups into roles. Also, the passwordCompare() method configures the encoder and the name of the password’s attribute.

package com.memorynotfound.ldap.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.encoding.LdapShaPasswordEncoder;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.ldap.DefaultSpringSecurityContextSource;
import java.util.Collections;

@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .authorizeRequests()
                    .antMatchers("/managers").hasRole("MANAGERS")
                    .antMatchers("/employees").hasRole("EMPLOYEES")
                    .anyRequest().fullyAuthenticated()
                .and()
                    .formLogin();
    }

    @Override
    public void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth
                .ldapAuthentication()
                    .userDnPatterns("uid={0},ou=people")
                    .userSearchBase("ou=people")
                    .userSearchFilter("uid={0}")
                    .groupSearchBase("ou=groups")
                    .groupSearchFilter("uniqueMember={0}")
                .contextSource(contextSource())
                .passwordCompare()
                    .passwordEncoder(new LdapShaPasswordEncoder())
                    .passwordAttribute("userPassword");
    }

    @Bean
    public DefaultSpringSecurityContextSource contextSource() {
        return  new DefaultSpringSecurityContextSource(
                Collections.singletonList("ldap://localhost:12345"), "dc=memorynotfound,dc=com");
    }

}

Spring Security + Spring LDAP XML Configuration

This is the equivalent Spring Security LDAP XML Configuration.

@ImportResource("classpath:spring-security-config.xml")

<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/security"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xmlns:beans="http://www.springframework.org/schema/beans"
             xsi:schemaLocation="http://www.springframework.org/schema/security
                                 http://www.springframework.org/schema/security/spring-security.xsd
                                 http://www.springframework.org/schema/beans
                                 http://www.springframework.org/schema/beans/spring-beans.xsd">

    <http auto-config="true" use-expressions="true">
        <intercept-url pattern="/managers" access="hasRole('MANAGERS')"/>
        <intercept-url pattern="/employees" access="hasRole('EMPLOYEES')"/>
        <intercept-url pattern="/**" access="isFullyAuthenticated()"/>

        <form-login
                default-target-url="/"
                always-use-default-target="true" />
    </http>

    <authentication-manager>
        <ldap-authentication-provider
                user-dn-pattern="uid={0},ou=people"
                user-search-base="ou=people"
                user-search-filter="uid={0}"
                group-search-base="ou=groups"
                group-search-filter="uniqueMember={0}">
            <password-compare
                    hash="{sha}"
                    password-attribute="userPassword"/>
        </ldap-authentication-provider>
    </authentication-manager>

    <beans:bean class="org.springframework.security.ldap.DefaultSpringSecurityContextSource">
        <beans:constructor-arg value="ldap://localhost:12345"/>
        <beans:constructor-arg value="dc=memorynotfound,dc=com"/>
    </beans:bean>

</beans:beans>

Secured Rest Controller

For testing purposes, we created a simple Rest Service. This service is only available for fully authenticated users. We can obtain the logged in user information using the SecurityContextHolder.getContext().getAuthentication() method which returns a UsernamePasswordAuthenticationToken instance containing the user information.

package com.memorynotfound.ldap.controller;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.ldap.userdetails.LdapUserDetailsImpl;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class HomeController {

    private static Logger log = LoggerFactory.getLogger(HomeController.class);

    @GetMapping("/")
    public String index() {

        log.info("Getting UsernamePasswordAuthenticationToken from SecurityContextHolder");
        UsernamePasswordAuthenticationToken authentication =
                (UsernamePasswordAuthenticationToken)
                        SecurityContextHolder.getContext().getAuthentication();

        log.info("Getting principal from UsernamePasswordAuthenticationToken");
        LdapUserDetailsImpl principal = (LdapUserDetailsImpl) authentication.getPrincipal();

        log.info("authentication: " + authentication);
        log.info("principal: " + principal);

        return "Spring Security + Spring LDAP Authentication Configuration Example";
    }

    @GetMapping("/managers")
    public String managers(){
        return "Hello managers";
    }

    @GetMapping("/employees")
    public String employees(){
        return "Hello employees";
    }
}

Bootstrap Spring Application

We bootstrap the application using Spring Boot. In the example we used Spring Java Configuration. You can also use Spring XML configuration. If you need Spring XML Configuration, you can enable it by using the @ImportResource("classpath:spring-security-config.xml").

package com.memorynotfound.ldap;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Configuration;

@Configuration
@SpringBootApplication
// Enable if you want to use Spring Security + LDAP Authentication XML Configuration
// @ImportResource("classpath:spring-security-config.xml") 
public class Application {

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

}

Spring Security + Spring LDAP Authentication Example

After the application is initialized go to the http://localhost:8080 url and you’ll see the following screen. You can login using the username john with password secret.

After a succesfull login we see the following screen.

The user uid=john,ou=people resides in the group cn=managers,ou=groups which results in having a role ROLE_MANAGERS so he can access the managers rest service.

The user uid=john,ou=people does not in the group cn=employees,ou=groups which means he cannot access the employees rest service

Spring Security + Spring LDAP Authentication Integration Tests

Now we created a successful Spring Security LDAP authentication application, we can write some integration tests to verify everything keeps working.

The @AutoConfigureMockMvc annotation auto configures the MockMvc. Using the MockMvc class we can perform invocations on server side endpoints. In the following integration tests we first create a FormLoginRequestBuilder using SecurityMockMvcRequestBuilders.formLogin() method and pass the credentials. Next, we perform a MockMvc.perform() invocation and validate the result using the SecurityMockMvcResultMatchers.authenticated() or SecurityMockMvcResultMatchers.unauthenticated() result matchers, based on the expected outcome.

package com.memorynotfound.ldap;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestBuilders.FormLoginRequestBuilder;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;

import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestBuilders.formLogin;
import static org.springframework.security.test.web.servlet.response.SecurityMockMvcResultMatchers.authenticated;
import static org.springframework.security.test.web.servlet.response.SecurityMockMvcResultMatchers.unauthenticated;

@SpringBootTest
@AutoConfigureMockMvc
@ActiveProfiles("test")
@RunWith(SpringRunner.class)
public class ApplicationTests {

    @Autowired
    private MockMvc mockMvc;

    @Test
    public void loginWithValidUserThenAuthenticated() throws Exception {
        FormLoginRequestBuilder login = formLogin().user("john").password("secret");
        mockMvc.perform(login).andExpect(authenticated().withUsername("john"));
    }

    @Test
    public void loginWithInvalidUserThenUnauthenticated() throws Exception {
        FormLoginRequestBuilder login = formLogin().user("invalid").password("invalidpassword");
        mockMvc.perform(login).andExpect(unauthenticated());
    }

}

Spring Security + Spring LDAP Authentication Integration Test Results

Download

上一篇: Spring Boot + Spring Security + Thymeleaf Form Login Example
下一篇: Apache HttpClient 4.5 Multipart Upload Request Example
 评论 ( What Do You Think )
名称
邮箱
网址
评论
验证
   
 

 


  • 微信公众号

  • 我的微信

站点声明:

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

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

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