feat: consolidate mTLS channel errors (#480)
feat: consolidate mTLS channel errors
diff --git a/google/auth/exceptions.py b/google/auth/exceptions.py
index 4f66dc2..9501386 100644
--- a/google/auth/exceptions.py
+++ b/google/auth/exceptions.py
@@ -34,3 +34,7 @@
class DefaultCredentialsError(GoogleAuthError):
"""Used to indicate that acquiring default credentials failed."""
+
+
+class MutualTLSChannelError(GoogleAuthError):
+ """Used to indicate that mutual TLS channel creation is failed."""
diff --git a/google/auth/transport/grpc.py b/google/auth/transport/grpc.py
index 32ffabc..d62c415 100644
--- a/google/auth/transport/grpc.py
+++ b/google/auth/transport/grpc.py
@@ -20,6 +20,7 @@
import six
+from google.auth import exceptions
from google.auth.transport import _mtls_helper
try:
@@ -217,17 +218,8 @@
grpc.Channel: The created gRPC channel.
Raises:
- OSError: If the cert provider command launch fails during the application
- default SSL credentials loading process on devices with endpoint
- verification support.
- RuntimeError: If the cert provider command has a runtime error during the
- application default SSL credentials loading process on devices with
- endpoint verification support.
- ValueError:
- If the context aware metadata file is malformed or if the cert provider
- command doesn't produce both client certificate and key during the
- application default SSL credentials loading process on devices with
- endpoint verification support.
+ google.auth.exceptions.MutualTLSChannelError: If mutual TLS channel
+ creation failed for any reason.
"""
# Create the metadata plugin for inserting the authorization header.
metadata_plugin = AuthMetadataPlugin(credentials, request)
@@ -293,20 +285,21 @@
grpc.ChannelCredentials: The created grpc channel credentials.
Raises:
- OSError: If the cert provider command launch fails.
- RuntimeError: If the cert provider command has a runtime error.
- ValueError:
- If the context aware metadata file is malformed or if the cert provider
- command doesn't produce both the client certificate and key.
+ google.auth.exceptions.MutualTLSChannelError: If mutual TLS channel
+ creation failed for any reason.
"""
if self._context_aware_metadata_path:
- metadata = _mtls_helper._read_dca_metadata_file(
- self._context_aware_metadata_path
- )
- cert, key = _mtls_helper.get_client_ssl_credentials(metadata)
- self._ssl_credentials = grpc.ssl_channel_credentials(
- certificate_chain=cert, private_key=key
- )
+ try:
+ metadata = _mtls_helper._read_dca_metadata_file(
+ self._context_aware_metadata_path
+ )
+ cert, key = _mtls_helper.get_client_ssl_credentials(metadata)
+ self._ssl_credentials = grpc.ssl_channel_credentials(
+ certificate_chain=cert, private_key=key
+ )
+ except (OSError, RuntimeError, ValueError) as caught_exc:
+ new_exc = exceptions.MutualTLSChannelError(caught_exc)
+ six.raise_from(new_exc, caught_exc)
else:
self._ssl_credentials = grpc.ssl_channel_credentials()
diff --git a/google/auth/transport/requests.py b/google/auth/transport/requests.py
index 2d31d96..26096e2 100644
--- a/google/auth/transport/requests.py
+++ b/google/auth/transport/requests.py
@@ -355,23 +355,32 @@
will be used.
Raises:
- ImportError: If certifi or pyOpenSSL is not installed.
- OpenSSL.crypto.Error: If client cert or key is invalid.
- OSError: If the cert provider command launch fails during the
- application default SSL credentials loading process.
- RuntimeError: If the cert provider command has a runtime error during
- the application default SSL credentials loading process.
- ValueError: If the context aware metadata file is malformed or the
- cert provider command doesn't produce both client certicate and
- key during the application default SSL credentials loading process.
+ google.auth.exceptions.MutualTLSChannelError: If mutual TLS channel
+ creation failed for any reason.
"""
- self._is_mtls, cert, key = google.auth.transport._mtls_helper.get_client_cert_and_key(
- client_cert_callback
- )
+ try:
+ import OpenSSL
+ except ImportError as caught_exc:
+ new_exc = exceptions.MutualTLSChannelError(caught_exc)
+ six.raise_from(new_exc, caught_exc)
- if self._is_mtls:
- mtls_adapter = _MutualTlsAdapter(cert, key)
- self.mount("https://", mtls_adapter)
+ try:
+ self._is_mtls, cert, key = google.auth.transport._mtls_helper.get_client_cert_and_key(
+ client_cert_callback
+ )
+
+ if self._is_mtls:
+ mtls_adapter = _MutualTlsAdapter(cert, key)
+ self.mount("https://", mtls_adapter)
+ except (
+ ImportError,
+ OpenSSL.crypto.Error,
+ OSError,
+ RuntimeError,
+ ValueError,
+ ) as caught_exc:
+ new_exc = exceptions.MutualTLSChannelError(caught_exc)
+ six.raise_from(new_exc, caught_exc)
def request(
self,
diff --git a/google/auth/transport/urllib3.py b/google/auth/transport/urllib3.py
index 3b2ba28..c359f35 100644
--- a/google/auth/transport/urllib3.py
+++ b/google/auth/transport/urllib3.py
@@ -297,24 +297,33 @@
True if the channel is mutual TLS and False otherwise.
Raises:
- ImportError: If certifi or pyOpenSSL is not installed.
- OpenSSL.crypto.Error: If client cert or key is invalid.
- OSError: If the cert provider command launch fails during the
- application default SSL credentials loading process.
- RuntimeError: If the cert provider command has a runtime error during
- the application default SSL credentials loading process.
- ValueError: If the context aware metadata file is malformed or the
- cert provider command doesn't produce both client certicate and
- key during the application default SSL credentials loading process.
+ google.auth.exceptions.MutualTLSChannelError: If mutual TLS channel
+ creation failed for any reason.
"""
- found_cert_key, cert, key = transport._mtls_helper.get_client_cert_and_key(
- client_cert_callabck
- )
+ try:
+ import OpenSSL
+ except ImportError as caught_exc:
+ new_exc = exceptions.MutualTLSChannelError(caught_exc)
+ six.raise_from(new_exc, caught_exc)
- if found_cert_key:
- self.http = _make_mutual_tls_http(cert, key)
- else:
- self.http = _make_default_http()
+ try:
+ found_cert_key, cert, key = transport._mtls_helper.get_client_cert_and_key(
+ client_cert_callabck
+ )
+
+ if found_cert_key:
+ self.http = _make_mutual_tls_http(cert, key)
+ else:
+ self.http = _make_default_http()
+ except (
+ ImportError,
+ OpenSSL.crypto.Error,
+ OSError,
+ RuntimeError,
+ ValueError,
+ ) as caught_exc:
+ new_exc = exceptions.MutualTLSChannelError(caught_exc)
+ six.raise_from(new_exc, caught_exc)
if self._has_user_provided_http:
self._has_user_provided_http = False
diff --git a/tests/transport/test_grpc.py b/tests/transport/test_grpc.py
index 23e62a2..5c61f96 100644
--- a/tests/transport/test_grpc.py
+++ b/tests/transport/test_grpc.py
@@ -21,6 +21,7 @@
from google.auth import _helpers
from google.auth import credentials
+from google.auth import exceptions
from google.auth import transport
try:
@@ -315,7 +316,7 @@
# Mock that client cert and key are not loaded and exception is raised.
mock_get_client_ssl_credentials.side_effect = ValueError()
- with pytest.raises(ValueError):
+ with pytest.raises(exceptions.MutualTLSChannelError):
assert google.auth.transport.grpc.SslCredentials().ssl_credentials
def test_get_client_ssl_credentials_success(
diff --git a/tests/transport/test_requests.py b/tests/transport/test_requests.py
index 3f3e14c..d6770de 100644
--- a/tests/transport/test_requests.py
+++ b/tests/transport/test_requests.py
@@ -14,6 +14,7 @@
import datetime
import functools
+import sys
import freezegun
import mock
@@ -23,6 +24,7 @@
import requests.adapters
from six.moves import http_client
+from google.auth import exceptions
import google.auth.credentials
import google.auth.transport._mtls_helper
import google.auth.transport.requests
@@ -414,3 +416,21 @@
# Assert _MutualTlsAdapter constructor is not called.
mock_adapter_ctor.assert_not_called()
+
+ @mock.patch(
+ "google.auth.transport._mtls_helper.get_client_cert_and_key", autospec=True
+ )
+ def test_configure_mtls_channel_exceptions(self, mock_get_client_cert_and_key):
+ mock_get_client_cert_and_key.side_effect = ValueError()
+
+ auth_session = google.auth.transport.requests.AuthorizedSession(
+ credentials=mock.Mock()
+ )
+ with pytest.raises(exceptions.MutualTLSChannelError):
+ auth_session.configure_mtls_channel()
+
+ mock_get_client_cert_and_key.return_value = (False, None, None)
+ with mock.patch.dict("sys.modules"):
+ sys.modules["OpenSSL"] = None
+ with pytest.raises(exceptions.MutualTLSChannelError):
+ auth_session.configure_mtls_channel()
diff --git a/tests/transport/test_urllib3.py b/tests/transport/test_urllib3.py
index 0452e91..a25fcd7 100644
--- a/tests/transport/test_urllib3.py
+++ b/tests/transport/test_urllib3.py
@@ -12,12 +12,15 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+import sys
+
import mock
import OpenSSL
import pytest
from six.moves import http_client
import urllib3
+from google.auth import exceptions
import google.auth.credentials
import google.auth.transport._mtls_helper
import google.auth.transport.urllib3
@@ -221,3 +224,21 @@
assert not is_mtls
mock_get_client_cert_and_key.assert_called_once()
mock_make_mutual_tls_http.assert_not_called()
+
+ @mock.patch(
+ "google.auth.transport._mtls_helper.get_client_cert_and_key", autospec=True
+ )
+ def test_configure_mtls_channel_exceptions(self, mock_get_client_cert_and_key):
+ authed_http = google.auth.transport.urllib3.AuthorizedHttp(
+ credentials=mock.Mock()
+ )
+
+ mock_get_client_cert_and_key.side_effect = ValueError()
+ with pytest.raises(exceptions.MutualTLSChannelError):
+ authed_http.configure_mtls_channel()
+
+ mock_get_client_cert_and_key.return_value = (False, None, None)
+ with mock.patch.dict("sys.modules"):
+ sys.modules["OpenSSL"] = None
+ with pytest.raises(exceptions.MutualTLSChannelError):
+ authed_http.configure_mtls_channel()