这个问题之前在 StackOverflow 上出现过,因为我认为这是一个编程问题。看来这更像是一个与正确设置 Active Directory 相关的问题,所以我把它移到了这里。
好的,我已经研究这个问题一段时间了,但还没有找到解决方案。我经常使用我所在的服务器连接到 OpenLDAP,SSL 和 LDAP 一切正常。但是,现在我需要切换到 Active Directory,但遇到了麻烦。
为了设置系统,我执行以下操作:1)从 Server 2012 导出我的证书: http://pic.dhe.ibm.com/infocenter/rdirserv/v5r1m0/index.jsp?topic=%2Fcom.ibm.rational.rds.administering.doc%2Ftopics%2Ft_Exporting_certificate_Active_Directory_server.html
2)将我的证书从DER转换为PEM: http://www.novell.com/coolsolutions/tip/5838.html
3) 确保 TLS_REQCERT 设置为“从不”
4)验证我的ldap.conf文件是否指向我的证书的正确位置。
轰!我能够通过 ldap_connect() 进行连接,并能够与我的用户绑定。但是,当我去修改密码时,我收到了非常有用的错误消息“服务器不愿执行”。
有人认为这是 SSL 的问题。因此,我使用以下命令进行了一些测试:
*ldapsearch -H "ldaps://my.domain.tld" -b "" -s base -Omaxssf=0 -d7*
我收到的结果是:
ldap_send_initial_request
ldap_new_connection 1 1 0
ldap_int_open_connection
ldap_connect_to_host: TCP my.domain.tld:636
ldap_new_socket: 3
ldap_prepare_socket: 3
ldap_connect_to_host: Trying ip.add.re.ss:636
ldap_pvt_connect: fd: 3 tm: -1 async: 0
TLS: loaded CA certificate file /etc/openldap/certs/cert-name.pem
... certificate data ...
TLS: certificate [CN=my.domain.tld] **is valid**
... more certificate data ...
* host: my.domain.tld port: 636 (default)
refcnt: 2 status: Connected
last used: Fri Feb 21 11:50:13 2014
因此看来我已连接,并且我的证书有效。
尝试从命令行进行搜索:
ldapsearch -H "ldaps://my.domain.tld:636" -D "[email protected]" -W -x -b "CN=Person I. M. Lookingfor,CN=Users,DC=my,DC=domain,DC=tld"
返回我希望检索的所有信息。
目前,我认为这不是代码的问题,而是我认为 AD 中仍缺少一些设置。我不是 Windows 用户,所以我不知道我还可能缺少什么。如果您有其他想法,我将不胜感激。
生成 LDIF 的代码
function encodePwd($new_password) {
$newpass = '';
$new_password = "\"".$new_password."\"";
$len = strlen($new_password);
for ($i = 0; $i < $len; $i++) {
$newpass .= "{$new_password{$i}}\000";
}
$newpass = base64_encode($newpass);
return $newpass;
}
生成的 LDIF:
dn: CN=Tester B. Testerton,CN=Users,DC=my,DC=domain,DC=tld
changetype: modify
replace: unicodePwd
unicodePwd:: IgBiAHUAQAAoADUAJABpAF4APQA5AGwAawBDACIA
然后代码尝试:
$mods["unicodePwd"] = $new_pass64;
if(ldap_modify($ldap_conx,$ldap_user_dn,$mods) === false)
{
$e = ldap_error($ldap_conx);
$e_no = ldap_errno($ldap_conx);
echo "Error attempting to modify password in LDAP for user: $uname\n";
} else {
echo "Success! Changed password for user: $uname\n";
}
我将“域用户”组更改为“由”我的管理员用户帐户管理。然后,我运行伊迪夫德以管理员身份在 PowerShell 中执行命令,该命令现在起作用了,而在成为“管理员”之前它却不能:
Logging in as current user using SSPI
Importing directory from file ".\tester.ldif"
Loading entries..
1 entry modified successfully.
The command has completed successfully
但是,我仍然无法通过 PHP 修改密码;仍然缺少一些东西。我经常使用此 Linux 服务器来更新 OpenLDAP 和 Novell eDirectory 服务器,所以我知道我的 PHP LDAP 设置是正确的。
我的问题似乎更多在于设置 Active Directory 服务器以用于程序更新。我尝试使用 Python 进行密码更新,但结果是一样的。
更新 我查看了 Ryan 提供的链接(http://technet.microsoft.com/en-us/magazine/ff848710.aspx),并确认我尝试转换密码确实转换为正确的编码(即“car”转换为 IgBjAGEAcgAiAA==,如文章中所述)。现在看来,关键是要弄清楚如何向我的 LDAP 管理器添加扩展权限。
答案1
如您所知,unicodePwd
默认情况下,远程更新用户帐户的属性需要与域控制器建立 128 位或更好的 SSL/TLS 连接。如果是 2008R2 或 2012,则需要 SASL。看起来您已经满足要求,因为您有证书并且正在使用 LDAPS。
另外,仅供公众参考,该unicodePwd
属性是写-only。它永远不会在 LDAP 搜索的结果中返回。
我还看到您将纯文本密码括在引号中,然后对整个内容进行 base64 编码,这两项都是正确的。您太接近正确了!
但我在你的代码中没有看到你确保编码是 UTF-16。它有为 UTF-16。UTF-16 小端,然后确切地说是 base64 编码的。
“... DC 要求以 UTF-16 编码的 Unicode 字符串形式指定密码值,该字符串包含用引号括起来的密码,并且已根据对象(副本链接)语法将其 BER 编码为八位字节字符串。”
此外,为了我们不会错过显而易见的事情,请确保正确的权限:
为了使密码更改操作成功,服务器强制要求正在更改密码的用户或 inetOrgPerson 对象必须拥有自身的“用户更改密码”控制访问权限,
(即该帐户没有设置“用户无法更改密码”标志,)
并且 Vdel 必须是该对象的当前密码。为了成功重置密码,服务器强制要求客户端拥有要重置密码的用户或 inetOrgPerson 对象的“用户强制更改密码”控制访问权限。
再说一次,为了不忽视显而易见的事情,请确保您尝试设置的新值符合域的密码策略。
我不太懂 PHP 或 Perl,但这里有一些 Powershell,可以以您需要的正确编码格式获取密码:
PS C:\> [System.Convert]::ToBase64String([System.Text.Encoding]::Unicode.GetBytes("`"SweetNewPwd123!`""))
IgBTAHcAZQBlAHQATgBlAHcAUAB3AGQAMQAyADMAIQAiAA==
让我们仔细思考一下这个神秘unicodePwd
属性的文档:
http://msdn.microsoft.com/en-us/library/cc223248.aspx
另外,作为补充阅读,请查看这篇文章: