使用Python 3.x的ldap3修改Active Directory密码失败,求排查解决
我用Python的ldap3库编写脚本连接Active Directory服务器,输入用户名可以正常获取用户的cn(全名)、邮箱等信息,但修改密码功能执行失败。执行改密码时返回的LDAP结果如下:
LDAP Result: {'result': 53, 'description': 'unwillingToPerform', 'dn': '', 'message': '00002077: SvcErr: DSID-03190F5B, problem 5003 (WILL_NOT_PERFORM), data 0\n\x00', 'referrals': None, 'type': 'modifyResponse'}
怀疑是Active Directory的策略限制导致,求修改用户密码的可行方案。相关代码如下:
from ldap3 import Connection, Server def fetch_email(username): server = Server('#####') con = Connection(server, user="#####r", password="#####", auto_bind=True) con.search("DC=rohan,DC=com", "(&(objectcategory=person)(sAMAccountName={}))".format(username), attributes=["cn","mail"]) full_name = None email = None for entry in con.entries: if "cn" in entry: full_name_attr = entry.cn full_name = str(full_name_attr) # Convert Attribute to string if "mail" in entry: email_attr = entry.mail email = str(email_attr) # Convert Attribute to string if full_name and email: break con.unbind() return full_name, email def change_password(username, current_password, new_password): server = Server('#####') con = Connection(server, user="#####", password="######", auto_bind=True) con.search("DC=rohan,DC=com", "(&(objectcategory=person)(sAMAccountName={}))".format(username), attributes=["cn"]) user_dn = None for entry in con.entries: if "cn" in entry: user_dn = entry.entry_dn break if user_dn: response = con.extend.microsoft.modify_password(user_dn, new_password, current_password) print("Modify Password Response:", response) print("LDAP Result:", con.result) if response: print("Password change successful.") else: print("Password change failed.") else: print("User not found.") con.unbind() # Prompt user to enter the username username = input("Enter username: ") current_password = input("Enter current password: ") new_password = input("Enter new password: ") full_name, email = fetch_email(username) print("Full Name:", full_name) print("Email:", email) change_password(username, current_password, new_password)
返回的错误码53 (unwillingToPerform)结合AD的错误信息00002077,通常和AD的密码策略、连接安全要求或权限有关,以下是可行的排查和解决步骤:
确保连接使用SSL/TLS加密
AD默认要求修改密码的连接必须通过SSL(636端口)或TLS加密,明文连接会直接拒绝改密码操作。修改Server初始化代码,指定启用SSL:server = Server('#####', use_ssl=True, port=636)如果使用TLS,可以在连接绑定后启动加密:
con = Connection(server, user="#####", password="######", auto_bind=True) con.start_tls()验证新密码符合AD策略
错误中的data 0通常表示新密码不满足AD的密码规则,比如长度不足、缺少大小写/数字/特殊字符、与历史密码重复、未满足最小使用期限等。需要确认新密码完全符合域内的密码策略要求。检查执行账号的权限
- 若用管理员账号改密码:需确保该账号拥有修改目标用户密码的权限(可在AD用户属性的「安全」选项卡中配置)。
- 若用户自行改密码:需确认用户属性中勾选了「用户可以更改密码」,且当前密码输入正确。
调整modify_password参数顺序或省略冗余参数
部分AD环境对ldap3的modify_password参数顺序要求不同,可尝试调整参数顺序:response = con.extend.microsoft.modify_password(user_dn, current_password, new_password)管理员改密码时无需提供用户当前密码,可直接省略:
response = con.extend.microsoft.modify_password(user_dn, new_password)自行改密码场景使用用户自身账号绑定
如果是用户自己修改密码,建议在change_password函数中用用户自身的账号和当前密码绑定连接,而非固定管理员账号:def change_password(username, current_password, new_password): server = Server('#####', use_ssl=True, port=636) # 用用户自身账号绑定连接 con = Connection(server, user=f"{username}@rohan.com", password=current_password, auto_bind=True) con.search("DC=rohan,DC=com", "(&(objectcategory=person)(sAMAccountName={}))".format(username), attributes=["cn"]) user_dn = None for entry in con.entries: user_dn = entry.entry_dn break if user_dn: # 用户自行改密码只需传入新密码 response = con.extend.microsoft.modify_password(user_dn, new_password) # 后续打印逻辑不变
内容的提问来源于stack exchange,提问作者Rohan

