dnknth / ldap-ui

Minimalistic web frontend for OpenLDAP
MIT License
370 stars 28 forks source link

WEB-UI 500 Error #46

Closed Asher9971 closed 11 months ago

Asher9971 commented 12 months ago

After starting the Docker i get a 500 Error in Browser image

/api/whoami:1 Failed to load resource: the server responded with a status of 500 ()

`version: '2' services: openldap: image: bitnami/openldap:2 container_name: openldap ports:

networks: swag_proxy: external: true`

Something can get loaded, because in the tab i can see the icon image

I tried to connect via my swag_proxy network (nginx) also direct via port-mapping on host address. Same problem

Via LdapAdmin i can connect to my ldap without problems.

dnknth commented 12 months ago

Can't say much about your numeric service IP, but the errors look like the UI cannot reach your LDAP directory. Your Docker service is named openldap, so your LDAP_URL should probably be ldap://openldap:1389/. Are there any exceptions visible in the ldap-ui container logs that can help pinpointing the root cause?

Asher9971 commented 12 months ago

Hi, just switched to your suggested ldap_url variable.

Now i get this error in container logs

`[2023-11-09 08:30:15 +0000] [1] [INFO] Running on http://0.0.0.0:5000 (CTRL + C to quit) [2023-11-09 08:30:45 +0000] [1] [INFO] 127.0.0.1:39768 - - [09/Nov/2023:08:30:45 +0000] "GET / 1.1" 200 820 "-" "Wget" [2023-11-09 08:30:59 +0000] [1] [INFO] 172.20.0.13:35132 - - [09/Nov/2023:08:30:59 +0000] "GET / 1.0" 200 820 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36 Edg/118.0.2088.76" [2023-11-09 08:31:00 +0000] [1] [INFO] 172.20.0.13:35134 - - [09/Nov/2023:08:31:00 +0000] "GET /assets/index-5238eac8.js 1.0" 200 104943 "https://ldap-admin.spetzipartie.at/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36 Edg/118.0.2088.76" [2023-11-09 08:31:00 +0000] [1] [INFO] 172.20.0.13:35138 - - [09/Nov/2023:08:31:00 +0000] "GET /assets/index-0ec30a52.css 1.0" 200 45576 "https://ldap-admin.spetzipartie.at/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36 Edg/118.0.2088.76" [2023-11-09 08:31:00 +0000] [1] [INFO] 172.20.0.13:35144 - - [09/Nov/2023:08:31:00 +0000] "GET /api/whoami 1.0" 500 265 "https://ldap-admin.spetzipartie.at/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36 Edg/118.0.2088.76" [2023-11-09 08:31:00,269] ERROR in app: Exception on request GET /api/whoami Traceback (most recent call last): File "/app/app.py", line 32, in wrapped_view request.ldap = ldap.initialize(url) ^^^^^^^^^^^^^^^^^^^^ File "/usr/lib/python3.11/site-packages/ldap/functions.py", line 91, in initialize return LDAPObject( ^^^^^^^^^^^ File "/usr/lib/python3.11/site-packages/ldap/ldapobject.py", line 88, in init self._l = ldap.functions._ldap_function_call(ldap._ldap_module_lock,_ldap.initialize,uri) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/usr/lib/python3.11/site-packages/ldap/functions.py", line 52, in _ldap_function_call result = func(*args,**kwargs) ^^^^^^^^^^^^^^^^^^^^ ldap.LDAPError: (0, 'Error')

During handling of the above exception, another exception occurred:

Traceback (most recent call last): File "/usr/lib/python3.11/site-packages/quart/app.py", line 1489, in handle_request return await self.full_dispatch_request(request_context) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/usr/lib/python3.11/site-packages/quart/app.py", line 1514, in full_dispatch_request result = await self.handle_user_exception(error) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/usr/lib/python3.11/site-packages/quart/app.py", line 964, in handle_user_exception raise error File "/usr/lib/python3.11/site-packages/quart/app.py", line 1512, in full_dispatch_request result = await self.dispatch_request(request_context) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/usr/lib/python3.11/site-packages/quart/app.py", line 1557, in dispatch_request return await self.ensureasync(handler)(**request.view_args) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 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 52, in wrapped_view quart.abort(500, args.get('info', '') ^^^^^^^^ AttributeError: 'int' object has no attribute 'get' [2023-11-09 08:31:00 +0000] [1] [INFO] 172.20.0.13:35154 - - [09/Nov/2023:08:31:00 +0000] "GET /api/schema 1.0" 500 265 "https://ldap-admin.spetzipartie.at/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36 Edg/118.0.2088.76" [2023-11-09 08:31:00,321] ERROR in app: Exception on request GET /api/schema Traceback (most recent call last): File "/app/app.py", line 32, in wrapped_view request.ldap = ldap.initialize(url) ^^^^^^^^^^^^^^^^^^^^ File "/usr/lib/python3.11/site-packages/ldap/functions.py", line 91, in initialize return LDAPObject( ^^^^^^^^^^^ File "/usr/lib/python3.11/site-packages/ldap/ldapobject.py", line 88, in init self._l = ldap.functions._ldap_function_call(ldap._ldap_module_lock,_ldap.initialize,uri) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/usr/lib/python3.11/site-packages/ldap/functions.py", line 52, in _ldap_function_call result = func(*args,**kwargs) ^^^^^^^^^^^^^^^^^^^^ ldap.LDAPError: (0, 'Error')

During handling of the above exception, another exception occurred:

Traceback (most recent call last): File "/usr/lib/python3.11/site-packages/quart/app.py", line 1489, in handle_request return await self.full_dispatch_request(request_context) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/usr/lib/python3.11/site-packages/quart/app.py", line 1514, in full_dispatch_request result = await self.handle_user_exception(error) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/usr/lib/python3.11/site-packages/quart/app.py", line 964, in handle_user_exception raise error File "/usr/lib/python3.11/site-packages/quart/app.py", line 1512, in full_dispatch_request result = await self.dispatch_request(request_context) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/usr/lib/python3.11/site-packages/quart/app.py", line 1557, in dispatch_request return await self.ensureasync(handler)(**request.view_args) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 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 52, in wrapped_view quart.abort(500, args.get('info', '') ^^^^^^^^ AttributeError: 'int' object has no attribute 'get' [2023-11-09 08:31:15 +0000] [1] [INFO] 127.0.0.1:44326 - - [09/Nov/2023:08:31:15 +0000] "GET / 1.1" 200 820 "-" "Wget" [2023-11-09 08:31:45 +0000] [1] [INFO] 127.0.0.1:51084 - - [09/Nov/2023:08:31:45 +0000] "GET / 1.1" 200 820 "-" "Wget" [2023-11-09 08:32:15 +0000] [1] [INFO] 127.0.0.1:53736 - - [09/Nov/2023:08:32:15 +0000] "GET / 1.1" 200 820 "-" "Wget" [2023-11-09 08:32:45 +0000] [1] [INFO] 127.0.0.1:60168 - - [09/Nov/2023:08:32:45 +0000] "GET / 1.1" 200 820 "-" "Wget" `

Same error as i tried it with host-address as ldap_url

dnknth commented 11 months ago

Given a correct LDAP_URL, nothing should go wrong in line 32 of app.py (the root cause in your stack trace). Looking at your docker-compose.yml (without proper indentation), I wonder whether the environment mappings are syntactically correct YAML. It reads:

environment:
  - LDAP_URL="ldap://10.10.50.13:1389"

but this is probably incorrect and should read instead:

environment:
  - LDAP_URL: "ldap://10.10.50.13:1389"

(same for all other environmant settings)

dnknth commented 11 months ago

Closing this due to lack of activity. Feel free to re-open if the issue persists after fixing and linting your YAML.

prannonpendragas commented 11 months ago

Sorry to reopen this, but I've also made an attempt to use the ldap-ui in combination with the bitnami/openldap image, and I think I know what might be happening.

When I launch bitnami/openldap, I tell it to create an admin account. I then set up the ldap-ui image and try to log in. All attempts to log in with my admin account fail repeatedly, and I see these logs in the openldap container.

655d6030.1b1fe655 0x7f434ddc9700 conn=1006 fd=12 ACCEPT from IP=10.244.2.17:46602 (IP=0.0.0.0:1389)
655d6030.1b23357d 0x7f434d5c8700 conn=1006 op=0 SRCH base="dc=example,dc=net" scope=2 deref=0 filter="(cn=admin)"
655d6030.1b298cb4 0x7f434d5c8700 conn=1006 op=0 SEARCH RESULT tag=101 err=0 qtime=0.000026 etime=0.000500 nentries=0 text=
655d6030.1bc51fbb 0x7f434ddc9700 conn=1006 op=1 UNBIND
655d6030.1bc9173c 0x7f434ddc9700 conn=1006 fd=12 closed

But sneakily, the bitnami image will also set up a couple of extra users for fun. I try to log in with one of those (user01 / bitnami1) and it works!

655d610d.08c07191 0x7f434d5c8700 conn=1013 fd=12 ACCEPT from IP=10.244.2.17:54030 (IP=0.0.0.0:1389)
655d610d.08c3d0db 0x7f434ddc9700 conn=1013 op=0 SRCH base="dc=example,dc=net" scope=2 deref=0 filter="(cn=user01)"
655d610d.08ca0425 0x7f434ddc9700 conn=1013 op=0 SEARCH RESULT tag=101 err=0 qtime=0.000027 etime=0.000492 nentries=1 text=
655d610d.09653f69 0x7f434d5c8700 conn=1013 op=1 BIND dn="cn=user01,ou=users,dc=example,dc=net" method=128
655d610d.096754f3 0x7f434d5c8700 conn=1013 op=1 BIND dn="cn=user01,ou=users,dc=example,dc=net" mech=SIMPLE bind_ssf=0 ssf=0
655d610d.09699c9c 0x7f434d5c8700 conn=1013 op=1 RESULT tag=97 err=0 qtime=0.000033 etime=0.000362 text=
655d610d.0a07f6f4 0x7f434ddc9700 conn=1013 op=2 SRCH base="ou=users,dc=example,dc=net" scope=0 deref=0 filter="(objectClass=*)"
655d610d.0a0b84fd 0x7f434ddc9700 conn=1013 op=2 SEARCH RESULT tag=101 err=0 qtime=0.000026 etime=0.000307 nentries=1 text=
655d610d.0aba6c6d 0x7f434d5c8700 conn=1013 op=3 UNBIND

The ldap-ui knows how to search for users in the baseDN, but the admin account isn't the same thing and it doesn't exist under the baseDN in the same way. My guess is that the UI only cares to look for what is under the baseDN and it doesn't know how to authenticate with an admin user.

This seems in line with the app description:

What a particular user can see (and edit) is governed entirely by directory access rules. The app shows the directory contents, nothing less and nothing more.

It'd be nice if we could authenticate with root users, though. Would make this app immediately more handy.

dnknth commented 11 months ago

Fine to reopen it, even for maybe a different reason. What is the admin DN? Could you share a set of container environment variables / compose file or similar to reproduce the issue?

prannonpendragas commented 11 months ago

@dnknth Sure. I'm using kubernetes in my case, and I deploy openldap as a statefulset and the ldap-ui as a replicaset.

Here's the openldap:

kind: StatefulSet
apiVersion: apps/v1
metadata:
  name: openldap-server
  namespace: openldap
  labels:
    app.kubernetes.io/part-of: openldap
    app.kubernetes.io/name: openldap-server
    app.kubernetes.io/component: server
spec:
  selector:
    matchLabels:
      app.kubernetes.io/part-of: openldap
      app.kubernetes.io/name: openldap-server
      app.kubernetes.io/component: server
  replicas: 1
  template:
    metadata:
      labels:
        app.kubernetes.io/part-of: openldap
        app.kubernetes.io/name: openldap-server
        app.kubernetes.io/component: server
    spec:
      containers:
        - name: openldap
          env:
            - name: LDAP_ADMIN_USERNAME
              value: "admin"
            - name: LDAP_ADMIN_PASSWORD
              value: "adminpassword"
            - name: LDAP_ROOT
              value: "dc=example,dc=net"
          image: bitnami/openldap:2.5.16
          ports:
            - containerPort: 1389
              name: openldap

And here's the ldap-ui.

kind: ReplicaSet
apiVersion: apps/v1
metadata:
  name: ldap-ui
  namespace: openldap
  labels:
    app.kubernetes.io/part-of: openldap
    app.kubernetes.io/name: ldap-ui
    app.kubernetes.io/component: ui
spec:
  selector:
    matchLabels:
      app.kubernetes.io/part-of: openldap
      app.kubernetes.io/name: ldap-ui
      app.kubernetes.io/component: ui
  replicas: 1
  template:
    metadata:
      labels:
        app.kubernetes.io/part-of: openldap
        app.kubernetes.io/name: ldap-ui
        app.kubernetes.io/component: ui
    spec:
      containers:
        - name: ldap-ui
          env:
            - name: LDAP_URL
              value: "ldap://openldap-server.openldap.svc.cluster.local:1389"
            - name: BASE_DN
              value: "dc=example,dc=net"
            - name: LOGIN_ATTR
              value: "cn"
          image: dnknth/ldap-ui:latest-x86_64
          ports:
            - containerPort: 5000
              name: ldap-ui

And here are a couple of services that allow the ui to access the server, and also allow external access to the ui.

---
apiVersion: v1
kind: Service
metadata:
  labels:
    app.kubernetes.io/part-of: openldap
    app.kubernetes.io/name: openldap-server
    app.kubernetes.io/component: service
  name: openldap-server
  namespace: openldap
spec:
  ports:
  - name: openldap
    port: 1389
    protocol: TCP
    targetPort: openldap
  selector:
    app.kubernetes.io/name: openldap-server
    app.kubernetes.io/component: server
  type: ClusterIP
---
apiVersion: v1
kind: Service
metadata:
  labels:
    app.kubernetes.io/part-of: openldap
    app.kubernetes.io/name: ldap-ui
    app.kubernetes.io/component: service
  name: ldap-ui
  namespace: openldap
spec:
  ports:
  - name: http
    nodePort: 31500
    port: 5000
    protocol: TCP
    targetPort: ldap-ui
  selector:
    app.kubernetes.io/name: ldap-ui
    app.kubernetes.io/component: ui
  type: NodePort

This will set up the openldap server with the admin DN of cn=admin,dc=example,dc=net. Here's the code from the bitnami image powering this behavior: https://github.com/bitnami/containers/blob/83c4e509ec5796473828148f77b8e49ea8733622/bitnami/openldap/2.6/debian-11/rootfs/opt/bitnami/scripts/libopenldap.sh#L379

Provided everything is set up correctly, you should be able to get to the UI on http://${any ip of your cluster}:31500, and you will find that you can log in with user01 / bitnami1 and that you cannot log in with admin / adminpassword.

dnknth commented 11 months ago

Hello @prannonpendragas,

I can reproduce the issue with your environment, what exactly do you mean by 'root' user authentication? If it depends on any kind of SASL mechanism, that's not supported at present, see the README.

prannonpendragas commented 11 months ago

@dnknth Glad you could reproduce!

To be honest, I'm less familiar with the auth mechanisms in openldap, at least when you use terms like SASL.

My use case here was to set up an openldap server to store users and authorities for a system I'm building. I did not want to set up users or groups or authorities with LDIFs though, since I'm committing everything to a git repo and don't want to put in passwords or usernames beyond an initial bootstrapping user.

Since bitnami can set up an initial admin user, I figured that with a UI I could manage sensitive information by hand from there. As you note, phpldapadmin is ancient and unmaintained, and I found the ldap-ui and decided to give it a try.

If it's not supported, then it's not supported, but it would be nice to be able to log in with an initial user like this.

dnknth commented 11 months ago

@prannonpendragas, how do you normally authenticate as a root user?

prannonpendragas commented 11 months ago

@dnknth So, let's say that I set up my openldap server as above, with the LDAP_ADMIN_USERNAME and LDAP_ADMIN_PASSWORD variables defined. When the image launches, it will create a user called - for instance - "cn=admin,dc=example,dc=net" with the password "adminpassword."

Now let's say that I use ldapsearch to authenticate to the server. I can use a command like this from within the container, hitting the non-privileged port:

ldapsearch -H ldap://:1389/ -D "cn=admin,dc=example,dc=net" -w "adminpassword" -b "dc=example,dc=net"

I then get a directory listing of everything in the baseDN, and since this is my admin user I should have access to create and modify literally anything within this instance. "cn=admin,dc=example,dc=net" is my "root" user, and I'm using a simple bind to authenticate.

The openldap server records my bind like so in the logs:

655e79a7.108ffb4e 0x7f3a210e7700 conn=1009 fd=12 ACCEPT from IP=[::1]:35264 (IP=[::]:1389)
655e79a7.1091fd48 0x7f3a218e8700 conn=1009 op=0 BIND dn="cn=admin,dc=example,dc=net" method=128
655e79a7.1093079a 0x7f3a218e8700 conn=1009 op=0 BIND dn="cn=admin,dc=example,dc=net" mech=SIMPLE bind_ssf=0 ssf=0
655e79a7.109444a3 0x7f3a218e8700 conn=1009 op=0 RESULT tag=97 err=0 qtime=0.000026 etime=0.000228 text=
655e79a7.1096a076 0x7f3a210e7700 conn=1009 op=1 SRCH base="dc=example,dc=net" scope=2 deref=0 filter="(objectClass=*)"
655e79a7.109a14d3 0x7f3a210e7700 conn=1009 op=1 SEARCH RESULT tag=101 err=0 qtime=0.000010 etime=0.000251 nentries=5 text=
655e79a7.109f5979 0x7f3a218e8700 conn=1009 op=2 UNBIND
655e79a7.10a0cf2d 0x7f3a218e8700 conn=1009 fd=12 closed

If I install a phpldapadmin container in place of ldap-ui, I see similar behavior.

655e79ea.28216b19 0x7f3a210e7700 conn=1010 fd=12 ACCEPT from IP=10.244.0.11:36136 (IP=0.0.0.0:1389)
655e79ea.2823eb16 0x7f3a218e8700 conn=1010 op=0 BIND dn="cn=admin,dc=example,dc=net" method=128
655e79ea.28258bff 0x7f3a218e8700 conn=1010 op=0 BIND dn="cn=admin,dc=example,dc=net" mech=SIMPLE bind_ssf=0 ssf=0
655e79ea.2827b35a 0x7f3a218e8700 conn=1010 op=0 RESULT tag=97 err=0 qtime=0.000025 etime=0.000327 text=
655e79ea.2836a5f4 0x7f3a210e7700 conn=1010 op=1 UNBIND

Contrast this with the behavior of ldap-ui, which seems to perform a SRCH action against the baseDN for the user I'm trying to log in as.

655d6030.1b1fe655 0x7f434ddc9700 conn=1006 fd=12 ACCEPT from IP=10.244.2.17:46602 (IP=0.0.0.0:1389)
655d6030.1b23357d 0x7f434d5c8700 conn=1006 op=0 SRCH base="dc=example,dc=net" scope=2 deref=0 filter="(cn=admin)"
655d6030.1b298cb4 0x7f434d5c8700 conn=1006 op=0 SEARCH RESULT tag=101 err=0 qtime=0.000026 etime=0.000500 nentries=0 text=
655d6030.1bc51fbb 0x7f434ddc9700 conn=1006 op=1 UNBIND
655d6030.1bc9173c 0x7f434ddc9700 conn=1006 fd=12 closed

This works for any user that exists within the directory structure of openldap, but it doesn't work for the openldap admin user which exists within the olcDatabase={2}mdb,cn=config schema in this setup.

Does this answer the question?

dnknth commented 11 months ago

Hello @prannonpendragas,

How did phpldapadmin guess the bind DN without searching? Did you specify it in full or is some configuration voodoo involved? Just asking because you could always use a BIND_PATTERN, in which case no search is made. See subsection (2) under "Authentication methods" in the README for an explanation.

prannonpendragas commented 11 months ago

@dnknth I specify the full DN. I'll give BIND_PATTERN a try and see if it addresses the issue!

dnknth commented 11 months ago

If you are fine with specifying the full DN for every user, just set BIND_PATTERN to %s. This should give you the same behaviour as with phpldapadmin.

prannonpendragas commented 11 months ago

That worked! The following environment variables got me to the desired behavior:

        - name: ldap-ui
          env:
            - name: LDAP_URL
              value: "ldap://openldap-server.openldap.svc.cluster.local:1389"
            - name: BASE_DN
              value: "dc=example,dc=net"
            - name: BIND_PATTERN
              value: "cn=%s,dc=example,dc=net"

Serves me right for not reading the README fully. Thanks for your help. :)