jupyterhub / ldapauthenticator

LDAP Authenticator Plugin for Jupyter
BSD 3-Clause "New" or "Revised" License
206 stars 178 forks source link

Escape username within DN correctly and remove `escape_userdn` #267

Closed consideRatio closed 2 months ago

consideRatio commented 2 months ago

Background

Why escape_userdn was introduced

escape_userdn was introduced after a non-conclusive discussion in https://github.com/jupyterhub/ldapauthenticator/pull/32#pullrequestreview-26048588, where it made things break for some, and fixed things for others.

I think that was a fluke related to other issues, such as using the userdn variable both in a binding operation and in other operations where it was part of a search filter. When a DN is part of a search filter as a value to find, it should be escaped with escape_filter_chars. With #238, we are good at using escape_filter_chars just-in-time where its needed.

Prevent LDAP injections and the escape_rdn function

The config valid_username_regex was this projects key defence for LDAP injection attacks, but since it was introduced there is now a escape_rdn function to help escaping usernames given to be part of a DN via bind_dn_template strings. This is stressed as important in the ldap3 Python package's docs:

image

What should be escaped?

PR changes

EDIT: Breaking change

This PR introduced a breaking change in a edge case scenario if both...

Then, these users' resulting JupyterHub usernames would be changed from looking like "lastname\\, firstname" to "lastname, firstname".

Related

consideRatio commented 2 months ago

@m-erhardt, @Nikolai-Hlubek, @manics, @minrk if you have capacity to review this a bit, I'd greatly appreciate it - this isn't a PR I feel comfortable merging without further input.

I think this is a crucial fix for the reliability and long term maintenance of this project, but I've not really tested the behavior changes from this change in any other setup than the CI system which doesn't have great coverage of configurations and LDAP servers.

consideRatio commented 2 months ago

(Rebased on main)

consideRatio commented 2 months ago

Going for a merge and aiming for this to be available to test practically in a beta release

Nikolai-Hlubek commented 1 month ago

@consideRatio Sorry for the late reply. I don't know about LDAP so I can only check the logic of the changes. I noticed two things which I wrote comments about, in the commit.

m-erhardt commented 1 month ago

I know, I'm a little late to the party. Unfortunatley I've been quite busy for the past weeks and had no capacity to dig into this.

As more testing/validation certainly wont hurt before the release of 2.0.0 I've just validated this change by testing the current version from the main-branch (0c65788) on our production system against our ActiveDirectory with the following (unchanged) config.

c.JupyterHub.authenticator_class = 'ldapauthenticator.LDAPAuthenticator'

c.LDAPAuthenticator.server_address = 'our.companys.ldap.server'
c.LDAPAuthenticator.server_port = 636
c.LDAPAuthenticator.use_ssl = True

c.LDAPAuthenticator.lookup_dn = True
c.LDAPAuthenticator.lookup_dn_search_filter = '({login_attr}={login})'
c.LDAPAuthenticator.lookup_dn_search_user = 'CN=jupyter.bind,OU=Users,DC=our,DC=company'
c.LDAPAuthenticator.lookup_dn_search_password = '***'
c.LDAPAuthenticator.user_search_base = 'DC=our,DC=company'
c.LDAPAuthenticator.user_attribute = 'sAMAccountName'
c.LDAPAuthenticator.lookup_dn_user_dn_attribute = 'cn'
c.LDAPAuthenticator.escape_userdn = False
c.LDAPAuthenticator.use_lookup_dn_username = False

c.LDAPAuthenticator.allowed_groups = [
    "CN=JupyterHubGroup,OU=Groups,DC=our,DC=company",
]

I've also validated that the issue described in #237 is still fixed (which is the case).

So thanks @consideRatio for decluttering the whole escape_userdn/escape_rdn issue and improving the documentation.

So for most users using ldapauthenticator with ActiveDirectory this should not be a breaking change.