From 370bc35178dd97dcdc54971ed55e28c84bd5a34b Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Fri, 23 May 2025 21:26:15 +0000 Subject: [PATCH 1/5] Refactor: Remove rsa and make cryptography a core dependency This commit removes the `rsa` library as a dependency and makes the `cryptography` library a required, core dependency. Previously, `cryptography` was an optional dependency, and the library would fall back to a pure Python RSA implementation using the `rsa` library if `cryptography` was not installed. Changes made: - Modified `setup.py` to remove `rsa` from dependencies and add `cryptography` with version constraints. - Updated `google/auth/crypt/rsa.py` to directly use the `cryptography`-based RSA implementation (`_cryptography_rsa.py`) and remove the fallback mechanism. - Removed the pure Python RSA implementation file (`google/auth/crypt/_python_rsa.py`). - Removed the corresponding tests for the pure Python RSA implementation (`tests/crypt/test__python_rsa.py`). Core unit tests pass after these changes. --- google/auth/crypt/_python_rsa.py | 175 ---------------------------- google/auth/crypt/rsa.py | 15 +-- setup.py | 14 +-- tests/crypt/test__python_rsa.py | 193 ------------------------------- 4 files changed, 7 insertions(+), 390 deletions(-) delete mode 100644 google/auth/crypt/_python_rsa.py delete mode 100644 tests/crypt/test__python_rsa.py diff --git a/google/auth/crypt/_python_rsa.py b/google/auth/crypt/_python_rsa.py deleted file mode 100644 index e553c25ed..000000000 --- a/google/auth/crypt/_python_rsa.py +++ /dev/null @@ -1,175 +0,0 @@ -# Copyright 2016 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""Pure-Python RSA cryptography implementation. - -Uses the ``rsa``, ``pyasn1`` and ``pyasn1_modules`` packages -to parse PEM files storing PKCS#1 or PKCS#8 keys as well as -certificates. There is no support for p12 files. -""" - -from __future__ import absolute_import - -import io - -from pyasn1.codec.der import decoder # type: ignore -from pyasn1_modules import pem # type: ignore -from pyasn1_modules.rfc2459 import Certificate # type: ignore -from pyasn1_modules.rfc5208 import PrivateKeyInfo # type: ignore -import rsa # type: ignore - -from google.auth import _helpers -from google.auth import exceptions -from google.auth.crypt import base - -_POW2 = (128, 64, 32, 16, 8, 4, 2, 1) -_CERTIFICATE_MARKER = b"-----BEGIN CERTIFICATE-----" -_PKCS1_MARKER = ("-----BEGIN RSA PRIVATE KEY-----", "-----END RSA PRIVATE KEY-----") -_PKCS8_MARKER = ("-----BEGIN PRIVATE KEY-----", "-----END PRIVATE KEY-----") -_PKCS8_SPEC = PrivateKeyInfo() - - -def _bit_list_to_bytes(bit_list): - """Converts an iterable of 1s and 0s to bytes. - - Combines the list 8 at a time, treating each group of 8 bits - as a single byte. - - Args: - bit_list (Sequence): Sequence of 1s and 0s. - - Returns: - bytes: The decoded bytes. - """ - num_bits = len(bit_list) - byte_vals = bytearray() - for start in range(0, num_bits, 8): - curr_bits = bit_list[start : start + 8] - char_val = sum(val * digit for val, digit in zip(_POW2, curr_bits)) - byte_vals.append(char_val) - return bytes(byte_vals) - - -class RSAVerifier(base.Verifier): - """Verifies RSA cryptographic signatures using public keys. - - Args: - public_key (rsa.key.PublicKey): The public key used to verify - signatures. - """ - - def __init__(self, public_key): - self._pubkey = public_key - - @_helpers.copy_docstring(base.Verifier) - def verify(self, message, signature): - message = _helpers.to_bytes(message) - try: - return rsa.pkcs1.verify(message, signature, self._pubkey) - except (ValueError, rsa.pkcs1.VerificationError): - return False - - @classmethod - def from_string(cls, public_key): - """Construct an Verifier instance from a public key or public - certificate string. - - Args: - public_key (Union[str, bytes]): The public key in PEM format or the - x509 public key certificate. - - Returns: - google.auth.crypt._python_rsa.RSAVerifier: The constructed verifier. - - Raises: - ValueError: If the public_key can't be parsed. - """ - public_key = _helpers.to_bytes(public_key) - is_x509_cert = _CERTIFICATE_MARKER in public_key - - # If this is a certificate, extract the public key info. - if is_x509_cert: - der = rsa.pem.load_pem(public_key, "CERTIFICATE") - asn1_cert, remaining = decoder.decode(der, asn1Spec=Certificate()) - if remaining != b"": - raise exceptions.InvalidValue("Unused bytes", remaining) - - cert_info = asn1_cert["tbsCertificate"]["subjectPublicKeyInfo"] - key_bytes = _bit_list_to_bytes(cert_info["subjectPublicKey"]) - pubkey = rsa.PublicKey.load_pkcs1(key_bytes, "DER") - else: - pubkey = rsa.PublicKey.load_pkcs1(public_key, "PEM") - return cls(pubkey) - - -class RSASigner(base.Signer, base.FromServiceAccountMixin): - """Signs messages with an RSA private key. - - Args: - private_key (rsa.key.PrivateKey): The private key to sign with. - key_id (str): Optional key ID used to identify this private key. This - can be useful to associate the private key with its associated - public key or certificate. - """ - - def __init__(self, private_key, key_id=None): - self._key = private_key - self._key_id = key_id - - @property # type: ignore - @_helpers.copy_docstring(base.Signer) - def key_id(self): - return self._key_id - - @_helpers.copy_docstring(base.Signer) - def sign(self, message): - message = _helpers.to_bytes(message) - return rsa.pkcs1.sign(message, self._key, "SHA-256") - - @classmethod - def from_string(cls, key, key_id=None): - """Construct an Signer instance from a private key in PEM format. - - Args: - key (str): Private key in PEM format. - key_id (str): An optional key id used to identify the private key. - - Returns: - google.auth.crypt.Signer: The constructed signer. - - Raises: - ValueError: If the key cannot be parsed as PKCS#1 or PKCS#8 in - PEM format. - """ - key = _helpers.from_bytes(key) # PEM expects str in Python 3 - marker_id, key_bytes = pem.readPemBlocksFromFile( - io.StringIO(key), _PKCS1_MARKER, _PKCS8_MARKER - ) - - # Key is in pkcs1 format. - if marker_id == 0: - private_key = rsa.key.PrivateKey.load_pkcs1(key_bytes, format="DER") - # Key is in pkcs8. - elif marker_id == 1: - key_info, remaining = decoder.decode(key_bytes, asn1Spec=_PKCS8_SPEC) - if remaining != b"": - raise exceptions.InvalidValue("Unused bytes", remaining) - private_key_info = key_info.getComponentByName("privateKey") - private_key = rsa.key.PrivateKey.load_pkcs1( - private_key_info.asOctets(), format="DER" - ) - else: - raise exceptions.MalformedError("No key could be detected.") - - return cls(private_key, key_id=key_id) diff --git a/google/auth/crypt/rsa.py b/google/auth/crypt/rsa.py index ed842d1eb..cde4f4065 100644 --- a/google/auth/crypt/rsa.py +++ b/google/auth/crypt/rsa.py @@ -14,17 +14,8 @@ """RSA cryptography signer and verifier.""" +from google.auth.crypt._cryptography_rsa import RSASigner +from google.auth.crypt._cryptography_rsa import RSAVerifier -try: - # Prefer cryptograph-based RSA implementation. - from google.auth.crypt import _cryptography_rsa - RSASigner = _cryptography_rsa.RSASigner - RSAVerifier = _cryptography_rsa.RSAVerifier -except ImportError: # pragma: NO COVER - # Fallback to pure-python RSA implementation if cryptography is - # unavailable. - from google.auth.crypt import _python_rsa - - RSASigner = _python_rsa.RSASigner # type: ignore - RSAVerifier = _python_rsa.RSAVerifier # type: ignore +__all__ = ["RSASigner", "RSAVerifier"] diff --git a/setup.py b/setup.py index 3874354fd..6974f8b7c 100644 --- a/setup.py +++ b/setup.py @@ -24,28 +24,22 @@ "pyasn1-modules>=0.2.1", # rsa==4.5 is the last version to support 2.7 # https://github.com/sybrenstuvel/python-rsa/issues/152#issuecomment-643470233 - "rsa>=3.1.4,<5", -) - -# TODO(https://github.com/googleapis/google-auth-library-python/issues/1737): Unit test fails with -# `No module named 'cryptography.hazmat.backends.openssl.x509' for Python 3.7``. -cryptography_base_require = [ "cryptography >= 38.0.3", "cryptography < 39.0.0; python_version < '3.8'", -] +) requests_extra_require = ["requests >= 2.20.0, < 3.0.0"] aiohttp_extra_require = ["aiohttp >= 3.6.2, < 4.0.0", *requests_extra_require] -pyjwt_extra_require = ["pyjwt>=2.0", *cryptography_base_require] +pyjwt_extra_require = ["pyjwt>=2.0"] reauth_extra_require = ["pyu2f>=0.1.5"] # TODO(https://github.com/googleapis/google-auth-library-python/issues/1738): Add bounds for cryptography and pyopenssl dependencies. -enterprise_cert_extra_require = ["cryptography", "pyopenssl"] +enterprise_cert_extra_require = ["pyopenssl"] -pyopenssl_extra_require = ["pyopenssl>=20.0.0", cryptography_base_require] +pyopenssl_extra_require = ["pyopenssl>=20.0.0"] # TODO(https://github.com/googleapis/google-auth-library-python/issues/1739): Add bounds for urllib3 and packaging dependencies. urllib3_extra_require = ["urllib3", "packaging"] diff --git a/tests/crypt/test__python_rsa.py b/tests/crypt/test__python_rsa.py deleted file mode 100644 index 4a4ebe44e..000000000 --- a/tests/crypt/test__python_rsa.py +++ /dev/null @@ -1,193 +0,0 @@ -# Copyright 2016 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import io -import json -import os - -import mock -from pyasn1_modules import pem # type: ignore -import pytest # type: ignore -import rsa # type: ignore - -from google.auth import _helpers -from google.auth.crypt import _python_rsa -from google.auth.crypt import base - - -DATA_DIR = os.path.join(os.path.dirname(__file__), "..", "data") - -# To generate privatekey.pem, privatekey.pub, and public_cert.pem: -# $ openssl req -new -newkey rsa:1024 -x509 -nodes -out public_cert.pem \ -# > -keyout privatekey.pem -# $ openssl rsa -in privatekey.pem -pubout -out privatekey.pub - -with open(os.path.join(DATA_DIR, "privatekey.pem"), "rb") as fh: - PRIVATE_KEY_BYTES = fh.read() - PKCS1_KEY_BYTES = PRIVATE_KEY_BYTES - -with open(os.path.join(DATA_DIR, "privatekey.pub"), "rb") as fh: - PUBLIC_KEY_BYTES = fh.read() - -with open(os.path.join(DATA_DIR, "public_cert.pem"), "rb") as fh: - PUBLIC_CERT_BYTES = fh.read() - -# To generate pem_from_pkcs12.pem and privatekey.p12: -# $ openssl pkcs12 -export -out privatekey.p12 -inkey privatekey.pem \ -# > -in public_cert.pem -# $ openssl pkcs12 -in privatekey.p12 -nocerts -nodes \ -# > -out pem_from_pkcs12.pem - -with open(os.path.join(DATA_DIR, "pem_from_pkcs12.pem"), "rb") as fh: - PKCS8_KEY_BYTES = fh.read() - -with open(os.path.join(DATA_DIR, "privatekey.p12"), "rb") as fh: - PKCS12_KEY_BYTES = fh.read() - -# The service account JSON file can be generated from the Google Cloud Console. -SERVICE_ACCOUNT_JSON_FILE = os.path.join(DATA_DIR, "service_account.json") - -with open(SERVICE_ACCOUNT_JSON_FILE, "rb") as fh: - SERVICE_ACCOUNT_INFO = json.load(fh) - - -class TestRSAVerifier(object): - def test_verify_success(self): - to_sign = b"foo" - signer = _python_rsa.RSASigner.from_string(PRIVATE_KEY_BYTES) - actual_signature = signer.sign(to_sign) - - verifier = _python_rsa.RSAVerifier.from_string(PUBLIC_KEY_BYTES) - assert verifier.verify(to_sign, actual_signature) - - def test_verify_unicode_success(self): - to_sign = u"foo" - signer = _python_rsa.RSASigner.from_string(PRIVATE_KEY_BYTES) - actual_signature = signer.sign(to_sign) - - verifier = _python_rsa.RSAVerifier.from_string(PUBLIC_KEY_BYTES) - assert verifier.verify(to_sign, actual_signature) - - def test_verify_failure(self): - verifier = _python_rsa.RSAVerifier.from_string(PUBLIC_KEY_BYTES) - bad_signature1 = b"" - assert not verifier.verify(b"foo", bad_signature1) - bad_signature2 = b"a" - assert not verifier.verify(b"foo", bad_signature2) - - def test_from_string_pub_key(self): - verifier = _python_rsa.RSAVerifier.from_string(PUBLIC_KEY_BYTES) - assert isinstance(verifier, _python_rsa.RSAVerifier) - assert isinstance(verifier._pubkey, rsa.key.PublicKey) - - def test_from_string_pub_key_unicode(self): - public_key = _helpers.from_bytes(PUBLIC_KEY_BYTES) - verifier = _python_rsa.RSAVerifier.from_string(public_key) - assert isinstance(verifier, _python_rsa.RSAVerifier) - assert isinstance(verifier._pubkey, rsa.key.PublicKey) - - def test_from_string_pub_cert(self): - verifier = _python_rsa.RSAVerifier.from_string(PUBLIC_CERT_BYTES) - assert isinstance(verifier, _python_rsa.RSAVerifier) - assert isinstance(verifier._pubkey, rsa.key.PublicKey) - - def test_from_string_pub_cert_unicode(self): - public_cert = _helpers.from_bytes(PUBLIC_CERT_BYTES) - verifier = _python_rsa.RSAVerifier.from_string(public_cert) - assert isinstance(verifier, _python_rsa.RSAVerifier) - assert isinstance(verifier._pubkey, rsa.key.PublicKey) - - def test_from_string_pub_cert_failure(self): - cert_bytes = PUBLIC_CERT_BYTES - true_der = rsa.pem.load_pem(cert_bytes, "CERTIFICATE") - load_pem_patch = mock.patch( - "rsa.pem.load_pem", return_value=true_der + b"extra", autospec=True - ) - - with load_pem_patch as load_pem: - with pytest.raises(ValueError): - _python_rsa.RSAVerifier.from_string(cert_bytes) - load_pem.assert_called_once_with(cert_bytes, "CERTIFICATE") - - -class TestRSASigner(object): - def test_from_string_pkcs1(self): - signer = _python_rsa.RSASigner.from_string(PKCS1_KEY_BYTES) - assert isinstance(signer, _python_rsa.RSASigner) - assert isinstance(signer._key, rsa.key.PrivateKey) - - def test_from_string_pkcs1_unicode(self): - key_bytes = _helpers.from_bytes(PKCS1_KEY_BYTES) - signer = _python_rsa.RSASigner.from_string(key_bytes) - assert isinstance(signer, _python_rsa.RSASigner) - assert isinstance(signer._key, rsa.key.PrivateKey) - - def test_from_string_pkcs8(self): - signer = _python_rsa.RSASigner.from_string(PKCS8_KEY_BYTES) - assert isinstance(signer, _python_rsa.RSASigner) - assert isinstance(signer._key, rsa.key.PrivateKey) - - def test_from_string_pkcs8_extra_bytes(self): - key_bytes = PKCS8_KEY_BYTES - _, pem_bytes = pem.readPemBlocksFromFile( - io.StringIO(_helpers.from_bytes(key_bytes)), _python_rsa._PKCS8_MARKER - ) - - key_info, remaining = None, "extra" - decode_patch = mock.patch( - "pyasn1.codec.der.decoder.decode", - return_value=(key_info, remaining), - autospec=True, - ) - - with decode_patch as decode: - with pytest.raises(ValueError): - _python_rsa.RSASigner.from_string(key_bytes) - # Verify mock was called. - decode.assert_called_once_with(pem_bytes, asn1Spec=_python_rsa._PKCS8_SPEC) - - def test_from_string_pkcs8_unicode(self): - key_bytes = _helpers.from_bytes(PKCS8_KEY_BYTES) - signer = _python_rsa.RSASigner.from_string(key_bytes) - assert isinstance(signer, _python_rsa.RSASigner) - assert isinstance(signer._key, rsa.key.PrivateKey) - - def test_from_string_pkcs12(self): - with pytest.raises(ValueError): - _python_rsa.RSASigner.from_string(PKCS12_KEY_BYTES) - - def test_from_string_bogus_key(self): - key_bytes = "bogus-key" - with pytest.raises(ValueError): - _python_rsa.RSASigner.from_string(key_bytes) - - def test_from_service_account_info(self): - signer = _python_rsa.RSASigner.from_service_account_info(SERVICE_ACCOUNT_INFO) - - assert signer.key_id == SERVICE_ACCOUNT_INFO[base._JSON_FILE_PRIVATE_KEY_ID] - assert isinstance(signer._key, rsa.key.PrivateKey) - - def test_from_service_account_info_missing_key(self): - with pytest.raises(ValueError) as excinfo: - _python_rsa.RSASigner.from_service_account_info({}) - - assert excinfo.match(base._JSON_FILE_PRIVATE_KEY) - - def test_from_service_account_file(self): - signer = _python_rsa.RSASigner.from_service_account_file( - SERVICE_ACCOUNT_JSON_FILE - ) - - assert signer.key_id == SERVICE_ACCOUNT_INFO[base._JSON_FILE_PRIVATE_KEY_ID] - assert isinstance(signer._key, rsa.key.PrivateKey) From 1d665b3a68dd821b1e497644c0328b922df4a572 Mon Sep 17 00:00:00 2001 From: Sai Sunder Srinivasan Date: Fri, 23 May 2025 22:07:14 +0000 Subject: [PATCH 2/5] update secret --- system_tests/secrets.tar.enc | Bin 10324 -> 10324 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/system_tests/secrets.tar.enc b/system_tests/secrets.tar.enc index c19e8785acd4dc496707e68ccea9c2f61430b0aa..9ecfb2d252214779460eb2deb013d6cf4d1b460c 100644 GIT binary patch literal 10324 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 literal 10324 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 From c6ad0e667c173986cc90e710ba840547fdf46942 Mon Sep 17 00:00:00 2001 From: Sai Sunder Srinivasan Date: Sat, 24 May 2025 05:40:44 +0000 Subject: [PATCH 3/5] fix doc issue --- docs/conf.py | 27 +++++++++++++++++++++++++++ google/auth/crypt/rsa.py | 7 +++---- 2 files changed, 30 insertions(+), 4 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index 8ab609390..00f6cc0b0 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -358,6 +358,33 @@ # texinfo_no_detailmenu = False +# -- Options for autodoc -------------------------------------------------- + + +def autodoc_skip_member_handler(app, what, name, obj, skip, options): + """ + Skips the RSASigner and RSAVerifier from the internal _cryptography_rsa module + if they are being documented under that internal module path, + as they are publicly exposed via google.auth.crypt. + """ + if name in ("RSASigner", "RSAVerifier") and hasattr(obj, "__module__"): + if obj.__module__ == "google.auth.crypt._cryptography_rsa": + # Check if it's also available via the public google.auth.crypt path + try: + import google.auth.crypt + + public_obj = getattr(google.auth.crypt, name, None) + if public_obj is obj: + return True # Skip this internal one + except ImportError: + pass # Should not happen if the library is installed + return None # Default behavior (don't skip) + + +def setup(app): + app.connect("autodoc-skip-member", autodoc_skip_member_handler) + + # Example configuration for intersphinx: refer to the Python standard library. intersphinx_mapping = { "python": ("https://docs.python.org/3.5", None), diff --git a/google/auth/crypt/rsa.py b/google/auth/crypt/rsa.py index cde4f4065..274bafc5f 100644 --- a/google/auth/crypt/rsa.py +++ b/google/auth/crypt/rsa.py @@ -14,8 +14,7 @@ """RSA cryptography signer and verifier.""" -from google.auth.crypt._cryptography_rsa import RSASigner -from google.auth.crypt._cryptography_rsa import RSAVerifier +from google.auth.crypt import _cryptography_rsa - -__all__ = ["RSASigner", "RSAVerifier"] +RSASigner = _cryptography_rsa.RSASigner +RSAVerifier = _cryptography_rsa.RSAVerifier From 2c461ce20168e2140a9ff8d5dabf5fc9461ed9a1 Mon Sep 17 00:00:00 2001 From: Sai Sunder Srinivasan Date: Tue, 27 May 2025 22:25:38 +0000 Subject: [PATCH 4/5] fix es256 sphix error --- docs/conf.py | 19 ++++++++++++++++--- system_tests/secrets.tar.enc | Bin 10324 -> 10324 bytes 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index 00f6cc0b0..c73f540a5 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -363,10 +363,11 @@ def autodoc_skip_member_handler(app, what, name, obj, skip, options): """ - Skips the RSASigner and RSAVerifier from the internal _cryptography_rsa module - if they are being documented under that internal module path, - as they are publicly exposed via google.auth.crypt. + Skips members from internal modules (like _cryptography_rsa or base) + if they are publicly exposed via a higher-level package (like google.auth.crypt), + to avoid duplicate documentation entries and ambiguous cross-references. """ + # Handle RSASigner and RSAVerifier from _cryptography_rsa if name in ("RSASigner", "RSAVerifier") and hasattr(obj, "__module__"): if obj.__module__ == "google.auth.crypt._cryptography_rsa": # Check if it's also available via the public google.auth.crypt path @@ -378,6 +379,18 @@ def autodoc_skip_member_handler(app, what, name, obj, skip, options): return True # Skip this internal one except ImportError: pass # Should not happen if the library is installed + + # Handle Signer and Verifier from base + elif name in ("Signer", "Verifier") and hasattr(obj, "__module__"): + if obj.__module__ == "google.auth.crypt.base": + # Check if it's also available via the public google.auth.crypt path + try: + import google.auth.crypt + public_obj = getattr(google.auth.crypt, name, None) + if public_obj is obj: + return True # Skip this internal one + except ImportError: + pass # Should not happen if the library is installed return None # Default behavior (don't skip) diff --git a/system_tests/secrets.tar.enc b/system_tests/secrets.tar.enc index 9ecfb2d252214779460eb2deb013d6cf4d1b460c..9bc5bbcfd6687ca1f670bea60ec15fe8f9217fce 100644 GIT binary patch literal 10324 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 From 6170a48b0285c51c1f7e56a4b17af7b0ef45430e Mon Sep 17 00:00:00 2001 From: Sai Sunder Srinivasan Date: Tue, 27 May 2025 23:00:18 +0000 Subject: [PATCH 5/5] lint --- docs/conf.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index c73f540a5..3c95be670 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -386,11 +386,12 @@ def autodoc_skip_member_handler(app, what, name, obj, skip, options): # Check if it's also available via the public google.auth.crypt path try: import google.auth.crypt + public_obj = getattr(google.auth.crypt, name, None) if public_obj is obj: - return True # Skip this internal one + return True # Skip this internal one except ImportError: - pass # Should not happen if the library is installed + pass # Should not happen if the library is installed return None # Default behavior (don't skip)