使用Python ldap3修改用户sn属性报错:属性只读,求助原因
解决ldap3修改LDAP用户属性提示“attribute 'sn' is read only”的问题
问题重现
使用Python的ldap3库修改LDAP用户的sn(姓氏)等属性时,报错提示“attribute 'sn' is read only”,但同一账号通过ldp.exe工具可正常修改,确认账号具备权限且属性并非只读。
排查与解决方案
1. 移除本地entry对象的无效修改
代码中先修改本地entry.sn = new_last_name,再调用modify接口属于冗余操作——本地entry的修改不会同步到服务器,反而可能引发逻辑冲突。直接删除这行代码,保留modify调用即可:
if confirmation == '1': # 移除 entry.sn = new_last_name 这行 ldap_connection.modify(entry.entry_dn, {'sn': [(MODIFY_REPLACE, [new_last_name])]}) print("Nazwisko użytkownika zostało zmienione.")
2. 确保LDAP连接启用加密并绑定成功
部分LDAP服务器(如Active Directory)拒绝明文连接下的写入操作,需使用LDAPS(636端口)或StartTLS加密连接,同时确认账号绑定状态正常:
from ldap3 import Server, Connection, MODIFY_REPLACE, SUBTREE, START_TLS # 方式1:使用LDAPS加密连接 server = Server('dc.test.local', use_ssl=True, port=636) # 方式2:使用StartTLS加密 # server = Server('dc.test.local') ldap_connection = Connection(server, user='CN=你的操作账号,DC=test,DC=local', password='账号密码', auto_bind=True) # auto_bind_strategy=START_TLS) # 用StartTLS时添加此行
3. 验证modify操作的参数格式
确保modify方法中属性值为列表格式(即使是单个值),代码中[new_last_name]的写法是正确的,避免传入单个字符串而非列表。
4. 添加连接与查询结果验证
在代码中增加绑定状态、用户查询结果的验证,提前排查异常:
# 验证连接绑定是否成功 if not ldap_connection.bind(): print(f"绑定失败: {ldap_connection.result}") exit() # 验证是否查询到用户 ldap_connection.search(...) if not ldap_connection.entries: print("未找到对应PESEL的用户") ldap_connection.unbind() exit()
修正后的完整代码示例
from ldap3 import Server, Connection, MODIFY_REPLACE, SUBTREE def is_valid_serial_number(pesel): # 保留你的PESEL验证逻辑 return len(pesel) == 11 # 初始化加密LDAP连接 server = Server('dc.test.local', use_ssl=True, port=636) ldap_connection = Connection(server, user='CN=Admin,DC=test,DC=local', password='AdminPass', auto_bind=True) while True: pesel = input("Wprowadź PESEL użytkownika dla którego chcesz zmienić nazwisko: ") if not is_valid_serial_number(pesel): print("Nieprawidłowy numer PESEL.") continue break ldap_connection.search(search_base=f'dc=test,dc=local', search_filter=f'(serialNumber={pesel})', search_scope=SUBTREE, attributes=['sAMAccountName', 'givenName', 'sn', 'serialNumber','cn']) if not ldap_connection.entries: print("未找到对应PESEL的用户") ldap_connection.unbind() exit() entry = ldap_connection.entries[0] dn = entry.entry_dn print(dn) new_last_name = input("Wprowadź nowe nazwisko: ") print(entry.entry_attributes_as_dict) old_last_name = entry['sn'].value print(f"Potwierdź, czy chcesz zmienić nazwisko dla użytkownika {entry.sAMAccountName.value} z {old_last_name} na {new_last_name}.") confirmation = input("1. Tak\n2. Nie\nWybierz opcję: ") if confirmation == '1': result = ldap_connection.modify(entry.entry_dn, {'sn': [(MODIFY_REPLACE, [new_last_name])]}) if result: print("Nazwisko użytkownika zostało zmienione.") else: print(f"修改失败: {ldap_connection.result}") else: print("Anulowano zmianę nazwiska.") ldap_connection.unbind()
内容的提问来源于stack exchange,提问作者godelko ツ
相关产品推荐
相关产品推荐

