Skip to content
Merged
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
29 changes: 12 additions & 17 deletions google/auth/transport/_mtls_helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -408,28 +408,23 @@ def client_cert_callback():


def check_use_client_cert():
"""Returns the value of the GOOGLE_API_USE_CLIENT_CERTIFICATE variable,
or an inferred value('true' or 'false') if unset.
"""Returns boolean for whether the client certificate should be used for mTLS.

This value is meant to be interpreted as a "true" or "false" value
representing whether the client certificate should be used, but could be any
arbitrary string.

If GOOGLE_API_USE_CLIENT_CERTIFICATE is unset, the value 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", otherwise "false".
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.
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,
otherwise False.

Returns:
str: The value of GOOGLE_API_USE_CLIENT_CERTIFICATE, or an inferred value
("true" or "false") if unset. This string should contain a value, but may
be an any arbitrary string read from the user's set
GOOGLE_API_USE_CLIENT_CERTIFICATE.
bool: Whether the client certificate should be used for mTLS connection.
"""
use_client_cert = getenv("GOOGLE_API_USE_CLIENT_CERTIFICATE")
# Check if the value of GOOGLE_API_USE_CLIENT_CERTIFICATE is set.
if use_client_cert:
return use_client_cert.lower()
return use_client_cert.lower() == "true"
else:
# Check if the value of GOOGLE_API_CERTIFICATE_CONFIG is set.
cert_path = getenv("GOOGLE_API_CERTIFICATE_CONFIG")
Expand All @@ -439,7 +434,7 @@ def check_use_client_cert():
content = json.load(f)
# verify json has workload key
content["cert_configs"]["workload"]
return "true"
return True
except (
FileNotFoundError,
OSError,
Expand All @@ -448,4 +443,4 @@ def check_use_client_cert():
json.JSONDecodeError,
) as e:
_LOGGER.debug("error decoding certificate: %s", e)
return "false"
return False
6 changes: 3 additions & 3 deletions google/auth/transport/grpc.py
Original file line number Diff line number Diff line change
Expand Up @@ -255,13 +255,13 @@ def my_client_cert_callback():
# If SSL credentials are not explicitly set, try client_cert_callback and ADC.
if not ssl_credentials:
use_client_cert = _mtls_helper.check_use_client_cert()
if use_client_cert == "true" and client_cert_callback:
if use_client_cert and client_cert_callback:
# Use the callback if provided.
cert, key = client_cert_callback()
ssl_credentials = grpc.ssl_channel_credentials(
certificate_chain=cert, private_key=key
)
elif use_client_cert == "true":
elif use_client_cert:
# Use application default SSL credentials.
adc_ssl_credentils = SslCredentials()
ssl_credentials = adc_ssl_credentils.ssl_credentials
Expand Down Expand Up @@ -292,7 +292,7 @@ class SslCredentials:

def __init__(self):
use_client_cert = _mtls_helper.check_use_client_cert()
if use_client_cert != "true":
if not use_client_cert:
self._is_mtls = False
else:
# Load client SSL credentials.
Expand Down
17 changes: 17 additions & 0 deletions google/auth/transport/mtls.py
Original file line number Diff line number Diff line change
Expand Up @@ -110,3 +110,20 @@ def callback():
return cert_path, key_path, passphrase_bytes

return callback


def should_use_client_cert():
"""Returns boolean for whether the client certificate should be used for mTLS.

This is a wrapper around _mtls_helper.check_use_client_cert().
If GOOGLE_API_USE_CLIENT_CERTIFICATE is set to true or false, a corresponding
bool value will be returned
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,
otherwise False.

Returns:
bool: indicating whether the client certificate should be used for mTLS.
"""
return _mtls_helper.check_use_client_cert()
2 changes: 1 addition & 1 deletion google/auth/transport/requests.py
Original file line number Diff line number Diff line change
Expand Up @@ -443,7 +443,7 @@ def configure_mtls_channel(self, client_cert_callback=None):
creation failed for any reason.
"""
use_client_cert = google.auth.transport._mtls_helper.check_use_client_cert()
if use_client_cert != "true":
if not use_client_cert:
self._is_mtls = False
return
try:
Expand Down
2 changes: 1 addition & 1 deletion google/auth/transport/urllib3.py
Original file line number Diff line number Diff line change
Expand Up @@ -334,7 +334,7 @@ def configure_mtls_channel(self, client_cert_callback=None):
creation failed for any reason.
"""
use_client_cert = transport._mtls_helper.check_use_client_cert()
if use_client_cert != "true":
if not use_client_cert:
return False
try:
import OpenSSL
Expand Down
19 changes: 12 additions & 7 deletions tests/transport/test__mtls_helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -643,7 +643,7 @@ def test_crypto_error(self):
def test_check_use_client_cert(self, monkeypatch):
monkeypatch.setenv("GOOGLE_API_USE_CLIENT_CERTIFICATE", "true")
use_client_cert = _mtls_helper.check_use_client_cert()
assert use_client_cert == "true"
assert use_client_cert is True

def test_check_use_client_cert_for_workload_with_config_file(self, monkeypatch):
config_data = {
Expand All @@ -663,19 +663,24 @@ def test_check_use_client_cert_for_workload_with_config_file(self, monkeypatch):
mock_file_handle = mock.mock_open(read_data=config_file_content)
with mock.patch("builtins.open", mock_file_handle):
use_client_cert = _mtls_helper.check_use_client_cert()
assert use_client_cert == "true"
assert use_client_cert is True

def test_check_use_client_cert_false(self, monkeypatch):
monkeypatch.setenv("GOOGLE_API_USE_CLIENT_CERTIFICATE", "false")
use_client_cert = _mtls_helper.check_use_client_cert()
assert use_client_cert == "false"
assert use_client_cert is False

def test_check_use_client_cert_unsupported_value(self, monkeypatch):
monkeypatch.setenv("GOOGLE_API_USE_CLIENT_CERTIFICATE", "dummy")
use_client_cert = _mtls_helper.check_use_client_cert()
assert use_client_cert is False

def test_check_use_client_cert_for_workload_with_config_file_not_found(
self, monkeypatch
):
monkeypatch.setenv("GOOGLE_API_USE_CLIENT_CERTIFICATE", "")
use_client_cert = _mtls_helper.check_use_client_cert()
assert use_client_cert == "false"
assert use_client_cert is False

def test_check_use_client_cert_for_workload_with_config_file_not_json(
self, monkeypatch
Expand All @@ -688,7 +693,7 @@ def test_check_use_client_cert_for_workload_with_config_file_not_json(
mock_file_handle = mock.mock_open(read_data=config_file_content)
with mock.patch("builtins.open", mock_file_handle):
use_client_cert = _mtls_helper.check_use_client_cert()
assert use_client_cert == "false"
assert use_client_cert is False

def test_check_use_client_cert_for_workload_with_config_file_no_workload(
self, monkeypatch
Expand All @@ -702,11 +707,11 @@ def test_check_use_client_cert_for_workload_with_config_file_no_workload(
mock_file_handle = mock.mock_open(read_data=config_file_content)
with mock.patch("builtins.open", mock_file_handle):
use_client_cert = _mtls_helper.check_use_client_cert()
assert use_client_cert == "false"
assert use_client_cert is False

def test_check_use_client_cert_when_file_does_not_exist(self, monkeypatch):
config_filename = "mock_certificate_config.json"
monkeypatch.setenv("GOOGLE_API_CERTIFICATE_CONFIG", config_filename)
monkeypatch.setenv("GOOGLE_API_USE_CLIENT_CERTIFICATE", "")
use_client_cert = _mtls_helper.check_use_client_cert()
assert use_client_cert == "false"
assert use_client_cert is False
9 changes: 9 additions & 0 deletions tests/transport/test_mtls.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,3 +94,12 @@ def test_default_client_encrypted_cert_source(
callback = mtls.default_client_encrypted_cert_source("cert_path", "key_path")
with pytest.raises(exceptions.MutualTLSChannelError):
callback()


@mock.patch("google.auth.transport._mtls_helper.check_use_client_cert", autospec=True)
def test_should_use_client_cert(check_use_client_cert):
check_use_client_cert.return_value = mock.Mock()
assert mtls.should_use_client_cert()

check_use_client_cert.return_value = False
assert not mtls.should_use_client_cert()