Closed abn0mad closed 5 months ago
Hello @abn0mad,
app.schema
appears to be None
. As this is loaded when the client requests api/schema
from the backend, I would assume that the root cause shows up earlier in the log. Could you please check for other exceptions and share the first one if present?
Thanks for the reply @dnknth - much appreciated :)
Indeed the ldap-ui instance cannot access cn=schema. It can only be accessed using the internal ldapi://// ... on the container running the openldap instance. The log indeed immediately shows that 'cn=schema' doesn't exist (although it does, it's just not accessible through DN bind).
I'm by no means a seasoned ldap expert, but from what I can find out on the internet; everyone seems to say the same: don't allow DN bind access to cn=config,cn=schema for security reasons. Is it really necessary for ldap-ui to have that level of access? Isn't the ability to read groups, ou, people etc enough for basic day to day tasks?
If there is no way to configure ldap-ui to operate in such a way at present, might it be an option to add different operational modes to ldap-ui - i.e. 'basic' and 'full' ?
Or should I perhaps look into how I should alter my ACL to allow read-only access...? I did see in settings.py that there is a lookup of cn=subschema, which on my deployment does not seem to exist...
As for the initial exception upon starting ldap-ui and attempting to access it via a browser:
[2024-04-14 05:24:46,737] ERROR in app: Exception on request GET /api/schema
Traceback (most recent call last):
File "/usr/lib/python3.11/site-packages/quart/app.py", line 1396, in handle_request
return await self.full_dispatch_request(request_context)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3.11/site-packages/quart/app.py", line 1434, in full_dispatch_request
result = await self.handle_user_exception(error)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3.11/site-packages/quart/app.py", line 1029, in handle_user_exception
raise error
File "/usr/lib/python3.11/site-packages/quart/app.py", line 1432, in full_dispatch_request
result = await self.dispatch_request(request_context)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3.11/site-packages/quart/app.py", line 1526, in dispatch_request
return await self.ensure_async(handler)(**request_.view_args) # type: ignore
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/app/app.py", line 106, in wrapped_view
resp = await view(**values)
^^^^^^^^^^^^^^^^^^^^
File "/app/app.py", line 120, in wrapped_view
data = await connected(authenticated(view))(**values)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/app/app.py", line 46, in wrapped_view
data = await view(**values)
^^^^^^^^^^^^^^^^^^^^
File "/app/app.py", line 77, in wrapped_view
return await view(**values)
^^^^^^^^^^^^^^^^^^^^
File "/app/app.py", line 560, in schema
_dn, subschema_entry = await unique(
^^^^^^^^^^^^^
File "/app/app.py", line 146, in unique
raise ValueError("Expected unique result")
ValueError: Expected unique result
Hello @abn0mad,
There is no way to use ldap-ui without read-only access to the schema. The software is basically an LDAP editor, and everything it knows about the structure of individual entries in the tree is derived from schema information. I am a bit surprised that even the tree was shown. What's clearly missing is an error message when schema retrieval fails.
I cannot advise on the security aspects of read-only bind access to the schema, but until now people have run into all sorts of pitfalls except this one. At least on Debian (my production box) and Alpine (Docker images) schema read access appears to be enabled by default. Is ldaps://idm.example.com
running just OpenLdap or some customised / hardened setup?
@dnknth - thank you for the prompt reply, again much appreciated.
It is a custom built image based on almalinux running in rootless podman, originally based on the following two guides:
https://tylersguides.com/guides/install-openldap-from-source-on-centos-8/ https://tylersguides.com/guides/configuring-openldap-for-linux-authentication/
So far I've only been using it to get ldap authentication working for a few apps on a vps. There's only one person in the database (me), so I could start over if need be in order to get it to work with ldap-ui.
The deployment is based on this:
dn: cn=config
objectClass: olcGlobal
cn: config
olcArgsFile: /opt/openldap/var/run/slapd.args
olcPidFile: /opt/openldap/var/run/slapd.pid
olcTLSCACertificateFile: /etc/ssl/ca.pem
olcTLSCertificateFile: /etc/ssl/fullchain.pem
olcTLSCertificateKeyFile: /etc/ssl/privkey.pem
olcTLSCipherSuite: TLSv1.2:HIGH:!aNULL:!eNULL
olcTLSProtocolMin: 3.3
dn: cn=schema,cn=config
objectClass: olcSchemaConfig
cn: schema
dn: cn=module,cn=config
objectClass: olcModuleList
cn: module
olcModulepath: /opt/openldap/libexec/openldap
olcModuleload: back_mdb.la
olcModuleload: argon2.la
include: file:///opt/openldap/etc/openldap/schema/core.ldif
include: file:///opt/openldap/etc/openldap/schema/cosine.ldif
include: file:///opt/openldap/etc/openldap/schema/nis.ldif
include: file:///opt/openldap/etc/openldap/schema/inetorgperson.ldif
include: file:///opt/openldap/etc/openldap/schema/dyngroup.ldif
#include: file:///opt/openldap/etc/openldap/schema/ppolicy.ldif
#include: file:///opt/openldap/etc/openldap/schema/openssh-lpk.ldif
dn: olcDatabase=frontend,cn=config
objectClass: olcDatabaseConfig
objectClass: olcFrontendConfig
olcDatabase: frontend
olcPasswordHash: {ARGON2}
olcAccess: to * by dn.base="gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth" manage by * none
dn: olcDatabase=config,cn=config
objectClass: olcDatabaseConfig
olcDatabase: config
olcRootDN: cn=config
olcAccess: to * by dn.base="gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth" manage by * none
rootDN:
dn: olcDatabase=mdb,cn=config
objectClass: olcDatabaseConfig
objectClass: olcMdbConfig
olcDatabase: mdb
olcSuffix: dc=example,dc=com
olcRootDN: cn=admin,dc=example,dc=com
olcRootPW: REPLACE ME WITH $( slappaswd -o module-load=argon2 -h {ARGON2} )
olcDbDirectory: /var/lib/ldap
olcDbIndex: objectClass,uid,uidNumber,gidNumber eq
olcDbMaxSize: 107374182400
olcAccess: to attrs=userPassword
by self write
by anonymous auth
by dn.subtree="gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth" manage
by * none
olcAccess: to attrs=shadowLastChange by self write
by dn.subtree="gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth" manage
by dn.subtree="ou=system,dc=example,dc=com" read
by * none
olcAccess: to dn.subtree="ou=system,dc=example,dc=com" by dn.subtree="gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth" manage
by * none
olcAccess: to dn.subtree="dc=example,dc=com" by dn.subtree="gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth" manage
by users read
by * none
I have hooked up ldap-ui to it using cn=admin,dc=example,dc=com - which does display the basic tree but won't display any details, along with giving an error message right off the bat. I used the admin login as I thought that would be necessary to make any changes to the entries in the database. I do have cn=readonly,ou=system,dc=example,dc=com as well, but from my limited undertanding of ldap, this wouldn't be able to access cn=config,cn=schema any more than cn=admin would in this particular setup ..? (correct me if I'm wrong, you clearly are far more adept at this than I am).
As for error messages; in my previous post I pasted the first error that ldap-ui generates, all other errors are like the one in my first post.
So I guess I should look up how to make cn=schema available read-only to cn=admin,dc=example,dc=com ..?
Hello @abn0mad,
The ACL of olcDatabase=frontend,cn=config
ends with by * none
which prevents read access to the schema by anyone except the local root
user via the ldapi://
protocol. The default Debian configuration explicitly allows it by adding
to dn.base="cn=Subschema" by * read
If you prefer to restrict access to a specific user, replace by * read
with that user's DN like in by dn.exact="cn=admin,dc=example,dc=com" read by * none
, if only authenticated user should be allowed read access, then this is by users read by * none
etc.
I wonder where you may have seen advice that exposing the schema read-only may have security implications? After all it contains structural information that is already widely published, and having that information should gain an adversary nothing if the ACLs prevent access to sensitive information.
@dnknth - again, many thanks for the thorough and helpful reply. :)
(Deeply embarrassed) You're absolutely right. And changing the ACL as you specified did the job. I can now use ldap-ui as intended.
I believe I read it in some old Red Hat and / or IBM posts when I first got started with OpenLDAP. I can't quite remember where: quick, annoyed browsing, skimming text… (More embarrassment…)
Thank you very much for the help, and I do apologise for wasting your time, although it was educational. My hat is off to you, good sir.
Hello @abn0mad,
don't worry, OpenLdap is notorious for complexity. Glad that it works now for you as yours truly intended.
By the way, there should have been a big red "Unknown error" message on page load. Did you see that?
Only if I clicked on Admin, for everything else including first load it was a big yellow / orange-ish bar saying internal server error...
Hi there,
First off, many thanks for your app, a much needed alternative to phpldapadmin etc.
I'm having a bit of trouble with the app...
I have it running in a (rootless) podman container, behind an nginx proxy that provides TLS. I can log in fine and it does display the basic tree, but right of the bat I get the "Internal Server Error" message, which repeats if I click on any entry.
It is connected to an OpenLDAP instance (ldaps://idm.example.com:636)
The console error (edited):
Could you perhaps shed some light on what I should investigate or do next?
Do I need to change settings.py perhaps or update the ldap schema somehow?
I have the LDAP server connected to various apps such as SFTPGo, Forgejo / Gitea, as well as Authelia where it authenticates a planning app called Planka. All of that works fine...