SpringBoot LDAP user authentication operation

Keywords: Spring Java Maven Gradle

Opening word

This guide will guide you through the creation of the Spring Security Application protected by LDAP module.
 

Apps you will create

We will create a simple Web application protected by Spring Security's embedded Java LDAP server. We will load the LDAP server with a data file that contains a set of users.
 

Tools you will need

How to complete this guide

Like most Spring Getting Started Guide Similarly, you can start from scratch and complete each step, or you can bypass the basic setup steps that you are already familiar with. In either case, you end up with code that works.

When you are ready, you can check the code in the GS authenticating LDAP / complete directory.
 

Start with Spring Initializr

For all Spring applications, you should Spring Initializr Start. Initializr provides a quick way to extract the dependencies required by your application and complete many settings for you. This example requires only Spring Web dependencies.

Because the guide focuses on secure and insecure Web applications, we will first build insecure Web applications, and then add the dependency of Spring Security and LDAP functions.

The following figure shows the Initializr settings for this sample project:

The figure above shows Initializr with Maven as the build tool. You can also use the Gradle. It also displays the values of com.example and authenticating LDAP as Group and Artifact, respectively. These values will be used for the rest of this example.

The following listing shows the pom.xml file created when Maven was selected:

<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.2.2.RELEASE</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
	<groupId>com.example</groupId>
	<artifactId>authenticating-ldap</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>authenticating-ldap</name>
	<description>Demo project for Spring Boot</description>

	<properties>
		<java.version>1.8</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-test</artifactId>
			<scope>test</scope>
			<exclusions>
				<exclusion>
					<groupId>org.junit.vintage</groupId>
					<artifactId>junit-vintage-engine</artifactId>
				</exclusion>
			</exclusions>
		</dependency>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>

</project>

The following listing shows the build.gradle file that was created when Gradle was selected:

plugins {
	id 'org.springframework.boot' version '2.2.2.RELEASE'
	id 'io.spring.dependency-management' version '1.0.8.RELEASE'
	id 'java'
}

group = 'com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '1.8'

repositories {
	mavenCentral()
}

dependencies {
	implementation 'org.springframework.boot:spring-boot-starter-web'
	testImplementation('org.springframework.boot:spring-boot-starter-test') {
		exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
	}
}

test {
	useJUnitPlatform()
}

 

Create a simple Web controller

In Spring, the REST endpoint is the Spring MVC controller. The following Spring MVC controllers (from src/main/java/com/example/authenticatingldap/HomeController.java) process GET / requests by returning a simple message:

package com.example.authenticatingldap;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class HomeController {

  @GetMapping("/")
  public String index() {
    return "Welcome to the home page!";
  }

}

The entire class is marked with @ RestController so that Spring MVC can automatically detect the controller (by using its built-in scanning capabilities) and automatically configure the necessary Web routes.

@RestController also tells Spring MVC to write the text directly to the HTTP response body because there is no view. Instead, when we visit the page, we get a simple message in the browser (because the guide focuses on protecting the page with LDAP).
 

Building insecure Web applications

Before you protect a Web Application, you should verify that it is functioning properly. To do this, we need to define some key bean s, which can be done by creating the Application class. The following listing (from Src / main / Java / COM / example / authenticatingldap / authenticatingldappapplication. Java) shows this class:

package com.example.authenticatingldap;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class AuthenticatingLdapApplication {

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

}

@SpringBootApplication is a convenient annotation that adds all of the following:

  • @Configuration: mark the class as the source defined by the application context Bean;
  • @Enable autoconfiguration: tells Spring Boot to add beans according to the configuration of classpath, other beans, and various properties.
  • @ComponentScan: Tell Spring to look for other components, configurations and services in the COM / example.xxxxx package.

The main() method uses Spring Boot's SpringApplication.run() method to start the application.
 

Operation and Application

We can run the application from the command line in combination with Gradle or Maven. We can also build an executable JAR file that contains all the necessary dependencies, classes, and resources, and then run it. In the whole development life cycle, cross environment and so on, building executable jars can easily publish, version and deploy services as applications.

If you use Gradle, you can run the application with. / gradlew bootRun. Or build the JAR file with. / gradlew build, and then run the JAR file as follows:

java -jar build/libs/gs-authenticating-ldap-0.1.0.jar

If you use Maven, you can run it with. / mvnw spring boot: run. Or you can use. / mvnw clean package to build a JAR file, and then run the JAR file as follows:

java -jar target/gs-authenticating-ldap-0.1.0.jar

We can still Build a classic WAR file.

When accessed through a browser http://localhost:8080 When, we should see the following plain text output:

Welcome to the home page!

 

Configure Spring Security

To configure Spring Security, you first need to add some additional dependencies to the build.
For Gradle based builds, add the following dependencies to the build.gradle file:

implementation 'org.springframework.boot:spring-boot-starter-security:2.2.2.RELEASE'
implementation 'org.springframework.boot:spring-boot-starter-data-ldap:2.2.2.RELEASE'
implementation 'org.springframework.security:spring-security-ldap:5.2.1.RELEASE'
implementation 'com.unboundid:unboundid-ldapsdk:4.0.14'

Because of Gradle's artifact resolution, spring TX must be inserted. Otherwise, Gradle will get an old version that doesn't work.

For Maven based builds, add the following dependencies to the pom.xml file:

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-security</artifactId>
	<version>2.2.2.RELEASE</version>
</dependency>
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-data-ldap</artifactId>
	<version>2.2.2.RELEASE</version>
</dependency>
<dependency>
	<groupId>org.springframework.security</groupId>
	<artifactId>spring-security-ldap</artifactId>
	<version>5.2.1.RELEASE</version>
</dependency>
<dependency>
	<groupId>com.unboundid</groupId>
	<artifactId>unboundid-ldapsdk</artifactId>
    <version>4.0.14</version>
</dependency>

These dependencies add Spring Security and an open source LDAP server, UnboundId. With these dependencies, we can use pure java to configure security policies, as shown in the following example (from src/main/java/com/example/authenticatingldap/WebSecurityConfig.java):

package com.example.authenticatingldap;

import org.springframework.context.annotation.Configuration;
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.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;

@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

  @Override
  protected void configure(HttpSecurity http) throws Exception {
    http
      .authorizeRequests()
        .anyRequest().fullyAuthenticated()
        .and()
      .formLogin();
  }

  @Override
  public void configure(AuthenticationManagerBuilder auth) throws Exception {
    auth
      .ldapAuthentication()
        .userDnPatterns("uid={0},ou=people")
        .groupSearchBase("ou=groups")
        .contextSource()
          .url("ldap://localhost:8389/dc=springframework,dc=org")
          .and()
        .passwordCompare()
          .passwordEncoder(new BCryptPasswordEncoder())
          .passwordAttribute("userPassword");
  }

}

@The EnableWebSecurity annotation activates the bean s required to use Spring Security.
We need an LDAP server. Spring Boot provides automatic configuration for embedded servers written in pure Java, which the guide will use. The LdapAuthentication() method is configured to insert the user name on the login form into {0} so that it searches the LDAP server for uid = {0}, ou = people, dc = springframework, dc = org. In addition, the passwordCompare() method configures the encoder and the name of the password property.
 

Set user data

LDAP servers can use LDIF (LDAP data exchange format) files to exchange user data. Spring Boot can pull in the LDIF data file through the spring.ldap.embedded.ldif property in application.properties. This makes it easy to preload presentation data. The following listing (from src/main/resources/test-server.ldif) shows the LDIF file for this example:

dn: dc=springframework,dc=org
objectclass: top
objectclass: domain
objectclass: extensibleObject
dc: springframework

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

dn: ou=subgroups,ou=groups,dc=springframework,dc=org
objectclass: top
objectclass: organizationalUnit
ou: subgroups

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

dn: ou=space cadets,dc=springframework,dc=org
objectclass: top
objectclass: organizationalUnit
ou: space cadets

dn: ou=\"quoted people\",dc=springframework,dc=org
objectclass: top
objectclass: organizationalUnit
ou: "quoted people"

dn: ou=otherpeople,dc=springframework,dc=org
objectclass: top
objectclass: organizationalUnit
ou: otherpeople

dn: uid=ben,ou=people,dc=springframework,dc=org
objectclass: top
objectclass: person
objectclass: organizationalPerson
objectclass: inetOrgPerson
cn: Ben Alex
sn: Alex
uid: ben
userPassword: $2a$10$c6bSeWPhg06xB1lvmaWNNe4NROmZiSpYhlocU/98HNr2MhIOiSt36

dn: uid=bob,ou=people,dc=springframework,dc=org
objectclass: top
objectclass: person
objectclass: organizationalPerson
objectclass: inetOrgPerson
cn: Bob Hamilton
sn: Hamilton
uid: bob
userPassword: bobspassword

dn: uid=joe,ou=otherpeople,dc=springframework,dc=org
objectclass: top
objectclass: person
objectclass: organizationalPerson
objectclass: inetOrgPerson
cn: Joe Smeth
sn: Smeth
uid: joe
userPassword: joespassword

dn: cn=mouse\, jerry,ou=people,dc=springframework,dc=org
objectclass: top
objectclass: person
objectclass: organizationalPerson
objectclass: inetOrgPerson
cn: Mouse, Jerry
sn: Mouse
uid: jerry
userPassword: jerryspassword

dn: cn=slash/guy,ou=people,dc=springframework,dc=org
objectclass: top
objectclass: person
objectclass: organizationalPerson
objectclass: inetOrgPerson
cn: slash/guy
sn: Slash
uid: slashguy
userPassword: slashguyspassword

dn: cn=quote\"guy,ou=\"quoted people\",dc=springframework,dc=org
objectclass: top
objectclass: person
objectclass: organizationalPerson
objectclass: inetOrgPerson
cn: quote\"guy
sn: Quote
uid: quoteguy
userPassword: quoteguyspassword

dn: uid=space cadet,ou=space cadets,dc=springframework,dc=org
objectclass: top
objectclass: person
objectclass: organizationalPerson
objectclass: inetOrgPerson
cn: Space Cadet
sn: Cadet
uid: space cadet
userPassword: spacecadetspassword



dn: cn=developers,ou=groups,dc=springframework,dc=org
objectclass: top
objectclass: groupOfUniqueNames
cn: developers
ou: developer
uniqueMember: uid=ben,ou=people,dc=springframework,dc=org
uniqueMember: uid=bob,ou=people,dc=springframework,dc=org

dn: cn=managers,ou=groups,dc=springframework,dc=org
objectclass: top
objectclass: groupOfUniqueNames
cn: managers
ou: manager
uniqueMember: uid=ben,ou=people,dc=springframework,dc=org
uniqueMember: cn=mouse\, jerry,ou=people,dc=springframework,dc=org

dn: cn=submanagers,ou=subgroups,ou=groups,dc=springframework,dc=org
objectclass: top
objectclass: groupOfUniqueNames
cn: submanagers
ou: submanager
uniqueMember: uid=ben,ou=people,dc=springframework,dc=org

For production systems, using LDIF files is not a standard configuration. However, it is useful for testing purposes or guidance.

When we visit again http://localhost:8080 We should be redirected to the login page provided by Spring Security.

Enter the user name ben and password benspassword. We should see the following message in the browser:

Welcome to the home page!

 

Summary

Congratulations! We have written a Web application and passed the Spring Security It is protected. In this case, we use the LDAP Based user storage.
 

See also

The following guidelines may also help:

Would you like to see the rest of the guide? Visit the column of the guide:< Official Spring guide>

Published 87 original articles, won praise 6, visited 4099
Private letter follow

Posted by dgoosens on Sun, 26 Jan 2020 02:56:04 -0800