Modifying Active Directory Passwords via ldapmodify
Asked Answered
P

1

7

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?

Punctilious answered 23/1, 2014 at 18:43 Comment(0)
B
5

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.

Banana answered 26/1, 2014 at 15:57 Comment(6)
I've tried encoding the password with quotes, but my method for encoding it must be off. I tried to encode my password in Python using base64.b64encode(unicode("\"AnExamplePassword1!\"")), which yielded IkFuRXhhbXBsZVBhc3N3b3JkMSEi. I was able to successfully add the user via LDIF with your version of the password.Punctilious
I was able to generate your value of unicodePwd by following my Python script's method of generating the password more closely. I was taking some of the character encoding for granted because it appeared unchanged when it was printed. I went through all of the same steps as in the Python script, and then I used base64.b64encode(password_value). This gave me your IgBB... value.Punctilious
Have you tested the password after creation?Banana
I've confirmed the password as accurate. I am able to sign into a workstation with the LDIF-created account using the assigned password of 'AnExamplePassword1!' (minus quotes).Punctilious
Nice work..! I'm sorry I didn't read your question properly where you had stated that you had already tried encoding. Have a great day/night/etc :)Banana
I had tried encoding, but I was doing it incorrectly by jumping straight to Base64 for the LDIF file. Your response made me re-examine my process and gave me a correct value to compare my results against. Thanks. :)Punctilious

© 2022 - 2024 — McMap. All rights reserved.