Spring Security LDAP + Maven + XML Configuration
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
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.
Contents
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>
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
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>
<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.
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
<!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>
<!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>
<!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>
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 { }
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; } }
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
http://localhost:8080/secure/dev


References
Spring Security ReferenceAuthenticating a User with LDAP