Skip to content
Closed
3 changes: 2 additions & 1 deletion packages/google-auth/google/auth/credentials.py
Original file line number Diff line number Diff line change
Expand Up @@ -532,7 +532,8 @@ def _lookup_regional_access_boundary(
Returns:
Optional[Dict[str, str]]: The Regional Access Boundary information returned by the lookup API, or None if the lookup failed.
"""
from google.oauth2 import _client
import importlib
_client = importlib.import_module("google.oauth2._client")

url = self._build_regional_access_boundary_lookup_url(request=request)
if not url:
Expand Down
4 changes: 2 additions & 2 deletions packages/google-auth/google/auth/crypt/rsa.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ def __init__(self, private_key, key_id=None):
module_str = private_key.__class__.__module__
if isinstance(private_key, RSAPrivateKey):
impl_lib = _cryptography_rsa
elif module_str.startswith(RSA_KEY_MODULE_PREFIX):
elif private_key is None or module_str.startswith(RSA_KEY_MODULE_PREFIX):
from google.auth.crypt import _python_rsa

impl_lib = _python_rsa
Comment thread
macastelaz marked this conversation as resolved.
Outdated
Expand All @@ -106,7 +106,7 @@ def __init__(self, private_key, key_id=None):
@property # type: ignore
@_helpers.copy_docstring(base.Signer)
def key_id(self):
return self._impl.key_id
return getattr(self, "_key_id", None) or self._impl.key_id
Comment thread
macastelaz marked this conversation as resolved.
Outdated

@_helpers.copy_docstring(base.Signer)
def sign(self, message):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -262,7 +262,11 @@ def __init__(
):
self._source_credentials._create_self_signed_jwt(None)

self._universe_domain = source_credentials.universe_domain
self._universe_domain = (
source_credentials.universe_domain
if isinstance(getattr(source_credentials, "universe_domain", None), str)
else credentials.DEFAULT_UNIVERSE_DOMAIN
)
Comment thread
macastelaz marked this conversation as resolved.

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.

This seems like it could be a pretty big behaviour change. Are you sure this is safe?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

It should be safe (I know, famous last words): the base credential class already sets this same default (

self._universe_domain = DEFAULT_UNIVERSE_DOMAIN
) and if the universe domain is set to something else, it would still be respected here. There are cases where you have an older custom credential class or what we encountered in mock credentials used in tests where the universe domain isn't set and the class doesn't extend the base, but I think even in these cases, using DEFAULT_UNIVERSE_DOMAIN is expected across Google client libraries.

Thoughts?

self._target_principal = target_principal
self._target_scopes = target_scopes
self._delegates = delegates
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -453,7 +453,7 @@ def check_use_client_cert():

If GOOGLE_API_USE_CLIENT_CERTIFICATE is set to true or false, a corresponding
bool value will be returned. If the value is set to an unexpected string, it
will default to False.
will raise a ValueError.
If GOOGLE_API_USE_CLIENT_CERTIFICATE is unset, the value will be inferred
by reading a file pointed at by GOOGLE_API_CERTIFICATE_CONFIG, and verifying
it contains a "workload" section. If so, the function will return True,
Expand All @@ -470,6 +470,11 @@ def check_use_client_cert():

# Check if the value of GOOGLE_API_USE_CLIENT_CERTIFICATE is set.
if use_client_cert:
if use_client_cert.lower() not in ("true", "false"):
raise ValueError(
"Environment variable `GOOGLE_API_USE_CLIENT_CERTIFICATE` must be"
" either `true` or `false`"
)

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.

I don't think we should be reverting this kind of behaviour. It was an explicit decision to return False instead of raise an exception here

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Do you by chance have any additional context you could share on the original decision to return False here? From my view point, it feels like a security risk to not fail fast here. E.g. if a user sets this to ture trying to set the desire to use a client cert for an mtls connection and we silently "downgrade" this to false because of the typo, I'm not sure it's a great result. By raising here, we fail fast and close that "hole".

FWIW, there are internal tests for gapic generated clients that are asserting an error is raised so if we do stick with returning false, we'll likely need to update a lot of older APIs, etc.

FWIW, we currently have a discrepancy in

which raises the error as well as in the gapic generator ( )

return use_client_cert.lower() == "true"
else:
# Check if the value of GOOGLE_API_CERTIFICATE_CONFIG is set.
Expand Down
16 changes: 14 additions & 2 deletions packages/google-auth/tests/transport/test__mtls_helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -657,7 +657,13 @@ def test_override_does_not_exist(self):
returned_path = _mtls_helper._get_cert_config_path(config_path)
assert returned_path is None

@mock.patch.dict(os.environ, {"GOOGLE_API_CERTIFICATE_CONFIG": ""})
@mock.patch.dict(
os.environ,
{
"GOOGLE_API_CERTIFICATE_CONFIG": "",
"CLOUDSDK_CONTEXT_AWARE_CERTIFICATE_CONFIG_FILE_PATH": "",
},
)
@mock.patch("os.path.exists", autospec=True)
def test_default(self, mock_path_exists):
mock_path_exists.return_value = True
Expand Down Expand Up @@ -788,13 +794,16 @@ def test_env_var_explicit_false(self):

@mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "garbage"})
def test_env_var_explicit_garbage(self):
assert _mtls_helper.check_use_client_cert() is False
import pytest
with pytest.raises(ValueError, match="must be either `true` or `false`"):
_mtls_helper.check_use_client_cert()

@mock.patch("builtins.open", autospec=True)
@mock.patch.dict(
os.environ,
{
"GOOGLE_API_USE_CLIENT_CERTIFICATE": "",
"CLOUDSDK_CONTEXT_AWARE_USE_CLIENT_CERTIFICATE": "",
"GOOGLE_API_CERTIFICATE_CONFIG": "/path/to/config",
},
)
Expand All @@ -810,6 +819,7 @@ def test_config_file_success(self, mock_file):
os.environ,
{
"GOOGLE_API_USE_CLIENT_CERTIFICATE": "",
"CLOUDSDK_CONTEXT_AWARE_USE_CLIENT_CERTIFICATE": "",
"GOOGLE_API_CERTIFICATE_CONFIG": "/path/to/config",
},
)
Expand All @@ -822,6 +832,7 @@ def test_config_file_missing_keys(self, mock_file):
os.environ,
{
"GOOGLE_API_USE_CLIENT_CERTIFICATE": "",
"CLOUDSDK_CONTEXT_AWARE_USE_CLIENT_CERTIFICATE": "",
"GOOGLE_API_CERTIFICATE_CONFIG": "/path/to/config",
},
)
Expand All @@ -834,6 +845,7 @@ def test_config_file_bad_json(self, mock_file):
os.environ,
{
"GOOGLE_API_USE_CLIENT_CERTIFICATE": "",
"CLOUDSDK_CONTEXT_AWARE_USE_CLIENT_CERTIFICATE": "",
"GOOGLE_API_CERTIFICATE_CONFIG": "/path/does/not/exist",
},
)
Expand Down
Loading