Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: consolidate mTLS channel errors #480

Merged
merged 3 commits into from
Apr 1, 2020
Merged
Changes from 1 commit
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
Next Next commit
feat: consolidate mTLS channel errors
  • Loading branch information
arithmetic1728 committed Apr 1, 2020
commit fd01dd919e2563668eba5f0d7ed39d8605a64724
4 changes: 4 additions & 0 deletions google/auth/exceptions.py
Original file line number Diff line number Diff line change
@@ -34,3 +34,7 @@ class UserAccessTokenError(GoogleAuthError):

class DefaultCredentialsError(GoogleAuthError):
"""Used to indicate that acquiring default credentials failed."""


class MutualTlsChannelError(GoogleAuthError):
arithmetic1728 marked this conversation as resolved.
Show resolved Hide resolved
"""Used to indicate that mutual TLS channel creation is failed."""
39 changes: 16 additions & 23 deletions google/auth/transport/grpc.py
Original file line number Diff line number Diff line change
@@ -20,6 +20,7 @@

import six

from google.auth import exceptions
from google.auth.transport import _mtls_helper

try:
@@ -217,17 +218,8 @@ def my_client_cert_callback():
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 @@ def ssl_credentials(self):
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()

39 changes: 24 additions & 15 deletions google/auth/transport/requests.py
Original file line number Diff line number Diff line change
@@ -355,23 +355,32 @@ def configure_mtls_channel(self, client_cert_callback=None):
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,
41 changes: 25 additions & 16 deletions google/auth/transport/urllib3.py
Original file line number Diff line number Diff line change
@@ -297,24 +297,33 @@ def configure_mtls_channel(self, client_cert_callabck=None):
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
3 changes: 2 additions & 1 deletion tests/transport/test_grpc.py
Original file line number Diff line number Diff line change
@@ -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 @@ def test_get_client_ssl_credentials_failure(
# 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(
20 changes: 20 additions & 0 deletions tests/transport/test_requests.py
Original file line number Diff line number Diff line change
@@ -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 @@ def test_configure_mtls_channel_non_mtls(

# 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()
21 changes: 21 additions & 0 deletions tests/transport/test_urllib3.py
Original file line number Diff line number Diff line change
@@ -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 @@ def test_configure_mtls_channel_non_mtls(
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()