From a91f0795300110a601fe7391b7e9796dfb33b2a8 Mon Sep 17 00:00:00 2001 From: Oliver Date: Wed, 21 Oct 2026 10:00:53 +1100 Subject: [PATCH] Deduplicate social backends (#13046) * Deduplicate social backends - Closes https://github.com/inventree/InvenTree/issues/13044 - Fixes bug which can cause duplication of social backends - Added regression tests * Update src/backend/InvenTree/InvenTree/config.py Simplify implementation Co-authored-by: Philipp Fruck * Ensure consistent ordering * Bump API version --------- Co-authored-by: Philipp Fruck --- .../InvenTree/InvenTree/api_version.py | 5 ++- src/backend/InvenTree/InvenTree/config.py | 16 +++++++++ src/backend/InvenTree/InvenTree/settings.py | 10 +----- src/backend/InvenTree/InvenTree/tests.py | 35 +++++++++++++++++++ 4 files changed, 56 insertions(+), 10 deletions(-) diff --git a/src/backend/InvenTree/InvenTree/api_version.py b/src/backend/InvenTree/InvenTree/api_version.py index 7469e45007..f585ca92ad 100644 --- a/src/backend/InvenTree/InvenTree/api_version.py +++ b/src/backend/InvenTree/InvenTree/api_version.py @@ -1,11 +1,14 @@ """InvenTree API version information.""" # InvenTree API version -INVENTREE_API_VERSION = 560 +INVENTREE_API_VERSION = 561 """Increment this API version number whenever there is a significant change to the API that any clients need to know about.""" INVENTREE_API_TEXT = """ +v561 -> 2026-10-21 : https://github.com/inventree/InvenTree/pull/13046 + - Fix ordering of social applications in API schema + v560 -> 2026-10-17 : https://github.com/inventree/InvenTree/pull/12737 - Adds search and ordering fields across remaining API endpoints (machine, stock, importer, report) diff --git a/src/backend/InvenTree/InvenTree/config.py b/src/backend/InvenTree/InvenTree/config.py index facd3b9872..7cf2ee5191 100644 --- a/src/backend/InvenTree/InvenTree/config.py +++ b/src/backend/InvenTree/InvenTree/config.py @@ -546,6 +546,22 @@ def get_custom_file( return value +def get_social_backends(defaults: list[str], backends: list[str]) -> list[str]: + """Return a de-duplicated list of fully-qualified allauth social provider apps. + + Backends may be specified either as the short provider name (e.g. 'openid_connect') + or the full module path (e.g. 'allauth.socialaccount.providers.openid_connect'). + Names are normalized before de-duplication, so both forms map to the same app. + The returned list is sorted alphabetically. + """ + prefix = 'allauth.socialaccount.providers.' + + return sorted({ + app if app.startswith(prefix) else prefix + app + for app in [*defaults, *backends] + }) + + def get_frontend_settings(debug=True): """Return a dictionary of settings for the frontend interface.""" # New settings diff --git a/src/backend/InvenTree/InvenTree/settings.py b/src/backend/InvenTree/InvenTree/settings.py index 3e0445dbb3..096ff73a25 100644 --- a/src/backend/InvenTree/InvenTree/settings.py +++ b/src/backend/InvenTree/InvenTree/settings.py @@ -994,17 +994,9 @@ SOCIAL_BACKENDS = get_setting( ) DEFAULT_SOCIAL = ['saml', 'openid_connect'] -_SOCIAL_BACKENDS = list(dict.fromkeys([*DEFAULT_SOCIAL, *SOCIAL_BACKENDS])) # region auth -for app in _SOCIAL_BACKENDS: # pragma: no cover - # Ensure that the app starts with 'allauth.socialaccount.providers' - social_prefix = 'allauth.socialaccount.providers.' - - if not app.startswith(social_prefix): - app = social_prefix + app - - INSTALLED_APPS.append(app) +INSTALLED_APPS.extend(config.get_social_backends(DEFAULT_SOCIAL, SOCIAL_BACKENDS)) SOCIALACCOUNT_PROVIDERS = {a: {} for a in DEFAULT_SOCIAL} _PROVIDER_SETTINGS = get_setting( diff --git a/src/backend/InvenTree/InvenTree/tests.py b/src/backend/InvenTree/InvenTree/tests.py index 3be60551dc..e54c91e564 100644 --- a/src/backend/InvenTree/InvenTree/tests.py +++ b/src/backend/InvenTree/InvenTree/tests.py @@ -1328,6 +1328,41 @@ class TestSettings(InvenTreeTestCase): set_global_setting('PLUGIN_ON_STARTUP', False) + def test_social_backends(self): + """Test that social backends are normalized and de-duplicated.""" + prefix = 'allauth.socialaccount.providers.' + defaults = ['saml', 'openid_connect'] + + # Full module path for a default backend must not produce a duplicate + self.assertEqual( + config.get_social_backends(defaults, [f'{prefix}openid_connect']), + [f'{prefix}openid_connect', f'{prefix}saml'], + ) + + # Mixed short and full names, with duplicates, are sorted alphabetically + self.assertEqual( + config.get_social_backends( + defaults, ['github', f'{prefix}github', 'saml', f'{prefix}google'] + ), + [ + f'{prefix}github', + f'{prefix}google', + f'{prefix}openid_connect', + f'{prefix}saml', + ], + ) + + # No extra backends + self.assertEqual( + config.get_social_backends(defaults, []), + [f'{prefix}openid_connect', f'{prefix}saml'], + ) + + # The running configuration must not contain duplicate apps + self.assertEqual( + len(settings.INSTALLED_APPS), len(set(settings.INSTALLED_APPS)) + ) + def test_helpers_cfg_file(self): """Test get_config_file.""" # normal run - not configured