Changing User Passwords with the LDAP Component
The way a password is changed depends on the type of directory server. In Active Directory (AD), passwords are stored in the unicodePwd attribute, which can only be modified over a secure connection. In most other LDAP directories (such as OpenLDAP), passwords are stored in the userPassword attribute.
Changing a Password in Active Directory
The LDAP component's ChangePassword method changes the password of a user in Active Directory. It takes the user's name, the current password, and the new password. Since AD only allows passwords to be changed over SSL, set ServerPort to the server's SSL port (typically 636) and SSLStartMode to sslImplicit before calling the method.
LDAP ldap = new LDAP();
ldap.ServerName = "dc1.example.com";
ldap.ServerPort = 636;
ldap.SSLStartMode = LDAPSSLStartModes.sslImplicit;
ldap.Timeout = 30;
// Bind as the user whose password is being changed.
ldap.DN = "EXAMPLE\\jsmith";
ldap.Password = "OldPassword1!";
ldap.ChangePassword("John Smith", "OldPassword1!", "NewPassword2!");
The user parameter is the common name (CN) of the user's entry, which the component combines with the DN of the container that holds the user entries. By default, the component finds this container automatically by querying the server's root DSE, and uses the Users container of the domain (e.g., CN=Users,DC=example,DC=com). If the user entries are stored in a different container or organizational unit, set the UsersDN configuration setting to its DN.
ldap.Config("UsersDN=OU=Staff,DC=example,DC=com");
If the component is not already bound to the server, ChangePassword binds using the DN and Password properties, and unbinds when the operation is complete. The Timeout property must be set to a value greater than 0, since this method cannot be called in a non-blocking manner.
Old Password vs. Administrative Reset
Active Directory handles password changes differently depending on who is making the change:
- When the user changes their own password, the old password must be provided. The component sends a single modify request that deletes the old value and adds the new one, and the server enforces the domain's password policy (including password history).
- When an administrator resets another user's password, the old password is not required. Pass an empty string for the oldPassword parameter, and the component replaces the password instead. The account used to bind must have the "Reset Password" permission on the user's entry.
// Bind as an administrator, and reset the user's password.
ldap.DN = "EXAMPLE\\admin";
ldap.Password = "AdminPassword";
ldap.ChangePassword("John Smith", "", "NewPassword2!");
Changing a Password in Other LDAP Directories
In directories such as OpenLDAP, the password is changed by modifying the userPassword attribute of the user's entry. This is done by adding an attribute to the Attributes collection with its modification operation set to amoReplace, and then calling the Modify method.
LDAP ldap = new LDAP();
ldap.ServerName = "ldap.example.com";
ldap.ServerPort = 636;
ldap.SSLStartMode = LDAPSSLStartModes.sslImplicit;
ldap.DN = "uid=jsmith,ou=people,dc=example,dc=com";
ldap.Password = "OldPassword1!";
ldap.Bind();
// Replace the value of the userPassword attribute of the user's entry.
ldap.DN = "uid=jsmith,ou=people,dc=example,dc=com";
ldap.Attributes.Clear();
ldap.Attributes.Add(new LDAPAttribute("userPassword", "NewPassword2!", LDAPAttributeModOps.amoReplace));
ldap.Modify();
if (ldap.ResultCode != 0) {
Console.WriteLine("Password change failed: " + ldap.ResultDescription);
}
ldap.Unbind();
Although many of these directories do not require SSL for password changes, using a secure connection is strongly recommended, since the new password is otherwise sent to the server in plain text. Some directories store the password exactly as it is provided, so check the server's documentation for whether it hashes passwords automatically, or whether a hashed value (such as an {SSHA} hash) must be provided instead.
Notes
- By default, Active Directory treats userPassword as an ordinary attribute, and writing to it does not change the user's password. This behavior is controlled by the dsHeuristics attribute of the directory. In AD LDS (formerly ADAM), userPassword is an alias for unicodePwd by default.
- To modify unicodePwd manually (for example, when the user entry is not in the container used by ChangePassword), the value must be the password enclosed in double quotes and encoded as UTF-16LE (e.g., Encoding.Unicode.GetBytes("\"NewPassword2!\"")), and set through the attribute's ValueB field.
- If the server rejects the change, the ResultCode and ResultDescription properties describe the error. For example, result code 19 (constraint violation) usually means that the new password does not meet the domain's password policy, or that the old password is incorrect.
- The server's certificate is checked during the SSL handshake. To accept a certificate that is not trusted by the system (such as a self-signed certificate on a test server), handle the SSLServerAuthentication event.
Note that in older versions of IPWorks, attributes were specified using the AttrCount, AttrType, AttrValue, and AttrModOp array properties, which have been replaced by the Attributes collection.
We appreciate your feedback. If you have any questions, comments, or suggestions about this article please contact our support team at support@nsoftware.com.