I have a Windows 2012 R2 server and a LDAP server on it. I wrote a python script to modify the password of user (the user, who isn't admin, want to modify is own password. I have an other function which modify the password when you're admin, but I don't want to set a password, but modify it). This is a sample of my code :
ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, ldap.OPT_X_TLS_NEVER)
ld = ldap.initialize('ldaps://XXX:636')
ld.simple_bind_s('XXXXXXXX#ad2012.local', 'ZZZZZ')
new = {'unicodePwd':[str('"YYYYY"').decode('utf8').encode('utf-16-le')]}
old = {'unicodePwd':[str('"ZZZZZ"').decode('utf8').encode('utf-16-le')]}
ldif = modlist.modifyModlist(old, new)
ld.modify_s('A DN',ldif)
But when I run it, I have an error (on the last line):
{'info': '00000056: AtrErr: DSID-03191083, #1:\n\t0: 00000056: DSID-03191083, problem 1005 (CONSTRAINT_ATT_TYPE), data 0, Att 9005a (unicodePwd)\n', 'desc': 'Constraint violation'}
I checked the error :
"The specified network password is not correct."
But, I use the same password to connect to user to change it.
I tried with(out) double quote, with(out) utf-8, enter a real bad old password... but nothing change, I always have the same error
If someone could help me, thanks in advance.
I achieved to change the password, here is the code :
#!/usr/bin/env python
#coding:utf-8
import ldap
import ldap.modlist as modlist
ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, ldap.OPT_X_TLS_NEVER)
ld = ldap.initialize('ldaps://XXX:636')
ld.simple_bind_s('XXX#ad2012.local', 'XXX')
newpassword = 'YYY'
oldpassword = 'ZZZ'
newpassword = unicode('\"' + newpassword + '\"').encode('utf-16-le')
oldpassword = unicode('\"' + oldpassword + '\"').encode('utf-16-le')
pass_mod = [(ldap.MOD_DELETE, 'unicodePwd', [oldpassword]), (ldap.MOD_ADD, 'unicodePwd', [newpassword])]
result = ld.modify_s('A DN', pass_mod)
I hope it will help someone ! :D
Related
I'm on the very last section of my password changer, and for some reason it just won't change the password. It's connecting to the AD server fine (checked event logs), there are no errors when trying it, but for some reason the password won't actually change.
Here's the connection code:
server= Server("DCNAME", port = 636, use_ssl = True)
connection= Connection(server, user='DOMAIN\\USER', password='PASSWORD', authentication=NTLM , auto_bind=True)
And here's the password changing code:
dn = "cn = {0}, ou= Users, dc=DC, dc=local".format(user_name.get())
connection.extend.microsoft.modify_password(dn, new_password=user_password.get())
All together should work like this:
User inputs email --> Sent otp --> Put in username (stored in user_name entry in tkinter) --> Enter password sent to their email (stored in user_password entry in tkinter) --> change password
Does anyone know why it won't change the password in AD?
Thanks in advance!
EDIT: Just added the ssl encryption when connecting to the server, but still not changing password
EDIT2: Made it print the connection results and get this back:
{'result': 32, 'description': 'noSuchObject', 'dn': 'OU=Users,DC=DC,DC=local', 'message': "0000208D: NameErr: DSID-0310020A, problem 2001 (NO_OBJECT), data 0, best match of:\n\t'OU=Users,DC=DC,DC=local'\n\x00", 'referrals': None, 'type': 'modifyResponse'}
Am I right in saying it's completely ignoring the CN?
Have you tried without the blanks after the equal signs in the dn?
.
So, I am trying to run a search with ldap, and trying to check if I am able to initialize it first. However, I keep getting the error {'desc': 'No such object'} I even tried wrong credentials but I don't even get to that error message. If someone could shed light on this, it'd be really helpful. Thanks in advance!
#!/usr/bin/python
import os, os.path
import subprocess as sp
import ldap
l = ldap.initialize('ldap://ldap.domain.com')
username = "uid=%s,ou=People,dc=domain,dc=com"
password = "password"
try:
l.protocol_version = ldap.VERSION3
l.simple_bind_s(username, password)
valid = True
except Exception, error:
print error
except ldap.INVALID_CREDENTIALS:
print "Your username or password is incorrect."
sys.exit(0)
I was getting the same error.
A quick and dirty fix to successfully bind is to change the username variable:
username = "user#domain.com"
the problem with your variable is that the %s is a string formatting syntax (which it borrows from C).
the proper use of that variable would look something like:
username = "uid=%s,ou=People,dc=domain,dc=com" %('insert-username-here')
I can't seem to change a users password using the ldap3 python module against an OpenLDAP server. A similar question has been asked before but that's specific to Active Directory.
What I've tried:
from ldap3.extend.standard.modifyPassword import ModifyPassword
from ldap3.utils.hashed import hashed
password = hashed(HASHED_SALTED_SHA, password)
# or..
password = '{SASL}theuser#domain.com'
modify = ModifyPassword(
connection, user.entry_get_dn(), new_password=password)
resp = modify.send()
print(modify.result)
{'referrals': None, 'result': 0, 'description': 'success', 'type': 'extendedResp', 'message': '', 'responseName': None, 'new_password': None, 'dn': '', 'responseValue': None}
The description says success, but the password isn't actually changed.
I've also tried to send a modify replace message:
def modify_user_password(self, user, password):
dn = user.entry_get_dn()
hashed_password = hashed(HASHED_SALTED_SHA, 'MyStupidPassword')
changes = {
'userPassword': [(MODIFY_REPLACE, [hashed_password])]
}
logger.debug('dn: ' + dn)
logger.debug('changes: ' + str(changes))
success = self.engage_conn.modify(dn, changes=changes)
if success:
logger.debug('Changed password for: %s', dn)
print(self.engage_conn.result)
else:
logger.warn('Unable to change password for %s', dn)
logger.debug(str(self.engage_conn.result))
raise ValueError('stop')
The connection is not an SSL connection. The answer to the AD question requires that the connection be over SSL. Is this also a requirement for OpenLDAP?
Edit:
After changing the dn to user.entry_get_dn() the code seemed to work about 90% of the time. After running these tests again today it appears that it now works consistently. I'm going to chalk this up to not viewing fresh data in my directory browser.
Changing the password seems to work as described in the docs and shown in the edit of my question above. For future reference, this code seems to work:
from ldap3 import (
HASHED_SALTED_SHA, MODIFY_REPLACE
)
from ldap3.utils.hashed import hashed
def modify_user_password(self, user, password):
dn = user.entry_get_dn()
hashed_password = hashed(HASHED_SALTED_SHA, password)
changes = {
'userPassword': [(MODIFY_REPLACE, [hashed_password])]
}
success = self.connection.modify(dn, changes=changes)
if not success:
print('Unable to change password for %s' % dn)
print(self.connection.result)
raise ValueError('Unable to change password')
To clarify a few things:
This is connecting to an OpenLDAP server (with multiple databases)
There is NO SSL here. We plan on implementing SSL but this works without it.
I am trying to make a Python script that will open an LDAP connection to a server running AD, take a search entry (in this case a name), search for that entry and change that users password to a randomly generated password (as well as set the option to change password on logon) and then send them an automated secure email containing the new temporary password.
So far I have been able to connect to the server, and search for a single DN which returns. The temporary password is being generated, and an email is being sent (although the password is not hashed, and the email is not secure yet). However, I cannot find any information on where to go from here.
I have found Change windows user password with python however I see that this does not play well with AD, and the other LDAP in Python documentation I have been finding seems to be outdated from 2.x and no longer works. The documentation for ldap3 (https://media.readthedocs.org/pdf/ldap3/stable/ldap3.pdf) also doesnt seem to really mention anything for it, and exhaustive Googling has been fruitless. I am new to this kind of programming having only low level or academic knowledge previously, so this has been a bit frustrating but Python is my strongest language.
----------------EDITED CODE TO CURRENT STATUS-----------------------
#Takes input for name which will be used for search criterion
zid = input("ZID: ")
zid = str(zid).lower()
print(zid)
#Binds session to the server and opens a connection
try:
server = ldap3.Server('ldap://<IP_Address>', get_info=all)
conn = ldap3.Connection(server, '%s#something.com' %zid, password = "<something>", auto_bind=True)
print("Successfully bound to server.\n")
except:
print("Unsucessful initialization of <IP_Address>")
try:
server = ldap3.Server('ldap://<IP_Address>', get_info=all)
conn = ldap3.Connection(server, '%s#something.com' %zid, password = "<something>", auto_bind=True)
print("Successfully bound to server.\n")
except:
print("Unsucessful initialization of <IP_Address>")
try:
server = ldap3.Server('ldap://<IP_Address>', get_info=all)
conn = ldap3.Connection(server, '%s#something.com', password = "<something>", auto_bind=True) %zid
print("Successfully bound to server.\n")
except:
print("Unsucessful initialization of <IP_Address>")
sys.exit(0)
#Searches and prints LDAP entries
try:
base_dn = 'DC=<something>,DC=<something>,DC=<something>,DC=<something>,DC=com'
zid_filter = '(sAMAccountName=%s)' %zid
conn.search(base_dn, zid_filter, attributes=['mail'])
#i.e. "DN: CN=<First Last>,OU=<something>, DC= <something>
user_dn = str(conn.entries)
#i.e. "CN=<First Last>"
front = user_dn.find('C')
back = user_dn.find(',')
user_cn = user_dn[front:back]
#i.e. "<First Last>"
display_name = user_cn[3:]
#i.e. "first.last#<something>.com"
raw_email = str(conn.entries)
front = raw_email.find('mail: ')
back = raw_email.find('#<something>.com')
user_email = raw_email[front + 6:back] + '#<something>.com'
except:
print("Could not search entries")
#Generates random 12 digit alpha-numeric password
try:
new_password = ''.join(random.SystemRandom().choice(string.ascii_letters + string.digits) for _ in range(12))
print(new_password)
print("New password successfully generated")
except:
print("New password could not be generated")
#Set and replace AD Password
try:
conn.extend.microsoft.modify_password(user_dn, None, new_password)
print ("Active Directory password was set successfully!")
except:
print('Error setting AD password')
sys.exit(0)
Any suggestions on how to get/set the user password and hash the password for security purposes during this whole ordeal? For the email I imagine I can force it to use HTTPS and that would be sufficient, but the connection to the server passing the new_password to I would like to secure.
ldap3 contains a specific method for changing AD password, just add the following after you generated a new password:
dn = conn.entries[0].entry_get_dn() # supposing you got back a single entry
conn.extend.microsoft.modify_password(dn, None, new_password)
This should properly encode the password and store it in AD.
This code is working with Windows 2012 R2 AD:
First, install latest ldap3:
sudo pip3 install ldap
#!/usr/bin/python3
import ldap3
SERVER='127.0.0.1'
BASEDN="DC=domain,DC=com"
USER="user_domain_login_name#domain.com"
CURREENTPWD="current_password"
NEWPWD="new_password"
SEARCHFILTER='(&(userPrincipalName='+USER+')(objectClass=person))'
USER_DN=""
USER_CN=""
ldap_server = ldap3.Server(SERVER, get_info=ldap3.ALL)
conn = ldap3.Connection(ldap_server, USER, CURREENTPWD, auto_bind=True)
conn.start_tls()
print(conn)
conn.search(search_base = BASEDN,
search_filter = SEARCHFILTER,
search_scope = ldap3.SUBTREE,
attributes = ['cn', 'givenName', 'userPrincipalName'],
paged_size = 5)
for entry in conn.response:
if entry.get("dn") and entry.get("attributes"):
if entry.get("attributes").get("userPrincipalName"):
if entry.get("attributes").get("userPrincipalName") == USER:
USER_DN=entry.get("dn")
USER_CN=entry.get("attributes").get("cn")
print("Found user:", USER_CN)
if USER_DN:
print(USER_DN)
print(ldap3.extend.microsoft.modifyPassword.ad_modify_password(conn, USER_DN, NEWPWD, CURREENTPWD, controls=None))
else:
print("User DN is missing!")
Here i'm attached the python files to create user and authenticating user in windows active Directory 2008 r2
create.py
import ldap
import ldap.modlist as modlist
name='testing3'
password='p#ssw0rd'
l = ldap.initialize('ldap://##2.168.3#.##')
l.simple_bind_s('Administrator#example.local', 'p#ssw0rd1')
dn="cn="+name+",ou=oli,dc=example,dc=local"
attrs = {}
attrs['objectclass'] = ['Top','person','organizationalPerson','user']
attrs['cn'] = name
attrs['displayName'] = name
attrs['name'] = name
attrs['givenName'] = name
attrs['mail'] = name
attrs['ou'] = "Users"
#attrs['pwdLastSet'] = "-1"
attrs['userPrincipalName'] = name + "#naanal.local
attrs['userAccountControl'] = '514'
attrs['sAMAccountName'] = name
attrs['userPassword'] = password
ldif = modlist.addModlist(attrs)
l.add_s(dn,ldif)
l.unbind_s()
Using this program create user in the Active directory but unable to create the enabled user account. i can user the userAccountcontrol=''512` but it not working .userAccountcontrol='514' its working but user account was disabled.
using ldap modify change the userAccountcontrol getting error "when i'm try to enable the user account getting error "{'info': '0000052D: SvcErr: DSID-031A120C, problem 5003 (WILL_NOT_PERFORM), data 0\n', 'desc': 'Server is unwilling to perform'}""
Authe.py
import ldap
username='shan'
password='p#ssw0rd'
LDAP_SERVER = 'ldap://###.##.##.##'
LDAP_USERNAME = '%s#example.local' % username
LDAP_PASSWORD = password
base_dn = 'DC=example,DC=example'
ldap_filter = 'userPrincipalName=%s#example.local' % username
attrs = ['memberOf']
try:
ldap_client = ldap.initialize(LDAP_SERVER)
ldap_client.set_option(ldap.OPT_REFERRALS,0)
ldap_client.simple_bind_s(LDAP_USERNAME, LDAP_PASSWORD)
print 'successfull'
except ldap.INVALID_CREDENTIALS:
ldap_client.unbind()
print 'Wrong username ili password'
except ldap.SERVER_DOWN:
print 'AD server not awailable'
create the user account using create.py .then enable the user account manually in the active directory.after i'm try to authenticate the created user account not detected.but manually created account detected by using authe.py file
i'm using Ubuntu 14.04 64 bit
There are two problems with your code:
Active Directory stores the password in the unicodePwd attribute and not userPassword. See this link for more details. This article also explains how the value for unicodePwd must be encoded (UTF-16)
The other problem (this is also explained in the referenced article) is that you must connect over a secure connection to Active Directory whenever you are making changes to the password attribute (including creating a user). The URL starting with ldap:// makes me believe that your connection is not secure.
I hope this helps.