0

我有一个 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 文件的片段。

弹簧安全.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.searchthrows 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)

...


谢谢卡利安

4

1 回答 1

0

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

dont use the DefaultValuesAuthenticationSourceDecorator, if you want to use only default user and password. The DefaultValuesAuthenticationSourceDecorator try to use the spring security user in session to perform the actions in LdapContext:

Solution:

<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>
于 2014-01-28T19:30:41.137 回答