LDAP Controls Support
python-ldap-faker supports the following LDAP controls:
Root DSE Advertisement
Our LDAP Control support is automatically advertised in the Root DSE when clients query for supported controls:
rdata = conn.search_s(
"",
ldap.SCOPE_BASE,
"(objectClass=*)",
attrlist=["supportedControl"]
)
# Example: VLV OID will be present in supportedControl
vlv_oid = b"2.16.840.1.113730.3.4.9"
Simple Paged Results Control Support
Simple Paged Results Control is an LDAP control extension that allows clients to request a specific “window” of results around a target position, which is particularly useful for implementing pagination in user interfaces.
Simple Paged Results Control is supported out of the box in python-ldap-faker
and is automatically advertised in the Root DSE when clients query for supported
controls.
This is easy to use because python-ldap supports it directly:
import ldap
from ldap.controls import SimplePagedResultsControl
# Create paged results control
paged_results_control = SimplePagedResultsControl(
True, # critical
"1000", # size
"", # initial cookie
)
while True:
# Perform paged search
msgid = conn.search_ext(
'ou=users,dc=example,dc=com',
ldap.SCOPE_SUBTREE,
'(objectClass=person)',
serverctrls=[paged_results_control]
)
# Retrieve results
rtype, rdata, rmsgid, rctrls = conn.result3(msgid)
# Get paged results control
paged_results_control = rctrls[0]
# Get paged results cookie
paged_results_control.cookie = paged_results_control.cookie
# If there are no more results, break
if not paged_results_cookie:
break
# Update paged results control with new cookie
paged_results_control.cookie = paged_results_cookie
Server Side Sort Control Support
Server Side Sort Control is an LDAP control extension that allows clients to request that search results be sorted by the server before being returned. This is particularly useful for implementing ordered lists in user interfaces and for use with pagination controls like Virtual List View (VLV).
Server Side Sort Control is supported out of the box in python-ldap-faker and is automatically advertised in the Root DSE when clients query for supported controls.
Sort Request Control
The Sort request control (OID: 1.2.840.113556.1.4.473) allows clients to specify
one or more sort keys for ordering search results. Each sort key contains:
attributeType: The LDAP attribute name to sort by (required)
orderingRule: Optional ordering rule OID (defaults to attribute’s natural ordering)
reverseOrder: Optional boolean flag for descending order (defaults to false)
The control value must be BER-encoded according to RFC 2891. Example usage:
import ldap
from ldap.controls import LDAPControl
from pyasn1.codec.ber import encoder
from pyasn1.type import namedtype, univ
# Define SortKey ASN.1 structure
class SortKey(univ.Sequence):
componentType = namedtype.NamedTypes(
namedtype.NamedType("attributeType", univ.OctetString()),
namedtype.OptionalNamedType("orderingRule", univ.OctetString()),
namedtype.DefaultedNamedType("reverseOrder", univ.Boolean(False))
)
class SortKeyList(univ.SequenceOf):
componentType = SortKey()
# Create sort control for single attribute
sort_key = SortKey()
sort_key.setComponentByName("attributeType", "cn")
sort_key_list = SortKeyList()
sort_key_list.setComponentByPosition(0, sort_key)
encoded_value = encoder.encode(sort_key_list)
sort_control = LDAPControl(
'1.2.840.113556.1.4.473',
True,
encoded_value
)
# Perform sorted search
msgid = conn.search_ext(
'ou=users,dc=example,dc=com',
ldap.SCOPE_SUBTREE,
'(objectClass=person)',
serverctrls=[sort_control]
)
# Get sorted results
rtype, rdata, rmsgid, rctrls = conn.result3(msgid)
Multi-key sorting is also supported:
# Create sort control for multiple attributes (sort by cn, then uid)
sort_key_list = SortKeyList()
# First sort key: cn (ascending)
cn_key = SortKey()
cn_key.setComponentByName("attributeType", "cn")
sort_key_list.setComponentByPosition(0, cn_key)
# Second sort key: uid (ascending)
uid_key = SortKey()
uid_key.setComponentByName("attributeType", "uid")
sort_key_list.setComponentByPosition(1, uid_key)
encoded_value = encoder.encode(sort_key_list)
sort_control = LDAPControl('1.2.840.113556.1.4.473', True, encoded_value)
For descending order, set the reverseOrder flag:
# Sort by cn in descending order
sort_key = SortKey()
sort_key.setComponentByName("attributeType", "cn")
sort_key.setComponentByName("reverseOrder", True)
Sort Response Control
Unlike some LDAP controls, Server Side Sort does not return a response control. The sorting is applied directly to the search results returned in the normal search response. If sorting fails or is not supported for a particular attribute, the results may be returned unsorted, but no error is typically generated.
Integration with Other Controls
Server Side Sort Control works seamlessly with other LDAP controls:
Paged Results: Sorting is applied first, then paging is applied to the sorted results
Virtual List View (VLV): VLV requires a sort control to be present (RFC 2891)
Size Limit: Size limits are applied after sorting
Example with VLV:
# Sort control is required for VLV
sort_control = LDAPControl('1.2.840.113556.1.4.473', True, encoded_sort_value)
# VLV control for pagination
vlv_control = LDAPControl(
'2.16.840.1.113730.3.4.9',
True,
"1,1,5".encode('utf-8') # 1 before, 1 after, target position 5
)
# Perform sorted VLV search
msgid = conn.search_ext(
'ou=users,dc=example,dc=com',
ldap.SCOPE_SUBTREE,
'(objectClass=person)',
serverctrls=[sort_control, vlv_control]
)
Edge Cases
Missing attributes: Entries without the sort attribute are placed at the beginning of the sorted results
Case sensitivity: Sorting is performed case-insensitively on string attributes
Multi-valued attributes: Only the first value of multi-valued attributes is used for sorting
Invalid sort keys: Malformed BER encoding or unknown attributes in sort keys are handled gracefully, with results potentially returned unsorted
Empty result sets: Sort controls are processed normally even when no results match the search filter
Virtual List View (VLV) Control Support
Virtual List View (VLV) is an LDAP control extension that provides efficient pagination of large result sets. It allows clients to request a specific “window” of results around a target position, which is particularly useful for implementing pagination in user interfaces.
VLV is supported out of the box in python-ldap-faker and is automatically advertised in the Root DSE when clients query for supported controls.
VLV Request Control
The VLV request control (OID: 2.16.840.1.113730.3.4.9) allows clients to specify:
beforeCount: Number of entries to return before the target position
afterCount: Number of entries to return after the target position
target: The target position (0-based index) in the result set
contextID: Optional context identifier for maintaining state
Example usage:
import ldap
from ldap.controls import LDAPControl
# Create VLV control: get 1 entry before and after position 1
vlv_value = "1,1,1".encode('utf-8')
vlv_control = LDAPControl(
'2.16.840.1.113730.3.4.9',
True,
vlv_value,
)
# Perform VLV search
msgid = conn.search_ext(
'dc=example,dc=com',
ldap.SCOPE_SUBTREE,
'(objectClass=person)',
serverctrls=[vlv_control]
)
# Get results
rtype, rdata, rmsgid, rctrls = conn.result3(msgid)
VLV Response Control
The VLV response control (OID: 2.16.840.1.113730.3.4.10) is automatically
returned with VLV search results and contains:
targetPosition: The actual target position used (may be adjusted if requested position was beyond available entries)
contentCount: Total number of entries in the result set
contextID: The context identifier if one was provided
The response control value is encoded as a comma-separated string: "targetPosition,contentCount".
Edge Cases
Target beyond available entries: If the requested target position is beyond the available entries, the target is clamped to the last valid position
Empty result sets: VLV response control is still returned with target position 0 and content count 0
Invalid control values: Malformed VLV control values are handled gracefully