LDAP query in python
I want to execute the following query in the ldap
ldapsearch -h hostname -b dc=ernet,dc=in -x "(&(uid=w2lame)(obj开发者_运维问答ectClass=posixAccount))" gidnumber
ldapsearch -h hostname -b dc=ernet,dc=in -x "(&(gidNumber=1234)(objectClass=posixGroup))" cn
And use the variables thus obtained. How can I do that?
While the accepted answer does in fact show a proper way to bind to an LDAP server I do feel it didn't answer the question holistically. Here is what I ended up implementing to grab the mail and department of a user. This somewhat blends the required attributes from the original question.
l = ldap.initialize('ldap://ldap.myserver.com:389')
binddn = "cn=myUserName,ou=GenericID,dc=my,dc=company,dc=com"
pw = "myPassword"
basedn = "ou=UserUnits,dc=my,dc=company,dc=com"
searchFilter = "(&(gidNumber=123456)(objectClass=posixAccount))"
searchAttribute = ["mail","department"]
#this will scope the entire subtree under UserUnits
searchScope = ldap.SCOPE_SUBTREE
#Bind to the server
try:
l.protocol_version = ldap.VERSION3
l.simple_bind_s(binddn, pw)
except ldap.INVALID_CREDENTIALS:
print "Your username or password is incorrect."
sys.exit(0)
except ldap.LDAPError, e:
if type(e.message) == dict and e.message.has_key('desc'):
print e.message['desc']
else:
print e
sys.exit(0)
try:
ldap_result_id = l.search(basedn, searchScope, searchFilter, searchAttribute)
result_set = []
while 1:
result_type, result_data = l.result(ldap_result_id, 0)
if (result_data == []):
break
else:
## if you are expecting multiple results you can append them
## otherwise you can just wait until the initial result and break out
if result_type == ldap.RES_SEARCH_ENTRY:
result_set.append(result_data)
print result_set
except ldap.LDAPError, e:
print e
l.unbind_s()
You probably want to use the ldap
module. Code would look something like:
import ldap
l = ldap.initialize('ldap://ldapserver')
username = "uid=%s,ou=People,dc=mydotcom,dc=com" % username
password = "my password"
try:
l.protocol_version = ldap.VERSION3
l.simple_bind_s(username, password)
valid = True
except Exception, error:
print error
Here's an example generator for python-ldap.
The ldap_server
is the object you get from ldap.initialize(). You will probably need to bind before calling this function, too, depending on what LDAP server you are using and what you are trying to query for. The base_dn
and filter_
are similar to what you've got in your command line version. The limit
is the maximum number of records returned.
def _ldap_list(ldap_server, base_dn, filter_, limit=0):
""" Generator: get a list of search results from LDAP asynchronously. """
ldap_attributes = ["*"] # List of attributes that you want to fetch.
result_id = ldap_server.search(base_dn, ldap.SCOPE_SUBTREE, filter_, ldap_attributes)
records = 0
while 1:
records += 1
if limit != 0 and records > limit:
break
try:
result_type, result_data = ldap_server.result(result_id, 0)
except ldap.NO_SUCH_OBJECT:
raise DirectoryError("Distinguished name (%s) does not exist." % base_dn)
if result_type == ldap.RES_SEARCH_ENTRY:
dn = result_data[0][0]
data = result_data[0][1]
yield dn, data
else:
break
Please keep in mind that interpolating user-provided values into your LDAP query is dangerous! It's a form of injection that allows a malicious user to change the meaning of the query. See: http://www.python-ldap.org/doc/html/ldap-filter.html
I cobbled this together this morning while skimming through the documentation of the ldap
module. It can fulfil the requirements of the OP changing the filter and the other settings to his liking.
The documentation of the ldap
module is pretty good if you understand the context (that's what took me a while). And the module is surprinsingly easy to use. We have a similar script written in bash using ldapserach
that is at least 3 or 4 times longer and more complex to read.
This code accepts a partial search string (email, name, uid or part of it) and returns the results in LDIF format. The idea is to make it very simple to use for a very specific task and if possible without using flags so that my less skilled co-workers can find the relevant info quickly.
Note that this is written for an LDAP server that runs on a machine that is not accessible from outside our internal network and which is secured with 2FA authentication. It can, thus, safely accept anonymous queries. But adding user and password should be trivial.
#! /usr/bin/python3
### usearch
### searches in the LDAP database for part of a name, uid or email and returns mail, uid, and full name
import ldap
import argparse
import sys
import ldif
l = ldap.initialize('ldaps://your.fancy.server.url', bytes_mode=False)
basedn = "dc=foo,dc=bar,dc=baz"
## ARGPARSE stuff!!!
parser=argparse.ArgumentParser(
description ='searches the LDAP server',
usage='usearch PARTIAL_MATCH (email, name, username)',
formatter_class = argparse.ArgumentDefaultsHelpFormatter)
parser.add_argument('istr', help='searches stuffz')
parser.print_help
args = parser.parse_args(None if sys.argv[1:] else ['-h'])
str1 = args.istr
sfilter = "(|(sn=*{}*)(mail=*{}*)(uid=*{}*))".format(str1,str1,str1)
attributes = ["mail","uid","cn"]
scope = ldap.SCOPE_SUBTREE
r = l.search_s(basedn,scope,sfilter,attributes)
ldif_writer=ldif.LDIFWriter(sys.stdout)
for dn, entry in r:
ldif_writer.unparse(dn,entry)
And as I was at it, here a version with the ldap3 module. The argparse
part is copy-pasted. This time the output is "human readable", instead of LDIF:
#! /usr/bin/python3
## usearch3
## LDAP3 version
import ldap3
import argparse
import sys
server = ldap3.Server('ldaps://foo.bar.baz')
conn = ldap3.Connection(server)
conn.bind()
basedn = 'dc=foobar,dc=dorq,dc=baz'
attribs = ['mail','uid','cn']
parser=argparse.ArgumentParser(
description ='searches the LDAP server and returns user, full name and email. Accepts any partial entry',
usage='usearch3 PARTIAL_MATCH (email, name, username)',
formatter_class = argparse.ArgumentDefaultsHelpFormatter)
parser.add_argument('istr', help='searches stuffz')
parser.print_help
args = parser.parse_args(None if sys.argv[1:] else ['-h'])
str1 = args.istr
sfilter = "(|(sn=*{}*)(mail=*{}*)(uid=*{}*))".format(str1,str1,str1)
conn.search(basedn,sfilter)
conn.search(basedn,sfilter,attributes = attribs)
leng = len(conn.entries)
for i in range(leng):
user = conn.entries[i].uid
fullname = conn.entries[i].cn
email = conn.entries[i].mail
print("user:\t{}\nname:\t{}\nemail:\t{}\n\n".format(user,fullname,email))
you can use the commands module, and the getoutput to parse the result of the ldap query:
from commands import getoutput
result = getoutput('ldapsearch -h hostname -b dc=ernet,dc=in -x "(&(uid=w2lame)(objectClass=posixAccount))"')
print result
you have to have ldapsearch binary installed in your system.
精彩评论