From 9f77a12c866fb547ecdc095dea249959dceb7bb6 Mon Sep 17 00:00:00 2001 From: Dave Page Date: Wed, 26 Aug 2026 15:03:38 +0100 Subject: [PATCH] Fix OAuth2 userinfo request crash when endpoint is present but None get_user_profile() tested key presence ('OAUTH2_USERINFO_ENDPOINT' not in ...) rather than truthiness, so a config copied from the shipped config.py template - which ships OAUTH2_USERINFO_ENDPOINT: None - would pass the check and call client.get(None), raising requests.exceptions.MissingSchema instead of skipping the call. Closes #10349 --- web/pgadmin/authenticate/oauth2.py | 4 +- .../tests/test_oauth2_userinfo_endpoint.py | 59 +++++++++++++++++++ 2 files changed, 61 insertions(+), 2 deletions(-) create mode 100644 web/pgadmin/authenticate/tests/test_oauth2_userinfo_endpoint.py diff --git a/web/pgadmin/authenticate/oauth2.py b/web/pgadmin/authenticate/oauth2.py index 4e04b5b23be..806744619b7 100644 --- a/web/pgadmin/authenticate/oauth2.py +++ b/web/pgadmin/authenticate/oauth2.py @@ -744,8 +744,8 @@ def get_user_profile(self): # For non-OIDC providers or when ID token is insufficient, # call the userinfo endpoint - if 'OAUTH2_USERINFO_ENDPOINT' not in self.oauth2_config[ - self.oauth2_current_client]: + if not self.oauth2_config[ + self.oauth2_current_client].get('OAUTH2_USERINFO_ENDPOINT'): if self._is_oidc_provider(): # OIDC provider should have provided claims in ID token current_app.logger.warning( diff --git a/web/pgadmin/authenticate/tests/test_oauth2_userinfo_endpoint.py b/web/pgadmin/authenticate/tests/test_oauth2_userinfo_endpoint.py new file mode 100644 index 00000000000..65df0beaa68 --- /dev/null +++ b/web/pgadmin/authenticate/tests/test_oauth2_userinfo_endpoint.py @@ -0,0 +1,59 @@ +########################################################################## +# +# pgAdmin 4 - PostgreSQL Tools +# +# Copyright (C) 2013 - 2026, The pgAdmin Development Team +# This software is released under the PostgreSQL Licence +# +########################################################################## + +"""Verify that an OAUTH2_USERINFO_ENDPOINT of None (the shipped config +template default) is treated the same as an absent key, rather than being +passed to the HTTP client and crashing (issue #10349). +""" + +import sys +from unittest.mock import MagicMock, patch + +from pgadmin.utils.route import BaseTestGenerator + + +class OAuth2UserinfoEndpointNoneTestCase(BaseTestGenerator): + """Exercises get_user_profile() directly - no server connection needed.""" + + def setUp(self): + pass + + def runTest(self): + # Resolved at call time, rather than imported at module load time: + # test_auth_gating (run earlier in this same package) deliberately + # forces pgadmin.authenticate.oauth2 to be re-imported, which would + # leave a module-level import here bound to a stale module object + # whose globals patch('...session', ...) below wouldn't reach. + oauth2_module = sys.modules['pgadmin.authenticate.oauth2'] + OAuth2Authentication = oauth2_module.OAuth2Authentication + + auth = OAuth2Authentication.__new__(OAuth2Authentication) + auth.oauth2_current_client = 'test_provider' + auth.oauth2_config = { + 'test_provider': { + 'OAUTH2_NAME': 'test_provider', + # Shipped config.py template default - key present, not set. + 'OAUTH2_USERINFO_ENDPOINT': None, + } + } + mock_client = MagicMock() + auth.oauth2_clients = {'test_provider': mock_client} + + with self.app.app_context(), \ + patch.object(auth, '_authorize_access_token', + return_value={'access_token': 'tok'}), \ + patch.object(auth, '_is_oidc_provider', + return_value=False), \ + patch('pgadmin.authenticate.oauth2.session', {}): + profile = auth.get_user_profile() + + self.assertEqual(profile, {}) + # The bug: client.get(None) raised requests.exceptions.MissingSchema + # instead of skipping the call. + mock_client.get.assert_not_called()