我正在使用带有 Ubuntu 24.04 Noble 的 Vagrant VM 来开发一个项目。我正在使用 Node 20.18.0 和 NestJs 10.4.5。
在其中一条路线中,我尝试使用 NodeJs 的 ldapts 库访问安全的 ldap 服务器。安全连接的目的是在AD中写入unicodePwd字段。
Microsoft 有 此文档 与编写 unicodePwd 属性相关。基本上,密码必须用双引号括起来,并且必须采用 UTF-16 编码。那么该属性应该写入安全连接中。
最初我尝试通过这种方式连接:
const client = new Client({
url: 'ldaps://<ldapip>',
timeout: 0,
connectTimeout: 0,
});
const bindDN = 'CN=Administrator,CN=Users,DC=myproject,DC=local';
const password = 'mypdw';
try {
console.log('D1');
let cert = fs.readFileSync('/vagrant/backend/certs/mycert.crt');
console.log(cert.toString('base64'));
await client.startTLS({
ca: [cert],
});
console.log('D2');
await client.bind(bindDN, password);
console.log('D3');
(...)
} catch (error) {
return { status: 500, msg: 'LDAP fail', error }
} finally {
await client.unbind();
}
当我运行此代码时,D0、D1 和证书打印正确,但未到达 D2 点。它失败并出现以下错误:
{"code":"UNABLE_TO_VERIFY_LEAF_SIGNATURE"}}
我确信该证书是由 AD 的 CA 发出的。我正在使用 Chromium 并且 CA 已正确导入其中。 我还尝试创建一个包含用户证书和 CA 证书的文件,但它也不起作用。
然后我对代码做了一些更改,现在它可以连接了,但我不确定我是否有安全连接,因为我无法用它做我需要做的事情(编写 unicodePwd 属性)。有没有办法检查安全连接是否到位?或者只是连接并绑定到 ldaps://myserver:636 就足以保证安全连接?
这是代码的当前版本:
// I tried the line below both with ca and client certs with equal results
let cert = fs.readFileSync('/vagrant/backend/certs/client-cert.crt');
let opts = {
ca: [cert],
host: 'myurl.myproject.local',
rejectUnauthorized: false,
secure: true
};
const client = new Client({
url: 'ldaps://myurl.myproject.local:636',
timeout: 0,
tlsOptions: {
...opts,
minVersion: 'TLSv1.1'
},
connectTimeout: 0,
});
const bindDN = 'CN=Administrator,CN=Users,DC=myproject,DC=local';
const password = 'mypdw';
try {
console.log('D1');
console.log(cert.toString('base64'));
console.log('D2');
await client.bind(bindDN, password);
console.log('D3', client.isConnected);
let passwdUtf16 = this.encodePassword("mypwd");
var newUser = {
sn: 'teste',
objectClass: ["organizationalPerson", "person", "user"],
unicodePwd: passwdUtf16
}
await client.add('cn=test,ou=MyCompany,ou=Organizations,dc=myproject,dc=local', newUser);
console.log('D4');
我还尝试添加不带 unicodePwd 属性的用户(它有效),然后执行以下操作:
let change = new Change({ operation: 'replace', modification: new Attribute({ type: 'unicodePwd;binary', values: [passwdUtf16] }) });
await client.modify('cn=test,ou=MyCompany,ou=Organizations,dc=myproject,dc=local', change);
在这两种情况下,我都会收到 UnwillingToPerformError 错误,这让我认为我没有建立安全连接。
这是encodePassword函数:
encodePassword(str) {
const text = '"' + str + '"';
let byteArray = new Uint8Array(text.length * 2);
for (let i = 0; i < text.length; i++) {
byteArray[i * 2] = text.charCodeAt(i); // & 0xff;
byteArray[i * 2 + 1] = text.charCodeAt(i) >> 8; // & 0xff;
}
return String.fromCharCode.apply(String, byteArray);
}
现在我有问题:
如何断言这是一个安全连接以便正确写入 unicodePwd 属性?
我写密码有什么错误吗?
“在 Windows Server 2003 操作系统及更高版本上,DC 还允许修改受 128 位(或更好)简单身份验证和安全层 (SASL) 层加密而不是 SSL/TLS 保护的连接上的 unicodePwd 属性。” 参考:https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-adts/6e803168-f140-4d23-b2d3-c3a8ab5917d2
我认为该属性的特殊之处在于文档中说:
“为了使密码更改操作成功,服务器强制要求要更改密码的用户或 inetOrgPerson 对象必须拥有自身的“用户更改密码”控制访问权限,并且 Vdel 必须是当前密码在物体上。”
您可以通过此链接提高 LDAP 日志记录级别 https://learn.microsoft.com/en-us/troubleshoot/windows-server/active-directory/configure-ad-and-lds-event-logging。本文中引用的诊断子项可以选择为 16 或 27,分别检查 LDAP 接口事件或 PDC 密码更新通知。日志记录级别可以选择 4(详细)。