杰瑞科技汇

Python LDAP结果如何高效处理?

Of course! Getting results from an LDAP query in Python is a fundamental task. The process involves connecting, searching, and then parsing the returned data.

Python LDAP结果如何高效处理?-图1
(图片来源网络,侵删)

The most common library for this is python-ldap. It's a robust, feature-rich library that provides a fairly direct mapping to the C LDAP API.

Here's a complete guide, from installation to a detailed explanation of the result object.

Installation

First, you need to install the library. It also requires the OpenLDAP development libraries to be installed on your system.

Using pip:

Python LDAP结果如何高效处理?-图2
(图片来源网络,侵删)
pip install python-ldap

System Dependencies (for Linux): You'll need to install the development headers for OpenLDAP.

  • Debian / Ubuntu:
    sudo apt-get update
    sudo apt-get install libldap2-dev libsasl2-dev
  • Red Hat / CentOS / Fedora:
    sudo yum install openldap-devel python3-devel
  • macOS (using Homebrew):
    brew install openldap

Basic LDAP Search and Result Parsing

Let's walk through a complete example. We'll perform a simple search and then explore the structure of the result.

Example Code

import ldap
import ldap.filter
# --- Configuration ---
# Use 'ldap://' for non-SSL, 'ldaps://' for SSL
SERVER_URI = 'ldap://ldap.forumsys.com'
# A public test LDAP server that allows anonymous binds
BASE_DN = 'dc=example,dc=com'
SEARCH_SCOPE = ldap.SCOPE_SUBTREE  # or ldap.SCOPE_ONELEVEL, ldap.SCOPE_BASE
SEARCH_FILTER = '(objectClass=person)' # Search for all entries with objectClass 'person'
# --- 1. Establish Connection ---
# For a public server, we can use anonymous bind.
# For a real server, you would use: conn.simple_bind_s('cn=admin,dc=example,dc=com', 'your_password')
try:
    conn = ldap.initialize(SERVER_URI)
    conn.protocol_version = ldap.VERSION3
    # Perform an anonymous bind
    conn.simple_bind_s('', '') 
    print("Successfully connected to LDAP server.")
except ldap.LDAPError as e:
    print(f"Error connecting to LDAP server: {e}")
    exit()
# --- 2. Perform Search ---
try:
    # The search method returns a tuple: (msgid, result_list)
    # We use the synchronous version search_s() to get the results directly.
    result_set = conn.search_s(
        base=BASE_DN,
        scope=SEARCH_SCOPE,
        filterstr=SEARCH_FILTER
    )
    print(f"\nFound {len(result_set)} results.")
    # --- 3. Parse the Result ---
    for dn, entry in result_set:
        print("-" * 40)
        print(f"Distinguished Name (DN): {dn}")
        print("Attributes:")
        for attr_name, attr_values in entry.items():
            # LDAP attributes can have multiple values (e.g., multiple email addresses)
            print(f"  - {attr_name}: {attr_values}")
except ldap.LDAPError as e:
    print(f"Error during LDAP search: {e}")
finally:
    # --- 4. Close the Connection ---
    conn.unbind_s()
    print("\nConnection closed.")

Running the Example Output

When you run the code above, you'll get output similar to this:

Successfully connected to LDAP server.
Found 5 results.
----------------------------------------
Distinguished Name (DN): uid=jwayne,dc=example,dc=com
Attributes:
  - objectClass: ['top', 'person', 'organizationalPerson', 'inetOrgPerson']
  - cn: ['John Wayne']
  - sn: ['Wayne']
  - telephoneNumber: ['+1 512 555 0199']
  - mail: ['jwayne@example.com']
  - userPassword: ['password']
  - uid: ['jwayne']
----------------------------------------
Distinguished Name (DN): uid=jsmith,dc=example,dc=com
Attributes:
  - objectClass: ['top', 'person', 'organizationalPerson', 'inetOrgPerson']
  - cn: ['John Smith']
  - sn: ['Smith']
  - telephoneNumber: ['+1 512 555 0187']
  - mail: ['jsmith@example.com']
  - userPassword: ['password']
  - uid: ['jsmith']
... (and so on for the other entries)
----------------------------------------
Connection closed.

Understanding the LDAP Result Object

The key to working with LDAP results in Python is understanding the structure returned by conn.search_s().

Python LDAP结果如何高效处理?-图3
(图片来源网络,侵删)

The function returns a list of tuples. Each tuple represents a single LDAP entry found by the search.

Structure: [(dn_1, entry_1), (dn_2, entry_2), ...]

Let's break down each part of the tuple:

Part 1: The Distinguished Name (DN)

The first element of the tuple is a string representing the entry's unique identifier in the directory tree.

dn, entry = result_set[0]
print(dn) 
# Output: uid=jwayne,dc=example,dc=com

Part 2: The Entry (Attributes Dictionary)

The second element is a dictionary containing the entry's attributes. This is the most important part.

Structure: {attribute_name: [value1, value2, ...], ...}

Key characteristics of this dictionary:

  • Keys: The keys are strings representing the attribute names (e.g., cn, mail, telephoneNumber).
  • Values: Crucially, the values are always lists. This is because LDAP attributes can have multiple values. Even if an attribute only has one value (like a person's sn or uid), it is returned as a single-element list.
dn, entry = result_set[0]
# Accessing a single-valued attribute
common_names = entry['cn']
print(common_names)
# Output: ['John Wayne']
# You must access the first element of the list to get the actual string value
first_cn = entry['cn'][0]
print(first_cn)
# Output: John Wayne
# Accessing a multi-valued attribute (though 'cn' is usually single-valued)
object_classes = entry['objectClass']
print(object_classes)
# Output: ['top', 'person', 'organizationalPerson', 'inetOrgPerson']

Part 3: Handling Binary Data (e.g., JPEGPhoto)

Some attributes, like jpegPhoto or userCertificate, contain binary data, not text. The python-ldap library handles this gracefully.

If an attribute contains binary data, its values in the dictionary will be bytes objects instead of strings.

# Example search for an entry with a photo
# SEARCH_FILTER_PHOTO = '(uid=jkondo)'
# result_set_photo = conn.search_s(BASE_DN, SCOPE_SUBTREE, SEARCH_FILTER_PHOTO)
# dn, entry = result_set_photo[0]
# The 'jpegPhoto' attribute will contain bytes
# photo_data = entry['jpegPhoto'][0]
# print(type(photo_data))
# Output: <class 'bytes'>
# You can then write this to a file
# with open('user_photo.jpg', 'wb') as f:
#     f.write(photo_data)

Common Tasks and Best Practices

Searching with Specific Attributes

By default, search_s() returns all attributes for an entry. To improve performance and get only what you need, use the attrlist parameter.

# Only request the 'cn' and 'mail' attributes
result_set_specific = conn.search_s(
    base=BASE_DN,
    scope=SEARCH_SCOPE,
    filterstr=SEARCH_FILTER,
    attrlist=['cn', 'mail'] 
)
for dn, entry in result_set_specific:
    print(f"DN: {dn}, CN: {entry.get('cn', ['N/A'])[0]}, Mail: {entry.get('mail', ['N/A'])[0]}")

Note: Using entry.get(key, []) is safer than entry[key] because it returns an empty list if the attribute doesn't exist, preventing a KeyError.

Handling Search Errors

LDAP searches can fail for many reasons (invalid DN, insufficient permissions, malformed filter, etc.). Always wrap your search in a try...except block.

try:
    # A malformed filter will cause an exception
    conn.search_s(BASE_DN, SCOPE_SUBTREE, filterstr='(&(objectClass=person))')
except ldap.FILTER_ERROR as e:
    print(f"LDAP Filter Error: The search filter was invalid. Details: {e}")
except ldap.INSUFFICIENT_ACCESS as e:
    print(f"LDAP Access Error: You don't have permission to perform this search. Details: {e}")
except ldap.LDAPError as e:
    print(f"A general LDAP error occurred: {e}")

Asynchronous Searches

For very large directories or to avoid blocking your application, you can use asynchronous searches.

msgid = conn.search(
    base=BASE_DN,
    scope=SEARCH_SCOPE,
    filterstr=SEARCH_FILTER
)
print(f"Search request sent with message ID: {msgid}")
# Now, you can do other work...
# time.sleep(1)
# Retrieve the results when you're ready
try:
    # ldap.RES_SEARCH_RESULT is the message type you're waiting for
    result_type, result_data = conn.result(msgid, all=0)
    if result_type == ldap.RES_SEARCH_RESULT:
        print("Asynchronous search complete.")
        for dn, entry in result_data:
            print(f"Found entry: {dn}")
except ldap.LDAPError as e:
    print(f"Error getting async results: {e}")
分享:
扫描分享到社交APP
上一篇
下一篇