I have summarized how to operate LDAP with python in three parts. When developing with multiple people, everyone needs to understand the ldap3 library and LDAP, but that takes time and effort. So I created a class so that anyone can use it if they only know that LDAP is tree-structured data.
--Can be used without being aware of LDAP --You can add rules (such as ou after dc = xxx) --Easy to understand at a glance
First of all, I will describe how to operate LDAP when using this class. When using it, it will be easier to understand if you change the class name, so by changing the Domain class to Address, Organization to Owner, and Common to Pet, you can change the hierarchy of Address-> Owner-> Pet. You can be aware that there is.
main.py
from ldap_obj.Address import Address
#Add location
address = Address('localhost', 'LdapPass', 'admin', 'sample-ldap')
address.set_item('tokyo')
address.save()
#Add people
owner = address.create_owner()
owner.set_item('sato')
owner.save()
#Pets(Marble)Add
pet_tama = owner.create_pet()
pet_tama.set_item('tama')
pet_tama.save({'sn': 'sato', 'st': 'tama', 'title': 'cat'})
#Pets(Pochi)Add
pet_pocho = owner.create_pet()
pet_pocho.set_item('pochi')
pet_pocho.save({'sn': 'sato', 'st': 'pochi', 'title': 'dog'})
#Get the value of cn from the domain layer with title as the search condition
address.set_filter('title')
print(address.get_common())
print('***********************')
#Generate Address
address_get = Address('localhost', 'LdapPass', 'admin', 'sample-ldap')
address_get.set_item('tokyo')
# Address ->Owner generation
owner_get = address_get.create_owner()
owner_get.set_item('sato')
# Address -> Owner ->Pet generation
pet_get = owner_get.create_pet()
pet_get.set_item('tama')
print(pet_get.get_common())
The LDAP class creates a class for each hierarchy.
\--
|--ldap_obj\
| |--BaseClass.py (Criteria class)
| |--CommonClass.py (class of cn)
| |--DomainClass.py (dc class)
| |--OrganizationClass.py (ou class)
|
|--main.py
The base class is basically a wrapper for ldap3. I'm not doing anything particularly complicated. The contractor generates the class required for the connection, and get_xxx () passes the object class to _read_ldap () to get the information from LDAP. This function will increase as the number of object classes increases.
BaseClass.py
from ldap3 import Server, Connection, ObjectDef, Reader
class BaseClass(object):
def __init__(self, host, passwd, user, top_domain, dn=None):
self.passwd = passwd
self.user = user
self.host = host
self.top_domain = top_domain
self.filter = None
if (dn):
self.dn = dn
else:
self.dn = 'dc=' + top_domain
self.server = Server(self.host)
self.conn = Connection(self.host, 'cn={},dc={}'.format(user, top_domain), password=passwd)
def set_filter(self, filter):
self.filter = filter
def get_domain(self):
return self._read_ldap('domain', self.filter)
def get_organizational(self):
return self._read_ldap('organizationalUnit', self.filter)
def get_common(self):
return self._read_ldap('inetOrgPerson', self.filter)
def get_domain_dict(self):
return self._read_ldap_dict('domain', self.filter)
def get_organizational_dict(self):
return self._read_ldap_dict('organizationalUnit', self.filter)
def get_common_dict(self):
return self._read_ldap_dict('inetOrgPerson', self.filter)
def _read_ldap(self, object_type, search_attr = None):
data_list = []
self.conn.bind()
obj_dn = ObjectDef(object_type, self.conn)
data_reader = Reader(self.conn, obj_dn, self.dn)
data_reader.search(search_attr)
for data in data_reader:
data_list.append(data)
data_reader.reset()
self.conn.unbind()
return data_list
def _read_ldap_dict(self, object_type, search_attr = None):
data_list = []
self.conn.bind()
obj_dn = ObjectDef(object_type, self.conn)
data_reader = Reader(self.conn, obj_dn, self.dn)
data_reader.search(search_attr)
for data in data_reader:
data_list.append(data.entry_attributes_as_dict)
data_reader.reset()
self.conn.unbind()
return data_list
Create a class that inherits the above standard class for each hierarchy.
Since the value of dc is required, the value of dc is added to the string of dn with `set_item ()`
. Use this self.dn to get information with the base class `get_xxx ()`
or add it with
save ()``. ``
create_organization ()` `` creates and returns a class for ou. In this example, we want dc = xxx, ou = yyy, so there is only a generation function for ou, but if you want dc = xxx, dc = yyy, you can create a generation function for dc in the same way.
DomainClass.py
from ldap_obj.BaseClass import BaseClass
from ldap_obj.OrganizationClass import OrganizationClass
class DomainClass(BaseClass):
def set_item(self, item):
self.dn = 'dc=' + item + ',' + self.dn
def create_organization(self):
return OrganizationClass(self.host, self.passwd, self.user, self.top_domain, self.dn)
def save(self):
self.conn.bind()
result = self.conn.add(self.dn, 'domain')
self.conn.unbind()
return result
Since the Organization class generated from the Domain class contains the path to cn in self.dn, the value of ou is added with `set_item ()`
. Use this self.dn to get information with the base class `get_xxx ()`
or add it with
save ()``. ``
create_common ()` `` creates and returns a class for cn. In this example, I want dc = xxx, ou = yyy, cn = zzzz, so there is only a generation function for cn, but if you want to have another configuration, create a generation function for it.
OrganizationClass.py
from ldap_obj.BaseClass import BaseClass
from ldap_obj.CommonClass import CommonClass
class OrganizationClass(BaseClass):
def set_item(self, item):
self.dn = 'ou=' + item + ',' + self.dn
def create_common(self):
return CommonClass(self.host, self.passwd, self.user, self.top_domain, self.dn)
def save(self):
self.conn.bind()
result = self.conn.add(self.dn, 'organizationalUnit')
self.conn.unbind()
return result
Since the Common class generated from the Organization class contains the path to ou in self.dn, the value of cn is added with `set_item ()`
. Use this self.dn to get information with the base class `get_xxx ()`
or add it with
save ()` ``. Since this example is the last in this cn, there is no generation function, but if the hierarchy is deeper, create a generation function for it.
CommonClass.py
from ldap_obj.BaseClass import BaseClass
class CommonClass(BaseClass):
def set_item(self, item):
self.dn = 'cn=' + item + ',' + self.dn
def save(self, attr_dict):
self.conn.bind()
result = self.conn.add(self.dn, 'inetOrgPerson', attr_dict)
self.conn.unbind()
return result
To use these classes, first generate a DomainClass and then enter the value of dc, then use the generated DomainClass `create_organization ()`
to create an Organization class and the value of ou. Put in. To create common, use the generated Organization class `create_common ()`
and enter the value of cn. Use the get function and additional functions in each generation class to operate LDAP.
main.py
from ldap_obj.DomainClass import DomainClass
domain = DomainClass('localhost', 'LdapPass', 'admin', 'sample-ldap')
domain.set_item('sample-component')
domain_item_list = domain.get_domain()
for domain_item in domain_item_list:
print(domain_item)
print("=====================")
domain.set_filter('st')
domain_item_list = domain.get_common()
for domain_item in domain_item_list:
print(domain_item)
print("=====================")
organization = domain.create_organization()
organization.set_item('sample-unit')
organization_list = organization.get_organizational()
for organization_item in organization_list:
print(organization_item)
print("=====================")
common = organization.create_common()
common.set_item('sample-name')
common_list = common.get_common()
for common_item in common_list:
print(common_item)
print("***********************************")
new_domain = DomainClass('localhost', 'LdapPass', 'admin', 'sample-ldap')
new_domain.set_item('new-component')
print(new_domain.save())
print("=====================")
new_organization = new_domain.create_organization()
new_organization.set_item('new-organization')
print(new_organization.save())
print("=====================")
new_common = new_organization.create_common()
new_common.set_item('new-common')
print(new_common.save({'st':'new-st', 'sn': 'new-sn'}))
print("=====================")
new_common_list = new_common.get_common()
for common_item in new_common_list:
print(common_item)
I tried to create a class that can be operated by eliminating LDAP elements as much as possible. If you know the library of ldap3, the operation via the class seems to be troublesome, but when you actually look at the source, it becomes easier to understand what you are doing at a glance. This time I added get and add functions, but I think that delete, move and update should add a function that uses ldap3 to the base class. If it is easy to understand so far, I think that there will be no hesitation in using it as a candidate for data storage.
Recommended Posts