【问题标题】:Node JS LDAP Auth User节点 JS LDAP 验证用户
【发布时间】:2013-07-22 18:42:40
【问题描述】:

我正在创建一个登录身份验证页面,用户将在那里输入活动目录用户名和密码,并使用 NodeJS 我会检查它是否有效,但我不断收到

[Error: LDAP Error Bad search filter]

[Error: Search returned != 1 results]

当我尝试搜索用户名和密码时,我的代码如下:

我使用的是:https://github.com/jeremycx/node-LDAP,假设用户输入的用户名是 hhill

    var ldap = require('LDAP');
    var ldapServer = new ldap({ uri: 'ldap://batman.lan', version: 3});

    ldapServer.open(function(error) {
        if(error) {
           throw new Error('Cant not connect');
        } else {
            console.log('---- connected to ldap ----');

            username = '(cn='+username+')';
            ldapServer.findandbind({
                base: 'ou=users,ou=compton,dc=batman,dc=lan',
                filter: username,
                password: password
            }, function(error, data) {
                if(error){
                    console.log(error);
                } else {
                    console.log('---- verified user ----');
                }
            });
        }
    });

有人对我做错了什么有任何建议吗?

更新

如果有人需要,这是我想出的解决方案,在下面的答案的帮助下

    var username = request.param('username');
    var password = request.param('password');

    var ldap = require('ldapjs');
    ldap.Attribute.settings.guid_format = ldap.GUID_FORMAT_B;
    var client = ldap.createClient({
          url: 'ldap://batman.com/cn='+username+', ou=users, ou=compton, dc=batman, dc=com',
          timeout: 5000,
          connectTimeout: 10000
    });
    var opts = {
      filter: '(&(objectclass=user)(samaccountname='+username+'))',
      scope: 'sub',
      attributes: ['objectGUID']
    };

    console.log('--- going to try to connect user ---');

    try {
        client.bind(username, password, function (error) {
            if(error){
                console.log(error.message);
                client.unbind(function(error) {if(error){console.log(error.message);} else{console.log('client disconnected');}});
            } else {
                console.log('connected');
                client.search('ou=users, ou=compton, dc=batman, dc=com', opts, function(error, search) {
                    console.log('Searching.....');

                    search.on('searchEntry', function(entry) {
                        if(entry.object){
                            console.log('entry: %j ' + JSON.stringify(entry.object));
                        }
                    });

                    search.on('error', function(error) {
                        console.error('error: ' + error.message);
                    });

                    client.unbind(function(error) {if(error){console.log(error.message);} else{console.log('client disconnected');}});
                });
            }
        });
    } catch(error){
        console.log(error);
        client.unbind(function(error) {if(error){console.log(error.message);} else{console.log('client disconnected');}});
    }

【问题讨论】:

  • 第一种情况,究竟是哪个过滤器传输到服务器的?在第二种情况下,不止一个对象与搜索参数匹配:也许它只需要一个匹配项。

标签: node.js authentication ldap


【解决方案1】:

在这种情况下,你需要ldapClient而不是ldapServer,这是来自官方doc的示例代码:

var ldap = require('ldapjs');

ldap.Attribute.settings.guid_format = ldap.GUID_FORMAT_B;

var client = ldap.createClient({
  url: 'ldap://127.0.0.1/CN=test,OU=Development,DC=Home'
});

var opts = {
  filter: '(objectclass=user)',
  scope: 'sub',
  attributes: ['objectGUID']
};

client.bind('username', 'password', function (err) {
  client.search('CN=test,OU=Development,DC=Home', opts, function (err, search) {
    search.on('searchEntry', function (entry) {
      var user = entry.object;
      console.log(user.objectGUID);
    });
  });
});

【讨论】:

  • 我已经尝试了上述方法,我收到以下错误 oSuchObjectError: 0000208D: NameErr: DSID-0310020A, 问题 2001 (NO_OBJECT), data 0, best match of: 'OU=Users,OU= Newyork,DC=basingloc,DC=lan' 可以连接,但是搜索失败。就行 search.on @sza
  • 刚刚解决了我使用此解决方案时遇到的问题。谢谢@zsong!
【解决方案2】:

@Sukh 感谢您发布更新解决方案;但是,您在 UPDATE 中发布的代码存在问题。虽然它适用于简单的情况,但对于较大的查询,您会发现在结果输出之前您已解除绑定。我的解决方案是将您的解除绑定移到 search.on 函数中。

这是对您的更新的编辑:

var ldap = require('ldapjs');
ldap.Attribute.settings.guid_format = ldap.GUID_FORMAT_B;
var client = ldap.createClient({
      url: 'ldap://batman.com/cn='+username+', ou=users, ou=compton, dc=batman, dc=com',
      timeout: 5000,
      connectTimeout: 10000
});
var opts = {
  filter: '(&(objectclass=user)(samaccountname='+username+'))',
  scope: 'sub',
  //attributes: ['objectGUID']
  // This attribute list is what broke your solution
  attributes: ['objectGUID','sAMAccountName','cn','mail','manager','memberOf']
};

console.log('--- going to try to connect user ---');

try {
    client.bind(username, password, function (error) {
        if(error){
            console.log(error.message);
            client.unbind(function(error) {if(error){console.log(error.message);} else{console.log('client disconnected');}});
        } else {
            console.log('connected');
            client.search('ou=users, ou=compton, dc=batman, dc=com', opts, function(error, search) {
                console.log('Searching.....');

                search.on('searchEntry', function(entry) {
                    if(entry.object){
                        console.log('entry: %j ' + JSON.stringify(entry.object));
                    }
                    client.unbind(function(error) {if(error){console.log(error.message);} else{console.log('client disconnected');}});
                });

                search.on('error', function(error) {
                    console.error('error: ' + error.message);
                    client.unbind(function(error) {if(error){console.log(error.message);} else{console.log('client disconnected');}});
                });

                // don't do this here
                //client.unbind(function(error) {if(error){console.log(error.message);} else{console.log('client disconnected');}});
            });
        }
    });
} catch(error){
    console.log(error);
    client.unbind(function(error) {if(error){console.log(error.message);} else{console.log('client disconnected');}});
}

至少这是我在将您的解决方案与 Active Directory 搜索结合使用时发现的。 memberOf 在我的用例中返回了很多条目,并且取消绑定过早完成,所以我收到以下错误:

error: 1__ldap://my.domain.com/,OU=Employees,OU=Accounts,DC=my,DC=domain,DC=com closed
client disconnected

【讨论】:

    【解决方案3】:

    建议

    1.不要使用 ldapauth-fork(巨大的挂起问题,如果我们遇到多个请求,那么一段时间后库会无响应并且不返回任何内容。)

    2.不要使用passport-ldapauth(内部调用ldapauth-fork)

    我们可以使用ldapjs,它实现简单,基于事件驱动的方法。

    下面的 nodejs 代码解释了 ldap 身份验证和搜索的完整解决方案。

    JS 代码

    const ldap = require('ldapjs');
    let client
    
    // unbind after completion of process
    function closeConnection() {
        console.log('closeConnection')
        client.unbind(err => {
            console.log('unbind error', err)
        });
    }
    
    function search() {
        const searchOptions = {
            filter: '(uid=yourSearchText)', // search text
            scope: 'sub'
        };
        return new Promise((resolve, reject) => {
            client.search('ou=consultants,' + 'ou="Your OU",ou=yourOu,dc=yourDc,dc=com', searchOptions, (err, res) => {
                res.on('searchEntry', entry => {
                    console.log('searchEntry', entry.object);
                    resolve(entry.object)
                });
                res.on('searchReference', referral => {
                    console.log('referral: ' + referral.uris.join());
                    resolve(referral.uris.join())
                });
                res.on('error', err => {
                    console.error('search error: ' + err.message);
                    reject(err)
                });
                res.on('end', result => {
                    console.log('If not found', result);
                    reject({ message:'User not found'})
                });
            });
        })
    }
    
    function authenticate() {
        const server = 'ldap server ip';
        client = ldap.createClient({
            url: `ldap://${server}`
        });
    
        return new Promise((resolve, reject) => {
            client.bind('cn=yourcn,dc=yourdc,dc=com', 'sortedSolutions', err => {
                if (err) {
                    reject(err)
                }
                resolve('Authenticated successfully')
            });
        })
    }
    
    function start(req, res) {
        let searchResponseData
        authenticate()
            .then(authenticateResponse => {
                console.log('authenticateResponse', authenticateResponse)
                return search()
            })
            .then(searchResponse => {
                console.log('searchResponsesearchResponse', searchResponse)
                searchResponseData = searchResponse
                return closeConnection()
            })
            .then(closeConnectionResponse => {
                console.log('ldap connection closed', closeConnectionResponse)
                res.status(200).send(searchResponseData)
            })
            .catch(error => {
                console.log('catch error', error)
                res.status(400).send(error)
            })
    
    }
    
    module.exports.start = start
    

    // 我们可以使用相同的代码,无需认证,只需传递 '' 绑定函数 client.bind('', '', err => { //同上 })

    【讨论】:

      猜你喜欢
      • 2020-04-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多