Spring LdapTemplate search()方法无法返回dn属性的问题
问题:Spring LDAP搜索结果中缺少DN属性
我编写了一个基于CN执行LDAP搜索并映射所有返回属性的Java程序,代码如下。程序运行后返回的属性列表里没有DN属性,但用ldapsearch执行等价搜索时,DN能正常返回。
import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import javax.naming.NamingEnumeration; import javax.naming.NamingException; import javax.naming.directory.Attribute; import javax.naming.directory.Attributes; import org.springframework.ldap.core.AttributesMapper; import org.springframework.ldap.core.LdapTemplate; import org.springframework.ldap.core.support.LdapContextSource; import org.springframework.ldap.query.ConditionCriteria; import org.springframework.ldap.query.ContainerCriteria; import static org.springframework.ldap.query.LdapQueryBuilder.query; import org.springframework.security.ldap.DefaultSpringSecurityContextSource; public class LDAPSearchTest { public static void main(String[] args) { LdapContextSource contextSource = new DefaultSpringSecurityContextSource("ldaps://localhost:636"); contextSource.setUserDn(""); contextSource.setPassword(""); contextSource.setAnonymousReadOnly(false); contextSource.afterPropertiesSet(); LdapTemplate ldapTemplate = new LdapTemplate(contextSource); ConditionCriteria condition = query() .base("baseDNValue") .where("cn"); ContainerCriteria filter = condition.is("cnValue"); List<Map<String, List<Object>>> results = ldapTemplate.search( filter, new DefaultAttributesMapper()); for (Map<String, List<Object>> groupSearchResult : results) { for (String attributeName : groupSearchResult.keySet()) { System.out.println(String.format(" %s", attributeName)); for (Object attributeValue : groupSearchResult.get(attributeName)) { System.out.println(String.format(" %s", attributeValue == null ? null : attributeValue.toString())); } } } } private static class DefaultAttributesMapper implements AttributesMapper<Map<String, List<Object>>> { @Override public Map<String, List<Object>> mapFromAttributes(Attributes attributes) throws NamingException { Map<String, List<Object>> mappedAttributes = new LinkedHashMap<>(); NamingEnumeration<? extends Attribute> attributesEnumeration = attributes.getAll(); while (attributesEnumeration.hasMore()) { Attribute nextAttribute = attributesEnumeration.next(); mappedAttributes.put(nextAttribute.getID(), new ArrayList<>()); NamingEnumeration attributeValuesEnumeration = nextAttribute.getAll(); while (attributeValuesEnumeration.hasMore()) { Object nextAttributeValue = attributeValuesEnumeration.next(); mappedAttributes.get(nextAttribute.getID()).add(nextAttributeValue); } } return mappedAttributes; } } }
原因分析
- DN的本质:LDAP中的DN(Distinguished Name)是条目的唯一路径标识,不属于条目本身的属性集合,它是用来定位条目的“地址”,而非条目存储的属性。
- 工具与API的差异:
ldapsearch工具默认会将DN作为搜索结果的元数据返回,但Spring LDAP底层依赖的JDNI API中,Attributes对象仅包含条目自身存储的属性,不会自动包含DN。 - Mapper的局限性:当前使用的
AttributesMapper仅负责处理条目属性,无法访问到DN这类元数据信息。
解决思路
方案1:改用ContextMapper获取DN和属性
ContextMapper可以访问到DirContextOperations对象,该对象同时包含DN和条目属性。修改搜索逻辑如下:
import java.util.Collections; // 需导入Collections类 // 替换原search代码段 List<Map<String, List<Object>>> results = ldapTemplate.search( filter, new ContextMapper<Map<String, List<Object>>>() { @Override public Map<String, List<Object>> mapFromContext(Object ctx) throws NamingException { DirContextOperations dirContext = (DirContextOperations) ctx; Map<String, List<Object>> mappedAttributes = new LinkedHashMap<>(); // 添加DN到结果Map mappedAttributes.put("dn", Collections.singletonList(dirContext.getDn().toString())); // 遍历并添加其他属性 Attributes attributes = dirContext.getAttributes(); NamingEnumeration<? extends Attribute> attrEnum = attributes.getAll(); while (attrEnum.hasMore()) { Attribute attr = attrEnum.next(); List<Object> values = new ArrayList<>(); NamingEnumeration<?> valueEnum = attr.getAll(); while (valueEnum.hasMore()) { values.add(valueEnum.next()); } mappedAttributes.put(attr.getID(), values); } return mappedAttributes; } });
方案2:直接获取SearchResult对象
SearchResult包含条目名称(可转换为DN)和属性,使用SearchResultCallbackHandler处理结果:
ldapTemplate.search(filter, new SearchResultCallbackHandler() { @Override public void handleSearchResult(SearchResult searchResult) throws NamingException { // 获取完整DN String dn = searchResult.getNameInNamespace(); System.out.println("dn: " + dn); // 处理其他属性 Attributes attributes = searchResult.getAttributes(); NamingEnumeration<? extends Attribute> attrEnum = attributes.getAll(); while (attrEnum.hasMore()) { Attribute attr = attrEnum.next(); System.out.println(" " + attr.getID()); NamingEnumeration<?> valueEnum = attr.getAll(); while (valueEnum.hasMore()) { System.out.println(" " + valueEnum.next()); } } } });
内容的提问来源于stack exchange,提问作者alessandro ferrucci
相关产品推荐
相关产品推荐

