
Implementing User Authentication with LDAP in Spring Boot
Learn how to integrate LDAP protocol in Spring Boot projects to implement user authentication, including dependency setup, configuration, user object classes, login logic, and user status determination.
1. Add spring-boot-starter-data-ldap Dependency
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-ldap</artifactId>
</dependency>
2. Configuration File
spring:
ldap:
urls: ldap://xx.xx.xx.xx:389
base: OU=xxx,DC=xxx,DC=com
username: xxx@xx.com
password: xxx
Fill in the URL, baseDN, username, and password information in the configuration file
3. Create User Object Class
import com.alibaba.fastjson.annotation.JSONField;
import lombok.Data;
import org.springframework.ldap.odm.annotations.Attribute;
import org.springframework.ldap.odm.annotations.Entry;
import org.springframework.ldap.odm.annotations.Id;
import javax.naming.Name;
/**
* LDAP protocol person class
*/
@Data
@Entry(objectClasses = "person")
public class Person {
/**
* Unique identifier
*/
@Id
@JSONField(serialize = false)
private Name distinguishedName;
/**
* Login account
*/
@Attribute(name = "sAMAccountName")
private String loginName;
/**
* User name
*/
@Attribute(name = "cn")
private String name;
/**
* Permission code
*/
@Attribute(name = "userAccountControl")
private Integer userAccountControl;
/**
* Is deleted
*/
private Boolean isDelete;
}
4. User Login
4.1 Example Code
import org.springframework.ldap.core.LdapTemplate;
import org.springframework.ldap.filter.EqualsFilter;
private final LdapTemplate ldapTemplate;
private static final String LDAP_USERNAME_ATTR = "sAMAccountName";
public void login(String userName, String password) {
EqualsFilter filter = new EqualsFilter(LDAP_USERNAME_ATTR, userName);
boolean result = ldapTemplate.authenticate("", filter.toString(), password);
}
The basic logic is to call the ldapTemplate’s authenticate method for authentication.
4.2 Complete Code
package com.cowave.meter.admin.user.service.impl;
import cn.hutool.core.util.IdUtil;
import com.cowave.commons.framework.access.Access;
import com.cowave.commons.framework.filter.security.AccessToken;
import com.cowave.commons.framework.filter.security.TokenService;
import com.cowave.commons.framework.support.mybatis.page.PageDO;
import com.cowave.commons.framework.util.Asserts;
import com.cowave.commons.framework.util.AssertsException;
import com.cowave.meter.admin.user.dao.SysDeptDao;
import com.cowave.meter.admin.user.dao.SysRoleDao;
import com.cowave.meter.admin.user.dao.SysUserDao;
import com.cowave.meter.admin.user.pojo.Person;
import com.cowave.meter.admin.user.pojo.SysDept;
import com.cowave.meter.admin.user.pojo.SysRole;
import com.cowave.meter.admin.user.pojo.SysUser;
import com.cowave.meter.admin.user.service.LdapService;
import com.cowave.meter.admin.user.service.SysUserService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.ldap.core.LdapTemplate;
import org.springframework.ldap.filter.EqualsFilter;
import org.springframework.ldap.query.LdapQueryBuilder;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;
import java.util.List;
@Slf4j
@Service
@RequiredArgsConstructor
public class LdapServiceImpl implements LdapService {
private final LdapTemplate ldapTemplate;
private final TokenService tokenService;
private final SysUserDao sysUserDao;
private final SysUserService userService;
private final SysDeptDao sysDeptDao;
private final SysRoleDao sysRoleDao;
private final BCryptPasswordEncoder bcryptPasswordEncoder = new BCryptPasswordEncoder();
private static final String LDAP_USERNAME_ATTR = "sAMAccountName";
/**
* Domain account login
*
* @param userName
* @param password
* @return
*/
@Override
public AccessToken domainLogin(String userName, String password) {
EqualsFilter filter = new EqualsFilter(LDAP_USERNAME_ATTR, userName);
boolean authenticate = ldapTemplate.authenticate("", filter.toString(), password);
if (!authenticate) {
throw new AssertsException("auth.failed");
}
Boolean domainUserAccountExist = sysUserDao.domainUserAccountExist(userName);
if (Boolean.FALSE.equals(domainUserAccountExist)) {
LdapQueryBuilder ldapQuery = LdapQueryBuilder.query();
ldapQuery.filter(filter);
Person person = ldapTemplate.findOne(ldapQuery, Person.class);
if (ObjectUtils.isEmpty(person)) {
throw new AssertsException("user.notexist");
}
SysUser sysUser = new SysUser();
sysUser.setUserAccount(userName);
Asserts.isFalse(userService.userAccountExist(sysUser), "Account name already exists");
sysUser.setUserName(person.getName());
sysUser.setUserPasswd(bcryptPasswordEncoder.encode(password));
sysUser.setDomainUserAccount(userName);
// Set department
SysDept sysDept = sysDeptDao.queryRootDept();
if (!ObjectUtils.isEmpty(sysDept)) {
sysUser.setDeptId(sysDept.getDeptId());
}
// Set role
PageDO<SysRole> sysRolePageDO = sysRoleDao.queryPage(null, "2", 1, 1);
if (sysRolePageDO.getPages() > 0) {
SysRole sysRole = sysRolePageDO.getList().get(0);
sysUser.setRoleId(sysRole.getRoleId());
}
userService.saveOrUpdate(sysUser);
}
SysUser sysUser = sysUserDao.getByDomainUserAccount(userName);
String userId = sysUser.getUserId();
AccessToken accessToken = new AccessToken();
accessToken.setType(AccessToken.TYPE_USER);
accessToken.setUserCode(userId);
accessToken.setUsername(sysUser.getUserAccount());
accessToken.setUserNick(sysUser.getUserName());
accessToken.setDeptCode(sysUser.getDeptId());
accessToken.setRoles(List.of(sysUser.getRoleId()));
accessToken.setLoginIp(Access.ip());
accessToken.setLoginTime(Access.time());
accessToken.setAccessIp(Access.ip());
accessToken.setAccessTime(Access.time());
accessToken.setId(IdUtil.fastSimpleUUID());
String token = tokenService.newToken(accessToken);
accessToken.setToken(token);
return accessToken;
}
}
4.3 Check if User is Disabled
/**
* Determine whether the user is disabled based on AD domain's userAccountControl attribute
*
* @param userAccContr
* @return
*/
private Boolean getUserDelete(int userAccContr) {
//TRUSTED_TO_AUTH_FOR_DELEGATION - Allow this account to be delegated
if (userAccContr >= 16777216) {
userAccContr = userAccContr - 16777216;
}
//PASSWORD_EXPIRED - (Windows 2000/Windows Server 2003) User's password has expired
if (userAccContr >= 8388608) {
userAccContr = userAccContr - 8388608;
}
//DONT_REQ_PREAUTH
if (userAccContr >= 4194304) {
userAccContr = userAccContr - 4194304;
}
//USE_DES_KEY_ONLY - (Windows 2000/Windows Server 2003) Restrict this user to use only Data Encryption Standard (DES) encryption type keys
if (userAccContr >= 2097152) {
userAccContr = userAccContr - 2097152;
}
//NOT_DELEGATED - When this flag is set, the user's security context will not be delegated to the service even if the service account is trusted for Kerberos delegation
if (userAccContr >= 1048576) {
userAccContr = userAccContr - 1048576;
}
//TRUSTED_FOR_DELEGATION - When this flag is set, the service account (user or computer account) running the service is trusted for Kerberos delegation.
// Any such service can impersonate the client requesting the service. To allow a service for Kerberos delegation, this flag must be set on the service account's userAccountControl attribute
if (userAccContr >= 524288) {
userAccContr = userAccContr - 524288;
}
//SMARTCARD_REQUIRED - When this flag is set, the user will be forced to use a smart card to log in
if (userAccContr >= 262144) {
userAccContr = userAccContr - 262144;
}
//MNS_LOGON_ACCOUNT - This is an MNS logon account
if (userAccContr >= 131072) {
userAccContr = userAccContr - 131072;
}
//DONT_EXPIRE_PASSWORD - Password never expires
if (userAccContr >= 65536) {
userAccContr = userAccContr - 65536;
}
//MNS_LOGON_ACCOUNT - This is an MNS logon account
if (userAccContr >= 2097152) {
userAccContr = userAccContr - 2097152;
}
//SERVER_TRUST_ACCOUNT - This is a computer account for a domain controller that belongs to this domain
if (userAccContr >= 8192) {
userAccContr = userAccContr - 8192;
}
//WORKSTATION_TRUST_ACCOUNT - This is a computer account for a computer running Microsoft Windows NT 4.0 Workstation, Microsoft Windows NT 4.0 Server,
// Microsoft Windows 2000 Professional, or Windows 2000 Server that belongs to this domain
if (userAccContr >= 4096) {
userAccContr = userAccContr - 4096;
}
//INTERDOMAIN_TRUST_ACCOUNT - For system domains that trust other domains, this attribute allows accounts that trust this system domain
if (userAccContr >= 2048) {
userAccContr = userAccContr - 2048;
}
//NORMAL_ACCOUNT - This is the default account type representing a typical user
if (userAccContr >= 512) {
userAccContr = userAccContr - 512;
}
//TEMP_DUPLICATE_ACCOUNT - This account belongs to a user whose primary account is in another domain. This account provides the user with access to this domain,
// but not access to any domains that trust this domain. Sometimes this account is called a "local user account"
if (userAccContr >= 256) {
userAccContr = userAccContr - 256;
}
//ENCRYPTED_TEXT_PASSWORD_ALLOWED - User can send encrypted passwords
if (userAccContr >= 128) {
userAccContr = userAccContr - 128;
}
//PASSWD_CANT_CHANGE - User cannot change password. This flag can be read but cannot be set directly
if (userAccContr >= 64) {
userAccContr = userAccContr - 64;
}
//PASSWD_NOTREQD - Password not required
if (userAccContr >= 32) {
userAccContr = userAccContr - 32;
}
//LOCKOUT
if (userAccContr >= 16) {
userAccContr = userAccContr - 16;
}
//HOMEDIR_REQUIRED - Home folder required
if (userAccContr >= 8) {
userAccContr = userAccContr - 8;
}
if (userAccContr >= 2) {
return true;
}
return false;
}