Search code examples
pythonldap3

Create AD user with python ldap3 not working correctly


Here's my code:

'''

def create_ad_user(samaccountname, email, ou, nome='Test'):

print(samaccountname, email, ou)

server = Server('ldap://<my ldap server>', get_info=ALL, use_ssl=True)
conn = Connection(server, user='<my admin user>', password='<my admin 
password>',auto_bind=True)

password = 'Password123!'

# Crea l'utente
user_dn = f"CN={nome},{ou}"
attributes = {
    "objectClass": ["top", "person", "organizationalPerson", "user"],
    "sAMAccountName": samaccountname,
    "givenName": 'Test',
    "sn": 'Test',
    "mail": email,
    "description": 'Test creazione utenti con ldap3',
    "userPrincipalName": f"{samaccountname}@ssn.local",
    "unicodePwd": f'"{password}"'.encode("utf-16-le"),
    "userAccountControl": 512,  # Abilita l'account
}

success = conn.add(user_dn, attributes=attributes)
if not success:
    print(f"Errore nella creazione dell'utente: {conn.result}")
    return

# Modifica l'attributo pwdLastSet per forzare il cambio della password al prossimo accesso
conn.modify(user_dn, {"pwdLastSet": [(MODIFY_REPLACE, [0])]})

print(f"Utente {samaccountname} creato con successo in {ou}.")

'''

If i remove 'unicodePwd' and 'userAccountControl' everything works fine while if I add them the following exception is generated (output of conn.result):

{'result': 53, 'description': 'unwillingToPerform', 'dn': '', 'message': '0000001F: SvcErr: DSID-031A12E8, problem 5003 (WILL_NOT_PERFORM) , data 0\n\x00', 'referrals': None, 'type': 'addResponse'}

what am I doing wrong?


Solution

  • userAccountControl and unicodePwd are refused by AD when you're adding a new user. To overcome this, you need to:

    1. Add the user account without those attributes. It will be locked/disabled after success.

    2. Unlock the account:

      conn.extend.microsoft.unlock_account(user=user_dn)

    3. Set password:

      conn.extend.microsoft.modify_password(user=user_dn, new_password=password, old_password=None)

    4. Set userAccountControl and pwdLastSet:

      conn.modify(user_dn, changes={"userAccountControl": (MODIFY_REPLACE, [512]), "pwdLastSet": [(MODIFY_REPLACE, [0])]})