简体   繁体   English

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

[英]Changing Active Directory user password with PHP script

I am trying to get a very simple PHP script to change a user password in my Active Directory domain.我正在尝试使用一个非常简单的PHP脚本来更改我的Active Directory域中的用户密码

Here is the script I found some where online:这是我在网上找到的一些脚本:

<?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));

}
?>

The output of this PHP page was this error message:此 PHP 页面的输出是此错误消息:

53 Server is unwilling to perform 53 服务器不愿意执行

And the script simply didn't work (the password of the user was NOT changed).并且脚本根本不起作用(用户的密码没有更改)。

I know the main principle that AD stores the passwords in unicodePwd field (if that is still the case till now), and I knew that I have to use secure connection and I am using it (hopfully it is correctly setup).我知道 AD 将密码存储在 unicodePwd 字段中的主要原则(如果到目前为止仍然如此),并且我知道我必须使用安全连接并且我正在使用它(希望它正确设置)。

I googled about that error message but I couldn't find any functional solution.我在谷歌上搜索了该错误消息,但找不到任何功能解决方案。

I also tried some other scripts but this one was the best till now because the others gave me some errors in some previous steps (for example binding).我还尝试了一些其他脚本,但这是迄今为止最好的脚本,因为其他脚本在之前的某些步骤中给了我一些错误(例如绑定)。

I really appreciate any help to solve that problem , or even another functional script may be a good idea!我真的很感谢任何帮助解决这个问题,或者甚至另一个功能脚本可能是一个好主意! Thanks in advance.提前致谢。

You may not change a password using this method unless you connect over SSL/TLS.除非您通过 SSL/TLS 连接,否则您不得使用此方法更改密码。 If you Google or Bing for the word unicodePwd , which you already knew because you included it in your post, one of the first if not the first result will be the MSDN documentation for unicodePwd , which states within the first three sentences:如果您在 Google 或 Bing 上搜索unicodePwd一词,因为您已经将其包含在您的帖子中,那么第一个(如果不是一个)结果将是unicodePwdMSDN 文档,它在前三个句子中说明:

This attribute is written by an LDAP Modify under the following restricted conditions.此属性由 LDAP Modify 在以下受限条件下写入。 Windows 2000 operating system servers require that the client have a 128-bit (or better) SSL/TLS-encrypted connection to the DC in order to modify this attribute. Windows 2000 操作系统服务器要求客户端具有到 DC 的 128 位(或更好)SSL/TLS 加密连接才能修改此属性。 On Windows Server 2003 operating system, Windows Server 2008 operating system, Windows Server 2008 R2 operating system, Windows Server 2012 operating system, Windows Server 2012 R2 operating system, and Windows Server 2016 Technical Preview operating system, the DC also permits modification of the unicodePwd attribute on a connection protected by 128-bit (or better) Simple Authentication and Security Layer (SASL)-layer encryption instead of SSL/TLS.在 Windows Server 2003 操作系统、Windows Server 2008 操作系统、Windows Server 2008 R2 操作系统、Windows Server 2012 操作系统、Windows Server 2012 R2 操作系统和 Windows Server 2016 Technical Preview 操作系统上,DC 还允许修改 unicodePwd受 128 位(或更好)简单身份验证和安全层 (SASL) 层加密而不是 SSL/TLS 保护的连接上的属性。 In Windows Server 2008, Windows Server 2008 R2, Windows Server 2012, Windows Server 2012 R2, and Windows Server 2016 Technical Preview, if the fAllowPasswordOperationsOverNonSecureConnection heuristic of the dSHeuristics attribute (section 6.1.1.2.4.1.2) is true and Active Directory is operating as AD LDS, then the DC permits modification of the unicodePwd attribute over a connection that is neither SSL/TLS-encrypted nor SASL-encrypted.在 Windows Server 2008、Windows Server 2008 R2、Windows Server 2012、Windows Server 2012 R2 和 Windows Server 2016 Technical Preview 中,如果 dSHeuristics 属性的 fAllowPasswordOperationsOverNonSecureConnection 启发式(第 6.1.1.2.4.1.2 节)为 true 并且 Active Directory作为 AD LDS 运行,则 DC 允许通过既不是 SSL/TLS 加密也不是 SASL 加密的连接修改 unicodePwd 属性。 The unicodePwd attribute is never returned by an LDAP search. LDAP 搜索永远不会返回 unicodePwd 属性。

If you just perform a simple search for unicodePwd , again one of the very first results you'll get is STEP BY STEP CODE on how to do this:如果您只是对unicodePwd执行简单的搜索,那么您将获得的第一个结果之一是关于如何执行此操作的STEP BY STEP CODE

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

Realise I'm a year late to this party;意识到我参加这个派对晚了一年; but having discovered this post whilst troubleshooting a similar problem...但是在解决类似问题的同时发现了这篇文章......

Suspect ldaps is/was providing a certificate that wasn't trusted by the server hosting this php script (linux?);怀疑 ldaps 正在/正在提供托管此 php 脚本(linux?)的服务器不信任的证书; OP mentions having changed the code to use ldaps and getting to exit('Could not connect to LDAP server'); OP 提到已更改代码以使用 ldaps 并退出('无法连接到 LDAP 服务器'); but connecting OK via Apache Directory Studio which may be on a machine that DOES trust the certificate (ie a domain joined workstation that trusts the DC).但是通过 Apache Directory Studio 连接正常,它可能位于信任证书的机器上(即信任 DC 的加入域的工作站)。

To fix this proper, investigate your Private Key Infrastructure (a big topic, start here : https://social.technet.microsoft.com/wiki/contents/articles/2980.ldap-over-ssl-ldaps-certificate.aspx )要正确解决此问题,请调查您的私钥基础结构(一个大主题,从这里开始: https : //social.technet.microsoft.com/wiki/contents/articles/2980.ldap-over-ssl-ldaps-certificate.aspx

Alternatively, just tell the php server to trust the LDAP self-signed cert as see: Authenticating a self-signed certificate for LDAPS connection或者,只需告诉 php 服务器信任 LDAP 自签名证书,请参见: Authenticating a self-signed certificate for LDAPS connection

To verify this is the case before embarking (ie not recommended in production) consider configuring LDAP on the php host (assumed linux server) to ignore errors caused by the certificate authority/trust by doing putting要在开始之前验证这种情况(即不建议在生产中使用),请考虑在 php 主机(假定为 linux 服务器)上配置 LDAP,以通过执行 put 忽略由证书颁发机构/信任引起的错误

TLS_REQCERT never

at the end of /etc/ldap/ldap.conf (restart apache / webserver after change)在/etc/ldap/ldap.conf末尾(更改后重启apache/webserver)

As Ryan Ries has noted, you must make a secure connection in order to change a password, but the code you've posted does not do so.正如 Ryan Ries 所指出的,您必须建立安全连接才能更改密码,但您发布的代码并没有这样做。

The problematic code is:有问题的代码是:

$ldap = ldap_connect('localhost');

As you can see, this makes a non-secure connection.如您所见,这会造成不安全的连接。

To make a secure connection , you need to specify an LDAPS URI:要建立安全连接,您需要指定一个 LDAPS URI:

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

You're creating the unicode password wrong.您创建的 unicode 密码错误。 Here is code that works at least for me on Server 2012.这是至少适用于我在 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!");
}

Notice how I encode the " with the new password, that was the trick that got it working for me.请注意我如何使用新密码对 " 进行编码,这就是让它为我工作的技巧。

$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);
}

I'm running SAMBA 4.11 as AD/DC and had to use ldap_modify_batch to get this working.我正在将 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);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM