CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-ldap3

A strictly RFC 4510 conforming LDAP V3 pure Python client library

81

1.08x
Overview
Eval results
Files

operations.mddocs/

LDAP Operations

All standard LDAP operations including search, add, modify, delete, compare, and abandon operations with full control support and multiple response formats.

Capabilities

Search Operations

Perform LDAP search operations with various scopes, filters, and result processing options.

def search(self, search_base, search_filter, search_scope=SUBTREE, 
           dereference_aliases=DEREF_ALWAYS, attributes=None, size_limit=0, 
           time_limit=0, types_only=False, get_operational_attributes=False, 
           controls=None, paged_size=None, paged_criticality=False, 
           paged_cookie=None):
    """
    Perform LDAP search operation.

    Args:
        search_base (str): Base DN for search
        search_filter (str): LDAP search filter (RFC 4515)
        search_scope (str): Search scope (BASE, LEVEL, SUBTREE)
        dereference_aliases (str): Alias dereferencing behavior (NEVER, SEARCH, BASE, ALWAYS)
        attributes (list, optional): Attributes to retrieve (None for all)
        size_limit (int): Maximum number of entries to return (0 for no limit)
        time_limit (int): Search time limit in seconds (0 for no limit)
        types_only (bool): Return attribute types only, not values
        get_operational_attributes (bool): Include operational attributes
        controls (list, optional): LDAP controls for search
        paged_size (int, optional): Page size for paged search
        paged_criticality (bool): Paged search criticality
        paged_cookie (bytes, optional): Paged search cookie

    Returns:
        bool: True if search successful, False otherwise
    """

Search Result Access:

  • connection.entries: List of Entry objects (abstract layer)
  • connection.response: Raw LDAP response
  • connection.result: Operation result information

Add Operations

Add new entries to the LDAP directory with specified object classes and attributes.

def add(self, dn, object_class=None, attributes=None, controls=None):
    """
    Add new entry to LDAP directory.

    Args:
        dn (str): Distinguished Name of new entry
        object_class (str or list, optional): Object class(es) for entry
        attributes (dict, optional): Entry attributes as {name: value} or {name: [values]}
        controls (list, optional): LDAP controls for add operation

    Returns:
        bool: True if add successful, False otherwise
    """

Modify Operations

Modify existing LDAP entries by adding, deleting, replacing, or incrementing attribute values.

def modify(self, dn, changes, controls=None):
    """
    Modify existing LDAP entry.

    Args:
        dn (str): Distinguished Name of entry to modify
        changes (dict): Modifications as {attribute: [(operation, [values])]}
                       Operation: MODIFY_ADD, MODIFY_DELETE, MODIFY_REPLACE, MODIFY_INCREMENT
        controls (list, optional): LDAP controls for modify operation

    Returns:
        bool: True if modify successful, False otherwise
    """

Delete Operations

Delete entries from the LDAP directory.

def delete(self, dn, controls=None):
    """
    Delete entry from LDAP directory.

    Args:
        dn (str): Distinguished Name of entry to delete
        controls (list, optional): LDAP controls for delete operation

    Returns:
        bool: True if delete successful, False otherwise
    """

Modify DN Operations

Rename or move LDAP entries by modifying their distinguished names.

def modify_dn(self, dn, relative_dn, delete_old_dn=True, new_superior=None, controls=None):
    """
    Modify distinguished name of entry (rename/move).

    Args:
        dn (str): Current distinguished name
        relative_dn (str): New relative distinguished name
        delete_old_dn (bool): Delete old RDN attribute values
        new_superior (str, optional): New parent DN for move operation
        controls (list, optional): LDAP controls for modify DN operation

    Returns:
        bool: True if modify DN successful, False otherwise
    """

Compare Operations

Compare attribute values in LDAP entries without retrieving the actual values.

def compare(self, dn, attribute, value, controls=None):
    """
    Compare attribute value in LDAP entry.

    Args:
        dn (str): Distinguished Name of entry
        attribute (str): Attribute name to compare
        value (str or bytes): Value to compare against
        controls (list, optional): LDAP controls for compare operation

    Returns:
        bool: True if values match, False if different or error
    """

Abandon Operations

Abandon ongoing LDAP operations using their message IDs.

def abandon(self, message_id, controls=None):
    """
    Abandon ongoing LDAP operation.

    Args:
        message_id (int): Message ID of operation to abandon
        controls (list, optional): LDAP controls for abandon operation

    Returns:
        bool: True if abandon request sent successfully
    """

Extended Operations

Perform LDAP extended operations with custom request names and values.

def extended(self, request_name, request_value=None, controls=None):
    """
    Perform LDAP extended operation.

    Args:
        request_name (str): Extended operation request name (OID)
        request_value (bytes, optional): Extended operation request value
        controls (list, optional): LDAP controls for extended operation

    Returns:
        bool: True if extended operation successful
    """

Response Processing

Access and process LDAP operation responses in various formats.

def response_to_ldif(self):
    """
    Convert last response to LDIF format.

    Returns:
        str: Response in LDIF format
    """

def response_to_json(self):
    """
    Convert last response to JSON format.

    Returns:
        str: Response in JSON format
    """

def response_to_file(self, target, raw=False):
    """
    Save response to file.

    Args:
        target (str): Target file path
        raw (bool): Save raw response vs formatted
    """

Usage Examples

Basic Search

import ldap3

server = ldap3.Server('ldap://ldap.example.com')
conn = ldap3.Connection(server, 'cn=user,dc=example,dc=com', 'password', auto_bind=True)

# Search for all people
conn.search('dc=example,dc=com', '(objectClass=person)', attributes=['cn', 'mail', 'telephoneNumber'])

for entry in conn.entries:
    print(f"Name: {entry.cn}")
    print(f"Email: {entry.mail}")
    print(f"Phone: {entry.telephoneNumber}")
    print("---")

Advanced Search with Filters

# Complex search filter
filter_str = '(&(objectClass=person)(|(cn=John*)(mail=*@example.com)))'
conn.search('ou=people,dc=example,dc=com', filter_str, 
           search_scope=ldap3.LEVEL, 
           attributes=['cn', 'mail', 'description'],
           size_limit=100)

# Access raw response
for response_item in conn.response:
    if response_item['type'] == 'searchResEntry':
        dn = response_item['dn']
        attributes = response_item['attributes']
        print(f"DN: {dn}")
        print(f"Attributes: {attributes}")

Paged Search for Large Results

# Paged search to handle large result sets
search_base = 'dc=example,dc=com'
search_filter = '(objectClass=person)'
search_paged_size = 100

# Perform first page
conn.search(search_base, search_filter, paged_size=search_paged_size)
total_entries = len(conn.entries)

# Continue with additional pages
while True:
    cookie = conn.result['controls']['1.2.840.113556.1.4.319']['value']['cookie']
    if not cookie:
        break
    
    conn.search(search_base, search_filter, paged_size=search_paged_size, paged_cookie=cookie)
    total_entries += len(conn.entries)

print(f"Total entries found: {total_entries}")

Adding Entries

# Add new person entry
new_dn = 'cn=John Doe,ou=people,dc=example,dc=com'
attributes = {
    'cn': 'John Doe',
    'sn': 'Doe',
    'givenName': 'John',
    'mail': 'john.doe@example.com',
    'telephoneNumber': '+1-555-1234',
    'userPassword': 'secretpassword'
}

result = conn.add(new_dn, object_class=['inetOrgPerson', 'person'], attributes=attributes)
if result:
    print("Entry added successfully")
else:
    print(f"Failed to add entry: {conn.result}")

Modifying Entries

# Modify existing entry
target_dn = 'cn=John Doe,ou=people,dc=example,dc=com'

# Different types of modifications
changes = {
    'mail': [(ldap3.MODIFY_REPLACE, 'newemail@example.com')],  # Replace email
    'telephoneNumber': [(ldap3.MODIFY_ADD, '+1-555-5678')],   # Add phone number
    'description': [(ldap3.MODIFY_DELETE, [])],               # Delete all descriptions
    'loginCount': [(ldap3.MODIFY_INCREMENT, 1)]               # Increment counter
}

result = conn.modify(target_dn, changes)
if result:
    print("Entry modified successfully")
else:
    print(f"Failed to modify entry: {conn.result}")

Complex Modify with Multiple Changes

# Multiple attribute modifications in single operation
changes = {
    'mail': [(ldap3.MODIFY_REPLACE, ['primary@example.com', 'secondary@example.com'])],
    'telephoneNumber': [(ldap3.MODIFY_DELETE, '+1-555-1234'),  # Delete specific phone
                       (ldap3.MODIFY_ADD, ['+1-555-9999', '+1-555-8888'])], # Add new phones
    'title': [(ldap3.MODIFY_REPLACE, 'Senior Developer')]
}

conn.modify('cn=John Doe,ou=people,dc=example,dc=com', changes)

Moving/Renaming Entries

# Rename entry (change CN)
old_dn = 'cn=John Doe,ou=people,dc=example,dc=com'
new_rdn = 'cn=John Smith'
conn.modify_dn(old_dn, new_rdn, delete_old_dn=True)

# Move entry to different OU
current_dn = 'cn=John Smith,ou=people,dc=example,dc=com'
new_superior = 'ou=employees,dc=example,dc=com'
conn.modify_dn(current_dn, 'cn=John Smith', new_superior=new_superior)

Deleting Entries

# Delete single entry
entry_dn = 'cn=John Smith,ou=employees,dc=example,dc=com'
result = conn.delete(entry_dn)
if result:
    print("Entry deleted successfully")
else:
    print(f"Failed to delete entry: {conn.result}")

Compare Operation

# Compare attribute value without retrieving it
entry_dn = 'cn=admin,dc=example,dc=com'
result = conn.compare(entry_dn, 'userPassword', 'secretpassword')
if result:
    print("Password matches")
elif conn.result['result'] == 5:  # RESULT_COMPARE_FALSE
    print("Password does not match")
else:
    print(f"Compare operation failed: {conn.result}")

Working with Controls

# Search with server-side sorting control
from ldap3.protocol.rfc2696 import paged_search_control
from ldap3.protocol.rfc2891 import sort_control

# Server-side sort by cn attribute
sort_ctrl = sort_control([('cn', True)])  # True = ascending
conn.search('dc=example,dc=com', '(objectClass=person)', 
           controls=[sort_ctrl], attributes=['cn', 'mail'])

# Process sorted results
for entry in conn.entries:
    print(f"{entry.cn}: {entry.mail}")

Asynchronous Operations

# Asynchronous connection for non-blocking operations
server = ldap3.Server('ldap://ldap.example.com')
conn = ldap3.Connection(server, 'cn=user,dc=example,dc=com', 'password', 
                       client_strategy=ldap3.ASYNC, auto_bind=True)

# Start search operation (returns immediately)
message_id = conn.search('dc=example,dc=com', '(objectClass=person)')

# Do other work while search is running
import time
time.sleep(1)

# Get results when ready
result, response = conn.get_response(message_id)
if result:
    for item in response:
        if item['type'] == 'searchResEntry':
            print(f"Found: {item['dn']}")

Response Format Examples

# JSON response format
conn.search('dc=example,dc=com', '(objectClass=person)', attributes=['cn', 'mail'])
json_response = conn.response_to_json()
print(json_response)

# LDIF response format  
ldif_response = conn.response_to_ldif()
print(ldif_response)

# Save to file
conn.response_to_file('/tmp/search_results.ldif')

Install with Tessl CLI

npx tessl i tessl/pypi-ldap3

docs

abstract.md

config.md

connection.md

extended.md

index.md

operations.md

tile.json