ActiveDirectory is an Node.js ldapjs client for authN (authentication) and authZ (authorization) for Microsoft Active Directory with range retrieval support for large Active Directory installations.
| 文件 | 最后提交记录 | 最后更新时间 |
|---|---|---|
| 10 年前 | ||
| 10 年前 | ||
| 11 年前 | ||
| 12 年前 | ||
| 10 年前 | ||
| 12 年前 | ||
| 10 年前 |
活动目录(ActiveDirectory)用于Node.js
活动目录是一个基于ldapjs客户端,专用于微软Active Directory的身份验证(authN)和授权(authZ),并且支持大型Active Directory安装的大范围检索功能。这个代码是从我几年前编写的一个存在的C#库(未公开发布)移植过来的。以下是主要特性:
- 身份验证
- 权限验证(通过组成员信息)
- 支持嵌套组
- 范围指定器/检索支持(http://msdn.microsoft.com/en-us/library/dd358433.aspx)
- 自动分页支持(默认情况下,Active Directory结果(MaxPageSize)每请求限制为1000条)
- 回收站(tombstone)查询支持
- 遥控指针支持
所需库
活动目录使用以下额外的Node.js模块:
- underscore - JavaScript的工具带库,提供了很多函数式编程支持
- async - 适用于Node.js和浏览器的异步工具
- ldapjs - 在Node.js中实现LDAP客户端和服务器的纯JavaScript框架
- bunyan - 一个简单快速的JSON日志模块,适用于node.js服务
安装
npm install activedirectory
使用
var ActiveDirectory = require('activedirectory');
var config = { url: 'ldap://dc.domain.com',
baseDN: 'dc=domain,dc=com',
username: 'username@domain.com',
password: 'password' }
var ad = new ActiveDirectory(config);
配置中指定的用户名和密码用于用户和组查找操作。
文档
- authenticate
- isUserMemberOf
- find
- findUser
- findGroup
- findUsers
- findGroups
- groupExists
- userExists
- getGroupMembershipForGroup
- getGroupMembershipForUser
- getUsersForGroup
- getRootDSE
- findDeletedObjects
### authenticate(username, password, callback)
使用指定的凭据进行简单的绑定来验证用户名和密码。
参数
- username - 要验证的用户名。
- password - 认证用的密码。
- callback(err, authenticated) - 验证完成后调用的回调函数。
示例
var ad = new ActiveDirectory(config);
var username = 'john.smith@domain.com';
var password = 'password';
ad.authenticate(username, password, function(err, auth) {
if (err) {
console.log('ERROR: '+JSON.stringify(err));
return;
}
if (auth) {
console.log('已认证!');
}
else {
console.log('认证失败!');
}
});
### isUserMemberOf(opts, username, groupName, callback)
检查用户是否属于指定的组。此函数还会检查组内的成员资格。即使用户并未明确列为特定组的成员,但其所属的组是该组的成员时,此函数也会返回true。
参数
- opts - 可选参数,扩展或覆盖功能。参见可选参数。
- username - 检查成员资格的用户名。可以是sAMAccountName、userPrincipalName或distinguishedName(dn)。
- groupName - 检查成员资格的组名。可以是commonName(cn)或distinguishedName(dn)。
- callback - 完成后执行的回调。callback(err: {Object}, result: {Boolean})
示例
var username = 'user@domain.com';
var groupName = 'Employees';
var ad = new ActiveDirectory(config);
ad.isUserMemberOf(username, groupName, function(err, isMember) {
if (err) {
console.log('ERROR: ' +JSON.stringify(err));
return;
}
console.log(username + ' 是 ' + groupName + ' 的成员: ' + isMember);
});
### groupExists(opts, groupName, callback)
检查指定的组是否存在。
参数
- opts - 可选参数,扩展或覆盖功能。参见可选参数。
- groupName - 检查定义的组名。可以是commonName(cn)或distinguishedName(dn)。
- callback - 完成后执行的回调。callback(err: {Object}, result: {Boolean})
示例
var groupName = 'Employees';
var ad = new ActiveDirectory(config);
ad.groupExists(groupName, function(err, exists) {
if (err) {
console.log('ERROR: ' +JSON.stringify(err));
return;
}
console.log(groupName + ' 存在: ' + exists);
});
### userExists(opts, username, callback)
检查指定的用户是否存在。
参数
- opts - 可选参数,扩展或覆盖功能。参见可选参数。
- username - 检查是否存在用户名。可以是sAMAccountName、userPrincipalName或distinguishedName(dn)。
- callback - 完成后执行的回调。callback(err: {Object}, result: {Boolean})
示例
var username = 'john.smith@domain.com';
var ad = new ActiveDirectory(config);
ad.userExists(username, function(err, exists) {
if (err) {
console.log('ERROR: ' +JSON.stringify(err));
return;
}
console.log(username + ' 存在: ' + exists);
});
### getUsersForGroup(opts, groupName, callback)
对于指定的组,获取所有属于该组的用户。如果组包含其他组,那么也将递归地检索这些组的成员,以构建出完整属于指定组的用户列表。
参数
- opts - 可选参数,扩展或覆盖功能。参见可选参数。
- groupName - 获取成员身份的组名。可以是commonName(cn)或distinguishedName(dn)。
- callback - 完成后执行的回调。callback(err: {Object}, users: {Array[User]})
示例
var groupName = 'Employees';
var ad = new ActiveDirectory(config);
ad.getUsersForGroup(groupName, function(err, users) {
if (err) {
console.log('ERROR: ' +JSON.stringify(err));
return;
}
if (! users) console.log('找不到名为:' + groupName + ' 的组。');
else {
console.log(JSON.stringify(users));
}
});
### getGroupMembershipForUser(opts, username, callback)
对于指定的用户名,获取用户所属于的所有组。如果检索到的组是另一个组的成员,那么也会递归地检索该组以构建完整的用户所属组的层级结构。
参数
- opts - 可选参数,扩展或覆盖功能。参见可选参数。
- username - 获取组成员身份的用户名。可以是sAMAccountName、userPrincipalName,或是distinguishedName(dn)。
- callback - 完成后执行的回调。callback(err: {Object}, groups: {Array[Group]})
示例
var sAMAccountName = 'john.smith@domain.com';
var ad = new ActiveDirectory(config);
ad.getGroupMembershipForUser(sAMAccountName, function(err, groups) {
if (err) {
console.log('ERROR: ' +JSON.stringify(err));
return;
}
if (! groups) console.log('未找到用户名:' + sAMAccountName + '。');
else console.log(JSON.stringify(groups));
});
### getGroupMembershipForGroup(opts, groupName, callback)
对于指定的组,获取该组所属于的所有组。如果检索到的组是其他组的成员,那么也会递归地检索这些组,以构建完整的组所属关系的层级结构。
参数
- opts - 可选参数,扩展或覆盖功能。参见可选参数。
- groupName - 获取组成员身份的组名。可以是sAMAccountName、userPrincipalName,或是distinguishedName(dn)。
- callback - 完成后执行的回调。callback(err: {Object}, groups: {Array[Group]})
示例
var groupName = 'Employees';
var ad = new ActiveDirectory(config);
ad.getGroupMembershipForGroup(groupName, function(err, groups) {
if (err) {
console.log('ERROR: ' +JSON.stringify(err));
return;
}
if (! groups) console.log('未找到名为:' + groupName + ' 的组。');
else console.log(JSON.stringify(groups));
});
### find(opts, callback)
执行针对指定的LDAP查询过滤器的一般搜索。此函数会返回匹配指定过滤器的用户和组。对结果不识别为用户或组的项(例如计算机账户等)可以在结果的"other"属性/数组中找到。
参数
- opts - 可选参数,扩展或覆盖功能。参见可选参数。如果只提供字符串,则假设它是LDAP过滤器。
- callback - 完成后执行的回调。callback(err: {Object}, groups: {Array[Group]})
示例
var _ = require('underscore');
var query = 'cn=*Exchange*';
var options = {
includeMembership: ['group', 'user'], // 或者可以使用 'all'
includeDeleted: false
};
var activeDirectory = new ActiveDirectory(config);
activeDirectory.find(query, function(error, results) {
if (error || !results) {
console.error('错误:', JSON.stringify(error));
return;
}
console.log('组:');
_.forEach(results.groups, function(group) {
console.log(' ' + group.cn);
});
console.log('用户:');
_.forEach(results.users, function(user) {
console.log(' ' + user.cn);
});
console.log('其他:');
_.forEach(results.other, function(other) {
console.log(' ' + other.cn);
});
});
查找已删除的对象(findDeletedObjects)
如果启用了活动目录安装的墓碑(回收站)功能,则使用findDeletedObjects来检索回收站中的项目。
关于墓碑和启用设置的更多信息,请参阅:
注意:当LDAP条目/对象被墓碑化时,并非所有属性都会保留。这是Active Directory本身的限制,而非库的限制。
参数
opts- 可选参数,用于扩展或覆盖功能。见可选参数。如果只提供字符串,则该字符串被认为是LDAP过滤器。callback- 完成时执行的回调函数。callback(err: {Object}, result: {Array})
如果没有指定baseDN,则会在附加的URL上执行一个RootDSE查询,并追加'ou-Deleted Objects'。
示例
var url = 'ldap://yourdomain.com';
var opts = {
baseDN: 'ou=Deleted Objects, dc=yourdomain, dc=com',
filter: 'cn=*Bob*'
};
activeDirectory.findDeletedObjects(opts, function(err, result) {
if (err) {
console.error('ERROR:', JSON.stringify(err));
return;
}
console.log('findDeletedObjects:', JSON.stringify(result));
});
查找用户(findUser)
通过sAMAccountName、userPrincipalName、distinguishedName(dn)或自定义过滤器查找用户名。如果找到,返回的对象包含所有请求的属性。默认情况下,以下属性被返回:
- userPrincipalName, sAMAccountName, mail, lockoutTime, whenCreated, pwdLastSet, userAccountControl, employeeID, sn, givenName, initials, cn, displayName, comment, description
参数
opts- 可选参数,用于扩展或覆盖功能。见可选参数。username- 要获取信息的用户名。也可以传递用户的distinguishedName(dn)来检索。callback(err, user)- 完成时执行的回调函数。callback(err: {Object}, user: {User})
示例
// 可以搜索任何类型的用户名
var sAMAccountName = 'username';
var userPrincipalName = 'username@domain.com';
var dn = 'CN=Smith\\, John,OU=Users,DC=domain,DC=com';
// 通过sAMAccountName查找用户
var activeDir = new ActiveDirectory(config);
activeDir.findUser(sAMAccountName, function(err, user) {
if (err) {
console.error('ERROR:', JSON.stringify(err));
return;
}
if (!user) console.log('用户: ' + sAMAccountName + ' 未找到。');
else console.log(JSON.stringify(user));
});
查找用户们(findUsers)
执行一个通用搜索,以匹配指定筛选器的用户。默认的用户LDAP过滤器为((&(|(objectClass=user)(objectClass=person))(!(objectClass=computer))(!(objectClass=group))))。
参数
opts- 可选参数,用于扩展或覆盖功能。见可选参数。如果只提供字符串,则该字符串被认为是追加在默认LDAP过滤器最后的额外条件。callback- 完成时执行的回调函数。callback(err: {Object}, users: {Array[User]})
示例
var query = 'cn=*George*';
var activeDir = new ActiveDirectory(config);
activeDir.findUsers(query, function(err, users) {
if (err) {
console.error('ERROR:', JSON.stringify(err));
return;
}
if (!users || users.length === 0) console.log('没有找到用户。');
else {
console.log('findUsers:', JSON.stringify(users));
}
});
此文档提供了与Active Directory操作相关的JavaScript代码示例,包括查找用户、用户组以及已删除的对象等功能的实现方法和调用示例,以及如何初始化Active Directory实例并执行基本查询的操作。
高级用法
属性
默认情况下,用户和组返回以下属性:
- 用户:distinguishedName, userPrincipalName, sAMAccountName, mail, lockoutTime, whenCreated, pwdLastSet, userAccountControl, employeeID, sn, givenName, initials, cn, displayName, comment, description
- 组:distinguishedName, objectCategory, cn, description
如果需要覆盖这些默认设置,可以在创建ActiveDirectory实例时指定:
var ad = new ActiveDirectory({
url: 'ldap://dc.domain.com',
baseDN: 'dc=domain,dc=com',
username: 'username@domain.com',
password: 'password',
attributes: {
user: ['myCustomAttribute', 'mail', 'userPrinicipalName'],
group: ['anotherCustomAttribute', 'objectCategory']
}
});
如果要覆盖“user”或“group”的属性,必须指定所有想要的属性。现有的默认值会被覆盖。可选地,你可以使用opts参数按调用基础来重写属性。
引导记录
默认情况下,引导记录追踪是禁用的。要启用它,在创建实例时指定referrals属性。referrals对象具有以下语法:
{
referrals: {
enabled: false,
excluded: [
'ldaps?://ForestDnsZones\\./.*',
'ldaps?://DomainDnsZones\\./.*',
'ldaps?://.*/CN=Configuration,.*'
]
}
}
excluded选项是一系列正则表达式过滤器,用于忽略特定的引导记录。默认排除列表已在上方列出,忽略了ActiveDirectory默认创建的特殊分区。要指定这些选项,如下所示进行覆盖:
var ad = new ActiveDirectory({
url: 'ldap://dc.domain.com',
baseDN: 'dc=domain,dc=com',
username: 'username@domain.com',
password: 'password',
attributes: {...},
referrals: {
enabled: true,
excluded: []
}
});
如果启用引导记录追踪,指定的用户名必须是"userPrincipalName"。
自定义条目解析
如果你希望以不同方式处理搜索条目,或者用额外的数据增强搜索结果,可以传递一个自定义解析器。例如,如果你想改变二进制值objectSid或GUID,这很有用。
示例:
function customEntryParser(entry, raw, callback){
if (raw.hasOwnProperty("objectSid")){
entry.objectSid = raw.objectSid;
}
if (raw.hasOwnProperty("objectGUID")){
entry.objectGUID = raw.objectGUID;
}
callback(entry);
};
如果你想指定自己的解析器,可以如下覆盖默认解析器:
var ad = new ActiveDirectory({
url: 'ldap://dc.domain.com',
baseDN: 'dc=domain,dc=com',
username: 'username@domain.com',
password: 'password',
attributes: {...},
referrals: {...},
entryParser : customEntryParser
});
可选地,你可以在opts对象中指定你的自定义条目解析器。有关更多信息,请参阅可选参数。
var opts = function(entry, raw, callback) {
entry.retrievedAt = new Date();
callback(entry);
};
ad.findUser(opts, 'userPrincipalName=bob@domain.com', function(err, user) {
...
});
### 可选参数 / 扩展功能
任何接受opts参数的方法都允许添加额外的选项。支持activedirectory.js和内部ldapjs客户端的选项。
目前支持的ldapjs opts选项包括:
- url - 有效的LDAP URL。
- host - 要连接的主机名(与端口一起使用代替URL)。
- port - 连接的端口号(与主机名一起使用代替URL)。
- secure - 表示使用的是ldaps://还是ldap://。(与主机名/端口配合使用代替URL)。
- tlsOptions - 添加其他TLS选项(请参阅ldapjs了解更多详细信息)。
- socketPath - 如果你在Unix域套接字上运行LDAP服务器,可以使用这个。
- log - 可以选择性传入一个bunyan实例,让客户端使用它获取日志器。客户端会将所有消息记录在trace级别。
- timeout - 客户端应允许操作持续多长时间,然后超时。默认为Infinity。
- idleTimeout - 在TCP连接超时前等待多久。默认由操作系统决定。
- bindDN - 所有连接应该绑定的身份标识DN。
- bindCredentials - 与bindDN配合使用的凭据。
- scope - 基、单、或子之一。默认为基。
- filter - 一个字符串形式的LDAP筛选器(见下文),或程序化构建的Filter对象。默认为(objectclass=*)。
- attributes - 要选择并返回的属性(如果设置了这些属性,服务器只会返回这些属性)。默认为空集,意味着所有属性。
- sizeLimit - 最大返回的条目数。默认为0(无限制)。
- timeLimit - 服务器响应的最大时间,单位为秒。默认为10。很多服务器会忽略这个。
对于activedirectory.js的选项包括:
- baseDN - 用于替代构造函数中指定的baseDN的备用baseDN。
- includeMembership - 指定搜索或查找操作是否应枚举指定结果类型的组成员资格。支持的值包括 [ 'user', 'group', 'all' ]。
- includeDeleted - 指定结果应包括被删除/墓碑化的项。请参阅findDeletedObject了解更多的注意事项和警告。
- entryParser - 允许指定一个解析结果ldap对象的自定义函数。例如,将外部RDBMS数据与ldap数据相结合。function onParse(entry, raw, callback) { callback(entry); } 如果返回null,则排除结果。
示例
var opts = {
scope: 'sub',
filter: 'objectClass=User',
includeMembership: [ 'user' ],
entryParser: function(entry, raw, callback) {
// 返回null以排除结果
if (entry.ignore) return(null);
entry.retrievedAt = new Date();
entry.preferredServer = getPreferredServerFromDatabase(entry.userPrincipalName);
callback(entry);
}
};