使用PHP脚本更改Active Directory用户密码

时间:2016-03-12 04:07:17

标签: active-directory php ldap

我正在尝试使用一个非常简单的 PHP 脚本来更改 Active Directory 域中的用户密码

以下是我在网上找到的一些脚本:

<?php
$uid = 'Mohammed Noureldin';
$newPassword = '5omeGoodP@ssword';
$bindDn = 'CN=Administrator,OU=UsersOU,DC=example,DC=local';
$bindPassword = 'An0therGoodP@ssword';
$baseDn = 'OU=UsersOU,DC=example,DC=local';
$protocolVersion = 3;

$ldap = ldap_connect('localhost');
if (!ldap_set_option($ldap, LDAP_OPT_PROTOCOL_VERSION, $protocolVersion))
{
    exit('Failed to set protocol version to '.$protocolVersion);
}
// bind anonymously so that we can verify if the server really is running
ldap_bind($ldap);
if (ldap_errno($ldap) !== 0)
{
    exit('Could not connect to LDAP server');
}

// now bind with the correct username and password
ldap_bind($ldap, $bindDn, $bindPassword);
if (ldap_errno($ldap) !== 0)
{
    exit('ERROR: '.ldap_error($ldap));
}

$searchResults = ldap_search($ldap, $baseDn, 'cn='.$uid);
// no matching records
if ($searchResults === false)
{
    exit('No user found');
}

if (!is_resource($searchResults))
{
    exit('Error in search results.');
}
// create the unicode password
$len = strlen($newPassword);
$newPass = '"';
for ($i = 0; $i < $len; $i++)
{
    $newPass .= "{$newPassword{$i}}\000";
}
$newPass .= '"';

$entry = ldap_first_entry($ldap, $searchResults);
if (!is_resource($entry))
{
    exit('Couldn\'t get entry');
}
$userDn = ldap_get_dn($ldap, $entry);
if (!$userDn)
{
exit('Errrrrrrrrr1');

}
if (!ldap_modify($ldap, $userDn, array('unicodePwd' => $newPass)))
{
exit(ldap_errno($ldap)." ". ldap_error($ldap));

}
?>

此PHP页面的输出是错误消息:

  

53服务器不愿意执行

脚本根本不起作用(用户的密码 NOT 已更改)。

我知道AD将密码存储在unicodePwd字段中的主要原则(如果到目前为止仍然如此),我知道我必须使用安全连接并且我正在使用它(这是正确的设置)。

我搜索了该错误消息,但我找不到任何功能性解决方案。

我还尝试过其他一些脚本,但是这个脚本是最好的,因为其他脚本在之前的一些步骤中给了我一些错误(例如绑定)。

我非常感谢解决问题的任何帮助,甚至另一个功能脚本可能是个好主意! 提前谢谢。

6 个答案:

答案 0 :(得分:6)

除非您通过SSL / TLS连接,否则您不能使用此方法更改密码。如果您使用Google或Bing作为unicodePwd这个词,因为您已将其包含在帖子中,那么第一个 第一个结果中的第一个将是MSDN documentation for unicodePwd ,在前三个句子中说明:

  

此属性由LDAP Modify在以下内容中编写   限制条件。 Windows 2000操作系统服务器需要   客户端具有128位(或更好)SSL / TLS加密   连接到DC以修改此属性。在Windows上   Server 2003操作系统,Windows Server 2008操作系统,   Windows Server 2008 R2操作系统,Windows Server 2012操作系统   系统,Windows Server 2012 R2操作系统和Windows Server   2016年技术预览操作系统,DC也允许   修改受保护的连接上的unicodePwd属性   128位(或更好)简单身份验证和安全层   (SASL) - 层加密而不是SSL / TLS。在Windows Server 2008中,   Windows Server 2008 R2,Windows Server 2012,Windows Server 2012 R2,   和Windows Server 2016技术预览,如果   fAllowPasswordOperationsOverNonSecureConnection的启发式   dSHeuristics属性(第6.1.1.2.4.1.2节)为true且为Active   目录作为AD LDS运行,然后DC允许修改   两者都没有的unicodePwd属性   SSL / TLS加密或SASL加密。 unicodePwd属性是   从未通过LDAP搜索返回。

如果你只是对unicodePwd进行简单搜索,那么就是第一次 您将得到的结果是逐步代码,了解如何执行此操作:

https://support.microsoft.com/en-us/kb/269190

答案 1 :(得分:2)

正如Ryan Ries所说,您必须建立安全连接才能更改密码,但您发布的代码不会这样做。

有问题的代码是:

$ldap = ldap_connect('localhost');

如您所见,这会产生非安全连接。

To make a secure connection,您需要指定LDAPS URI:

$ldap = ldap_connect('ldaps://localhost');

答案 2 :(得分:2)

意识到我参加这个派对已经晚了一年;但在解决类似问题的同时发现了这篇文章...

怀疑ldaps是否正在提供托管此php脚本的服务器不信任的证书(linux?); OP提到更改了代码以使用ldaps并退出('无法连接到LDAP服务器');但是可以通过Apache Directory Studio连接OK,该目录可能位于信任该证书的计算机上(即一个域加入了信任该DC的工作站)。

要解决此问题,请调查您的私钥基础结构(一个很大的主题,从这里开始:https://social.technet.microsoft.com/wiki/contents/articles/2980.ldap-over-ssl-ldaps-certificate.aspx

或者,只需告诉php服务器信任LDAP自签名证书,请参阅:Authenticating a self-signed certificate for LDAPS connection

要在启动之前验证是这种情况(即不建议在生产中),请考虑在php主机(假设的linux服务器)上配置LDAP,以忽略由证书颁发机构/信任引起的错误

snapshot

在/etc/ldap/ldap.conf的末尾 (更改后重启apache / webserver)

答案 3 :(得分:1)

您正在创建错误的unicode密码。这是在Server 2012上至少对我有效的代码。

// create the unicode password
$newpassword = "\"" . $newpassword . "\"";
$len = strlen($newpassword);
for ($i = 0; $i < $len; $i++) $newpass .= "{$newpassword{$i}}\000";
$entry["unicodePwd"] = $newpass;

// Modify the password
if (ldap_mod_replace($ldap, $userDn, $entry))
{
  exit("Successfully updated password!");
}

注意我如何编码&#34;使用新密码,这是让它为我工作的技巧。

答案 4 :(得分:0)

$server = "ldaps://172.1.200.1:636";
$dn = "dc=srv,dc=world";
$message = array();

function changePassword($server,$dn,$user,$oldPassword,$newPassword,$newPasswordCnf){
  global $message;

  error_reporting(0);
  putenv('LDAPTLS_REQCERT=allow');
  $con=ldap_connect($server);
  ldap_set_option($con, LDAP_OPT_PROTOCOL_VERSION, 3);
  ldap_set_option($con, LDAP_OPT_REFERRALS, 0);

  $findWhat = array ("cn","mail");
  $findWhat = array();
  $findWhere = $dn;
  $findFilter = "(sAMAccountName=$user)";

  $ldaprdn = 'mydomain' . "\\" . $user;
  $ldapbind = ldap_bind($con, $ldaprdn, $oldPassword);
  if ($ldapbind) {
      $message[] = "ldapbind  ($ldapbind) with sAMAccountName=$user";
  } else {
    $error = ldap_error($con);
    $errno = ldap_errno($con);
    $message[] = "ldapbind error $errno - $error";
    ldap_close($con);
    return false;
  }
  $sr = ldap_search($con,$dn,$findFilter,$findWhat);
  $records = ldap_get_entries($con, $sr);

 if ($records["count"] != "1") {
    $message[] = "Error E100 - Wrong user or password.";
    return false;
  }else {
    $message[] = "Found user <b>".$records[0]["cn"][0]." DN=".$records[0]["dn"]." </b>". print_r($records[0],true);
  }


  $entry = array();
  #seems a more correct way that handles complicated characters
  $entry["unicodePwd"] = iconv("UTF-8", "UTF-16LE", '"' . $newPassword . '"');
  # base64_encode is only needed in ldif text files !
  #$entry["unicodePwd"] = base64_encode($newPassw);

  $result = ldap_modify($con,$records[0]["dn"],$entry);
  if ($result === false){
    $message[] = $newpass.",".$entry["unicodePwd"]." Your password was not changed . with:".print_r($result, true);
    $error = ldap_error($con);
    $errno = ldap_errno($con);
    $message[] = "$errno - $error";
  }
  else {
    $message[] = " Your password has been changed. ";
    //mail($records[0]["mail"][0],"Password change notice : ".$user,"Your password has just been changed.");
    }
ldap_close($con);
}

答案 5 :(得分:0)

我将SAMBA 4.11作为AD / DC运行,并且必须使用ldap_modify_batch才能正常工作。

    $modifs = [
            [
                    "attrib"  => "unicodePwd",
                    "modtype" => LDAP_MODIFY_BATCH_REMOVE,
                    "values"  => [iconv("UTF-8", "UTF-16LE", '"' . $curPassword . '"')],
            ],
            [
                    "attrib"  => "unicodePwd",
                    "modtype" => LDAP_MODIFY_BATCH_ADD,
                    "values"  => [iconv("UTF-8", "UTF-16LE", '"' . $newPassword . '"')],
            ],
    ];
    $result = ldap_modify_batch($ldapconn, $dn, $modifs);
    error_log("Batch modify result:".print_r($result, true));
    $errorMessage = ldap_errno($ldapconn)." ". ldap_error($ldapconn);
    error_log("$errorMessage:".$errorMessage);