Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

LDAP Configuration doesn't pick up AUTH_LDAP_USER_SEARCH correctly. #25

Open
the-maldridge opened this issue Jan 20, 2023 · 15 comments
Open
Assignees

Comments

@the-maldridge
Copy link

I am trying to debug LDAP configuration for allowing users to sign in with single sign on. My LDAP server is OpenLDAP with base schemas available for posixAccount and InetOrgPerson, which should be sufficient. SSO from netbox to ldap works, so I know it is possible to get django-auth-ldap to be happy with this setup at the least.

I added the following lines to my environment file to configure ldap, and changed the tag on the pulled image to be the ldap one:

AUTH_LDAP_ATTR_FIRSTNAME: "cn"
AUTH_LDAP_GROUP_SEARCH_BASEDN: "dc=example,dc=com"
AUTH_LDAP_GROUP_SEARCH_CLASS: "groupOfNames"
AUTH_LDAP_GROUP_TYPE: "GroupOfNamesType"
AUTH_LDAP_IS_ADMIN_DN: "cn=netbox_admin,ou=group,dc=example,dc=com"
AUTH_LDAP_IS_SUPERUSER_DN: "cn=netbox_admin,ou=group,dc=example,dc=com"
AUTH_LDAP_MIRROR_GROUPS: "true"
AUTH_LDAP_REQUIRE_GROUP_DN: "cn=netbox_ro,ou=group,dc=example,dc=com"
AUTH_LDAP_SERVER_URI: "ldaps://ldap.example.com"
AUTH_LDAP_START_TLS: "false"
AUTH_LDAP_USER_SEARCH_BASEDN: "ou=people,dc=example,dc=com"
AUTH_LDAP_USER_SEARCH_ATTR: "uid"
AUTH_LDAP_USER_DN_TEMPLATE: "uid=%(user)s,ou=people,dc=example,dc=com"
AUTH_LDAP_BIND_AS_AUTHENTICATING_USER: "true"

I reliably get the error message that AUTH_LDAP_USER_SEARCH is not an instance of LDAPSearch:

image

However when I check the type of that config attribute via a manage.py shell, the type is clearly LDAPSearch:

>>> type(_loaded_configurations[1].AUTH_LDAP_USER_SEARCH)
<class 'django_auth_ldap.config.LDAPSearch'>

I'm at my whit's end here for what could still be preventing this from working, is there something I've just missed?

@gmazoyer
Copy link
Member

gmazoyer commented Feb 6, 2023

Did you try to enable django ldap logging to see if it gives something, with a config like (see also logging.py)?

LOGGING = {
    "version": 1,
    "formatters": {
        "simple": {
            "format": "%(asctime)s | %(levelname)s | %(message)s",
            "datefmt": "%Y-%m-%d %H:%M:%S",
        }
    },
    "handlers": {"console": {"class": "logging.StreamHandler", "formatter": "simple"}},
    "loggers": {
        "django_auth_ldap": {"handlers": ["console"], "level": "DEBUG"},
    },
}

@the-maldridge
Copy link
Author

Hmm, I have not yet attempted to do this inside the container as I couldn't come up with a good way to configure logging inside. Is there some trick to setting up logging or should I just exec in and edit the file?

@gmazoyer
Copy link
Member

gmazoyer commented Feb 6, 2023

The file should be mounted in the container if you use the docker compose base setup. Just editing it and restarting the containers should be enough.

@the-maldridge
Copy link
Author

Ah, I am deploying the containers via another mechanism. I'll just exec in and make an edit, will likely be tomorrow though before I can mess with this again though.

@the-maldridge
Copy link
Author

Doesn't look like that has made any change. I ported all my ldap config down to the docker-compose environment so I could debug more easily. This is what the log shows for my login attempt:

peering-manager-docker-peering-manager-1  | 2023/02/08 20:15:33 [info] 40#40 "peeringmanager" application started
peering-manager-docker-peering-manager-1  | 172.22.0.1 - - [08/Feb/2023:20:15:33 +0000] "GET /login/?next=/ HTTP/1.1" 200 3280 "http://localhost:8080/" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36"
peering-manager-docker-peering-manager-1  | 2023-02-08 20:15:40 | WARNING | AUTH_LDAP_USER_SEARCH must be an LDAPSearch instance. while authenticating maldridge
peering-manager-docker-peering-manager-1  | AUTH_LDAP_USER_SEARCH must be an LDAPSearch instance. while authenticating maldridge
peering-manager-docker-peering-manager-1  | 172.22.0.1 - - [08/Feb/2023:20:15:40 +0000] "POST /login/ HTTP/1.1" 500 1261 "http://localhost:8080/login/?next=/" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36"

Anything else I need to do to make logging work in the compose environment?

@gmazoyer
Copy link
Member

gmazoyer commented Feb 8, 2023

Do you see some lines like Loaded config <path to file> in your docker logs?
Did you mount all the configuration directory like it's done in the docker compose example ./configuration:/etc/peering-manager/config?

@the-maldridge
Copy link
Author

the-maldridge commented Feb 8, 2023 via email

@gmazoyer
Copy link
Member

gmazoyer commented Feb 9, 2023

Too bad it does not log anything then :/

Did you try to inspect via manage.py shell the actual variables that are in the settings module like the following?

>>> from django.conf import settings
>>> settings.VERSION
'v1.7.4'
>>> settings.LDAP_CONFIGURED
True
>>> settings.AUTH_LDAP_USER_SEARCH
...

@the-maldridge
Copy link
Author

Well, that looks like a smoking gun to me:

$ docker compose exec -it peering-manager /bin/sh
/opt/peering-manager $ . venv/bin/activate
(venv) /opt/peering-manager $ ./manage.py shell
⚙️  Loaded config '/etc/peering-manager/config/configuration.py'
⚙️  Loaded config '/etc/peering-manager/config/extra.py'
⚙️  Loaded config '/etc/peering-manager/config/logging.py'
⚙️  Loaded config '/etc/peering-manager/config/ldap/ldap_config.py'
⚙️  Loaded config '/etc/peering-manager/config/ldap/extra.py'
Python 3.9.16 (main, Dec 10 2022, 13:47:19) 
[GCC 10.3.1 20210424] on linux
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> from django.conf import settings
>>> settings.VERSION
'v1.7.4'
>>> settings.LDAP_CONFIGURED
True
>>> settings.AUTH_LDAP_USER_SEARCH
Traceback (most recent call last):
  File "<console>", line 1, in <module>
  File "/opt/peering-manager/venv/lib/python3.9/site-packages/django/conf/__init__.py", line 88, in __getattr__
    val = getattr(self._wrapped, name)
AttributeError: 'Settings' object has no attribute 'AUTH_LDAP_USER_SEARCH'

What's curious to me is that in configuration/ldap/ldap_config.py at the root of this repo is the following block:

AUTH_LDAP_USER_SEARCH = LDAPSearch(
    AUTH_LDAP_USER_SEARCH_BASEDN,
    ldap.SCOPE_SUBTREE,
    "(" + AUTH_LDAP_USER_SEARCH_ATTR + "=%(user)s)",
)

This gets installed to /etc/peering-manager/config/ldap/ldap_config.py which then gets read by /opt-peering-manager/peering_manager/ldap_config.py. The value looks pretty clearly defined, so I'm not really seeing why this shouldn't work. In fact all ldap attributes seem to behave this way even though they're set in the environment. This is really behaving like the environment parsing or the loading via this other file is just broken.

@gmazoyer
Copy link
Member

OK so I tried to reproduce your issue and managed to so by using the default setup.

However that's actually weird behaviour. Peering Manager settings load the peering_manager.ldap_config module to know if LDAP is config and imports all variables defined in it. In the container CLI, I can see that the module is there and properly loaded.

(venv) /opt/peering-manager $ python manage.py shell
Python 3.9.16 (main, Dec 10 2022, 13:47:19) 
[GCC 10.3.1 20210424] on linux
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> from peering_manager import ldap_config as l
>>> l.AUTH_LDAP_USER_SEARCH
<LDAPSearch: ou=people,dc=example,dc=com>
>>> 

But for some reason, the main settings module does not pick these settings up.

>>> from django.conf import settings
>>> settings.AUTH_LDAP_USER_SEARCH
Traceback (most recent call last):
  File "<console>", line 1, in <module>
  File "/opt/peering-manager/venv/lib/python3.9/site-packages/django/conf/__init__.py", line 88, in __getattr__
    val = getattr(self._wrapped, name)
AttributeError: 'Settings' object has no attribute 'AUTH_LDAP_USER_SEARCH'
>>>

I either don't know how this work anymore or there is an issue somewhere, well there's obviously an issue somewhere.

@gmazoyer gmazoyer self-assigned this Feb 10, 2023
@the-maldridge
Copy link
Author

At any rate I'm glad this isn't just me having missed something simple. Let me know if there's anything I can do to further assist in troubleshooting.

@madsi1m
Copy link

madsi1m commented Nov 13, 2024

Hi, any fixes or workarounds for this? I seem to be having the same issues.

I've also tried volume mounting directly over /opt/peering-manager/peering_manager/ldap_config.py to see what would happen and it seems when i do this ldap settings are totally ignored as i now get "Please enter a correct username and password. Note that both fields may be case-sensitive."

@madsi1m
Copy link

madsi1m commented Nov 13, 2024

some debug by volume mounting directly over /opt/peering-manager/peering_manager/ldap_config.py to see what would happen

bash-5.1# . venv/bin/activate
(venv) bash-5.1# ./manage.py shell
Python 3.9.17 (main, Jun  9 2023, 02:31:24)
[GCC 10.3.1 20210424] on linux
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> from django.conf import settings
>>> settings.VERSION
'1.8.3'
>>> settings.LDAP_CONFIGURED
True
>>> settings.AUTH_LDAP_USER_SEARCH
<LDAPSearch: ou=people,dc=example,dc=com>

Watching access logs on LDAP I do not see peering-manager hitting it.

Happy to try things if you have suggestions

@madsi1m
Copy link

madsi1m commented Nov 13, 2024

Progress Update + Final Success

Indeed volume mounting/overwriting ldap_config.py to /opt/peering-manager/peering_manager/ldap_config.py makes it take the configs.

Also blink and you miss it, the commented out logging file has 'filters': ['require_debug_false'], on console that blocked debug logs showing in the container logs...

With the above two fixed I was able to see what i needed to adjust in my ldap_config.py to make login work.

@gmazoyer
Copy link
Member

Also blink and you miss it, the commented out logging file has 'filters': ['require_debug_false'], on console that blocked debug logs showing in the container logs...

Nice catch. I completely overlooked this one.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants