Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ldap3 user created is "disabled" and "password not set" by default #460

Closed
asd78in opened this issue Dec 28, 2017 · 9 comments
Closed

ldap3 user created is "disabled" and "password not set" by default #460

asd78in opened this issue Dec 28, 2017 · 9 comments

Comments

@asd78in
Copy link

asd78in commented Dec 28, 2017

I am am trying to create a script to create and disable users in AD using your ldap3 module.

When I create a user using the following code,

from ldap3  import *
import ssl
tls_configuration = Tls(validate=ssl.CERT_REQUIRED, 
version=ssl.PROTOCOL_TLSv1)
tls_configuration.validate = ssl.CERT_NONE
s = Server('xxxxxx:389',use_ssl=False, get_info=ALL)
c=Connection(s,user='x\Administrator',password='x',
check_names=True,lazy=False,
raise_exceptions=False)
c.open()
c.bind()
c.add('cn=SubhasisB,ou=gssd users,dc=adldap,dc=com','User')

the users created using the above command are showing disabled with the attribute userAccountControl set to 546 with no password. When I try to modify the attribute to 512 to enable the user I get the error

c.modify('cn=SubhasisB,ou=gssd users,dc=adldap,dc=com', {'unicodePwd': [(MODIFY_REPLACE, ['xxxxx'])]}) 



False 



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

getting the same error for

c.modify('cn=SubhasisB,ou=gssd users,dc=adldap,dc=com', {'userAccountControl': [(MODIFY_REPLACE, ['512'])]})
However if I manually create a user in the Windows server I am able to disable it by setting the userAccountControl to 514 using ldap3.

Please help me create a user who is enabled and password set .

@cannatag
Copy link
Owner

cannatag commented Jan 1, 2018

Hi, have you tried using a secure TLS connection on port 636? I know that AD usually perform such operation only on a secure transport. You must have the server properly configurated then you can just define the Server object with use_ssl=True.

@Edlopushansky
Copy link

Hello cannatag, Thank you for creating this module.

I have the same issue as asd78in had or still has.
my server is setup for use_ssl=True

self.server = Server(self.host, use_ssl=True, get_info=ALL)
Connection(self.server, self.username, self.password,auto_bind=True)

but all users I have created are all have userAccountControl set to 0x222 instead of 0x220. Is any another attributes I should set ?

@lrhazi
Copy link

lrhazi commented Aug 29, 2018

I see the same behavior.. anyone knows how to enable an account using ldap3 module?

@Edlopushansky
Copy link

I also could not set to 0x220 , so I ended up creating as ['66080']

@ccsalway
Copy link
Contributor

ccsalway commented Aug 30, 2018

domain = 'directory.local'
loginun = 'Admin'
loginpw = 'zxiGZDHmaKQjx$NC'

username = 'john.smith'
useremail = 'john@smith.com'
userpswd = 'AbcDef$$1234567'
userdn = 'CN=john.smith,OU=Users,DC=directory,DC=local'

# connect - specifying port 636 is only for reference as it's inferred
s = Server('ldaps://<server_addr>:636', connect_timeout=5)
c = Connection(s, user='{}\{}'.format(domain, loginun), password=loginpw, authentication=NTLM)

if not c.bind():
    exit(c.result)

# create user
c.add(userdn, attributes={
   'objectClass': ['organizationalPerson', 'person', 'top', 'user'],
   'sAMAccountName': username,
   'userPrincipalName': "{}@{}".format(username, domain),
   'displayName': username,
   'mail': useremail  # optional
})

# set password - must be done before enabling user
# you must connect with SSL to set the password 
c.extend.microsoft.modify_password(userdn, userpswd)

# enable user (after password set)
c.modify(userdn, {'userAccountControl': [('MODIFY_REPLACE', 512)]})

# disable user
c.modify(userdn, {'userAccountControl': [('MODIFY_REPLACE', 2)]})

You can check out the userAccountControl flags (512, 2) at [1]

[1] https://support.microsoft.com/en-gb/help/305144/how-to-use-the-useraccountcontrol-flags-to-manipulate-user-account-pro

@GitHubGeek
Copy link

Just spent an afternoon getting it to work, I went through these steps

  1. Modifying userAccountControl gave the WILL_NOT_PERFORM error
  2. Tried other ways and still no go (setting it during add())
  3. Google said the userAccountControl attribute can only be changed after password is reset (See Note)
  4. Hey but I was already doing that?
  5. Turned out the ad_modify_password() calls were silently failing (returned False, which my code didn't check)
  6. Enabled raise_exceptions for the Connection object and saw that modifying unicodePwd gave the WILL_NOT_PERFORM error
  7. A bit more Googling
  8. Followed these steps to enable SSL / LDAPS
  9. PROFIT!!!

Note: Make sure the new password conforms to the AD server's password policy, or it'd be rejected

Perhaps, the ldap3 docs could mention SSL is required to modify passwords on AD?

@ccsalway
Copy link
Contributor

ccsalway commented Nov 1, 2018

@GitHubGeek if you followed my example above, you would have succeeded faster :)

@kcardona86
Copy link

kcardona86 commented Mar 9, 2019

Hi, how can I create a new user in a sub-container, say, Users > User OU 1, tried using modify_dn to move the user after creating in the main OU

conn.modify_dn('cn={},ou={}'.format(user_name, user_ou), 'cn={}'.format(user_name), new_superior='ou={},ou={},dc=company,dc=com'.format(user_sub_ou, user_ou))

conn.result shows {'result': 1, 'description': 'operationsError', 'dn': '', 'message': '000020D6: SvcErr: DSID-031007E5, problem 5012 (DIR_ERROR), data 0\n\x00', 'referrals': None, 'type': 'modDNResponse'}

@yarin-zhang
Copy link

domain = 'directory.local'
loginun = 'Admin'
loginpw = 'zxiGZDHmaKQjx$NC'

username = 'john.smith'
useremail = 'john@smith.com'
userpswd = 'AbcDef$$1234567'
userdn = 'CN=john.smith,OU=Users,DC=directory,DC=local'

# connect - specifying port 636 is only for reference as it's inferred
s = Server('ldaps://<server_addr>:636', connect_timeout=5)
c = Connection(s, user='{}\{}'.format(domain, loginun), password=loginpw, authentication=NTLM)

if not c.bind():
    exit(c.result)

# create user
c.add(userdn, attributes={
   'objectClass': ['organizationalPerson', 'person', 'top', 'user'],
   'sAMAccountName': username,
   'userPrincipalName': "{}@{}".format(username, domain),
   'displayName': username,
   'mail': useremail  # optional
})

# set password - must be done before enabling user
# you must connect with SSL to set the password 
c.extend.microsoft.modify_password(userdn, userpswd)

# enable user (after password set)
c.modify(userdn, {'userAccountControl': [('MODIFY_REPLACE', 512)]})

# disable user
c.modify(userdn, {'userAccountControl': [('MODIFY_REPLACE', 2)]})

You can check out the userAccountControl flags (512, 2) at [1]

[1] https://support.microsoft.com/en-gb/help/305144/how-to-use-the-useraccountcontrol-flags-to-manipulate-user-account-pro

I encountered a similar issue, and ldap3 doesn't provide any error or prompt in this case. In the end, I was able to solve the problem based on this piece of code. Many thanks to @ccsalway.

I'll try to summarize in order to provide assistance to others facing similar problems.

Apparently, Microsoft AD domain has several prerequisites in place to prevent the creation of insecure accounts, although these prerequisites are very subtle and not easily noticeable.

  1. An SSL connection is required to set a password. This can be resolved by configuring the certificate in IIS (since I'm using an intranet machine, I opted for a self-signed certificate).
  2. An account needs to be created using client.add before assigning user permissions using client.modify.
  3. A password must be set for the account before it can be set to "enabled" status.
  4. Additionally, the default port for LDAP SSL is 636 instead of 389, and the format for the user should be domain\loginusername.

In conclusion, as someone who is not particularly familiar with LDAP, having this code example has been extremely helpful. 👍🏻

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

8 participants