【问题标题】:Spring MVC REST: Method to Search Active Directory using LdapTemplate, LdapContextSource and SpringSecurityAuthenticationSourceSpring MVC REST:使用 LdapTemplate、LdapContextSource 和 SpringSecurityAuthenticationSource 搜索 Active Directory 的方法
【发布时间】:2014-01-29 03:30:41
【问题描述】:

我有一个 Spring MVC REST 应用程序。我已经使用 AD 作为身份验证提供程序实现了 Spring 安全性。我需要实现一些可以帮助搜索 AD 的控制器方法。因此,我定义了一个用户详细信息服务,它自动连接LdapTemplate 以在 AD 上执行查询。

UserDetailsS​​vc.java

@Component
public class UserDetailsSvc {

    @Autowired
    LdapTemplate ldapTemplate;

    private final Logger logger = Logger.getLogger(UserDetailsSvc.class);

    @SuppressWarnings("unchecked")
    public UserDetails getUserDetails(String username) {
        // Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        // logger.info("Auth Details: " + authentication.getPrincipal() + "/" + authentication.getCredentials());

        AndFilter filter = new AndFilter();
        filter.and(new EqualsFilter("objectClass", "user"));
        filter.and(new EqualsFilter("userPrincipalName", username));

        logger.info("AD filter: " + filter.encode());
        LinkedList<Map<String, String>> list = (LinkedList<Map<String, String>>) 
                 ldapTemplate.search("", filter.encode(), new UserAttributesMapper());
        logger.info("AD Search complete");

        UserDetails ud = new UserDetails();
        if (!list.isEmpty()) {
            // Should only return one item
            ud.setName(username);
            ud.setDetails(list.get(0));
        }
        return ud;
    }

    private class UserAttributesMapper implements AttributesMapper {
        @Override
        public Map<String, String> mapFromAttributes(Attributes attributes) throws javax.naming.NamingException {
            Map<String, String> map = new HashMap<String, String>();
            logger.info("UserAttributesMapper: " + attributes.toString() );

            String fullname = (String) attributes.get("displayName").get(); 
            String email = (String) attributes.get("mail").get(); 
            String title = (String) attributes.get("title").get();
            String image = (String) attributes.get("extensionAttribute1").get();
            String username = (String) attributes.get("uid").get();

            map.put("fullname", fullname);
            map.put("email", email);
            map.put("title", title);
            map.put("image", image);
            map.put("username", username);

            logger.info("user details : " + map.get("fullname") + map.get("email") + map.get("title") + map.get("image") + map.get("username"));

            return map;
        }
    }
}

spring security xml 文件的片段。

spring-security.xml

<beans:bean id="ldapTemplate" class="org.springframework.ldap.core.LdapTemplate">
    <beans:constructor-arg ref="contextSource" />
    <beans:property name="ignorePartialResultException" value="true" />
</beans:bean>
<beans:bean id="contextSource" class="org.springframework.ldap.core.support.LdapContextSource">
  <beans:property name="url" value="${ldap.url}" />
  <beans:property name="base" value="${ldap.basecn}" />
  <beans:property name="authenticationSource" ref="authenticationSource" />
</beans:bean>
<beans:bean id="authenticationSource" class="org.springframework.ldap.authentication.DefaultValuesAuthenticationSourceDecorator">
  <beans:property name="target" ref="springSecurityAuthenticationSource" />
  <beans:property name="defaultUser" value="{ldap.defuser}" />
  <beans:property name="defaultPassword" value="{ldap.password}" />
</beans:bean>
<beans:bean id="springSecurityAuthenticationSource"
  class="org.springframework.security.ldap.authentication.SpringSecurityAuthenticationSource" />

问题是ldapTemplate.search 抛出NullPointerException。你能帮忙吗?

这是我得到的例外:

java.lang.NullPointerException
        at java.util.Hashtable.put(Hashtable.java:542)
        at org.springframework.ldap.core.support.SimpleDirContextAuthenticationStrategy.setupEnvironment(SimpleDirContextAuthenticationStrategy.java:44)
        at org.springframework.ldap.core.support.AbstractContextSource.setupAuthenticatedEnvironment(AbstractContextSource.java:155)
        at org.springframework.ldap.core.support.AbstractContextSource.getAuthenticatedEnv(AbstractContextSource.java:481)
        at org.springframework.ldap.core.support.AbstractContextSource.getContext(AbstractContextSource.java:106)
        at org.springframework.ldap.core.support.AbstractContextSource.getReadOnlyContext(AbstractContextSource.java:125)
    at org.springframework.ldap.core.LdapTemplate.search(LdapTemplate.java:287)
    at org.springframework.ldap.core.LdapTemplate.search(LdapTemplate.java:259)
    at org.springframework.ldap.core.LdapTemplate.search(LdapTemplate.java:571)
    at org.springframework.ldap.core.LdapTemplate.search(LdapTemplate.java:556)
    at org.springframework.ldap.core.LdapTemplate.search(LdapTemplate.java:411)
    at org.springframework.ldap.core.LdapTemplate.search(LdapTemplate.java:431)
    at org.springframework.ldap.core.LdapTemplate.search(LdapTemplate.java:451)
    at com.vmware.concorde.appadm.service.UserDetailsSvc.getUserDetails(UserDetailsSvc.java:44)
    at com.vmware.concorde.appadm.web.UserController.findUsers(UserController.java:42)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:601)

    at org.springframework.web.method.support.InvocableHandlerMethod.invoke(InvocableHandlerMethod.java:213)
    at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:126)
    at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:96)
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:617)
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:578)
    at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:80)
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:923)
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:852)
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:882)
    at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:778)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:621)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:728)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:305)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)

...


谢谢 卡利安

【问题讨论】:

  • 无关:在开始您的自定义 AD 身份验证实施之前,您是否尝试过 built-in AD support
  • 我用过内置的alos。但我想覆盖 loadUserAuthorities。除了删除 final 以扩展 ActiveDirectoryLdapAuthenticationProvider 之外,我没有进行任何更改。你认为它与这个问题有某种关系吗?
  • 顺便说一句,我的 AD 身份验证工作正常。我需要实现一些 REST api 调用来搜索 AD 中的用户、组并关联自定义权限并将它们存储在数据库中。登录的用户无权修改 AD,因此需要将权限存储在自定义数据库中。除此之外,我还在我自己的数据库中存储与用户会话相关的信息(超时、超时等)。所以,CustomUserDetails 对我来说不是很有帮助,因为我需要搜索其他用户(不是登录的用户)的详细信息。
  • 问题似乎是由您的SpringSecurityAuthenticationSource bean 在调用getCredentials() 方法时返回null 密码引起的。不知道为什么会这样。

标签: spring-mvc spring-security spring-ldap


【解决方案1】:

http://forum.spring.io/forum/spring-projects/data/ldap/130283-search-active-directory-with-ldaptemplate-ldapcontextsource-sp-sec-auth-sou-rce

如果您只想使用默认用户和密码,请不要使用 DefaultValuesAuthenticationSourceDecorator。 DefaultValuesAuthenticationSourceDecorator 尝试在 session 中使用 spring 安全用户来执行 LdapContext 中的操作:

解决方案:

<beans:bean id="ldapTemplate" class="org.springframework.ldap.core.LdapTemplate">
    <beans:constructor-arg ref="contextSource" />
    <beans:property name="ignorePartialResultException" value="true" />
</beans:bean>
<beans:bean id="contextSource" class="org.springframework.ldap.core.support.LdapContextSource">
  <beans:property name="url" value="${ldap.url}" />
  <beans:property name="base" value="${ldap.basecn}" />
  <beans:property name="user" value="${ldap.defuser}" />
  <beans:property name="password" value="${ldap.password}" />

</beans:bean>

【讨论】:

    猜你喜欢
    • 2018-08-30
    • 1970-01-01
    • 2023-04-01
    • 2013-02-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多