python使用ldap3模块操作windows2012域

脚本

复制代码
#!/usr/bin/python3
# -*- coding: utf-8 -*-
# 注意:ldap3库如果要使用tls(安全连接),需要ad服务先安装并配置好证书服务,才能通过tls连接,否则连接测试时会报LDAPSocketOpenError('unable to open socket'
# 如果是进行账号密码修改及账户激活时,会报错:“WILL_NOT_PERFORM”


import json
from ldap3 import ALL_ATTRIBUTES,ALL
from ldap3 import Connection, NTLM, Server,ServerPool,SUBTREE
from ldap3 import MODIFY_REPLACE

server1 = Server("172.18.188.7", port=636, use_ssl=True, get_info=ALL, connect_timeout=5)

LDAP_SERVER_POOL = [server1]
SERVER_USER = 'southpark\\administrator'
SERVER_PASSWORD = "xxxxxxx"


class AD(object):
    '''    
    AD用户操作
    '''

    def __init__(self):
        '''初始化'''
        self.conn = Connection( # 配置服务器连接参数
            server=LDAP_SERVER_POOL,
            auto_bind=True,
            authentication=NTLM,  # 连接Windows AD需要配置此项
            read_only=False,  # 禁止修改数据:True
            user=SERVER_USER,  # 管理员账户
            password=SERVER_PASSWORD,
        )
        self.active_base_dn = 'ou=south,dc=southpark,dc=com'  # 正式员工账户所在OU
        self.search_filter = '(objectclass=user)'  # 只获取【用户】对象
        self.ou_search_filter = '(objectclass=organizationalUnit)'  # 只获取【OU】对象

    def users_get(self):
        '''获取所有的用户'''
        self.conn.search(search_base=self.active_base_dn, search_filter=self.search_filter, attributes=ALL_ATTRIBUTES)
        res = self.conn.response_to_json()
        res = json.loads(res)['entries']
        return res


    def OU_get(self):
        '''获取所有的OU'''
        self.conn.search(search_base=self.active_base_dn, search_filter=self.ou_search_filter, attributes=ALL_ATTRIBUTES)
        res = self.conn.response_to_json()
        res = json.loads(res)['entries']
        return res


    def create_obj(self, dn, type, attr=None):
        '''
        新建用户or部门,User需要设置密码,激活账户
        :param dn: dn = "ou=人事部3,ou=罗辑实验室,dc=adtest,dc=intra"  #创建的OU的完整路径
                   dn = "cn=张三,ou=人事部3,ou=罗辑实验室,dc=adtest,dc=intra"  #创建的User的完整路径
        :param type:选项:ou or user
        :param attr = {#User 属性表,需要设置什么属性,增加对应的键值对
                        "SamAccountName": "zhangsan",  # 账号
                        "EmployeeID":"1",    # 员工编号
                        "Sn": "张",  # 姓
                        "name": "张三",
                        "telephoneNumber": "12345678933",
                        "mobile": "12345678933",
                        "UserPrincipalName":"zhangsan@adtest.com",
                        "Mail":"zhangsan@adtest.com",
                        "Displayname": "张三",
                        "Manager":"CN=李四,OU=人事部,DC=adtest,DC=com",#需要使用用户的DN路径
                    }
                attr = {#OU属性表
                        'name':'人事部',
                        'managedBy':"CN=张三,OU=IT组,OU=罗辑实验室,DC=adtest,DC=intra", #部分负责人
                        }
        :return:True and success 是创建成功了
        (True, {'result': 0, 'description': 'success', 'dn': '', 'message': '', 'referrals': None, 'type': 'addResponse'})
        '''
        object_class = {'user': ['user', 'posixGroup', 'top'],
                        'ou': ['organizationalUnit', 'posixGroup', 'top'],
                        }
        res = self.conn.add(dn=dn, object_class=object_class[type], attributes=attr)
        if type == "user":  # 如果是用户时,我们需要给账户设置密码,并把账户激活
            self.conn.extend.microsoft.modify_password(dn, "123456")  # 设置用户密码为123456
            print(self.conn.result)
            self.conn.modify(dn, {'userAccountControl': [(MODIFY_REPLACE, ['66048'])]})  # 激活用户
            self.conn.unbind()
        return res, self.conn.result


    def del_obj(self, DN):
        '''
        删除用户 or 部门
        :param DN:
        :return:True
        '''
        res = self.conn.delete(dn=DN)
        return res


    def __rename_obj(self, dn, newname):
        '''
        OU or User 重命名方法
        :param dn:需要修改的object的完整dn路径
        :param newname: 新的名字,User格式:"cn=新名字";OU格式:"OU=新名字"
        :return:返回中有:'description': 'success', 表示操作成功
        {'result': 0, 'description': 'success', 'dn': '', 'message': '', 'referrals': None, 'type': 'modDNResponse'}
        '''
        self.conn.modify_dn(dn, newname)
        return self.conn.result

    def clock_unclock(self,dn,clock):
        """
        启用帐号:66048 为密码永不过期及启用帐号,单启用帐号为 512
        self.conn.modify(CN, {'userAccountControl': [('MODIFY_REPLACE', ['66048'])]})
        禁用帐号:66050 为密码永不过期及禁用帐号,单禁用帐号为 514
        self.conn.modify(CN, {'userAccountControl': [('MODIFY_REPLACE', ['66050'])]})
        :param dn: 'CN=李四,OU=south,DC=southpark,DC=com'
        :param clock: true为解锁账号,false为禁用账号
        :return:
        """
        if clock:
            self.conn.modify(dn, {'userAccountControl': [('MODIFY_REPLACE', ['66048'])]})
            self.conn.unbind()
            return self.conn.result
        else:
            self.conn.modify(dn, {'userAccountControl': [('MODIFY_REPLACE', ['66050'])]})
            self.conn.unbind()
            return self.conn.result

    def auth(self,username,password):
        """
        用户认证接口 #
        """
        ldap_user = '\\{}@southpark.com'.format(username)
        server = Server('172.18.188.7', use_ssl=False)
        connection = Connection(server, user=ldap_user, password=password, authentication=NTLM)
        connection.bind()
        res = connection.search(
            search_base="ou=south,dc=southpark,dc=com",
            search_filter='(sAMAccountName={})'.format(username),
            search_scope=SUBTREE,
            attributes=['cn', 'givenName', 'mail', 'sAMAccountName', 'memberOf'],
            paged_size=5
        )
        if res:
            entry = connection.response[0]
            attr_dict = entry['attributes']
            print(attr_dict)
            print("username:%s ;res: %s" %(username,connection.bind()))
            connection.closed
            return (True, attr_dict.get('cn'), None)
        else:
            connection.closed
            return (False, None, '账号已锁定或密码错误')


if __name__ == '__main__':
    # attr={
        # 'cn': '李四',
        # 'displayName': '李, 四',
        # 'distinguishedName': 'CN=李四,OU=south,DC=southpark,DC=com',
        # 'givenName': '四',
        # 'name': '李四',
        # 'objectCategory': 'CN=Person,CN=Schema,CN=Configuration,DC=southpark,DC=com',
        # 'userPrincipalName': 'lisi@southpark.com',
        # 'sAMAccountName': 'lisi',  #登陆用户名
        # 'sn': '李',
        # 'telephoneNumber': 'xxxxxxxxxxx',
        # 'mail': 'lisi@163.com',
        # 'description': '['运维工程师']',
    # }
    # rest=AD().create_obj('CN=李四,OU=south,DC=southpark,DC=com','user',attr)
    # print(rest)
    res=AD().auth('ls','123456')
    # AD().clock_unclock('CN=李四,OU=south,DC=southpark,DC=com',False)
    print(res)
复制代码

备注:
        windows server 2012域只需要搭建好证书服务器就能使用ldaps://x.x.x.x:636连接了,可以搜索ldp打开客户端测试

参考链接:
       https://cloud.tencent.com/developer/article/1623867 #ldap3模块使用方法
       https://blog.wlzs.cn/python%E4%BD%BF%E7%94%A8ldap3%E8%BF%9B%E8%A1%8Cwindows-ad%E5%9F%9F%E7%AE%A1%E7%90%86/     #Python使用Ldap3进行Windows AD域管理
       https://techexpert.tips/zh-hans/windows-zh-hans/%E9%80%9A%E8%BF%87-ssl-%E5%8A%9F%E8%83%BD%E5%90%AF%E7%94%A8%E6%B4%BB%E5%8A%A8%E7%9B%AE%E5%BD%95-ldap/      #活动目录-通过SSL启用LDAP
       https://www.cnblogs.com/haiya2019/p/10627730.html

 

posted @   風£飛  阅读(15)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
点击右上角即可分享
微信分享提示