From 6a9bbbe87a94989391cf026c81ce3d75d098ab96 Mon Sep 17 00:00:00 2001 From: dev-hari-prasad Date: Sun, 9 Aug 2026 13:51:53 +0530 Subject: [PATCH] Gate external auth providers behind SERVER_MODE --- web/pgadmin/authenticate/registry.py | 22 +-- .../authenticate/tests/test_auth_gating.py | 135 ++++++++++++++++++ 2 files changed, 147 insertions(+), 10 deletions(-) create mode 100644 web/pgadmin/authenticate/tests/test_auth_gating.py diff --git a/web/pgadmin/authenticate/registry.py b/web/pgadmin/authenticate/registry.py index 7b3d607b657..99487a5dcaa 100644 --- a/web/pgadmin/authenticate/registry.py +++ b/web/pgadmin/authenticate/registry.py @@ -10,6 +10,7 @@ """External Authentication Registry.""" +import config from pgadmin.utils.dynamic_registry import create_registry_metaclass @@ -19,20 +20,21 @@ def load_modules(cls, app=None): from . import internal as module submodules.append(module) - from . import kerberos as module - submodules.append(module) + if config.SERVER_MODE: + from . import kerberos as module + submodules.append(module) - from . import ldap as module - submodules.append(module) + from . import ldap as module + submodules.append(module) - from . import mfa as module - submodules.append(module) + from . import mfa as module + submodules.append(module) - from . import oauth2 as module - submodules.append(module) + from . import oauth2 as module + submodules.append(module) - from . import webserver as module - submodules.append(module) + from . import webserver as module + submodules.append(module) for module in submodules: if "init_app" in module.__dict__.keys(): diff --git a/web/pgadmin/authenticate/tests/test_auth_gating.py b/web/pgadmin/authenticate/tests/test_auth_gating.py new file mode 100644 index 00000000000..65a9ddaf308 --- /dev/null +++ b/web/pgadmin/authenticate/tests/test_auth_gating.py @@ -0,0 +1,135 @@ +########################################################################## +# +# pgAdmin 4 - PostgreSQL Tools +# +# Copyright (C) 2013 - 2026, The pgAdmin Development Team +# This software is released under the PostgreSQL Licence +# +########################################################################## + +import sys +import unittest +import config +from pgadmin.authenticate.registry import AuthSourceRegistry + + +class TestAuthSourceRegistryGating(unittest.TestCase): + """ + Test suite for SERVER_MODE gating of external authentication providers in + AuthSourceRegistry. + """ + + def setUp(self): + self._orig_server_mode = config.SERVER_MODE + if AuthSourceRegistry._registry: + self._orig_registry = dict(AuthSourceRegistry._registry) + else: + self._orig_registry = {} + + if AuthSourceRegistry._objects: + self._orig_objects = dict(AuthSourceRegistry._objects) + else: + self._orig_objects = {} + + def tearDown(self): + config.SERVER_MODE = self._orig_server_mode + AuthSourceRegistry._registry = self._orig_registry + AuthSourceRegistry._objects = self._orig_objects + + def _unload_external_auth_modules(self): + external_modules = [ + 'pgadmin.authenticate.kerberos', + 'pgadmin.authenticate.ldap', + 'pgadmin.authenticate.mfa', + 'pgadmin.authenticate.oauth2', + 'pgadmin.authenticate.webserver', + ] + for mod in external_modules: + sys.modules.pop(mod, None) + + def _reset_registry(self): + self._unload_external_auth_modules() + AuthSourceRegistry._registry = dict() + AuthSourceRegistry._objects = dict() + + if 'pgadmin.authenticate.internal' in sys.modules: + internal_module = sys.modules['pgadmin.authenticate.internal'] + if hasattr(internal_module, 'InternalAuthentication'): + AuthSourceRegistry._registry['internal'] = ( + internal_module.InternalAuthentication + ) + + def test_desktop_mode_gating(self): + """ + Verify that in desktop mode (SERVER_MODE = False), external + authentication provider modules are not imported or registered. + """ + config.SERVER_MODE = False + self._reset_registry() + + AuthSourceRegistry.load_modules() + + registry_keys = list(AuthSourceRegistry._registry.keys()) + + # Desktop mode must load 'internal' authentication + self.assertIn('internal', registry_keys) + + # External providers must NOT be registered in desktop mode + self.assertNotIn('kerberos', registry_keys) + self.assertNotIn('ldap', registry_keys) + self.assertNotIn('oauth2', registry_keys) + self.assertNotIn('webserver', registry_keys) + + # Verify external modules were NOT imported into sys.modules + self.assertNotIn('pgadmin.authenticate.kerberos', sys.modules) + self.assertNotIn('pgadmin.authenticate.ldap', sys.modules) + self.assertNotIn('pgadmin.authenticate.mfa', sys.modules) + self.assertNotIn('pgadmin.authenticate.oauth2', sys.modules) + self.assertNotIn('pgadmin.authenticate.webserver', sys.modules) + + def test_server_mode_loading(self): + """ + Verify that in server mode (SERVER_MODE = True), external + authentication provider modules are imported and registered. + """ + config.SERVER_MODE = True + self._reset_registry() + + # Dummy Flask-like app stub for init_app if called + class MockLoginManager: + logout_view = None + + class MockApp: + def __init__(self): + self.login_manager = MockLoginManager() + + def register_blueprint(self, *args, **kwargs): + pass + + def register_logout_hook(self, *args, **kwargs): + pass + + class Logger: + def warning(self, *args, **kwargs): + pass + + logger = Logger() + + app = MockApp() + AuthSourceRegistry.load_modules(app) + + registry_keys = list(AuthSourceRegistry._registry.keys()) + + # Server mode must load all providers + self.assertIn('internal', registry_keys) + self.assertIn('kerberos', registry_keys) + self.assertIn('ldap', registry_keys) + self.assertIn('oauth2', registry_keys) + self.assertIn('webserver', registry_keys) + + # Verify external modules WERE imported into sys.modules + self.assertIn('pgadmin.authenticate.kerberos', sys.modules) + self.assertIn('pgadmin.authenticate.ldap', sys.modules) + self.assertIn('pgadmin.authenticate.mfa', sys.modules) + self.assertIn('pgadmin.authenticate.oauth2', sys.modules) + self.assertIn('pgadmin.authenticate.webserver', sys.modules)