我有一个Spring MVC应用程序(使用3.0.5版本),需要使用Spring LDAP绑定到Active Directory,只是简单地验证用户的凭据。该应用程序托管在Linux服务器上,因此我需要一个 跨平台 解决方案。应用程序不使用Spring Security。
在此设置中实施用户身份验证的有效方法是什么? Active Directory支持FastBind
控件(id = 1.2.840.113556.1.4.1781
),因此我想利用它,因为我只需要验证输入凭据,而不需要从AD返回其他信息。
谢谢!
更新(2012年7月16日):我将继续使用解决方案的详细信息更新我的问题。
根据@ ig0774的回答,我写了以下connection control
类:
package com.company.authentication;
import javax.naming.ldap.Control;
public class FastBindConnectionControl implements Control {
@Override
public String getID() {
return "1.2.840.113556.1.4.1781";
}
@Override
public boolean isCritical() {
return true;
}
@Override
public byte[] getEncodedValue() {
return null;
}
}
然后,我使用AbstractContextSource
连接控制类扩展FastBind
:
package com.company.authentication;
import java.util.Hashtable;
import javax.naming.NamingException;
import javax.naming.directory.DirContext;
import javax.naming.ldap.Control;
import javax.naming.ldap.InitialLdapContext;
import org.springframework.ldap.core.support.AbstractContextSource;
public class FastBindActiveDirectoryContextSource extends AbstractContextSource {
@Override
protected DirContext getDirContextInstance(Hashtable env) throws NamingException {
return new InitialLdapContext(env, new Control[] { new FastBindConnectionControl() });
}
}
最后,一个服务类来封装认证机制:
package com.company.authentication;
import javax.naming.AuthenticationException;
import javax.naming.directory.DirContext;
import org.springframework.ldap.core.ContextSource;
import org.springframework.ldap.support.LdapUtils;
public class ActiveDirectoryAuthService implements IAuthenticate {
private ContextSource contextSource;
public void setContextSource(ContextSource contextSource) {
this.contextSource = contextSource;
}
@Override
public boolean authenticate(final String login, String password) {
try {
DirContext ctx = contextSource.getContext(login, password);
LdapUtils.closeContext(ctx);
return true;
}
catch (Exception e) {
return false;
}
}
}
在我的Spring应用程序上下文配置文件中,我添加了以下内容:
<bean id="ADContextSource" class="com.company.authentication.FastBindActiveDirectoryContextSource">
<property name="url" value="ldaps://x.x.x.x:636" />
</bean>
<bean id="userAuthenticationService" class="com.company.authentication.ActiveDirectoryAuthService">
<property name="contextSource" ref="ADContextSource" />
</bean>
最后,将userAuthenticationService
bean注入客户端类,比如登录控制器。
package com.company.web;
import com.company.authentication;
@Controller
public class LoginController {
@Autowired
private IAuthenticate userAuthenticationService;
public String authenticateUser(String login, String password) {
if (this.userAuthenticationService.authenticate(login, password)) {
return "welcome";
}
else {
return "login";
}
}
}
答案 0 :(得分:1)
在JNDI中实现FastBind
控件非常简单,如in this OTN forum post所述。
基本上,您为Control
控件创建了一个新的FastBind
类:
class FastBindConnectionControl implements Control {
public byte[] getEncodedValue() {
return null;
}
public String getID() {
return "1.2.840.113556.1.4.1781";
}
public boolean isCritical() {
return true;
}
}
然后用它来创建你的ldap上下文(错误处理和其他一切被忽略):
LdapContext ctx = new InitialLdapContext(env, new Control[] {new FastBindConnectionControl()});
理想情况下,这很容易插入Spring-LDAP,它是用于LDAP的JNDI API的包装器;但是,看起来内置LdapContextSource
的接口不接受处理连接控件的参数,因此您显然需要创建自己的AbstractContextSource
子类来处理那看起来应该是直截了当的:
class FastBindLdapContextSource extends AbstractContextSource {
protected DirContext getDirContextInstance(Hashtable env) {
return new InitialLdapContext(env, new Control[] {new FastBindConnectionControl()});
}
}
然后,您只需要将当前LdapContextSource
替换为FastBindLdapContextSource
的实例。
但请注意,此上下文源只能用于BIND
操作。正如我在对Terry Gardner的评论中所链接的MSDN document所述:
在此模式下,连接只接受简单绑定。由于没有进行组评估,因此始终处理连接,就好像没有为所有其他LDAP操作发生绑定一样。
这意味着您可能正在考虑维护两种类型的LDAP上下文,一种用于绑定,另一种用于实际执行您可能需要执行的任何查找。
查看source code for LdapTemplate,我看到authenticate
方法看起来不仅仅是一个简单的绑定。更具体地说,它搜索用户然后尝试绑定。因为,如果您正在使用启用了FastBind
的上下文,则您不太可能执行搜索(通常AD不允许在匿名连接上进行搜索)。基本上,这意味着您可能必须避免LdapTemplate
。
但是,假设您获得对ADContextSource bean的引用,它应该足够简单,可以执行类似
的操作boolean authenticate(String username, String password) {
try {
DirContext ctx = contextSource.getContext(username, password);
LdapUtils.closeContext(ctx);
return true;
} catch (Exception e) {
// note: this means an exception was thrown by #getContext() above
return false;
}
}
其中非常接近地模仿了LdapTemplate
将会做什么(唯一缺少的是AuthenticatedLdapEntryContextCallback
,在这种情况下没有任何价值,AuthenticationErrorCallback
,如果您想要这种行为,可以轻松添加。)
答案 1 :(得分:0)
由于FastBind
仅“检查用户的凭据”并且不执行组确定,因此最好使用专有名称和凭据简单地将BIND请求发送到服务器。任何简单的BIND请求都应通过安全连接传输。结果代码为0
(零)的响应表示:
UnboundID LDAP SDK是与目录服务器交互的最佳Java实现