我们有一个包含用户信息和散列密码的关系数据库,我想使用 LDAP 为单点登录提供服务,而MyVD似乎能够完成我们需要的一切。我的第一步是让搜索在没有任何身份验证的情况下工作,并且我的 LDAP 记录对用户及其属性来说很好,所以我现在要回去并为身份验证机制创建自己的自定义插入这将基本上散列绑定请求的密码并尝试将其与我们数据库中的散列密码匹配。
关于如何实现插入操作的特定细节的文档很少(有一个关于创建插入的相当好的概述),所以我一直在尝试将 MyVD 项目中的现有源作为一个我的代码的基础。现在我不断收到以下异常,我已经通过项目代码进行了追溯,但仍然无法弄清楚它发生的原因:
LDAPException: Could not bind to any services (49) Invalid Credentials
LDAPException: Server Message: uid=asdfasf@foobar.com,o=RBD,c=us
at net.sourceforge.myvd.router.Router.bind(Router.java:164)
at net.sourceforge.myvd.chain.BindInterceptorChain.nextBind(BindInterceptorChain.java:52)
at net.sourceforge.myvd.inserts.routing.MasterReplicaRouter.bind(MasterReplicaRouter.java:109)
at net.sourceforge.myvd.chain.BindInterceptorChain.nextBind(BindInterceptorChain.java:49)
at net.sourceforge.myvd.inserts.DumpTransaction.bind(DumpTransaction.java:142)
at net.sourceforge.myvd.chain.BindInterceptorChain.nextBind(BindInterceptorChain.java:49)
at net.sourceforge.myvd.protocol.ldap.BindHandler.messageReceived(BindHandler.java:153)
at net.sourceforge.myvd.protocol.ldap.LDAPOperation.messageReceived(LDAPOperation.java:84)
at org.apache.mina.handler.demux.DemuxingIoHandler.messageReceived(DemuxingIoHandler.java:141)
at net.sourceforge.myvd.protocol.ldap.LdapProtocolProvider$LdapProtocolHandler.messageReceived(LdapProtocolProvider.java:402)
at org.apache.mina.common.support.AbstractIoFilterChain$TailFilter.messageReceived(AbstractIoFilterChain.java:570)
at org.apache.mina.common.support.AbstractIoFilterChain.callNextMessageReceived(AbstractIoFilterChain.java:299)
at org.apache.mina.common.support.AbstractIoFilterChain.access$1100(AbstractIoFilterChain.java:53)
at org.apache.mina.common.support.AbstractIoFilterChain$EntryImpl$1.messageReceived(AbstractIoFilterChain.java:648)
at org.apache.mina.filter.codec.support.SimpleProtocolDecoderOutput.flush(SimpleProtocolDecoderOutput.java:58)
at org.apache.mina.filter.codec.ProtocolCodecFilter.messageReceived(ProtocolCodecFilter.java:180)
at org.apache.mina.common.support.AbstractIoFilterChain.callNextMessageReceived(AbstractIoFilterChain.java:299)
at org.apache.mina.common.support.AbstractIoFilterChain.access$1100(AbstractIoFilterChain.java:53)
at org.apache.mina.common.support.AbstractIoFilterChain$EntryImpl$1.messageReceived(AbstractIoFilterChain.java:648)
at org.apache.mina.filter.executor.ExecutorFilter.processEvent(ExecutorFilter.java:220)
at org.apache.mina.filter.executor.ExecutorFilter$ProcessEventsRunnable.run(ExecutorFilter.java:264)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
at org.apache.mina.util.NamePreservingRunnable.run(NamePreservingRunnable.java:51)
at java.lang.Thread.run(Thread.java:662)
正如您将在下面的插入类中看到的那样,我只是检查密码是否为123
,我可以从日志文件中看到这就是发送到类的内容:
[2013-10-08 16:21:24,198][MyVD-2] DEBUG DBAuthenticator - USER: asdfasf@foobar.com
[2013-10-08 16:21:24,198][MyVD-2] DEBUG DBAuthenticator - PASSWORD: 123
所以我很茫然,这就是我现在发布这个问题的原因;)这是我实现Insert
接口的自定义插入类:
package com.foobar.myvd;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Properties;
import net.sourceforge.myvd.chain.AddInterceptorChain;
import net.sourceforge.myvd.chain.BindInterceptorChain;
import net.sourceforge.myvd.chain.CompareInterceptorChain;
import net.sourceforge.myvd.chain.DeleteInterceptorChain;
import net.sourceforge.myvd.chain.ExetendedOperationInterceptorChain;
import net.sourceforge.myvd.chain.ModifyInterceptorChain;
import net.sourceforge.myvd.chain.PostSearchCompleteInterceptorChain;
import net.sourceforge.myvd.chain.PostSearchEntryInterceptorChain;
import net.sourceforge.myvd.chain.RenameInterceptorChain;
import net.sourceforge.myvd.chain.SearchInterceptorChain;
import net.sourceforge.myvd.core.NameSpace;
import net.sourceforge.myvd.inserts.Insert;
import net.sourceforge.myvd.types.Attribute;
import net.sourceforge.myvd.types.Bool;
import net.sourceforge.myvd.types.DistinguishedName;
import net.sourceforge.myvd.types.Entry;
import net.sourceforge.myvd.types.ExtendedOperation;
import net.sourceforge.myvd.types.Filter;
import net.sourceforge.myvd.types.Int;
import net.sourceforge.myvd.types.Password;
import net.sourceforge.myvd.types.Results;
import org.apache.log4j.Logger;
import com.novell.ldap.LDAPConstraints;
import com.novell.ldap.LDAPException;
import com.novell.ldap.LDAPModification;
import com.novell.ldap.LDAPSearchConstraints;
import com.novell.ldap.util.RDN;
public class DBAuthenticator implements Insert {
Logger logger = Logger.getLogger(DBAuthenticator.class);
String name;
@Override
public void add(AddInterceptorChain arg0, Entry arg1, LDAPConstraints arg2)
throws LDAPException {
arg0.nextAdd(arg1, arg2);
}
@Override
public void bind(BindInterceptorChain chain, DistinguishedName dn,
Password password, LDAPConstraints constraints)
throws LDAPException {
String user = ((RDN) dn.getDN().getRDNs().get(0)).getValue();
String passwordString = null;
try {
passwordString = new String(password.getValue(), "UTF-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
logger.debug("USER: " + user);
logger.debug("PASSWORD: " + passwordString);
if (!passwordString.equals("123"))
throw new LDAPException("Manual Invalid Credentials",
LDAPException.INVALID_CREDENTIALS,
"Manual Invalid Credentials");
logger.debug("NO THROW");
chain.nextBind(dn, password, constraints);
logger.debug("nextBind CALLED.");
}
@Override
public void compare(CompareInterceptorChain arg0, DistinguishedName arg1,
Attribute arg2, LDAPConstraints arg3) throws LDAPException {
arg0.nextCompare(arg1, arg2, arg3);
}
@Override
public void configure(String name, Properties arg1, NameSpace arg2)
throws LDAPException {
this.name = name;
}
@Override
public void delete(DeleteInterceptorChain arg0, DistinguishedName arg1,
LDAPConstraints arg2) throws LDAPException {
arg0.nextDelete(arg1, arg2);
}
@Override
public void extendedOperation(ExetendedOperationInterceptorChain arg0,
ExtendedOperation arg1, LDAPConstraints arg2) throws LDAPException {
arg0.nextExtendedOperations(arg1, arg2);
}
@Override
public String getName() {
return this.getClass().getSimpleName();
}
@Override
public void modify(ModifyInterceptorChain arg0, DistinguishedName arg1,
ArrayList<LDAPModification> arg2, LDAPConstraints arg3)
throws LDAPException {
arg0.nextModify(arg1, arg2, arg3);
}
@Override
public void postSearchComplete(PostSearchCompleteInterceptorChain arg0,
DistinguishedName arg1, Int arg2, Filter arg3,
ArrayList<Attribute> arg4, Bool arg5, LDAPSearchConstraints arg6)
throws LDAPException {
}
@Override
public void postSearchEntry(PostSearchEntryInterceptorChain arg0,
Entry arg1, DistinguishedName arg2, Int arg3, Filter arg4,
ArrayList<Attribute> arg5, Bool arg6, LDAPSearchConstraints arg7)
throws LDAPException {
arg0.nextPostSearchEntry(arg1, arg2, arg3, arg4, arg5, arg6, arg7);
}
@Override
public void rename(RenameInterceptorChain arg0, DistinguishedName arg1,
DistinguishedName arg2, Bool arg3, LDAPConstraints arg4)
throws LDAPException {
arg0.nextRename(arg1, arg2, arg3, arg4);
}
@Override
public void rename(RenameInterceptorChain arg0, DistinguishedName arg1,
DistinguishedName arg2, DistinguishedName arg3, Bool arg4,
LDAPConstraints arg5) throws LDAPException {
arg0.nextRename(arg1, arg2, arg3, arg4, arg5);
}
@Override
public void search(SearchInterceptorChain arg0, DistinguishedName arg1,
Int arg2, Filter arg3, ArrayList<Attribute> arg4, Bool arg5,
Results arg6, LDAPSearchConstraints arg7) throws LDAPException {
arg0.nextSearch(arg1, arg2, arg3, arg4, arg5, arg6, arg7);
}
@Override
public void shutdown() {
}
}
这是我当前配置服务器的 myvd.conf 文件:
#Listen on port 389
server.listener.port=10389
#Listen on 636 using SSL
#server.secure.listener.port=636
#server.secure.keystore=/var/keystores/myvd.ks
#server.secure.keypass=secret
#Cnfigure global chains
server.globalChain=LogAllTransactions,router
server.globalChain.LogAllTransactions.className=net.sourceforge.myvd.inserts.DumpTransaction
server.globalChain.LogAllTransactions.config.logLevel=info
server.globalChain.LogAllTransactions.config.label=Global
server.globalChain.router.className=net.sourceforge.myvd.inserts.routing.MasterReplicaRouter
server.globalChain.router.config.specifyToInclude=false
server.globalChain.router.config.readOnly=Rbdconnect
#Configure namespaces
server.nameSpaces=Root,Readusers
#Define RootDSE
server.Root.chain=RootDSE
server.Root.nameSpace=
server.Root.weight=0
server.Root.RootDSE.className=net.sourceforge.myvd.inserts.RootDSE
server.Root.RootDSE.config.namingContexts=o=RBD,c=us
#Define rbdconnect namespace
server.Readusers.chain=dbauth,db
server.Readusers.nameSpace=o=RBD,c=us
server.Readusers.weight=100
server.Readusers.db.className=net.sourceforge.myvd.inserts.jdbc.JdbcInsert
server.Readusers.db.config.driver=org.postgresql.Driver
server.Readusers.db.config.url=jdbc:postgresql://localhost:5432/foo
server.Readusers.db.config.user=bar
server.Readusers.db.config.pass=bat
server.Readusers.db.config.rdn=uid
server.Readusers.db.config.mapping=uid=username,ou=ou,cn=employee_name,givenName=firstname,sn=lastname,mail=email,active=active
server.Readusers.db.config.objectClass=inetOrgPerson
server.Readusers.db.config.sql=SELECT ad_user.isactive AS active, username, ad_user.name AS employee_name, firstname, lastname, email, CASE WHEN ad_role.name IS NULL THEN 'Unknown' ELSE ad_role.name END AS ou FROM ad_user LEFT OUTER JOIN ad_role ON ad_user.default_ad_role_id = ad_role.ad_role_id
server.Readusers.dbauth.className=com.retailingwireless.myvd.DBAuthenticator
我希望有人能告诉我我错过了什么,因为我已经盯着这个看了好几个小时了,而且(以我通常的方式)它可能很简单,就在我的眼皮底下。感谢您抽出宝贵的时间!