在 Node.js 上使用 passport-ldapauth 进行的 LDAP 身份验证失败

Failed LDAP authentication using passport-ldapauth on Node.js

您好,我是 openldap 和 nodejs 的新手。我正在尝试创建 openldap 身份验证并使用一个简单的节点应用程序来测试针对本地 ldap 服务器的身份验证。

我的理解是我可以创建 ldap 服务器并在 Apache Directory Studio 中添加所有用户。然后编写一个简单的节点应用程序,其配置与 ldap 服务器相同。使用邮递员发送认证请求,我应该可以得到授权结果。如果我错了,请纠正我。

以下是我采取的步骤:

  1. 我使用 Apache Directory Studio 在本地设置了一个 ldap 服务器。

  2. 然后我尝试搭建一个简单的nodejs应用(代码如下)

  3. 当我使用 Postman 向我之前使用 Apache Directory Studio 设置的某个用户发送身份验证请求时,我一直收到错误 Unauthorized.

  4. 我相信我可以通过邮递员调用访问节点应用程序,因为我能够使用 Apache Studio 中存在的用户名和密码获得 "Unauthorized" 响应。但是节点应用程序无法与 Apache Directory Studio 设置的 Ldap 服务器一起工作/连接,因为我可以将节点代码中的服务器字段更改为与 ldap 服务器完全不同,但仍然能够在邮递员中获得未经授权的响应. 我可能不完全了解 ldap 服务器,也许节点应用程序和 ldap 服务器是完全分开的? 或者这应该可以工作只是我的代码有问题?

下面是我最近的代码:

var express      = require('express'),
    passport     = require('passport'),
    bodyParser   = require('body-parser'),
    LdapStrategy = require('passport-ldapauth'),
    basicAuth = require('basic-auth')

var OPTS = {
  server: {
    url: 'ldap://localhost:389',
    bindDN: 'cn=admin,ou=users,dc=contoso,dc=com',
    bindCredentials: 'P@ss1W0Rd!',
    searchBase: 'ou=users,dc=contoso,dc=com',
    searchFilter: '(uid={{Username}})'
  },
  credentialsLookup: basicAuth
  // ,
  // usernameField: user,
  // passwordField: pass
};

var app = express();

passport.use(new LdapStrategy(OPTS));

app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: false}));
app.use(passport.initialize());

app.post('/login', passport.authenticate('ldapauth', {session: false}), function(req, res) {
  res.send({status: 'ok'});
});

app.listen(8080);


这是我一直在尝试验证的用户:


dn: cn=Aaron Painter,ou=users,dc=contoso,dc=com
objectClass: top
objectClass: posixAccount
objectClass: organizationalPerson
objectClass: person
objectClass: inetOrgPerson
cn: Aaron Painter
gidNumber: 70051
homeDirectory: /home/aaronp
sn: Painter
uid: aaronp
uidNumber: 70050
displayName: Aaron Painter
givenName: Aaron
mail: aaronp@contoso.com
manager: cn=Christine Koch,ou=users,dc=contoso,dc=com
telephoneNumber: (212) 555-8335
title: Strategy Consulting Manager
userPassword: AAA

这是我使用的邮递员电话: postman call

这是服务器中显示的日志:

contosoOpenLdap | 5d9b8107 conn=1062 fd=19 ACCEPT from IP=172.17.0.1:47712 (IP=0.0.0.0:389)
contosoOpenLdap | 5d9b8107 conn=1063 fd=20 ACCEPT from IP=172.17.0.1:47714 (IP=0.0.0.0:389)
contosoOpenLdap | 5d9b8107 conn=1063 op=0 BIND dn="cn=admin,ou=users,dc=contoso,dc=com" method=128
contosoOpenLdap | 5d9b8107 conn=1063 op=0 RESULT tag=97 err=49 text=
contosoOpenLdap | 5d9b8107 conn=1063 op=1 UNBIND
contosoOpenLdap | 5d9b8107 conn=1063 fd=20 closed

错误代码 49 表示 DN 或密码不正确。但是配置对我来说似乎是正确的。

请帮忙谢谢。

有 3 个问题需要解决(前提是您的凭据正确):

  • 搜索过滤器语法错误,不应在其中传递密码
  • searchBase 使用完整的 dn(不是 rdn)
  • 要么通过 credentialsLookup 从请求中获取凭据,要么设置 usernameFieldpasswordField

例如,使用正确的语法保持相同的用户名属性和搜索基础:

searchBase: 'ou=users,dc=contoso,dc=com',
searchFilter: '(cn={{Username}})'

这应该适用于使用以下 dn 模式对用户进行身份验证:

cn=<username>,<searchBase>  =>  cn=foo,ou=users,dc=contoso,dc=com

以上是基于您之前的配置,但如果没有进一步的详细信息,仍然无法猜测您的目录中的用户 dn 是什么样子。请注意,经理帐户 (bindDN) 和普通用户通常不会共享相同的 DN pattern/structure,并且您过滤器中的用户名属性 cn 可能是错误的。

也就是说,根据用户输入的 dn 字符串确定 dn 结构非常明显,例如,如果用户名属性是 uid 并且用户群位于 ou=people 下:

dn: uid=foo,ou=people,dc=contoso,dc=com
=> searchBase: 'ou=people,dc=contoso,dc=com'
=> searchFilter: '(uid={{Username}})'

现在,如果您决定通过请求 body 传递凭据,则应根据例如 usernameFieldpasswordField 进行设置。使用以下 body { "user": "test", "pass": "test" },您将设置:

    //credentialsLookup: basicAuth,
    usernameField: user,
    passwordField: pass

但是如果您更喜欢通过授权 header 设置凭据,那么您可以使用 credentialsLookup 和所需的授权类型,并在 Authorization Postman 中的选项卡。

请注意,如果您同时设置 credentialsLookup 和其他两个字段,则即使查找失败,credentialsLookup 也会获胜(无法回退)。