Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions web/pgacloud/providers/google.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,23 @@
# ##########################################################################
import json
import os
import sys
import time

from utils.io import debug, error, output
from utils.misc import get_my_ip, get_random_id
from providers._abstract import AbsProvider

# pgAdmin only authenticates to Google via google-auth, never the
# long-deprecated oauth2client. googleapiclient still tries to import
# oauth2client optionally, and on packaged installs the venv inherits the
# system site-packages (--system-site-packages, see issue #7173) where a
# stale oauth2client and an incompatible pyOpenSSL may be present. That
# optional import drags in the broken pyOpenSSL and crashes with "module
# 'lib' has no attribute 'GEN_EMAIL'". Blocking the module here makes
# googleapiclient fall back to google-auth cleanly. See issue #10110.
sys.modules.setdefault('oauth2client', None)

from googleapiclient import discovery
from googleapiclient.errors import HttpError
from google.auth.transport.requests import Request
Expand Down
13 changes: 13 additions & 0 deletions web/pgadmin/misc/cloud/google/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
# Google Cloud Deployment Implementation
import json
import os
import sys
from urllib.parse import unquote

from config import root
Expand All @@ -25,6 +26,18 @@
from flask_babel import gettext as _

from oauthlib.oauth2 import AccessDeniedError

# pgAdmin only authenticates to Google via google-auth and
# google-auth-oauthlib, never the long-deprecated oauth2client.
# googleapiclient still tries to import oauth2client optionally, and on
# packaged installs the venv inherits the system site-packages
# (--system-site-packages, see issue #7173) where a stale oauth2client and
# an incompatible pyOpenSSL may be present. That optional import drags in
# the broken pyOpenSSL and aborts startup with "module 'lib' has no
# attribute 'GEN_EMAIL'". Blocking the module here makes googleapiclient
# fall back to google-auth cleanly. See issue #10110.
sys.modules.setdefault('oauth2client', None)

from googleapiclient import discovery
from googleapiclient.errors import HttpError
from google_auth_oauthlib.flow import InstalledAppFlow
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
##########################################################################
#
# pgAdmin 4 - PostgreSQL Tools
#
# Copyright (C) 2013 - 2026, The pgAdmin Development Team
# This software is released under the PostgreSQL Licence
#
##########################################################################

"""
Regression test for issue #10110.

On packaged installs the venv inherits the system site-packages
(--system-site-packages, see issue #7173). When a stale ``oauth2client``
and an incompatible ``pyOpenSSL`` live there, googleapiclient's optional
``import oauth2client`` drags in the broken pyOpenSSL and aborts pgAdmin
startup with "module 'lib' has no attribute 'GEN_EMAIL'".

The cloud.google module guards against this by parking a ``None`` sentinel
under ``sys.modules['oauth2client']`` before importing googleapiclient, so
the optional import fails cleanly and google-auth is used instead.
"""

import sys
import unittest

from pgadmin.utils.route import BaseTestGenerator


class _SkipServerSetUpMixin:
"""Skip BaseTestGenerator's Postgres connection — pure logic tests."""

def setUp(self):
unittest.TestCase.setUp(self)


class TestOauth2ClientBlockedOnGoogleImport(
_SkipServerSetUpMixin, BaseTestGenerator):
"""Importing cloud.google must keep googleapiclient off oauth2client."""

scenarios = (('default', {}),)

def runTest(self):
# Importing the module installs the sentinel as a side effect.
import pgadmin.misc.cloud.google # noqa: F401

# The sentinel must be in place so googleapiclient never imports
# the deprecated oauth2client (and the pyOpenSSL it would pull in).
self.assertIsNone(
sys.modules.get('oauth2client', 'missing'),
"cloud.google must park a None sentinel under "
"sys.modules['oauth2client'] to block the optional import")

# googleapiclient must consequently report no oauth2client support.
import googleapiclient._auth as _auth
self.assertFalse(
_auth.HAS_OAUTH2CLIENT,
"googleapiclient must fall back to google-auth, not oauth2client")
Loading