TLDR:passportjs或passport-ldapauth 是否存在竞争条件问题?
我在 nodejs 应用程序中使用该koa-passport
库和passport-ldapauth
策略,旨在针对 AD(Active Directory)对用户进行身份验证。哇,那是一口。
这是我passport.authenticate
从 LDAP 中返回的错误:
BusyError: 00002024: LdapErr: DSID-0C060810, comment: No other operations may be performed on the connection while a bind is outstanding.
这里的问题很明显,有一个未完成的绑定,必须先关闭它,然后我才能进行另一个绑定以验证下一个用户。 然而,解决方案不是,它可能与 LDAP 相关,也可能与 passportjs 相关。我在这里希望为后者找到解决方案。(在等待对此#multiprocessing的响应时,将探索 LDAP 的配置选项)
这是我的代码:
import passport from 'koa-passport';
import LdapStrategy from 'passport-ldapauth';
import { readFileSync } from 'fs';
const ldapCert = readFileSync(process.env.LDAP_CERT, 'utf8');
const ldapConfig = {
server: {
url: process.env.LDAP_URL,
bindDN: process.env.LDAP_BINDDN,
bindCredentials: process.env.LDAP_PASSWORD,
searchBase: process.env.LDAP_SEARCH_BASE,
searchFilter: process.env.LDAP_SEARCH_FILTER,
searchAttributes: ['sAMAccountName'],
tlsOptions: {
ca: [ldapCert]
}
}
};
module.exports = async (ctx, next) => {
passport.initialize();
passport.use(new LdapStrategy(ldapConfig));
await passport.authenticate('ldapauth', { session: false }, async (err, user, info) => {
if (err) {
console.log('Invalid Authentication Error');
ctx.throw('INVALID_AUTHENTICATION');
} else if (!user) {
console.log('Invalid username or password Error');
ctx.throw('INVALID_USERNAME_PASSWORD');
} else {
await next(); // continue to authorization flow
}
})(ctx, next);
在我们开始之前,要知道ldapConfigs
在应用程序的整个生命周期中所有内容都保持不变,这意味着我在每次查找时都使用相同的 BINDDN 和 PASSWORD。
因此,如标题中所述,此错误间歇性地发生。因此,代码本身通常可以正常工作,并且我能够在大约 95% 的时间内对用户进行身份验证,并且如果它INVALID_AUTHENTICATION
在密码正确时抛出错误,那就是当我BusyError
在日志中获取 the 时。
当我输入虚假的用户名/密码时,这个问题更加突出并且更容易重现,理想情况下应该提示我INVALID_USERNAME_PASSWORD
错误,我大约有 75% 的时间。我得到的另外 25% INVALID_AUTHENTICATION
。
我什至尝试使用ldapsearch
与tmux
. 我使用相同的 binddn 同时在大约 20 个窗格中运行了一个调用,它们都恢复得很好(我应该尝试用更多来运行它吗?100 个?1000 个?)。这就是让我相信问题不在于 LDAP 或 AD 的原因,而更多的是 passportjs。
我得出的结论是,passportJS 可能存在种族条件问题,但我在互联网上找不到任何文献。有没有人遇到过这样的事情?我相信绑定可能没有关闭,因为有时passport.authenticate
可能会在调用回调之前返回?这甚至可能吗?它与我如何使用 async/await 进行编码有关吗?
我的后备方案可能是完全抛弃passportjs,只尝试使用ldapjs。任何想法,意见,建议,讨论将不胜感激
如果需要,这是完整的堆栈跟踪:
BusyError: 00002024: LdapErr: DSID-0C060810, comment: No other operations may be performed on the connection while a bind is outstanding., data 0, v3839
at messageCallback (/app/node_modules/ldapjs/lib/client/client.js:1419:45)
at Parser.onMessage (/app/node_modules/ldapjs/lib/client/client.js:1089:14)
at emitOne (events.js:116:13)
at Parser.emit (events.js:211:7)
at Parser.write (/app/node_modules/ldapjs/lib/messages/parser.js:111:8)
at TLSSocket.onData (/app/node_modules/ldapjs/lib/client/client.js:1076:22)
at emitOne (events.js:116:13)
at TLSSocket.emit (events.js:211:7)
at addChunk (_stream_readable.js:263:12)
at readableAddChunk (_stream_readable.js:250:11)
at TLSSocket.Readable.push (_stream_readable.js:208:10)
at TLSWrap.onread (net.js:597:20)
InternalServerError: INVALID_AUTHENTICATION
at Object.throw (/app/node_modules/koa/lib/context.js:97:11)