python ldap3 for domain validation and synchronization

Keywords: SQL Database pip Python

There are many intranet systems in the company. If each system has an independent login account, the company leader may have an opinion. In order to solve the problem of too many accounts, the login mode can adopt domain authentication. Here we share python's domain authentication and account synchronization through ldap3.

First download ldap3 via pip

pip install ldap3

Synchronize the information in the domain to the database and code it

from ldap3 import Server, Connection, ALL, SUBTREE, ServerPool
import MySQLdb
import re
import datetime

LDAP_SERVER_POOL = ['xx.xx.xx.xx'] #ip address of domain control server
LDAP_SERVER_PORT = 389     #port
ADMIN_DN = 'xxx@xxx.xx'    #Domain account with query authority
ADMIN_PASSWORD = 'xxxxx'    #The corresponding password
SEARCH_BASE = 'ou=Organization name,dc=xxx,dc=xx'

def connect_sql():
    db = MySQLdb.connect('localhost', 'root', 'password', 'databasename',
    charset='utf8')
    return db

def ldap_sync():
    ldap_server_pool = ServerPool(LDAP_SERVER_POOL)
    conn = Connection(ldap_server_pool, user=ADMIN_DN, password=ADMIN_PASSWORD,
            check_names=True, lazy=False, raise_exceptions=False)
    conn.open()
    conn.bind()

    res = conn.search(
            search_base = SEARCH_BASE,
            search_filter = '(objectclass=user)',#Query all users
            search_scope = SUBTREE,
            attributes = ['cn', 'sn', 'givenName', 'mail',
                'sAMAccountName'] #cn user's Chinese name, sn surname, givenName name, mail mail, sAMAccountName is account number.
            )
    db = connect_sql()
    cursor = db.cursor()
    if res:
        print('sync start')
        #print(len(conn.response))
        for entry in conn.response:
            dn = entry['dn']    #dn contains ou information dc information and so on, which can be used as authentication account when doing domain verification login.
            dict_attr = entry['attributes']
            cn = dict_attr['cn']
            sn = dict_attr['sn']
            givenName = dict_attr['givenName']
            mail = dict_attr['mail']
            sAMAccountName = dict_attr['sAMAccountName']
            # Here's the second part of the company's department name from ou information in dn
            ous = re.findall(r'OU=([^,]+),', str(dn))
            dep = ous[1]
            #print(dep)
            # Departmental id in database based on department name
            sql = 'select id from itassets_department where\
            name="{}";'.format(dep)
            cursor.execute(sql)
            data = cursor.fetchone()
            if data is None:    # This department does not exist in the database, so insert operation can be considered.
                print('department is not exist: %s' %(dep))
                continue
            dep_id = data[0]
            # user exist?
            sql = 'select id from itassets_myuser where \
                    username="{}";'.format(sAMAccountName)
            cursor.execute(sql)
            user = cursor.fetchone()
            if user:    # Update user information if the user exists, otherwise insert operation
                print('update user %s%s' % (sn, givenName))
                user_id = user[0]
                sql = 'update itassets_myuser set  \
                first_name="{}", last_name="{}", email="{}", name="{}", \
                dep_id="{}" where id="{}"'.format(givenName, sn, mail, cn,
                        dep_id, user_id)
                try:
                    cursor.execute(sql)
                    db.commit()
                except Exception as e:
                    print(e)
                    db.rollback()
            else:
                print('insert user %s' % (cn))
                # Create user information
                dt = datetime.datetime.now().strftime('%Y/%m/%d %H:%M:%S')
                #print(dt)
                sql = 'insert into itassets_myuser(password, is_superuser,\
                username, first_name, last_name, email, is_staff, is_active,\
                date_joined, name, dep_id, login_mode) values ("%s", 0, "%s","%s",\
                "%s", "%s", 1, 1, "%s", "%s", %d, 2);' % (' ', sAMAccountName,
                        givenName, sn, mail, dt, cn, int(dep_id))
                try:
                    cursor.execute(sql)
                    db.commit()
                except Exception as e:
                    print(e)
                    db.rollback()
        print('sync complete')
        #print(conn.entries)
    else:
        print('search faild')
    db.close()

if __name__ == '__main__':
    ldap_sync()

The code is very simple. The contents of the synchronization are changed according to the needs of the sql statement. But what information is provided by the AD domain, so we can go to search it.

Domain validation is understood as a few simple steps: 1. login the domain account with query privileges first; 2. query the user name of the current login operation, that is, the dn of sAMAccountName in the domain; 3. use dn and password to connect, and return the response ['description']='success'to log in successfully. The code is as follows:

ldap_server_pool = ServerPool(LDAP_SERVER_POOL)
conn = Connection(ldap_server_pool, user=ADMIN_DN, password=ADMIN_PASSWORD,
            check_names=True, lazy=False, raise_exceptions=False)
conn.open()
conn.bind()

res = conn.search(
            search_base = SEARCH_BASE,
            search_filter = '(sAMAccountName=lancy01)',
            search_scope = SUBTREE,
            )
if res:
    dn = conn.response[0]['dn']
    try:
        conn2 = Connection(ldap_server_pool, user=username, password=password,
            check_names=True, lazy=False, raise_exceptions=False)
        conn2.bind()
        if conn2.result['description'] == 'success':    # Represents successful validation
            pass
        else:
            pass
    except
        pass

Very simple, welcome to correct

Posted by monloi on Sun, 06 Oct 2019 21:40:47 -0700