Closed johannes-michael closed 1 year ago
I am not that deep into this topic, so this might not be completely accurate.
The OBJECT_DEF
is the LDAP objectClass
to look for (e.g. person
, inetOrgPerson
, User
, ...). The objectClass is an attribute of the LDAP object, one entry could have multiple objectClasses.
I think using a wild-card objectclass=*
or leaving it empty is not possible in SampleDB, so you might need to figure out a correct objectClass
to search for in your LDAP, e.g. by browsing the LDAP/having a look at a user object.
The uid
filter looks fine to me if the uid should be used for login.
The other configuration looks good at first glance.
Ok I figured out that the objectClass
is person
, but LDAP login still won't work. Maybe it has to do with formatting, in how SampleDB expects the variables to be set, but the documentation is not detailed enough in that regard.
I can get LDAP to work perfectly fine in a python script using this setup, but SampleDB does not work. Are there any log files one could look at? Or maybe someone can post their working version to compare against.
@johannes-michael Here is a simplified version (I mostly just removed captching exceptions and replaced checks that simply return False
if they fail with asserts, to help find the issue) of the LDAP code. I hope this helps you find the issue, as your configuration looks correct to me. Please try this code with your configuration and let me know whether that helps or you are still running into issues.
import typing
import ldap3
import ldap3.core.exceptions
import ldap3.utils.conv
LDAP_SERVER = ...
CONNECT_TIMEOUT = ...
LDAP_USER_BASE_DN = ...
LDAP_UID_FILTER = ...
LDAP_OBJECT_DEF = ...
LDAP_USER_DN = ...
LDAP_PASSWORD = ...
LDAP_MAIL_ATTRIBUTE = ...
user_ldap_uid = ...
password = ...
def _get_ldap_server_pool() -> ldap3.ServerPool:
ldap_server_urls = LDAP_SERVER
connect_timeout = CONNECT_TIMEOUT
servers = []
for ldap_server_url in ldap_server_urls.split(','):
ldap_server_url = ldap_server_url.strip()
if ldap_server_url:
servers.append(ldap3.Server(ldap_server_url, use_ssl=True, get_info=ldap3.ALL, connect_timeout=connect_timeout))
return ldap3.ServerPool(servers=servers, pool_strategy=ldap3.ROUND_ROBIN, active=True, exhaust=True)
def _get_user_dn_and_attributes(user_ldap_uid: str, attributes: typing.Sequence[str] = ()) -> typing.Optional[typing.Sequence[typing.Any]]:
user_base_dn = LDAP_USER_BASE_DN
uid_filter = LDAP_UID_FILTER
object_def = LDAP_OBJECT_DEF
user_dn = LDAP_USER_DN
password = LDAP_PASSWORD
server_pool = _get_ldap_server_pool()
connection = ldap3.Connection(server_pool, user=user_dn, password=password, auto_bind=ldap3.AUTO_BIND_NO_TLS, client_strategy=ldap3.SAFE_SYNC)
object_def = ldap3.ObjectDef(object_def, connection)
reader = ldap3.Reader(connection, object_def, user_base_dn, uid_filter.format(ldap3.utils.conv.escape_filter_chars(user_ldap_uid)))
reader.search(attributes)
# search if uid matches exactly one user, not more
if len(reader) != 1:
return None
user_attributes = [reader[0].entry_dn]
for attribute in attributes:
value = getattr(reader[0], attribute, None)
if value:
user_attributes.append(value[0])
else:
user_attributes.append(None)
return user_attributes
mail_attribute = LDAP_MAIL_ATTRIBUTE
user = _get_user_dn_and_attributes(user_ldap_uid, [mail_attribute])
assert user
user_dn, mail = user
assert mail
# try to bind with user credentials if a matching user exists
server_pool = _get_ldap_server_pool()
connection = ldap3.Connection(server_pool, user=user_dn, password=password, client_strategy=ldap3.SAFE_SYNC)
assert bool(connection.bind()[0])
Thanks for in the input. I figured it out. There were two problems.
I played around with your simplified version and also had a closer look at the objectClass
. Turns out, the mail
attribute is for some reason not part of the object class person
in my case. I needed to set it to organizationalPerson
. Due to this, I also needed to change the name attribute, since gecos
is not part of organizationalPerson
. I just used cn
instead.
Secondly, and this is a really dumb mistake, because I haven't worked with Docker a lot, the environment variables in the docker-compose.yml
can not be quoted. As can be seen in my original post, I quoted some variables that contained spaces or other equal signs.
Now the LDAP login works as expected. Here is the docker-compose.yml
excerpt from the final working example:
container_name: sampledb
environment:
# LDAP settings
- SAMPLEDB_LDAP_NAME=LDAP University of Rostock
- SAMPLEDB_LDAP_SERVER=ldaps://my.ldap.server
- SAMPLEDB_LDAP_CONNECT_TIMEOUT=10
- SAMPLEDB_LDAP_USER_BASE_DN=ou=people,o=uni-rostock,c=de
- SAMPLEDB_LDAP_UID_FILTER=(uid={})
- SAMPLEDB_LDAP_NAME_ATTRIBUTE=cn
- SAMPLEDB_LDAP_MAIL_ATTRIBUTE=mail
- SAMPLEDB_LDAP_OBJECT_DEF=organizationalPerson
- SAMPLEDB_LDAP_USER_DN=uid=myreader,ou=proxies,o=uni-rostock,c=de
- SAMPLEDB_LDAP_PASSWORD=<REDACTED>
Closing.
Good to hear! If you encounter further issues or need help setting up actions/schemas, let us know.
I can't seem to get LDAP to work. It certainly has to do with the configuration. Maybe someone can help me out.
This is my current configuration:
I'm not entirely sure what to set for UID_FILTER and OBJECT_DEF. I'm used to just providing the LDAP Server, the user for the search, the base_dn and the uid attribute (which is 'uid' in my case). Also, should the server address contain the "ldaps://" prefix?