在 Node.js 上使用 passport-ldapauth 进行的 LDAP 身份验证失败
Failed LDAP authentication using passport-ldapauth on Node.js
您好,我是 openldap 和 nodejs 的新手。我正在尝试创建 openldap 身份验证并使用一个简单的节点应用程序来测试针对本地 ldap 服务器的身份验证。
我的理解是我可以创建 ldap 服务器并在 Apache Directory Studio 中添加所有用户。然后编写一个简单的节点应用程序,其配置与 ldap 服务器相同。使用邮递员发送认证请求,我应该可以得到授权结果。如果我错了,请纠正我。
以下是我采取的步骤:
我使用 Apache Directory Studio 在本地设置了一个 ldap 服务器。
然后我尝试搭建一个简单的nodejs应用(代码如下)
当我使用 Postman 向我之前使用 Apache Directory Studio 设置的某个用户发送身份验证请求时,我一直收到错误 Unauthorized
.
我相信我可以通过邮递员调用访问节点应用程序,因为我能够使用 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
从请求中获取凭据,要么设置 usernameField
和 passwordField
。
例如,使用正确的语法保持相同的用户名属性和搜索基础:
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 传递凭据,则应根据例如 usernameField
和 passwordField
进行设置。使用以下 body { "user": "test", "pass": "test" }
,您将设置:
//credentialsLookup: basicAuth,
usernameField: user,
passwordField: pass
但是如果您更喜欢通过授权 header 设置凭据,那么您可以使用 credentialsLookup
和所需的授权类型,并在 Authorization Postman 中的选项卡。
请注意,如果您同时设置 credentialsLookup
和其他两个字段,则即使查找失败,credentialsLookup 也会获胜(无法回退)。
您好,我是 openldap 和 nodejs 的新手。我正在尝试创建 openldap 身份验证并使用一个简单的节点应用程序来测试针对本地 ldap 服务器的身份验证。
我的理解是我可以创建 ldap 服务器并在 Apache Directory Studio 中添加所有用户。然后编写一个简单的节点应用程序,其配置与 ldap 服务器相同。使用邮递员发送认证请求,我应该可以得到授权结果。如果我错了,请纠正我。
以下是我采取的步骤:
我使用 Apache Directory Studio 在本地设置了一个 ldap 服务器。
然后我尝试搭建一个简单的nodejs应用(代码如下)
当我使用 Postman 向我之前使用 Apache Directory Studio 设置的某个用户发送身份验证请求时,我一直收到错误
Unauthorized
.我相信我可以通过邮递员调用访问节点应用程序,因为我能够使用 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
从请求中获取凭据,要么设置usernameField
和passwordField
。
例如,使用正确的语法保持相同的用户名属性和搜索基础:
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 传递凭据,则应根据例如 usernameField
和 passwordField
进行设置。使用以下 body { "user": "test", "pass": "test" }
,您将设置:
//credentialsLookup: basicAuth,
usernameField: user,
passwordField: pass
但是如果您更喜欢通过授权 header 设置凭据,那么您可以使用 credentialsLookup
和所需的授权类型,并在 Authorization Postman 中的选项卡。
请注意,如果您同时设置 credentialsLookup
和其他两个字段,则即使查找失败,credentialsLookup 也会获胜(无法回退)。