【发布时间】:2014-01-29 03:30:41
【问题描述】:
我有一个 Spring MVC REST 应用程序。我已经使用 AD 作为身份验证提供程序实现了 Spring 安全性。我需要实现一些可以帮助搜索 AD 的控制器方法。因此,我定义了一个用户详细信息服务,它自动连接LdapTemplate 以在 AD 上执行查询。
UserDetailsSvc.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 对我来说不是很有帮助,因为我需要搜索其他用户(不是登录的用户)的详细信息。
-
问题似乎是由您的
SpringSecurityAuthenticationSourcebean 在调用getCredentials()方法时返回null密码引起的。不知道为什么会这样。
标签: spring-mvc spring-security spring-ldap