การพิสูจน์ตัวตนกับ Active Directory โดยใช้ python + ldap


89

ฉันจะพิสูจน์ตัวตนกับ AD โดยใช้ Python + LDAP ได้อย่างไร ฉันกำลังใช้ไลบรารี python-ldap และสิ่งที่ผลิตออกมาคือน้ำตา

ฉันไม่สามารถเชื่อมโยงเพื่อดำเนินการค้นหาง่ายๆ:

import sys
import ldap


Server = "ldap://my-ldap-server"
DN, Secret, un = sys.argv[1:4]

Base = "dc=mydomain,dc=co,dc=uk"
Scope = ldap.SCOPE_SUBTREE
Filter = "(&(objectClass=user)(sAMAccountName="+un+"))"
Attrs = ["displayName"]

l = ldap.initialize(Server)
l.protocol_version = 3
print l.simple_bind_s(DN, Secret)

r = l.search(Base, Scope, Filter, Attrs)
Type,user = l.result(r,60)
Name,Attrs = user[0]
if hasattr(Attrs, 'has_key') and Attrs.has_key('displayName'):
  displayName = Attrs['displayName'][0]
  print displayName

sys.exit()

การเรียกใช้สิ่งนี้myusername@mydomain.co.uk password usernameทำให้ฉันมีข้อผิดพลาดหนึ่งในสองข้อ:

Invalid Credentials - เมื่อฉันพิมพ์ผิดหรือจงใจใช้ข้อมูลประจำตัวที่ไม่ถูกต้องจะไม่สามารถตรวจสอบสิทธิ์ได้

ldap.INVALID_CREDENTIALS: {'info': '80090308: LdapErr: DSID-0C090334, comment: ข้อผิดพลาด AcceptSecurityContext, data 52e, vece', 'desc': 'Invalid credentials'}

หรือ

ldap.OPERATIONS_ERROR: {'info': '00000000: LdapErr: DSID-0C090627 แสดงความคิดเห็น: ในการดำเนินการนี้การเชื่อมต่อที่สำเร็จจะต้องเสร็จสิ้นในการเชื่อมต่อข้อมูล 0, vece', 'desc': 'ข้อผิดพลาดในการดำเนินการ '}

ฉันพลาดอะไรที่จะผูกมัดอย่างถูกต้อง?

ฉันได้รับข้อผิดพลาดเดียวกันบน fedora และ windows


2
"... และสิ่งที่ผลิตออกมาคือน้ำตา" ไม่น้ำตาคล้องจองกับหมีหรือเบียร์?
philshem

คำตอบ:


48

ฉันหายไป

l.set_option(ldap.OPT_REFERRALS, 0)

จากการเริ่มต้น


3
สาเหตุหลักของจุดบกพร่องนี้คือคุณมีการอ้างอิงในการตอบกลับครั้งแรกและรหัส LDAP ของ windows ไม่ส่งหนังสือรับรองไปยังเซิร์ฟเวอร์การอ้างอิง หากคุณใช้ข้อมูลรับรอง kerberos ควรใช้งานได้
schlenk

2
ฉันมีอาการที่แตกต่างกัน แต่ตัวเลือกเดียวกันนี้ช่วยแก้ปัญหาของฉันได้ สรุปไว้ในบล็อกโพสต์: chaverma.com/blog/index.php/2013/06/…
คริส

ไม่แน่ใจว่าเกี่ยวข้องหรือไม่ แต่ฉันมีปัญหาเดียวกันและดูเหมือนว่าวิธีแก้ปัญหาของ 1729 ทำอะไรบางอย่าง - แต่บางครั้งเซิร์ฟเวอร์ LDAP ก็ตอบรับเครดิตที่ไม่ถูกต้องทันที หลังจากนั้นไม่นานมันก็สงบลงและทำงานได้อีกครั้ง
Nitay

29

หากคุณเปิดให้ใช้ pywin32 คุณสามารถใช้การโทร Win32 จาก Python นี่คือสิ่งที่เราทำในเว็บเซิร์ฟเวอร์ CherryPy ของเรา:

import win32security
token = win32security.LogonUser(
    username,
    domain,
    password,
    win32security.LOGON32_LOGON_NETWORK,
    win32security.LOGON32_PROVIDER_DEFAULT)
authenticated = bool(token)

3
เรียบง่ายและสะอาด! ขอบคุณ!
alexroat

วิธีนี้ใช้ได้ผลสำหรับฉันในแอปพลิเคชัน Python Flask ในขณะที่อยู่เบื้องหลังพร็อกซีขององค์กร NTLM ที่ จำกัด ตัวเลือกอื่น ๆ ที่ใช้ LDAP จะไม่ทำงาน
Gigaflop

7

ที่ได้ผลสำหรับฉันl.set_option (ldap.OPT_REFERRALS, 0)เป็นกุญแจสำคัญในการเข้าถึง ActiveDirectory นอกจากนี้ฉันคิดว่าคุณควรเพิ่ม "con.unbind ()" เพื่อปิดการเชื่อมต่อก่อนที่จะจบสคริปต์


8
จากเอกสารpython-ldap : อินสแตนซ์ของLDAPObjectถูกส่งคืนโดยinitialize(). การเชื่อมต่อจะถูกยกเลิกโดยอัตโนมัติและปิดเมื่ออ็อบเจ็กต์ LDAP ถูกลบ
SørenLøvborg

คุณปิดเซสชันไม่ใช่การเชื่อมต่อ
Romulus

5

นี่คือรหัสง่ายๆที่เหมาะกับฉัน

import ldap  # run 'pip install python-ldap' to install ldap module.
conn = ldap.open("ldaphost.company.com")
conn.simple_bind_s("myuser@company.com", "mypassword")

นี้จะขึ้นอยู่กับคำตอบก่อนหน้า


1
ไม่ได้ผลอีกต่อไปคุณจะได้รับAttributeError: module 'ldap' has no attribute 'open'
Josh Correia

3

หากคุณติดตั้ง Kerberos และพูดคุยกับ AD เช่นเดียวกับกรณีที่ติดตั้งและเรียกใช้ Centrify Express คุณอาจใช้ python-kerberos เช่น

import kerberos
kerberos.checkPassword('joe','pizza','krbtgt/x.pizza.com','X.PIZZA.COM')`

จะส่งคืน True เนื่องจากผู้ใช้ 'joe' มีรหัสผ่าน 'pizza' ใน Kerberos realm X.PIZZA.COM (โดยทั่วไปฉันคิดว่าอันหลังจะเหมือนกับชื่อของ AD Domain)


2

ฉันเห็นความคิดเห็นของคุณถึง @Johan Buret เกี่ยวกับ DN ไม่ได้แก้ไขปัญหาของคุณ แต่ฉันก็เชื่อว่านั่นคือสิ่งที่คุณควรพิจารณา

จากตัวอย่างของคุณ DN สำหรับบัญชีผู้ดูแลระบบเริ่มต้นใน AD จะเป็น: cn = Administrator, cn = Users, dc = mydomain, dc = co, dc = uk - โปรดลองใช้


2

ขึ้นอยู่กับบทช่วยสอน ldap3 ที่ยอดเยี่ยม:

>>> from ldap3 import Server, Connection, ALL, NTLM
>>> server = Server('server_name_or_ip', get_info=ALL)
>>> conn = Connection(server, user="user_name", password="password", auto_bind=True)
>>> conn.extend.standard.who_am_i()
>>> server.info

ฉันทำข้างต้นใน Python3 แต่มันควรจะเข้ากันได้กับ Python 2


1

ฉันพยายามที่จะเพิ่ม

l.set_option (ldap.OPT_REFERRALS, 0)

แต่แทนที่จะเป็นข้อผิดพลาด Python เพียงแค่แฮงค์และจะไม่ตอบสนองต่อสิ่งใดอีก บางทีฉันอาจสร้างคำค้นหาผิดส่วนฐานของการค้นหาคืออะไร ฉันใช้เหมือนกันกับ DN สำหรับการผูกแบบง่าย (โอ้และฉันต้องทำl.simple_bindแทนl.simple_bind_s):

import ldap
local = ldap.initialize("ldap://127.0.0.1")
local.simple_bind("CN=staff,DC=mydomain,DC=com")
#my pc is not actually connected to this domain 
result_id = local.search("CN=staff,DC=mydomain,DC=com", ldap.SCOPE_SUBTREE, "cn=foobar", None)
local.set_option(ldap.OPT_REFERRALS, 0)
result_type, result_data = local.result(result_id, 0)

ฉันใช้ AD LDS และอินสแตนซ์ได้รับการลงทะเบียนสำหรับบัญชีปัจจุบัน


1

ฉันมีปัญหาเดียวกัน แต่เกี่ยวกับการเข้ารหัสรหัสผ่าน

.encode('iso-8859-1')

แก้ไขปัญหา



โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.