From 435508be1e33e30c2f5990d4c9b687c3bfd44cdc Mon Sep 17 00:00:00 2001
From: Florent Daigniere <nextgens@freenetproject.org>
Date: Fri, 27 Oct 2023 13:39:36 +0200
Subject: [PATCH] Introduce AUTH_REQUIRE_TOKENS

---
 core/admin/mailu/configuration.py  | 1 +
 core/admin/mailu/internal/nginx.py | 8 ++++++--
 docs/configuration.rst             | 6 +++++-
 towncrier/newsfragments/3004.misc  | 1 +
 4 files changed, 13 insertions(+), 3 deletions(-)
 create mode 100644 towncrier/newsfragments/3004.misc

diff --git a/core/admin/mailu/configuration.py b/core/admin/mailu/configuration.py
index d324bf8d..caccfe5e 100644
--- a/core/admin/mailu/configuration.py
+++ b/core/admin/mailu/configuration.py
@@ -72,6 +72,7 @@ DEFAULT_CONFIG = {
     'LOGO_URL': None,
     'LOGO_BACKGROUND': None,
     # Advanced settings
+    'AUTH_REQUIRE_TOKENS': False,
     'API': False,
     'WEB_API': '/api',
     'API_TOKEN': None,
diff --git a/core/admin/mailu/internal/nginx.py b/core/admin/mailu/internal/nginx.py
index 90b59712..4378ad67 100644
--- a/core/admin/mailu/internal/nginx.py
+++ b/core/admin/mailu/internal/nginx.py
@@ -50,8 +50,12 @@ def check_credentials(user, password, ip, protocol=None, auth_port=None, source_
                     app.logger.info(f'Login attempt for: {user}/{protocol}/{auth_port} from: {ip}/{source_port}: failed: badip: token-{token.id}: {token.comment or ""!r}')
                     return False # we can return directly here since the token is valid
     if user.check_password(password):
-        app.logger.info(f'Login attempt for: {user}/{protocol}/{auth_port} from: {ip}/{source_port}: success: password')
-        return True
+        if app.config['AUTH_REQUIRE_TOKENS'] and protocol != 'web':
+            app.logger.info(f'Login attempt for: {user}/{protocol}/{auth_port} from: {ip}/{source_port}: failed: password but AUTH_REQUIRE_TOKENS=True')
+            return False
+        else:
+            app.logger.info(f'Login attempt for: {user}/{protocol}/{auth_port} from: {ip}/{source_port}: success: password')
+            return True
     app.logger.info(f'Login attempt for: {user}/{protocol}/{auth_port} from: {ip}/{source_port}: failed: badauth: {utils.truncated_pw_hash(password)}')
     return False
 
diff --git a/docs/configuration.rst b/docs/configuration.rst
index fbf284a4..bccc9116 100644
--- a/docs/configuration.rst
+++ b/docs/configuration.rst
@@ -214,7 +214,11 @@ Depending on your particular deployment you most probably will want to change th
 Advanced settings
 -----------------
 
-The ``API_TOKEN`` (default: None) configures the authentication token.
+The ``AUTH_REQUIRE_TOKENS`` (default: False) setting controls whether thick clients can
+ authenticate using passwords or whether they are forced to use tokens/application
+ specific passwords.
+
+The ``API_TOKEN`` (default: None) setting configures the authentication token.
 This token must be passed as request header to the API as authentication token.
 This is a mandatory setting for using the RESTful API.
 
diff --git a/towncrier/newsfragments/3004.misc b/towncrier/newsfragments/3004.misc
new file mode 100644
index 00000000..69f46598
--- /dev/null
+++ b/towncrier/newsfragments/3004.misc
@@ -0,0 +1 @@
+Introduce AUTH_REQUIRE_TOKENS to enforce that thick clients use tokens instead of passwords