Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 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
33 changes: 16 additions & 17 deletions google/auth/transport/_mtls_helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -408,28 +408,27 @@ 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".
This value is meant to be interpreted as a boolean representing whether
the client certificate should be used. 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()
if use_client_cert.lower() == "true":
return True
# Check if GOOGLE_API_USE_CLIENT_CERTIFICATE is set to false explicitly.
# Invalid values for GOOGLE_API_USE_CLIENT_CERTIFICATE are not handled here.
# That will be handled by the code calling this function.
elif use_client_cert.lower() == "false":
return False
else:
# Check if the value of GOOGLE_API_CERTIFICATE_CONFIG is set.
cert_path = getenv("GOOGLE_API_CERTIFICATE_CONFIG")
Expand All @@ -439,7 +438,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 +447,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 use_client_cert:
self._is_mtls = False
else:
# Load client SSL credentials.
Expand Down
19 changes: 19 additions & 0 deletions google/auth/transport/mtls.py
Original file line number Diff line number Diff line change
Expand Up @@ -110,3 +110,22 @@ 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().
The value is meant to be interpreted as a boolean representing whether
the client certificate should be used. 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. Also, note
that if GOOGLE_API_USE_CLIENT_CERTIFICATE is set but is not 'true' or 'false'
(case-insensitive), this check is inconclusive, that case should be handled
by the caller.

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 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 use_client_cert:
return False
try:
import OpenSSL
Expand Down
14 changes: 7 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

def test_check_use_client_cert_for_workload_with_config_file(self, monkeypatch):
config_data = {
Expand All @@ -663,19 +663,19 @@ 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

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 not use_client_cert

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 not use_client_cert

def test_check_use_client_cert_for_workload_with_config_file_not_json(
self, monkeypatch
Expand All @@ -688,7 +688,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 not use_client_cert

def test_check_use_client_cert_for_workload_with_config_file_no_workload(
self, monkeypatch
Expand All @@ -702,11 +702,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 not use_client_cert

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 not use_client_cert
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()
Loading