python-ldapserver issueshttps://git.cccv.de/uffd/python-ldapserver/-/issues2023-11-04T13:00:41Zhttps://git.cccv.de/uffd/python-ldapserver/-/issues/22Integer pagination cookies can cause issues with buggy client software2023-11-04T13:00:41ZRuss GarrettInteger pagination cookies can cause issues with buggy client softwareThis is not really a bug in python-ldapserver but it might be worth fixing to avoid future pain...
We've been trying to get a piece of software running with uffd-ldapd and we were seeing weird LDAP sync issues. The software was only fet...This is not really a bug in python-ldapserver but it might be worth fixing to avoid future pain...
We've been trying to get a piece of software running with uffd-ldapd and we were seeing weird LDAP sync issues. The software was only fetching the first 50 users (which was not immediately obvious as we don't have loads more than 50 users).
It turns out the software, which is written in PHP, was calling `empty()` to check if a pagination cookie existed. And of course `empty('0') == true` 🙃.
It might be worth making the pagination cookie "more opaque" by prepending a fixed string to defend against hitting these kind of time-consuming bugs in other software.https://git.cccv.de/uffd/python-ldapserver/-/issues/20Prohibited character behaviour in stringprep/string matching differs in OpenLDAP2021-12-05T02:42:44ZJulianProhibited character behaviour in stringprep/string matching differs in OpenLDAPOpenLDAP matches attribute values with (at least some) prohibited characters in searches as if these characters were not prohibited. python-ldapserver strictly implements RFC4510 and consequently rejects (in case of matching: ignores) su...OpenLDAP matches attribute values with (at least some) prohibited characters in searches as if these characters were not prohibited. python-ldapserver strictly implements RFC4510 and consequently rejects (in case of matching: ignores) such values.
E.g. an entry with the `cn` value "foo" followed by `U+1D25` (part of A.1, unassigned code points) matches the search filter `(cn=foo*)` with OpenLDAP but not with an LDAP server based on python-ldapserver.
We should investigate why that is.https://git.cccv.de/uffd/python-ldapserver/-/issues/19Honor timeLimit on SEARCH requests2021-12-02T21:22:37ZJulianHonor timeLimit on SEARCH requestsSplit off from #14, not sure if we want to implement this.Split off from #14, not sure if we want to implement this.https://git.cccv.de/uffd/python-ldapserver/-/issues/18Evaluate decorator/Flask-like API2021-12-02T16:21:43ZJulianEvaluate decorator/Flask-like APISome ideas for a cleaner API.
The current API is based on subclassing LDAPRequestHandler and implementing/overwriting the methods you need.
In case of optional features (SASL auth, extension support), this requires setting both overwrit...Some ideas for a cleaner API.
The current API is based on subclassing LDAPRequestHandler and implementing/overwriting the methods you need.
In case of optional features (SASL auth, extension support), this requires setting both overwriting the method and setting a feature flag.
A decorator-based approach for registering handlers seems more powerful and more intuitive:
```python
server = ldapserver.Server(ldapserver.schema.RFC2307BIS_SCHEMA)
@server.bind_sasl_plain
def bind_sasl_plain(identity, password, authzid=None):
pass # ...
@server.bind_sasl('CUSTOM')
def bind_sasl_custom(mechanism, credentials=None, dn=None):
pass # ...
@server.extended('1.3.6.1.4.1.4203.1.11.3')
def who_am_i(value=None):
return b'foobar'
```
Decorators could also be used for entry objects to implement e.g. BIND locally for a specific object or a group of objects:
```python
service = server.add_entry('cn=service,ou=system,dc=example,dc=com',
objectclass=['top', 'organizationalRole', 'simpleSecurityObject'],
structuralObjectClass=['organizationalRole'])
@service.bind
def service_bind(password):
if password == bind_password:
return
raise LDAPInvalidCredentials()
```
Templating could be extended with a custom DSL similar to Python format strings:
```python
@server.template('uid={loginname},ou=users,dc=example,dc=com',
structuralObjectClass=['inetorgperson'],
objectClass=['top', 'inetorgperson', 'organizationalperson', 'person', 'posixaccount'],
sn=[' '],
cn=['{displayname}'],
displayname=['{displayname}'],
givenname=['{displayname}'],
homeDirectory=['/home/{loginname}'],
mail=['{email}'],
uid=['{loginname}'],
uidNumber=['{uid}'],
memberOf=['cn={*group_names},ou=groups,dc=example,dc=com'])
# Decorators could be used in a Flask-like fasion to add ACL checks to lookup functions
@ldapserver.disallow_unauthenticated
def users(loginname=None, uid=None, group_names=None, **kwargs):
request_params = {}
if not request_params and loginname is not None:
request_params = {'loginname': normalize_user_loginname(loginname)}
if not request_params and uid is not None:
request_params = {'id': uid}
if not request_params and group_names:
request_params = {'group': normalize_group_name(group_names[0])}
for user in api.get_users(**request_params):
yield users.create(loginname=user['loginname'], displayname=user['displayname'],
email=user['email'], uid=user['id'], groups=user['groups'])
@users.bind
def users_bind(entry, password):
if api.check_password(loginname=entry['uid'][0], password=password):
return
raise LDAPInvalidCredentials()
```https://git.cccv.de/uffd/python-ldapserver/-/issues/17Support RFC4529 "Requesting Attributes by Object Class"2021-11-17T19:56:49ZJulianSupport RFC4529 "Requesting Attributes by Object Class"Select all MAY and MUST attribute types of an object class with `@<objectclass>`.
Supported by OpenLDAP. Relativly easy to implement in our current architecture. Probably not used much.Select all MAY and MUST attribute types of an object class with `@<objectclass>`.
Supported by OpenLDAP. Relativly easy to implement in our current architecture. Probably not used much.https://git.cccv.de/uffd/python-ldapserver/-/issues/13Intro/howto documentation2021-11-14T22:27:23ZJulianIntro/howto documentationGuide on writing LDAP servers based on this library.Guide on writing LDAP servers based on this library.https://git.cccv.de/uffd/python-ldapserver/-/issues/12Tests for ObjectClassDefinition class2021-11-14T22:12:26ZJulianTests for ObjectClassDefinition classhttps://git.cccv.de/uffd/python-ldapserver/-/issues/11Tests for AttributeTypeDefinition class2021-11-14T22:12:08ZJulianTests for AttributeTypeDefinition classhttps://git.cccv.de/uffd/python-ldapserver/-/issues/9Make asn.1/ldap protocol objects comparable2021-11-14T22:15:27ZJulianMake asn.1/ldap protocol objects comparableThis would simplify unit testsThis would simplify unit testshttps://git.cccv.de/uffd/python-ldapserver/-/issues/8Binary Encoding Option (RFC4522)2021-11-17T01:01:41ZJulianBinary Encoding Option (RFC4522)Clients might expect this (mostly) legacy attribute type option to work, i.e. they might try to request `userPassword` with `userPassword;binary`. Since there are not many binary attribute types (userPassword and some public key/certific...Clients might expect this (mostly) legacy attribute type option to work, i.e. they might try to request `userPassword` with `userPassword;binary`. Since there are not many binary attribute types (userPassword and some public key/certificate stuff) implementing this is not a priority.
https://www.rfc-editor.org/rfc/rfc4522.htmlhttps://git.cccv.de/uffd/python-ldapserver/-/issues/5Consider switch to asyncio2021-10-19T10:07:28ZJulianConsider switch to asyncioMost of the request handling is already iterator-based, so this should be easy to do.Most of the request handling is already iterator-based, so this should be easy to do.https://git.cccv.de/uffd/python-ldapserver/-/issues/2Naming in LDAP protocol classes2021-07-28T19:29:10ZJulianNaming in LDAP protocol classesClass/instance attributes and enum values are mostly named after the ASN.1 descriptions used in RFC4511. This is not consistent (e.g. in the Filter classes). Also the names from the ASN.1 descriptions are pretty ugly in some cases (e.g. ...Class/instance attributes and enum values are mostly named after the ASN.1 descriptions used in RFC4511. This is not consistent (e.g. in the Filter classes). Also the names from the ASN.1 descriptions are pretty ugly in some cases (e.g. `ModifyDNRequest.deleteoldrdn`) and generally inconsistent with the rest of the codebase (cameCase in place of snake_style for attributes and cameCase in place of UPPER_CASE in enum values).
- [ ] Decide on whether to stick with the ASN.1 names
- [ ] Make nameing consistent
- [ ] Depending on the choice: Reenable linter warnings
- [ ] Add missing instance attribute type annotations for all LDAP classes