Skip to content

[codex] Handle missing pyOpenSSL for inferred mTLS#16921

Open
cneuralnetwork wants to merge 1 commit intogoogleapis:mainfrom
cneuralnetwork:codex/auto-mtls-missing-openssl
Open

[codex] Handle missing pyOpenSSL for inferred mTLS#16921
cneuralnetwork wants to merge 1 commit intogoogleapis:mainfrom
cneuralnetwork:codex/auto-mtls-missing-openssl

Conversation

@cneuralnetwork
Copy link
Copy Markdown

Fixes #16920.

Summary

This changes the requests and urllib3 mTLS setup paths so they no longer fail closed when client certificate use was inferred from certificate configuration but pyOpenSSL is not installed. In that auto-mTLS case, the transports now disable mTLS and continue using the regular TLS channel.

Explicit opt-in remains strict: if GOOGLE_API_USE_CLIENT_CERTIFICATE=true or the Cloud SDK fallback env var explicitly enables client certs, a missing pyOpenSSL dependency still raises MutualTLSChannelError as before.

Root Cause

check_use_client_cert() can now infer client certificate use from certificate config. The requests and urllib3 transports then imported OpenSSL before checking whether a cert/key could actually be used, so environments without optional pyOpenSSL could crash during automatically triggered mTLS configuration.

Changes

  • Add internal helpers to distinguish explicit client-cert opt-in from inferred client-cert enablement.
  • Make requests and urllib3 transports back off only for inferred mTLS when pyOpenSSL is unavailable.
  • Update stale mTLS docstrings to describe inferred certificate configuration behavior.
  • Add regression tests for inferred mTLS with missing OpenSSL in both requests and urllib3 transports.

Validation

  • /tmp/google-auth-venv/bin/python -m pytest tests/transport/test_requests.py::TestAuthorizedSession::test_configure_mtls_channel_exceptions tests/transport/test_requests.py::TestAuthorizedSession::test_configure_mtls_channel_inferred_missing_openssl tests/transport/test_urllib3.py::TestAuthorizedHttp::test_configure_mtls_channel_exceptions tests/transport/test_urllib3.py::TestAuthorizedHttp::test_configure_mtls_channel_inferred_missing_openssl tests/transport/test__mtls_helper.py::TestCheckUseClientCert (16 passed)
  • /tmp/google-auth-venv/bin/python -m pytest tests/transport/test_requests.py tests/transport/test_urllib3.py tests/transport/test__mtls_helper.py (140 passed, with existing pyOpenSSL deprecation warnings)
  • git diff --check
  • python -m compileall -q packages/google-auth/google/auth/transport/_mtls_helper.py packages/google-auth/google/auth/transport/requests.py packages/google-auth/google/auth/transport/urllib3.py packages/google-auth/tests/transport/test_requests.py packages/google-auth/tests/transport/test_urllib3.py

@google-cla
Copy link
Copy Markdown

google-cla Bot commented May 2, 2026

Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

View this failed invocation of the CLA check for more information.

For the most up to date status, view the checks section at the bottom of the pull request.

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request refactors client certificate environment variable handling and updates the mTLS configuration logic in both the requests and urllib3 transports. It introduces helper functions to centralize environment checks and modifies the mTLS setup to gracefully disable inferred mTLS if pyOpenSSL is missing, rather than raising an error. A potential NameError was identified in urllib3.py due to an incorrect reference to _mtls_helper.

try:
import OpenSSL
except ImportError as caught_exc:
if not transport._mtls_helper._is_client_cert_explicitly_enabled():
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The use of transport._mtls_helper here appears to be incorrect and will likely result in a NameError at runtime if OpenSSL is missing. In this package, _mtls_helper is typically imported directly from google.auth.transport. For consistency with the changes in packages/google-auth/google/auth/transport/requests.py and to ensure correctness, you should use _mtls_helper directly.

Suggested change
if not transport._mtls_helper._is_client_cert_explicitly_enabled():
if not _mtls_helper._is_client_cert_explicitly_enabled():

@cneuralnetwork cneuralnetwork marked this pull request as ready for review May 2, 2026 14:53
@cneuralnetwork cneuralnetwork requested review from a team as code owners May 2, 2026 14:53
@cneuralnetwork cneuralnetwork force-pushed the codex/auto-mtls-missing-openssl branch from 701f4d7 to c6ec744 Compare May 2, 2026 14:55
@cneuralnetwork
Copy link
Copy Markdown
Author

@gemini-code-assist review

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request refactors mutual TLS (mTLS) environment variable handling and updates the requests and urllib3 transports to gracefully disable mTLS when pyOpenSSL is missing and mTLS is not explicitly enabled. The changes include centralized environment variable lookups, updated docstrings, and new unit tests. Review feedback suggests simplifying the logic for environment variable fallbacks and boolean checks to be more idiomatic.

Comment on lines +453 to +458
use_client_cert = getenv(environment_vars.GOOGLE_API_USE_CLIENT_CERTIFICATE)
if use_client_cert is None or use_client_cert == "":
use_client_cert = getenv(
environment_vars.CLOUDSDK_CONTEXT_AWARE_USE_CLIENT_CERTIFICATE
)
return use_client_cert
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

This logic for falling back between environment variables can be simplified using the or operator, which is more idiomatic in Python for handling None or empty string fallbacks.

    return getenv(environment_vars.GOOGLE_API_USE_CLIENT_CERTIFICATE) or getenv(
        environment_vars.CLOUDSDK_CONTEXT_AWARE_USE_CLIENT_CERTIFICATE
    )

Comment on lines +463 to +464
use_client_cert = _get_use_client_cert_env()
return bool(use_client_cert and use_client_cert.lower() == "true")
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

This can be simplified by inlining the environment variable check and using a default empty string to handle the None case, making the logic more concise.

Suggested change
use_client_cert = _get_use_client_cert_env()
return bool(use_client_cert and use_client_cert.lower() == "true")
return (_get_use_client_cert_env() or "").lower() == "true"

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

auth: auto-mtls raises exception if openssl not available

1 participant