Răsfoiți Sursa

Support loading ldap secret from file

Bishtawi 1 an în urmă
părinte
comite
ee2af306d7
8 a modificat fișierele cu 33 adăugiri și 13 ștergeri
  1. 8 2
      DOCUMENTATION.md
  2. 1 1
      Dockerfile
  3. 1 1
      Dockerfile.dev
  4. 3 0
      config
  5. 1 0
      pyproject.toml
  6. 10 5
      radicale/auth/ldap.py
  7. 7 3
      radicale/config.py
  8. 2 1
      setup.py.legacy

+ 8 - 2
DOCUMENTATION.md

@@ -824,7 +824,13 @@ Default:
 
 ##### ldap_secret
 
-The password of the ldap_reader_dn. This parameter must be provided if auth type is ldap.
+The password of the ldap_reader_dn. Either this parameter or `ldap_secret_file` must be provided if auth type is ldap.
+
+Default:
+
+##### ldap_secret_file
+
+Path of the file containing the password of the ldap_reader_dn. Either this parameter or `ldap_secret` must be provided if auth type is ldap.
 
 Default:
 
@@ -869,7 +875,7 @@ Default:
 
 ##### lc_username
 
-Сonvert username to lowercase, must be true for case-insensitive auth 
+Сonvert username to lowercase, must be true for case-insensitive auth
 providers like ldap, kerberos
 
 Default: `False`

+ 1 - 1
Dockerfile

@@ -5,7 +5,7 @@ FROM python:3-alpine AS builder
 # Version of Radicale (e.g. v3)
 ARG VERSION=master
 
-# Optional dependencies (e.g. bcrypt)
+# Optional dependencies (e.g. bcrypt or ldap)
 ARG DEPENDENCIES=bcrypt
 
 RUN apk add --no-cache --virtual gcc libffi-dev musl-dev \

+ 1 - 1
Dockerfile.dev

@@ -1,6 +1,6 @@
 FROM python:3-alpine AS builder
 
-# Optional dependencies (e.g. bcrypt)
+# Optional dependencies (e.g. bcrypt or ldap)
 ARG DEPENDENCIES=bcrypt
 
 COPY . /app

+ 3 - 0
config

@@ -68,6 +68,9 @@
 # Password of the reader DN
 #ldap_secret = ldapreader-secret
 
+# Path of the file containing password of the reader DN
+#ldap_secret_file = /run/secrets/ldap_password
+
 # If the ldap groups of the user need to be loaded
 #ldap_load_groups = True
 

+ 1 - 0
pyproject.toml

@@ -41,6 +41,7 @@ dependencies = [
 [project.optional-dependencies]
 test = ["pytest>=7", "waitress", "bcrypt"]
 bcrypt = ["bcrypt"]
+ldap = ["ldap3"]
 
 [project.scripts]
 radicale = "radicale.__main__:run"

+ 10 - 5
radicale/auth/ldap.py

@@ -16,11 +16,12 @@
 """
 Authentication backend that checks credentials with a ldap server.
 Following parameters are needed in the configuration:
-   ldap_uri       The ldap url to the server like ldap://localhost
-   ldap_base      The baseDN of the ldap server
-   ldap_reader_dn The DN of a ldap user with read access to get the user accounts
-   ldap_secret    The password of the ldap_reader_dn
-   ldap_filter    The search filter to find the user to authenticate by the username
+   ldap_uri         The ldap url to the server like ldap://localhost
+   ldap_base        The baseDN of the ldap server
+   ldap_reader_dn   The DN of a ldap user with read access to get the user accounts
+   ldap_secret      The password of the ldap_reader_dn
+   ldap_secret_file The path of the file containing the password of the ldap_reader_dn
+   ldap_filter      The search filter to find the user to authenticate by the username
    ldap_load_groups If the groups of the authenticated users need to be loaded
 Following parameters controls SSL connections:
    ldap_use_ssl   If the connection
@@ -64,6 +65,10 @@ class Auth(auth.BaseAuth):
         self._ldap_load_groups = configuration.get("auth", "ldap_load_groups")
         self._ldap_secret = configuration.get("auth", "ldap_secret")
         self._ldap_filter = configuration.get("auth", "ldap_filter")
+        ldap_secret_file_path = configuration.get("auth", "ldap_secret_file")
+        if ldap_secret_file_path:
+            with open(ldap_secret_file_path, 'r') as file:
+                self._ldap_secret = file.read().rstrip('\n')
         if self._ldap_version == 3:
             self._ldap_use_ssl = configuration.get("auth", "ldap_use_ssl")
             if self._ldap_use_ssl:

+ 7 - 3
radicale/config.py

@@ -200,17 +200,21 @@ DEFAULT_CONFIG_SCHEMA: types.CONFIG_SCHEMA = OrderedDict([
             "help": "URI to the ldap server",
             "type": str}),
         ("ldap_base", {
-            "value": "none",
+            "value": "",
             "help": "LDAP base DN of the ldap server",
             "type": str}),
         ("ldap_reader_dn", {
-            "value": "none",
+            "value": "",
             "help": "the DN of a ldap user with read access to get the user accounts",
             "type": str}),
         ("ldap_secret", {
-            "value": "none",
+            "value": "",
             "help": "the password of the ldap_reader_dn",
             "type": str}),
+        ("ldap_secret_file", {
+            "value": "",
+            "help": "path of the file containing the password of the ldap_reader_dn",
+            "type": str}),
         ("ldap_filter", {
             "value": "(cn={0})",
             "help": "the search filter to find the user DN to authenticate by the username",

+ 2 - 1
setup.py.legacy

@@ -40,6 +40,7 @@ install_requires = ["defusedxml", "passlib", "vobject>=0.9.6",
                     "pika>=1.1.0",
                     ]
 bcrypt_requires = ["bcrypt"]
+ldap_requires = ["ldap3"]
 test_requires = ["pytest>=7", "waitress", *bcrypt_requires]
 
 setup(
@@ -58,7 +59,7 @@ setup(
     package_data={"radicale": [*web_files, "py.typed"]},
     entry_points={"console_scripts": ["radicale = radicale.__main__:run"]},
     install_requires=install_requires,
-    extras_require={"test": test_requires, "bcrypt": bcrypt_requires},
+    extras_require={"test": test_requires, "bcrypt": bcrypt_requires, "ldap": ldap_requires},
     keywords=["calendar", "addressbook", "CalDAV", "CardDAV"],
     python_requires=">=3.8.0",
     classifiers=[