文章目录
- 一、项目背景
- 二、准备工作
- 三、验证结果
- 四、易错点讲解
- 易错点1:java: 无法访问org.springframework.ldap.core.LdapTemplate
- 易错点2:java: 无法访问org.springframework.context.ConfigurableApplicationContext
- 易错点3:[LDAP: error code 34 - invalid DN]
- 易错点4:LDAP: error code 32 - No Such Object
- 易错点5:配置文件介绍
一、项目背景
我们公司原项目是Spring或者SpringBoot项目,现在假设收购了一家公司(人家所有账户信息都保存在ldap数据库中),现在需要把它集成进来,最终实现项目支持两种方式认证:
如果是http协议执行从mysql数据库查询账户,校验用户+密码
;另一种如果是ldap协议,则从ldap中查询账户,校验用户+密码
;
目前我的项目版本:
Spring版本:5.3.15
SpringBoot版本:2.6.3
二、准备工作
test.ldif文件 用于创建账户
注意点1:
必须先创建组,然后才能创建组下用户,不然cn=ldapUser1,ou=Develop,ou=Hytera,dc=yaobili,dc=com这么写是非法的
注意点2:
我创建了2个账户,ldapUser1账户1密码未加密Eadmin123456,ldapUser2账户2密码加密了设置的{SSHA}J3NuHvl3O8LdPuV2QFYc2pPy3wq1EzIN,它两都是相同的密码(即Eadmin123456和{SSHA}J3NuHvl3O8LdPuV2QFYc2pPy3wq1EzIN是等价的)
注意点3:
其中的{SSHA}代表采用SHA-1加密方式对密码进行了加密,详情可在服务器执行如下命令
[root@localhost ~]# slappasswd -s Eadmin123456
{SSHA}J3NuHvl3O8LdPuV2QFYc2pPy3wq1EzIN
创建组织架构
dn:ou=Hytera,dc=yaobili,dc=com
objectClass:organizationalUnit
ou:Hytera
dn:ou=Develop,ou=Hytera,dc=yaobili,dc=com
objectClass:organizationalUnit
ou:Develop
创建用户
dn: cn=ldapUser1,ou=Develop,ou=Hytera,dc=yaobili,dc=com
objectClass: inetOrgPerson
cn: ldapUser1
username: ldapUser1
userPassword: Eadmin123456
memberOf: ou=Develop,ou=Hytera,dc=yaobili,dc=com
dn: cn=ldapUser2,ou=Develop,ou=Hytera,dc=yaobili,dc=com
objectClass: inetOrgPerson
cn: ldapUser2
username: ldapUser2
userPassword: Eadmin123456
memberOf: ou=Develop,ou=Hytera,dc=yaobili,dc=com
dn: cn=ldapUser4,ou=Develop,ou=Hytera,dc=yaobili,dc=com
objectClass: inetOrgPerson
cn: ldapUser4
username: ldapUser4
userPassword: {SSHA}J3NuHvl3O8LdPuV2QFYc2pPy3wq1EzIN
memberOf: ou=Develop,ou=Hytera,dc=yaobili,dc=com
成功后页面长这样:
pom.xml
<?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">
<parent>
<artifactId>springboot-test</artifactId>
<groupId>org.example</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>Ldap-test</artifactId>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<!--解决@RestController注解爆红-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>${spring.boot.starter.web.version}</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</dependency>
<!--测试类-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<version>${spring.boot.starter.test.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-ldap</artifactId>
<version>2.6.3</version>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-ldap</artifactId>
<version>2.6.3</version>
</dependency>
<dependency>
<groupId>com.sun</groupId>
<artifactId>ldapbp</artifactId>
<version>1.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.ldap</groupId>
<artifactId>spring-ldap-core</artifactId>
<version>2.4.0</version>
</dependency>
<dependency>
<groupId>org.apache.directory.api</groupId>
<artifactId>api-all</artifactId>
<version>2.0.0</version>
</dependency>
</dependencies>
</project>
application.properties
server.port=8020
spring.ldap.urls=ldap://10.110.38.162:389
spring.ldap.username=cn=admin,dc=yaobili,dc=com
spring.ldap.password=123456
spring.ldap.base=dc=yaobili,dc=com
LdapConfiguration配置类
package com.ldap.config;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.ldap.core.LdapTemplate;
import org.springframework.ldap.core.support.LdapContextSource;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
/**
* LDAP 的自动配置类
* @Author 211145187
* @Date 2024/5/21 16:44
**/
@Configuration
public class LdapConfiguration {
private static Logger logger = LoggerFactory.getLogger(LdapConfiguration.class);
private LdapTemplate ldapTemplate;
@Value("${spring.ldap.urls}")
private String dbUrl;
@Value("${spring.ldap.username}")
private String username;
@Value("${spring.ldap.password}")
private String password;
@Value("${spring.ldap.base}")
private String base;
@Bean
public LdapContextSource contextSource() {
LdapContextSource contextSource = new LdapContextSource();
Map<String, Object> config = new HashMap();
contextSource.setUrl(dbUrl);
contextSource.setBase(base);
contextSource.setUserDn(username);
contextSource.setPassword(password);
// 解决 乱码 的关键一句
config.put("java.naming.ldap.attributes.binary", "objectGUID");
contextSource.setPooled(true);
contextSource.setBaseEnvironmentProperties(config);
return contextSource;
}
@Bean
public LdapTemplate ldapTemplate(LdapContextSource contextSource) {
if (Objects.isNull(contextSource)) {
throw new RuntimeException("ldap contextSource error");
}
if (null == ldapTemplate) {
ldapTemplate = new LdapTemplate(contextSource);
}
return ldapTemplate;
}
}
LdapUserAttributeMapper映射类
package com.ldap.mapper;
import com.ldap.entity.LdapUser;
import org.springframework.ldap.core.AttributesMapper;
import javax.naming.NamingException;
import javax.naming.directory.Attributes;
/**
* 将ldap返回的结果,转成指定对象
*/
public class LdapUserAttributeMapper implements AttributesMapper {
/**
* 将单个Attributes转成单个对象
* @param attrs
* @return
* @throws NamingException
*/
@Override
public Object mapFromAttributes(Attributes attrs) throws NamingException {
LdapUser user = new LdapUser();
if(attrs.get("uid") != null){
user.setUid( attrs.get("uid").get().toString());
}
if(attrs.get("cn") != null){
user.setCn( attrs.get("cn").get().toString());
}
if(attrs.get("dn") != null){
user.setDn( attrs.get("dn").get().toString());
}
if(attrs.get("sn") != null){
user.setSn( attrs.get("sn").get().toString());
}
if(attrs.get("userPassword") != null){
user.setUserPassword(new String((byte[])attrs.get("userPassword").get()));
}
return user;
}
}
LdapUser实体类
package com.ldap.entity;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.ldap.odm.annotations.Attribute;
import org.springframework.ldap.odm.annotations.Entry;
import org.springframework.ldap.odm.annotations.Id;
/**
* @Author 211145187
* @Date 2024/5/22 09:31
**/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class LdapUser {
private String uid;
private String dn;
private String cn;
private String sn;
private String userPassword;
}
LdapTest测试类
package com.ldap;
import com.ldap.entity.LdapUser;
import com.ldap.mapper.LdapUserAttributeMapper;
import com.sun.org.apache.xerces.internal.impl.dv.util.Base64;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.ldap.core.LdapTemplate;
import org.springframework.ldap.filter.AndFilter;
import org.springframework.ldap.filter.EqualsFilter;
import org.springframework.test.context.junit4.SpringRunner;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.List;
@SpringBootTest
@RunWith(SpringRunner.class)
public class LdapTest {
@Autowired
private LdapTemplate ldapTemplate;
@Test
public void listUsers() throws NoSuchAlgorithmException {
AndFilter filter = new AndFilter();
filter.and(new EqualsFilter("objectClass", "inetOrgPerson"));
List<LdapUser> users = ldapTemplate.search("ou=Develop,ou=Hytera", filter.encode(), new LdapUserAttributeMapper());
for (LdapUser user: users ) {
System.out.println("user: " + user);
System.out.println("userPassword:" + user.getUserPassword());
System.out.println(verifySHA(user.getUserPassword(), "Eadmin123456"));
}
// Assert.assertEquals(123, users.size());
}
@SuppressWarnings(value = "unchecked")
public static boolean verifySHA(String ldappw, String inputpw)
throws NoSuchAlgorithmException {
// MessageDigest 提供了消息摘要算法,如 MD5 或 SHA,的功能,这里LDAP使用的是SHA-1
MessageDigest md = MessageDigest.getInstance("SHA-1");
// 取出加密字符
if (ldappw.startsWith("{SSHA}")) {
ldappw = ldappw.substring(6);
} else if (ldappw.startsWith("{SHA}")) {
ldappw = ldappw.substring(5);
}
// 解码BASE64
byte[] ldappwbyte = Base64.decode(ldappw);
byte[] shacode;
byte[] salt;
// 前20位是SHA-1加密段,20位后是最初加密时的随机明文
if (ldappwbyte.length <= 20) {
shacode = ldappwbyte;
salt = new byte[0];
} else {
shacode = new byte[20];
salt = new byte[ldappwbyte.length - 20];
System.arraycopy(ldappwbyte, 0, shacode, 0, 20);
System.arraycopy(ldappwbyte, 20, salt, 0, salt.length);
}
// 把用户输入的密码添加到摘要计算信息
md.update(inputpw.getBytes());
// 把随机明文添加到摘要计算信息
md.update(salt);
// 按SSHA把当前用户密码进行计算
byte[] inputpwbyte = md.digest();
// 返回校验结果
return MessageDigest.isEqual(shacode, inputpwbyte);
}
}
三、验证结果
结论:从结果可以看出确实读出来了,而且我也把密码打印出来了。
接下来对打印结果进行讲解
代码
@Test
public void listUsers() throws NoSuchAlgorithmException {
AndFilter filter = new AndFilter();
filter.and(new EqualsFilter("objectClass", "inetOrgPerson"));
List<LdapUser> users = ldapTemplate.search("ou=Develop,ou=Hytera", filter.encode(), new LdapUserAttributeMapper());
for (LdapUser user: users ) {
System.out.println("user: " + user);
System.out.println("userPassword:" + user.getUserPassword());
System.out.println(verifySHA(user.getUserPassword(), "Eadmin123456"));
}
}
我的需求
:假设页面传入了用户名和密码,然后我想从ldap读取所有账户信息,进行账户+密码的比对是否相等,做这么个事儿。
四、易错点讲解
易错点1:java: 无法访问org.springframework.ldap.core.LdapTemplate
完整错误:
java: 无法访问org.springframework.ldap.core.LdapTemplate
错误的类文件: /E:/apache-maven-3.6.3/repository/org/springframework/ldap/spring-ldap-core/3.2.3/spring-ldap-core-3.2.3.jar!/org/springframework/ldap/core/LdapTemplate.class
类文件具有错误的版本 61.0, 应为 52.0
请删除该文件或确保该文件位于正确的类路径子目录中。
错误原因
:引入的依赖版本和Spring版本或者SpringBoot版本不适配(大白话讲:你引入的版本太高了)
我最开始的依赖版本用的是最新的,因为习惯性添加依赖就会莫名添加最新的,结果问题就是它导致的。
<dependency>
<groupId>org.springframework.ldap</groupId>
<artifactId>spring-ldap-core</artifactId>
<version>3.2.3</version>
</dependency>
解决方案:
选择适配的即可,最终可以使用的版本
<dependency>
<groupId>org.springframework.ldap</groupId>
<artifactId>spring-ldap-core</artifactId>
<version>2.4.0</version>
</dependency>
易错点2:java: 无法访问org.springframework.context.ConfigurableApplicationContext
完整错误:
java: 无法访问org.springframework.context.ConfigurableApplicationContext
错误的类文件: /E:/apache-maven-3.6.3/repository/org/springframework/spring-context/6.1.7/spring-context-6.1.7.jar!/org/springframework/context/ConfigurableApplicationContext.class
类文件具有错误的版本 61.0, 应为 52.0
请删除该文件或确保该文件位于正确的类路径子目录中。
错误原因
:引入的依赖版本和Spring版本或者SpringBoot版本不适配(大白话讲:你引入的版本太高了)
我最开始的依赖版本用的是最新的,因为习惯性添加依赖就会莫名添加最新的,结果问题就是它导致的。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-ldap</artifactId>
<version>3.3.0</version>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-ldap</artifactId>
<version>3.3.0</version>
</dependency>
解决方案:
选择适配的即可,最终可以使用的版本
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-ldap</artifactId>
<version>2.6.3</version>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-ldap</artifactId>
<version>2.6.3</version>
</dependency>
易错点3:[LDAP: error code 34 - invalid DN]
完整错误
org.springframework.ldap.InvalidNameException: [LDAP: error code 34 - invalid DN]; nested exception is javax.naming.InvalidNameException: [LDAP: error code 34 - invalid DN]
at org.springframework.ldap.support.LdapUtils.convertLdapException(LdapUtils.java:136)
at org.springframework.ldap.core.support.AbstractContextSource.createContext(AbstractContextSource.java:363)
at org.springframework.ldap.core.support.AbstractContextSource.doGetContext(AbstractContextSource.java:147)
at org.springframework.ldap.core.support.AbstractContextSource.getReadOnlyContext(AbstractContextSource.java:166)
at org.springframework.ldap.core.LdapTemplate.search(LdapTemplate.java:361)
at org.springframework.ldap.core.LdapTemplate.search(LdapTemplate.java:332)
at org.springframework.ldap.core.LdapTemplate.search(LdapTemplate.java:608)
at org.springframework.ldap.core.LdapTemplate.search(LdapTemplate.java:598)
at org.springframework.ldap.core.LdapTemplate.search(LdapTemplate.java:486)
at org.springframework.ldap.core.LdapTemplate.search(LdapTemplate.java:502)
at org.springframework.ldap.core.LdapTemplate.search(LdapTemplate.java:518)
at com.ldap.LdapTest.listUsers(LdapTest.java:31)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:59)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:56)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.springframework.test.context.junit4.statements.RunBeforeTestExecutionCallbacks.evaluate(RunBeforeTestExecutionCallbacks.java:74)
at org.springframework.test.context.junit4.statements.RunAfterTestExecutionCallbacks.evaluate(RunAfterTestExecutionCallbacks.java:84)
at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:75)
at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:86)
at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:84)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:366)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:251)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:97)
at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329)
at org.junit.runners.ParentRunner.access$100(ParentRunner.java:66)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293)
at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
at org.junit.runners.ParentRunner.run(ParentRunner.java:413)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:190)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:69)
at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:33)
at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:220)
at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:53)
Caused by: javax.naming.InvalidNameException: [LDAP: error code 34 - invalid DN]
at com.sun.jndi.ldap.LdapCtx.processReturnCode(LdapCtx.java:3095)
at com.sun.jndi.ldap.LdapCtx.processReturnCode(LdapCtx.java:2886)
at com.sun.jndi.ldap.LdapCtx.connect(LdapCtx.java:2800)
at com.sun.jndi.ldap.LdapCtx.<init>(LdapCtx.java:319)
at com.sun.jndi.ldap.LdapCtxFactory.getUsingURL(LdapCtxFactory.java:192)
at com.sun.jndi.ldap.LdapCtxFactory.getUsingURLs(LdapCtxFactory.java:210)
at com.sun.jndi.ldap.LdapCtxFactory.getLdapCtxInstance(LdapCtxFactory.java:153)
at com.sun.jndi.ldap.LdapCtxFactory.getInitialContext(LdapCtxFactory.java:83)
at javax.naming.spi.NamingManager.getInitialContext(NamingManager.java:684)
at javax.naming.InitialContext.getDefaultInitCtx(InitialContext.java:313)
at javax.naming.InitialContext.init(InitialContext.java:244)
at javax.naming.ldap.InitialLdapContext.<init>(InitialLdapContext.java:154)
at org.springframework.ldap.core.support.LdapContextSource.getDirContextInstance(LdapContextSource.java:42)
at org.springframework.ldap.core.support.AbstractContextSource.createContext(AbstractContextSource.java:351)
... 41 more
代码长这样:
application.properties
spring.ldap.urls=ldap://10.110.38.162:389
spring.ldap.username=admin
spring.ldap.password=123456
spring.ldap.base=dc=yaobili,dc=com
LdapTest
@Test
public void listUsers() throws NoSuchAlgorithmException {
AndFilter filter = new AndFilter();
filter.and(new EqualsFilter("objectClass", "inetOrgPerson"));
List<LdapUser> users = ldapTemplate.search("ou=Develop,ou=Hytera", filter.encode(), new LdapUserAttributeMapper());
for (LdapUser user: users ) {
System.out.println("user: " + user);
System.out.println("userPassword:" + user.getUserPassword());
System.out.println(verifySHA(user.getUserPassword(), "Eadmin123456"));
}
}
错误原因
:配置文件中spring.ldap.username这里错了,因为我创建了admin管理员账户,但是这里我不知道是输入admin 啊还是输入完整dn
解决方案
:此处应该输入完整dn:spring.ldap.username=cn=admin,dc=yaobili,dc=com
易错点4:LDAP: error code 32 - No Such Object
完整错误
org.springframework.ldap.NameNotFoundException: [LDAP: error code 32 - No Such Object]; nested exception is javax.naming.NameNotFoundException: [LDAP: error code 32 - No Such Object]; remaining name 'ou=Develop,ou=Hytera,dc=yaobili,dc=com'
at org.springframework.ldap.support.LdapUtils.convertLdapException(LdapUtils.java:183)
at org.springframework.ldap.core.LdapTemplate.search(LdapTemplate.java:380)
at org.springframework.ldap.core.LdapTemplate.search(LdapTemplate.java:332)
at org.springframework.ldap.core.LdapTemplate.search(LdapTemplate.java:608)
at org.springframework.ldap.core.LdapTemplate.search(LdapTemplate.java:598)
at org.springframework.ldap.core.LdapTemplate.search(LdapTemplate.java:486)
at org.springframework.ldap.core.LdapTemplate.search(LdapTemplate.java:502)
at org.springframework.ldap.core.LdapTemplate.search(LdapTemplate.java:518)
at com.ldap.LdapTest.listUsers(LdapTest.java:31)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:59)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:56)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.springframework.test.context.junit4.statements.RunBeforeTestExecutionCallbacks.evaluate(RunBeforeTestExecutionCallbacks.java:74)
at org.springframework.test.context.junit4.statements.RunAfterTestExecutionCallbacks.evaluate(RunAfterTestExecutionCallbacks.java:84)
at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:75)
at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:86)
at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:84)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:366)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:251)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:97)
at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329)
at org.junit.runners.ParentRunner.access$100(ParentRunner.java:66)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293)
at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
at org.junit.runners.ParentRunner.run(ParentRunner.java:413)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:190)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:69)
at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:33)
at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:220)
at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:53)
Caused by: javax.naming.NameNotFoundException: [LDAP: error code 32 - No Such Object]; remaining name 'ou=Develop,ou=Hytera,dc=yaobili,dc=com'
at com.sun.jndi.ldap.LdapCtx.mapErrorCode(LdapCtx.java:3179)
at com.sun.jndi.ldap.LdapCtx.processReturnCode(LdapCtx.java:3100)
at com.sun.jndi.ldap.LdapCtx.processReturnCode(LdapCtx.java:2891)
at com.sun.jndi.ldap.LdapCtx.searchAux(LdapCtx.java:1846)
at com.sun.jndi.ldap.LdapCtx.c_search(LdapCtx.java:1769)
at com.sun.jndi.toolkit.ctx.ComponentDirContext.p_search(ComponentDirContext.java:392)
at com.sun.jndi.toolkit.ctx.PartialCompositeDirContext.search(PartialCompositeDirContext.java:358)
at com.sun.jndi.toolkit.ctx.PartialCompositeDirContext.search(PartialCompositeDirContext.java:341)
at javax.naming.directory.InitialDirContext.search(InitialDirContext.java:267)
at org.springframework.ldap.core.LdapTemplate$4.executeSearch(LdapTemplate.java:326)
at org.springframework.ldap.core.LdapTemplate.search(LdapTemplate.java:367)
... 38 more
错误代码:
application.properties
spring.ldap.urls=ldap://10.110.38.162:389
spring.ldap.username=cn=admin,dc=yaobili,dc=com
spring.ldap.password=123456
spring.ldap.base=ou=Develop,ou=Hytera,dc=yaobili,dc=com
LdapTest
@Test
public void listUsers() throws NoSuchAlgorithmException {
AndFilter filter = new AndFilter();
filter.and(new EqualsFilter("objectClass", "inetOrgPerson"));
List<LdapUser> users = ldapTemplate.search("ou=Develop,ou=Hytera,dc=yaobili,dc=com", filter.encode(), new LdapUserAttributeMapper());
for (LdapUser user: users ) {
System.out.println("user: " + user);
System.out.println("userPassword:" + user.getUserPassword());
System.out.println(verifySHA(user.getUserPassword(), "Eadmin123456"));
}
}
疑惑
:32错误码对应dn设置不对,但是我感觉不出来哪里不对啊,感觉spring.ldap.base和ldapTemplate.search都设置了正确的dn 啊,而且"ou=Develop,ou=Hytera,dc=yaobili,dc=com"这个dn就是我要查询账户所在的完整dn路径啊,不信看图。
错误原因
:spring.ldap.base和ldapTemplate.search是有传递行的(你可以理解为拼接的效果,一因此不能设置一样的否则就乱套了,找不到了)。这易错点特别操蛋,因为根本别人的博客找不到还有这个规则说明,上来就是给你贴配置类文件和代码,然后照抄运行就报错,关键他们也不贴运行结果,我就只能挨个尝试去试错。
解决方案
:
- 如果
spring.ldap.base
设置了spring.ldap.base=“ou=Develop,ou=Hytera,dc=yaobili,dc=com”,那么search方法构面跟的就应该是空字符串“”)
spring.ldap.base=ou=Develop,ou=Hytera,dc=yaobili,dc=com
List<LdapUser> users = ldapTemplate.search("", filter.encode(), new LdapUserAttributeMapper());
- 如果
spring.ldap.base
设置了spring.ldap.base=dc=yaobili,dc=com,那么search方法构面跟的就应该是"ou=Develop,ou=Hytera"
spring.ldap.base=dc=yaobili,dc=com
List<LdapUser> users = ldapTemplate.search("ou=Develop,ou=Hytera", filter.encode(), new LdapUserAttributeMapper());
易错点5:配置文件介绍
spring.ldap.urls=ldap://10.110.38.162:389
spring.ldap.username=cn=admin,dc=yaobili,dc=com
spring.ldap.password=123456
spring.ldap.base=dc=yaobili,dc=com
spring.ldap.urls
配置url,端口分两种:389和3268端口 389
:这是 LDAP(轻量级目录访问协议)的标准端口号。通常,LDAP 服务器使用此端口号来监听 LDAP 请求。大多数基于 LDAP 的应用程序和工具都默认使用此端口号来与 LDAP 服务器通信。端口 3268
:这是全局目录服务接口(Global Catalog Service)的端口号。全局目录是 Active Directory 的一部分,它包含了多个域的数据。端口 3268 允许在全局目录上进行查询,而不仅仅是在单个域中。这使得可以在整个 Active Directory 环境中执行查询操作。
spring.ldap.username
配置管理元用户名,此处只能输入管理员账户的完整dn,即必须输入cn=admin,dc=yaobili,dc=com才有效,而配置admin会导致无法登陆spring.ldap.password
配置密码,这里我试过了,只能配置未加密密码,配置加密密码也会导致无法登陆。spring.ldap.base
用于配置 LDAP 查询的基础路径(Base DN)的属性。Base DN 是 LDAP 查询的起始点,它指定了在搜索 LDAP 目录时的起始位置。