diff --git a/dev-requirements.txt b/dev-requirements.txt index c4cc54a..b3fc751 100644 --- a/dev-requirements.txt +++ b/dev-requirements.txt @@ -154,6 +154,12 @@ pluggy==1.5.0 # via pytest pre-commit==4.0.1 # via imperial_coldfront_plugin (pyproject.toml) +pyasn1==0.6.1 + # via + # pyasn1-modules + # python-ldap +pyasn1-modules==0.4.1 + # via python-ldap pycparser==2.22 # via cffi pyopenssl==24.2.1 @@ -186,6 +192,8 @@ python-dateutil==2.9.0.post0 # arrow # coldfront # faker +python-ldap==3.4.4 + # via imperial_coldfront_plugin (pyproject.toml) python-memcached==1.62 # via coldfront pytz==2024.1 diff --git a/doc-requirements.txt b/doc-requirements.txt index 1d5176b..edac6ca 100644 --- a/doc-requirements.txt +++ b/doc-requirements.txt @@ -185,6 +185,12 @@ platformdirs==4.3.6 # via # mkdocs-get-deps # mkdocstrings +pyasn1==0.6.1 + # via + # pyasn1-modules + # python-ldap +pyasn1-modules==0.4.1 + # via python-ldap pycparser==2.22 # via cffi pygments==2.18.0 @@ -205,6 +211,8 @@ python-dateutil==2.9.0.post0 # coldfront # faker # ghp-import +python-ldap==3.4.4 + # via imperial_coldfront_plugin (pyproject.toml) python-memcached==1.62 # via coldfront pytz==2024.1 diff --git a/imperial_coldfront_plugin/ldap.py b/imperial_coldfront_plugin/ldap.py new file mode 100644 index 0000000..73790fa --- /dev/null +++ b/imperial_coldfront_plugin/ldap.py @@ -0,0 +1,23 @@ +"""Module for interacting with LDAP identity provider.""" + +import ldap +from django.conf import settings + + +def get_uid_from_ldap(username: str) -> int: + """Retrieve the UID from LDAP for a given username. + + Args: + username: The username to search for in LDAP. + + Returns: + The UID number associated with the given username. + """ + conn = ldap.initialize(settings.LDAP_SERVER_URI) + conn.set_option(ldap.OPT_REFERRALS, 0) + conn.set_option(ldap.OPT_PROTOCOL_VERSION, 3) + conn.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, ldap.OPT_X_TLS_ALLOW) + result = conn.search_s( + settings.LDAP_SEARCH_BASE, ldap.SCOPE_SUBTREE, f"(cn={username})", ["uidNumber"] + ) + return int(result[0][1]["uidNumber"][0].decode("utf-8")) diff --git a/imperial_coldfront_plugin/settings.py b/imperial_coldfront_plugin/settings.py new file mode 100644 index 0000000..52bf892 --- /dev/null +++ b/imperial_coldfront_plugin/settings.py @@ -0,0 +1,6 @@ +"""Plugin settings that are imported into the global settings namespace of Coldfront.""" + +from coldfront.config.env import ENV + +LDAP_SERVER_URI = ENV.str("LDAP_SERVER_URI", default="") +LDAP_SEARCH_BASE = ENV.str("LDAP_SEARCH_BASE", default="") diff --git a/pyproject.toml b/pyproject.toml index ff0b804..0f7c7a4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -12,6 +12,7 @@ dependencies = [ "django", "mozilla_django_oidc", "django-stubs-ext", + "python-ldap", ] [project.optional-dependencies] @@ -60,7 +61,7 @@ module = "tests.*" disallow_untyped_defs = false [[tool.mypy.overrides]] -module = ["mozilla_django_oidc.*"] +module = ["mozilla_django_oidc.*", "ldap.*"] ignore_missing_imports = true [[tool.mypy.overrides]] @@ -92,4 +93,4 @@ pydocstyle.convention = "google" ] # Missing docstring in public module, Missing docstring in public package [tool.django-stubs] -django_settings_module = "imperial_coldfront_plugin" # a lie but seems to satisfy +django_settings_module = "imperial_coldfront_plugin.settings" diff --git a/requirements.txt b/requirements.txt index 0967f0d..6a1e534 100644 --- a/requirements.txt +++ b/requirements.txt @@ -108,6 +108,12 @@ josepy==1.14.0 # via mozilla-django-oidc mozilla-django-oidc==4.0.1 # via imperial_coldfront_plugin (pyproject.toml) +pyasn1==0.6.1 + # via + # pyasn1-modules + # python-ldap +pyasn1-modules==0.4.1 + # via python-ldap pycparser==2.22 # via cffi pyopenssl==24.2.1 @@ -121,6 +127,8 @@ python-dateutil==2.9.0.post0 # arrow # coldfront # faker +python-ldap==3.4.4 + # via imperial_coldfront_plugin (pyproject.toml) python-memcached==1.62 # via coldfront pytz==2024.1