A class for PYTHON that can be operated without being aware of LDAP

Introduction

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.

environment

merit

--Can be used without being aware of LDAP --You can add rules (such as ou after dc = xxx) --Easy to understand at a glance

Example using this class

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())

LDAP class

The LDAP class creates a class for each hierarchy.

Directory structure

\--
  |--ldap_obj\
  |    |--BaseClass.py (Criteria class)
  |    |--CommonClass.py (class of cn)
  |    |--DomainClass.py (dc class)
  |    |--OrganizationClass.py (ou class)
  |
  |--main.py

Criteria class

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

Extension class

Create a class that inherits the above standard class for each hierarchy.

Domain class

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

Organization class

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

Common class

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

Caller main function

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)

in conclusion

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

A class for PYTHON that can be operated without being aware of LDAP
I created a template for a Python project that can be used universally
Can be used with AtCoder! A collection of techniques for drawing short code in Python!
[Python] A program to find the number of apples and oranges that can be harvested
Investigation of DC power supplies that can be controlled by Python
Created a library for python that can easily handle morpheme division
From a book that programmers can learn ... (Python): Review of arrays
I made a shuffle that can be reset (reverted) with Python
[python] I made a class that can write a file tree quickly
Understand the probabilities and statistics that can be used for progress management with a python program
[Python] A program that finds the maximum number of toys that can be purchased with your money
I wrote a tri-tree that can be used for high-speed dictionary implementation in D language and Python.
[Python] A program that finds a pair that can be divided by a specified value
[Python] A program that calculates the number of socks to be paired
A memo when creating an environment that can be debugged with Lambda @ Edge for the time being
Mathematical optimization that can be used for free work with Python + PuLP
A summary of Python e-books that are useful for free-to-read data analysis
A python script for Mac that zips without garbled characters on Windows
Article that can be a human resource who understands and masters the mechanism of API (with Python code)
A memo for making a figure that can be posted to a journal with matplotlib
[Python] The movement of the decorator that can be understood this time ② The decorator that receives the argument
I tried to create a class that can easily serialize Json in Python
You can call the method of the class directly in Python3 without adding @staticmethod
From a book that programmers can learn (Python): Class declaration (public / private, etc.)
I want to create a priority queue that can be updated in Python (2.7)
A personal memo of Pandas related operations that can be used in practice
I made a familiar function that can be used in statistics with Python
How to install a Python library that can be used by pharmaceutical companies
A collection of resources that may be useful for creating and expanding dotfiles
Functions that can be used in for statements
[Python / Tkinter] A class that creates a scrollable Frame
Python: Prepare a serializer for the class instance:
Python: Create a class that supports unpacked assignment
Overview and useful features of scikit-learn that can also be used for deep learning
A python script that generates a sample dataset for checking the operation of a classification tree
Summary of statistical data analysis methods using Python that can be used in business
A python script that gets the number of jobs for a specified condition from indeed.com
Geographic information visualization of R and Python that can be expressed in Power BI
[Python] Introduction to web scraping | Summary of methods that can be used with webdriver
How to create a property of relations that can be prefetch_related by specific conditions
A mechanism to call a Ruby method from Python that can be done in 200 lines
Use data class for data storage of Python 3.7 or higher
[Python] A program that counts the number of valleys
I made a VM that runs OpenCV for Python
A python implementation of the Bayesian linear regression class
Python knowledge notes that can be used with AtCoder
Python that merges a lot of excel into one excel
From a book that programmers can learn ... (Python): Pointer
Not being aware of the contents of the data in python
Python: Get a list of methods for an object
[Python] A program that compares the positions of kangaroos.
How to start a simple WEB server that can execute cgi of php and python
How to set up a simple SMTP server that can be tested locally in Python
I made a data extension class for tensorflow> = 2.0 because ImageDataGenerator can no longer be used.
Format summary of formats that can be serialized with gensim
Is your dll a dll that can take advantage of multi-core?
Basic knowledge of DNS that can not be heard now
Why can Linux commands be executed without writing a PATH?
From a book that programmers can learn ... (Python): About sorting
NumPy zeros can be defined even with a size of 0
Processing of python3 that seems to be usable in paiza