active directory - Use Python script to manage remote LDAP server -
background: working on api centralize user creation , management multiple resources(e.g. google apps, dropbox, etc...). on linux vm, developed api , web interface allows me(and co-admins) authenticate , manage user accounts these services. next thing need integrate our active directory hosted on remote windows server 2008.
i have been trying use python-ldap connect , retrieve/modify information have had issues dir_error operations errors(when trying query users) , naming_violation errors(when trying add users).
*code based on http://www.grotan.com/ldap/python-ldap-samples.html, stackoverflow questions, , python-ldap documentation binding code believe works:
import ldap try: l = ldap.open("serverip") l.protocol_version = ldap.version3 username = "myusername@adtest.local" password = "secret" result = l.simple_bind(username, password) print result except ldap.ldaperror, e: print e
which prints: (97, [], 1, [])
query users script: (tried without bind suggested article, received "in order perform operation successful bind must completed on connection.")
import ldap try: l = ldap.open("serverip", port=389) l.protocol_version = ldap.version3 username = "myusername@adtest.local" password = "secret" result = l.simple_bind(username, password) print result except ldap.ldaperror, e: print e # handle error basedn = "ou=users, o=adtest.local" searchscope = ldap.scope_subtree retrieveattributes = none searchfilter = "cn=*myusername*" try: ldap_result_id = l.search(basedn, searchscope, searchfilter, retrieveattributes) result_set = [] while 1: result_type, result_data = l.result(ldap_result_id, 0) if (result_data == []): break else: if result_type == ldap.res_search_entry: result_set.append(result_data) print result_set except ldap.ldaperror, e: print e
which results in following: (97, [], 1, []) {'info': '000020d6: svcerr: dsid-031007db, problem 5012 (dir_error), data 0\n','desc':'operations error'}
add user script:(using ldaps)
import ldap import ldap.modlist modlist # open connection l = ldap.initialize("ldaps://serverip:636/") # bind/authenticate user apropriate rights add objects l.simple_bind_s("myusername@adtest.local","secret") # dn of our new entry/object dn="cn=test,dc=adtest,dc=local" # dict build "body" of object attrs = {} attrs['objectclass'] = ['top','organizationalrole','simplesecurityobject'] attrs['cn'] = 'test' attrs['userpassword'] = 'adifferentsecret' attrs['description'] = 'test user' # convert our dict nice syntax add-function using modlist-module ldif = modlist.addmodlist(attrs) # add-operation ldapserver l.add_s(dn,ldif) # disconnect , free resources when done l.unbind_s()
which results in: ldap.server_down: {'info': 'a tls packet unexpected length received.','desc': "can't contact ldap server"}
*this made me think port might problem, changed initialize line l = ldap.initialize("ldap://serverip:389/")
similar other 2 scripts.
now get: ldap.naming_violation: {'info': "00002099: nameerr: dsid-0305109c, problem 2005 (naming_violation), data 0, best match of:\n\t'dc=adtest, dc=local'\n", 'desc': 'naming violation'}
additionally, have messed around adding ou , uid attrs no change in error.
what doing wrong or try differently? thank help/suggestions!
edit: checked server, , port 636 correctly set allow secure ldap traffic, don't know why giving me different errors normal ldap. edit2: tried changing following line in add script dn="cn=test,dc=adtest.local"
and new output(stack trace) have is(i added print statement in show bind taking place before error):
(97, [], 1, [])
traceback (most recent call last):
file "test2.py", line 21, in <module>
l.add_s(dn,ldif)
file "/usr/local/lib/python2.7/dist-packages/ldap/ldapobject.py", line 202, in add_s
return self.result(msgid,all=1,timeout=self.timeout)
file "/usr/local/lib/python2.7/dist-packages/ldap/ldapobject.py", line 465, in result
resp_type, resp_data, resp_msgid = self.result2(msgid,all,timeout)
file "/usr/local/lib/python2.7/dist-packages/ldap/ldapobject.py", line 469, in result2
resp_type, resp_data, resp_msgid, resp_ctrls = self.result3(msgid,all,timeout)
file "/usr/local/lib/python2.7/dist-packages/ldap/ldapobject.py", line 476, in result3
resp_ctrl_classes=resp_ctrl_classes
file "/usr/local/lib/python2.7/dist-packages/ldap/ldapobject.py", line 483, in result4
ldap_result = self._ldap_call(self._l.result4,msgid,all,timeout,add_ctrls,add_intermediates,add_extop)
file "/usr/local/lib/python2.7/dist-packages/ldap/ldapobject.py", line 106, in _ldap_call
result = func(*args,**kwargs)
ldap.referral: {'info': 'referral:\nldap://adtest.local/cn=test,dc=adtest.local', 'desc': 'referral'}
working query search!
credit to:
http://www.linuxjournal.com/article/6988?page=0,0
import ldap def main(): keyword = "user_query" try: l = ldap.open(serverip) l.simple_bind_s("myusername@adtest.local", "password") print "successfully bound server.\n" print "searching..\n" my_search(l,keyword) except ldap.ldaperror, e: print "couldn't connect. %s " % e def my_search(l, keyword): #base dn(distinguised name) of entry search should start base = "cn=users,dc=adtest,dc=local" #scope has 3 options, subtree searches sub-folder/directories scope = ldap.scope_subtree #filter consists of cn(common name) , keyword. #putting asterisks around our keyword match containing string f = "cn=" + "*" + keyword + "*" #determines attributes return. returns if set "none" retrieve_attributes = none count = 0 result_set = [] timeout = 0 result = l.search_s(base, scope, f, retrieve_attributes) print result[0][1].keys() try: result_id = l.search(base, scope, f, retrieve_attributes) while 1: result_type, result_data = l.result(result_id, timeout) if(result_data == []): break else: if result_type == ldap.res_search_entry: result_set.append(result_data) if len(result_set) == 0: print "no results" return in range(len(result_set)): entry in result_set[i]: try: name = entry[1]['cn'][0] count += 1 print str(count)+" "+name except: pass except ldap.ldaperror, e: print e if __name__=='__main__': main()
i fixed 1 mistake in code, still couldn't set properties because ldap uses plain-text , not allow private info sent without secure connection. in order add/modify user password info , useraccountcontrol flags(to enable user), switched ldaps using port 636, enabled on server adding active directory certificate services(*requires restart server).
additionally need include 'ldap.set_option(ldap.opt_x_tls_require_cert,0)' line before initialize.
working add user
credit to:
how set lockouttime , password of user of active directory
import ldap import ldap.modlist modlist ldap.set_option(ldap.opt_x_tls_require_cert,0) l = ldap.initialize("ldaps://10.99.0.214:636") l.set_option(ldap.opt_protocol_version, 3) l.set_option(ldap.opt_network_timeout, 10.0) t = l.simple_bind_s("myusername@adtest.local","password") dn="cn=testuser,cn=users,dc=adtest,dc=local" #make unicode password set user unicode_pass = unicode('\"'+"userpwd"+'\"', 'iso-8859-1') password_value = unicode_pass.encode('utf-16-le') #what set users, can find more looking through user's properties on dc. attrs = {} attrs['cn'] = 'testuser' attrs['displayname'] = 'testuser' attrs['givenname'] = 'test' attrs['mail'] = 'testuser@company.com' attrs['name'] = 'test user' attrs['objectclass'] = ['top','person','organizationalperson','user'] attrs['samaccountname'] = 'testuser' attrs['sn'] = 'user' attrs['unicodepwd'] = password_value attrs['userprincipalname'] = 'testuser@adtest.local' ldif = modlist.addmodlist(attrs) l.add_s(dn,ldif) #now user created , has password(needs meet ad requirements), can enabled #for full useraccountcontrol flag list: #http://support.microsoft.com/en-us/kb/305144 mod_acct = [(ldap.mod_replace, 'useraccountcontrol', '66048')] try: l.modify_s(dn, mod_acct) except ldap.ldaperror, e: print e l.unbind_s()
Comments
Post a Comment