Spring MVC REST:使用LdapTemplate,LdapContextSource和SpringSecurityAuthenticationSource搜索Active Directory的方法

时间:2013-08-08 11:08:59

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

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

弹簧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)

...


由于 格利扬

1 个答案:

答案 0 :(得分:0)

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

如果您只想使用默认用户和密码,请不要使用DefaultValuesAuthenticationSourceDecorator。 DefaultValuesAuthenticationSourceDecorator尝试在会话中使用spring security用户来执行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>