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

Add tls_kwargs config to configure underlying ldap3 package tls #273

Merged
merged 2 commits into from
Sep 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,26 @@ Supported `tls_strategy` values are:
When configuring `tls_strategy="on_connect"`, the default value of
`server_port` becomes 636.

#### `LDAPAuthenticator.tls_kwargs`

A dictionary that will be used as keyword arguments for the constructor
of the ldap3 package's Tls object, influencing encrypted connections to
the LDAP server.

For details on what can be configured and its effects, refer to the
ldap3 package's documentation and code:

- ldap3 documentation: https://ldap3.readthedocs.io/en/latest/ssltls.html#the-tls-object
- ldap3 code: https://github.com/cannatag/ldap3/blob/v2.9.1/ldap3/core/tls.py#L59-L82

You can for example configure this like:

```python
c.LDAPAuthenticator.tls_kwargs = {
"ca_certs_file": "file/path.here",
}
```

#### `LDAPAuthenticator.server_port`

Port on which to contact the LDAP server.
Expand Down
28 changes: 27 additions & 1 deletion ldapauthenticator/ldapauthenticator.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@
import ldap3
from jupyterhub.auth import Authenticator
from ldap3.core.exceptions import LDAPBindError
from ldap3.core.tls import Tls
from ldap3.utils.conv import escape_filter_chars
from ldap3.utils.dn import escape_rdn
from traitlets import Bool, Int, List, Unicode, Union, UseEnum, observe, validate
from traitlets import Bool, Dict, Int, List, Unicode, Union, UseEnum, observe, validate


class TlsStrategy(enum.Enum):
Expand Down Expand Up @@ -94,6 +95,29 @@ def _observe_use_ssl(self, change):
""",
)

tls_kwargs = Dict(
config=True,
help="""
A dictionary that will be used as keyword arguments for the constructor
of the ldap3 package's Tls object, influencing encrypted connections to
the LDAP server.

For details on what can be configured and its effects, refer to the
ldap3 package's documentation and code:

- ldap3 documentation: https://ldap3.readthedocs.io/en/latest/ssltls.html#the-tls-object
- ldap3 code: https://github.com/cannatag/ldap3/blob/v2.9.1/ldap3/core/tls.py#L59-L82

You can for example configure this like:

```python
c.LDAPAuthenticator.tls_kwargs = {
"ca_certs_file": "file/path.here",
}
```
""",
)

bind_dn_template = Union(
[List(), Unicode()],
config=True,
Expand Down Expand Up @@ -415,10 +439,12 @@ def get_connection(self, userdn, password):
use_ssl = False
auto_bind = ldap3.AUTO_BIND_NO_TLS

tls = Tls(**self.tls_kwargs)
server = ldap3.Server(
self.server_address,
port=self.server_port,
use_ssl=use_ssl,
tls=tls,
)
try:
self.log.debug(f"Attempting to bind {userdn}")
Expand Down
17 changes: 17 additions & 0 deletions ldapauthenticator/tests/test_ldapauthenticator.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
https://github.com/rroemhild/docker-test-openldap?tab=readme-ov-file#ldap-structure
"""

import pytest
from ldap3.core.exceptions import LDAPSSLConfigurationError

from ..ldapauthenticator import TlsStrategy


Expand Down Expand Up @@ -188,3 +191,17 @@ async def test_ldap_auth_state_attributes2(authenticator):
)
assert authorized["name"] == "leela"
assert authorized["auth_state"]["user_attributes"] == {"description": ["Mutant"]}


async def test_ldap_tls_kwargs_config_passthrough(authenticator):
"""
This test is just meant to verify that tls_kwargs is passed through to the
ldap3 Tls object when its constructed.
"""
authenticator.tls_kwargs = {
"ca_certs_file": "does-not-exist-so-error-expected",
}
with pytest.raises(LDAPSSLConfigurationError):
await authenticator.get_authenticated_user(
None, {"username": "leela", "password": "leela"}
)