Modifying Active Directory Passwords via ldapmodify
Why not use ldifde and unicode base64 encode the password as described here: http://support.microsoft.com/kb/263991
Your python script seems to be encoding the password as unicode / base64. Perhaps your password needs to be encoded in your ldif file (with the quotes when encoding) rather than plain text as you are doing in your example.
Eg:
unicodePwd:: IgBBAG4ARQB4AGEAbQBwAGwAZQBQAGEAcwBzAHcAbwByAGQAMQAhACIA
For the example password you provided.
Admin
Updated on June 13, 2022Comments
-
Admin almost 2 years
I'm investigating the scripting of various LDAP operations. However, I've hit a bit of a speed bump with Active Directory user creation.
The following LDIF fails when I load it in via the
ldapmodify
command:dn: CN=Frank,CN=Users,DC=domain,dc=local changeType: add objectClass: top objectClass: person objectClass: organizationalPerson objectClass: user cn: Frank userPrincipalName: [email protected] sAMAccountName: frank givenName: Frank sn: Stein displayName: Frank Stein description: Frankenstein's User userAccountControl: 512 unicodePwd: "AnExamplePassword1!"
When attempting to add the user via LDIF, I used the following command:
ldapmodify -H 'ldaps://<ip-of-server>:636' -D 'DOMAIN\Administrator' -x -W -f frank-add.ldif
This fails with the following error:
ldap_add: Server is unwilling to perform (53) additional info: 0000001F: SvcErr: DSID-031A120C, problem 5003 (WILL_NOT_PERFORM), data 0
This is a problem with the password policy denying the user.
However, the following Python script works:
#!/usr/bin/python import ldap import ldap.modlist as modlist AD_LDAP_URL='ldaps://<ip-of-server>:636' ADMIN_USER='DOMAIN\Administrator' # User must be authorized to create accounts, naturally. ADMIN_PASSWORD='password for ADMIN_USER' BASE_DN='dc=domain,dc=local' username='frank' firstname='Frank' surname='Stein' displayName = "Frank Stein" password='AnExamplePassword1!' # The value of password still needs to adhere to the domain's password policy. unicode_pass = unicode('\"' + password + '\"', 'iso-8859-1') password_value = unicode_pass.encode('utf-16-le') l = ldap.initialize(AD_LDAP_URL) l.simple_bind_s(ADMIN_USER, ADMIN_PASSWORD) dn=str('CN=%s,CN=Users,DC=domain,dc=local' % firstname) attrs = {} attrs['objectclass'] = ['top','person','organizationalPerson','user'] attrs['cn'] = str(username) attrs['sAMAccountname'] = str(username) attrs['unicodePwd'] = str(password_value) attrs['givenName'] = str(firstname) attrs['sn'] = str(surname) attrs['displayName'] = str(displayName) attrs['description'] = str("Frankenstein's User") attrs['userPrincipalName'] = str("%[email protected]" % username) attrs['userAccountControl'] = str(512) ldif = modlist.addModlist(attrs) l.add_s(dn,ldif)
Using the Python script, I am immediately able to sign in using the user's password (minus the quotes that were escaped out). I can still trigger the same "Unwilling to Perform" error by picking a password like 'password' that is too simple. However, in this case the password being used is the same.
So far as I can see, the operations should be identical. The difference that breaks the LDIF file is the way that I deal with the quotes that I need to enclose the password in. Creation via LDIF succeeds if I make a disabled account by setting the value of userAccountControl to 544 and not including a password. However, this means that I would need to manually go and reset the user's password.
So far, I've tried the following password formats via LDIF:
- Without quotes.
- Plain quotes.
- Escaped quotes via \
- Escaped quotes via ASCII: {\22}
- Using Python to Base64-encode the password (With and without quotes, and with the format of the LDIF modified to
unicodePwd::
)
While I'm happy that I have a working method of adding users via the Python, I'm still a bit confused about how to properly escape out password values when using LDIF files and
ldapmodify
. Is there an alternate method that I'm not considering?