Has anyone every successfully managed to create a valid and "working" user in Active Directory using Python ?
I've tried my best by using the https://pypi.org/project/python-ldap/ module but could not for the life of me get it to create the user...
The closest I ever got was using this piece of code:
conn = ldap.initialize('ldap://' + ldap_hostname)
conn.protocol_version = 3
conn.set_option(ldap.OPT_REFERRALS, 0)
conn.simple_bind_s(ldap_admin_dn, ldap_admin_pw)
attrs = {}
attrs['objectClass'] = ['top'.encode('utf-8'), 'person'.encode('utf-8'), 'organizationalPerson'.encode('utf-8'), 'user'.encode('utf-8')]
attrs['cn'] = "Test User".encode("utf-8")
attrs['userPrincipalName'] = "testuser@domain.com".encode("utf-8")
attrs['displayName'] = "Test User".encode("utf-8")
attrs['givenName'] = "Test".encode("utf-8")
attrs['sn'] = "User".encode("utf-8")
attrs['sAMAccountName'] = "testuser".encode("utf-8")
attrs['mail'] = "testuser@domain.com".encode("utf-8")
attrs['primaryGroupID'] = "513".encode("utf-8")
# Convert our dict to nice syntax for the add-function using
ldif = modlist.addModlist(attrs)
# Set up user dn
user_cn = "Test User"
user_dn = "CN={},{}".format(user_cn, ldap_users_ou_dn)
# Create user
conn.add_s(user_dn, ldif)
# Set initial password
password_value = "LaLaLaLaLa123123123!".encode('utf-16-le')
add_pass = [(ldap.MOD_REPLACE, 'unicodePwd', [password_value])]
conn.modify_s(user_dn, add_pass)
# Set user account control
mod_acct = [(ldap.MOD_REPLACE, 'userAccountControl', '66048')]
conn.modify_s(user_dn, mod_acct)
But unfortunately, it fails on conn.add_s
with this error message:
"errorMessage": "{'msgtype': 105, 'msgid': 2, 'result': 53, 'desc': 'Server is unwilling to perform', 'ctrls': \[\], 'info': '00000529: SvcErr: DSID-031A124C, problem 5003 (WILL\_NOT\_PERFORM), data 0\\n'}", "errorType": "UNWILLING\_TO\_PERFORM",
Am I pushing wrong arguments? Am I encoding them badly? What am I doing wrong ? Any help or "piece of code" which you guys actually used to make it work would be awesome ...
Again, this is specifically intended to connect to MICROSOFT AD, and not OpenLDAP.
Appreciated!
For anyone else who got here, here's what I noticed from my tests:
As such, considering the fact that my environment was in AWS and I was using AWS Microsoft AD Standard, here's my working example:
ldap_admin_pw = "MyAdminPassword123!"
ldap_hostname = "ldap.server.com"
ldap_admin_dn = "CN=Admin,OU=Users,DC=domain,DC=com"
ldap_users_ou_dn = "OU=Users,DC=domain,DC=com"
conn = ldap.initialize('ldap://' + ldap_hostname)
conn.protocol_version = 3
conn.set_option(ldap.OPT_REFERRALS, 0)
conn.set_option(ldap.OPT_X_TLS_NEWCTX, 0)
conn.simple_bind_s(ldap_admin_dn, ldap_admin_pw)
print('Successfully authenticated against LDAP server.')
print('Attempting to create user...')
attrs = {
'objectClass': [
'top'.encode('utf-8'),
'person'.encode('utf-8'),
'organizationalPerson'.encode('utf-8'),
'user'.encode('utf-8')
],
'cn': "Random Guy".encode("utf-8"),
'userPrincipalName': "randomguy@domain.com".encode("utf-8"),
'displayName': "Random Guy".encode("utf-8"),
'givenName': "Random".encode("utf-8"),
'sn': "Guy".encode("utf-8"),
'sAMAccountName': "randomguy".encode("utf-8"),
'mail': "random.guy@domain.com".encode("utf-8"),
'userAccountControl': "514".encode("utf-8")
}
# Set up user dn
user_cn = "Random Guy"
user_dn = "CN={},{}".format(user_cn, ldap_users_ou_dn)
# Create user
attrs_ldif = modlist.addModlist(attrs)
conn.add_s(user_dn, attrs_ldif)
print('Successfully created user with DN as {}'.format(user_dn))
# Wait a few seconds for AD to sync up
# I've noticed that if you attempt to create
# The password immediately after creating the user
# You might get a "user does not exist"
# Probably because it takes a few seconds
# For the Domain Controllers to sync up
# The new user you created
print('Waiting for user to be synchronized across domain controllers...')
time.sleep(10)
# Set new password
# I am in an AWS environment
# Therefore I am using the boto3 library
# To connect to AWS Directory Service
# And set up the password for the existing user
print('Attempting to set up password for user...')
client = boto3.client('ds', region_name=base_directory_region)
client.reset_user_password(
DirectoryId=base_directory_id,
UserName="randomguy",
NewPassword="SomeLongThingHere123!"
)
print('Successfully set up password for user.')
# Set user account control
print('Activating user...')
mod_acct = [(ldap.MOD_REPLACE, 'userAccountControl', '66048'.encode('utf-8'))]
conn.modify_s(user_dn, mod_acct)
print('Successfully activated user.')