Spring Security LDAP + Maven + XML Configuration

By Arvind Rai, December 23, 2019
On this page we will use LDAP with Spring Security to authenticate a user using Maven and XML configuration. The LDAP (Lightweight Directory Access Protocol) interacts with directory server. LDAP directory server is used for data store specially for storing information about users, groups, and applications. LDAP is used for authentication service in organizations.
To define a node in LDAP, we use keywords such as o (Organization), ou (Organizational Unit), cn (Common Name), sn (Surname), uid (User Id), dn (Distinguished Name), dc (Domain Component) etc. A user in LDAP can be defined as below.
dn: uid=surya,ou=people,dc=concretepage,dc=com 
To authenticate a user, unique LDAP dn from login name is obtained and password is matched against the password attribute (eg. userPassword) in the directory entry for the dn and then list of authorities of the user is loaded.
Here we will create Spring Boot Security LDAP example with XML configuration using UnboundID LDAP server as embedded server. We will use bcrypt password encoding strategy to store the password. Now find the complete example in detail step-by-step.

Technologies Used

Find the technologies being used in our example.
1. Java 11
2. Spring 5.2.1.RELEASE
3. Spring Boot 2.2.1.RELEASE
4. UnboundID LDAP SDK 4.0.12
5. Maven 3.5.2

Maven Dependencies

Find the maven dependencies used in our example.
pom.xml
<parent>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-parent</artifactId>
	<version>2.2.1.RELEASE</version>
	<relativePath />
</parent>
<properties>
	<context.path>spring-app</context.path>
	<java.version>11</java.version>
</properties>
<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>
	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-thymeleaf</artifactId>
	</dependency>
</dependencies> 
The unboundid-ldapsdk resolves dependency for UnboundID LDAP SDK. In our Spring Boot Security application, we are using UnboundID LDAP server as embedded server.

LDIF File

Find the LDIF file used in our example. We have kept this file in our project classpath.
my-server.ldif
dn: dc=concretepage,dc=com
objectclass: top
objectclass: domain
objectclass: extensibleObject
dc: concretepage

dn: ou=groups,dc=concretepage,dc=com
objectclass: top
objectclass: organizationalUnit
ou: groups

dn: ou=people,dc=concretepage,dc=com
objectclass: top
objectclass: organizationalUnit
ou: people

dn: uid=krishna,ou=people,dc=concretepage,dc=com
objectclass: top
objectclass: person
objectclass: organizationalPerson
objectclass: inetOrgPerson
cn: Krishna Sharma
sn: Sharma
uid: krishna
userPassword: $2a$10$nnu2.EBSnJUQZmOv5hbD8.3C8dlifeLi26AWpoKN31FqjNXrijQMq

dn: uid=surya,ou=people,dc=concretepage,dc=com
objectclass: top
objectclass: person
objectclass: organizationalPerson
objectclass: inetOrgPerson
cn: Surya Singh
sn: Singh
uid: surya
userPassword: $2a$10$DPzHnInANVY1utbuRfe0eOojtE02k23TGB5Q0L6mIHOBJQhKU7DTi

dn: cn=developers,ou=groups,dc=concretepage,dc=com
objectclass: top
objectclass: groupOfUniqueNames
cn: developers
ou: developer
uniqueMember: uid=krishna,ou=people,dc=concretepage,dc=com
uniqueMember: uid=surya,ou=people,dc=concretepage,dc=com

dn: cn=managers,ou=groups,dc=concretepage,dc=com
objectclass: top
objectclass: groupOfUniqueNames
cn: managers
ou: manager
uniqueMember: uid=krishna,ou=people,dc=concretepage,dc=com 
Here we have created two roles MANAGERS and DEVELOPERS and two users with credentials krishna/k123 and surya/s123 and password is in bcrypt encoding. The user krishna has MANAGERS and DEVELOPERS roles whereas the user surya has DEVELOPERS role only.

LDAP XML Configurations

LDAP server is configured using <ldap-server> element. It has following attributes.

id: A bean identifier.
url: Specifies a URL.
ldif: Explicitly specifies an ldif file to load into an embedded LDAP server. By default ldif files are loaded from classpath.
manager-dn: Username used to authenticate non-embedded LDAP server. Default is anonymous.
manager-password: Password used to authenticate LDAP server.
port: Specifies server port.
root: Optional root suffix for the embedded LDAP server.

Find the example to use <ldap-server> element.
<ldap-server url="ldap://localhost:2389/dc=concretepage,dc=com" /> 

Now we will define LDAP authentication provider. Spring Security provides <ldap-authentication-provider> element to define LDAP authentication provider. The <ldap-authentication-provider> has following attributes.

user-dn-pattern: Pattern used to build the user dn.
user-search-base: Search base for user searches.
user-search-filter: LDAP filter used to search for users.
group-search-base: Defines search base for group membership searches.
group-search-filter: Defines group search filter.
group-role-attribute: LDAP attribute name which contains the role name. Default is cn.
role-prefix: Defines role prefix, for example (ROLE_).
server-ref: Server to use. If omitted, then <ldap-server> with no id (if defined) is registered.
user-context-mapper-ref: Specifies UserDetailsContextMapper bean for explicit customization of loaded user object.
user-details-class: Specifies objectClass of the user entry. Default is person.

Find the example to use LDAP authentication provider.
<authentication-manager>
	<ldap-authentication-provider
		server-ref="ldapServer"
		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 password-attribute="userPassword">
	           <password-encoder ref="passwordEncoder"/>
	    </password-compare>
	</ldap-authentication-provider>
</authentication-manager> 
The <password-compare> configures LDAP compare operation of the user password to authenticate. The password-attribute specifies the attribute that contains user password. The <password-encoder> defines password encoding strategy. In our demo application we are using bcrypt password encoder.
<beans:bean name="passwordEncoder" 
            class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder"/> 

Find the complete Spring Security LDAP XML configuration used in our demo application.
security-config.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/security"
	xmlns:beans="http://www.springframework.org/schema/beans" 
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
	http://www.springframework.org/schema/beans/spring-beans.xsd
	http://www.springframework.org/schema/security
	http://www.springframework.org/schema/security/spring-security.xsd">
	
	<http>
		<intercept-url  pattern="/secure/man/**" access="hasRole('MANAGERS')" />
		<intercept-url  pattern="/secure/dev/**" access="hasRole('DEVELOPERS')" />		
		<form-login 
		   login-page="/login" 
		   login-processing-url="/appLogin"
		   username-parameter="username"
		   password-parameter="password"
		   default-target-url="/secure/dev"/>
		<logout 
		   logout-url="/appLogout" 
		   logout-success-url="/login"/>  
		<access-denied-handler error-page="/accessDenied"/>
	</http>

	<beans:bean name="passwordEncoder" class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder"/>
	
	<authentication-manager>
          <ldap-authentication-provider
                server-ref="ldapServer"
                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 password-attribute="userPassword">
                <password-encoder ref="passwordEncoder"/>
            </password-compare>
          </ldap-authentication-provider>
	</authentication-manager>
    
        <ldap-server id="ldapServer" url="ldap://localhost:2389/dc=concretepage,dc=com" />
        
</beans:beans> 


Complete Example

Find the project structure of our demo application.
Spring Security LDAP + Maven + XML Configuration
The files my-server.ldif, pom.xml and security-config.xml have been already given above in the article. Here find the other files of our demo application.
application.properties
spring.ldap.embedded.ldif=classpath:my-server.ldif
spring.ldap.embedded.base-dn=dc=concretepage,dc=com
spring.ldap.embedded.port=2389 
custom-login.html
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
    <head>
        <title>Spring Security Example</title>
        <link rel="stylesheet" href="/css/styles.css"/>
    </head>
    <body>
        <h3>Spring Security Example</h3> 
        <p th:if="${param.error}" class="error">
            Bad Credentials  
        </p>
        <form th:action="@{/appLogin}" method="POST">
            User Name : <input type="text" name="username"/> <br/><br/>
            Password: <input type="password" name="password"/> <br/><br/>
            <input type="submit" value="Login"/>
        </form>
    </body>
</html> 
info.html
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
<head>
      <title>Spring Security Example</title>
      <link rel="stylesheet" href="/css/styles.css"/>
</head>
<body>
            <h3>Spring Security Example</h3>
	    Welcome to <b th:inline="text"  class="user"> [[${#httpServletRequest.remoteUser}]] </b>
	    <br/><br/>
	    <form th:action="@{/appLogout}" method="POST">
	         <input type="submit" value="Logout"/>
	    </form>
</body>
</html> 
access-denied.html
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
<head>
      <title>Spring Security Example</title>
      <link rel="stylesheet" href="/css/styles.css"/>
</head>
<body>
    <h3>Access Denied Exception</h3>
    Logged in user: <b th:inline="text"  class="user"> [[${#httpServletRequest.remoteUser}]] </b>
    <br/><br/>
    <form th:action="@{/appLogout}" method="POST">
         <input type="submit" value="Logout"/>
    </form>
    <p class="error" th:text="${errorMsg}">Error</p>
</body>
</html> 
AppConfig.java
package com.concretepage;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportResource;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;

@Configuration
@ImportResource("classpath:security-config.xml")
@EnableWebSecurity
public class AppConfig {

} 
HomeController.java
package com.concretepage;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.servlet.ModelAndView;

@Controller
public class HomeController {
	@GetMapping("/login")
	public ModelAndView login() {
		ModelAndView mav = new ModelAndView();
		mav.setViewName("custom-login");
		return mav;
	}

	@GetMapping("/secure/man")
	public ModelAndView welcome1(Authentication authentication) {
		ModelAndView mav = new ModelAndView();
		mav.setViewName("info");
		return mav;
	}

	@GetMapping("/secure/dev")
	public ModelAndView welcome2(Authentication authentication) {
		ModelAndView mav = new ModelAndView();
		mav.setViewName("info");
		return mav;
	}

	@GetMapping("/accessDenied")
	public ModelAndView error() {
		ModelAndView mav = new ModelAndView();
		String errorMessage = "You are not authorized to access this page.";
		mav.addObject("errorMsg", errorMessage);
		mav.setViewName("access-denied");
		return mav;
	}
} 
Main.java
package com.concretepage;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class Main {
	public static void main(String[] args) {
		SpringApplication.run(Main.class, args);
	}
} 

Output

Download the project and run the following command from root folder of the project using command prompt.
mvn spring-boot:run 
Access the URL.
http://localhost:8080/secure/dev 
Enter credentials surya/s123
Spring Security LDAP + Maven + XML Configuration
We will see welcome page as following.
Spring Security LDAP + Maven + XML Configuration

References

Spring Security Reference
Authenticating a User with LDAP

Download Source Code

POSTED BY
ARVIND RAI
ARVIND RAI
LEARN MORE








©2024 concretepage.com | Privacy Policy | Contact Us