Skip to content
This repository has been archived by the owner on Sep 5, 2023. It is now read-only.

Commit

Permalink
feat: add mtls support and resource path parse methods (via synth) (#4)
Browse files Browse the repository at this point in the history
  • Loading branch information
yoshi-automation committed May 28, 2020
1 parent 4292038 commit c20fa3f
Show file tree
Hide file tree
Showing 7 changed files with 351 additions and 58 deletions.
27 changes: 3 additions & 24 deletions .coveragerc
@@ -1,39 +1,18 @@
# -*- coding: utf-8 -*-
#
# Copyright 2020 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# Generated by synthtool. DO NOT EDIT!
[run]
branch = True

[report]
fail_under = 100
show_missing = True
omit =
google/cloud/recaptchaenterprise/__init__.py
exclude_lines =
# Re-enable the standard pragma
pragma: NO COVER
# Ignore debug-only repr
def __repr__
# Ignore abstract methods
raise NotImplementedError
# Ignore pkg_resources exceptions.
# This is added at the module level as a safeguard for if someone
# generates the code and tries to run it without pip installing. This
# makes it virtually impossible to test properly.
except pkg_resources.DistributionNotFound
omit =
*/gapic/*.py
*/proto/*.py
*/core/*.py
*/site-packages/*.py
Expand Up @@ -16,7 +16,8 @@
#

from collections import OrderedDict
from typing import Dict, Sequence, Tuple, Type, Union
import re
from typing import Callable, Dict, Sequence, Tuple, Type, Union
import pkg_resources

import google.api_core.client_options as ClientOptions # type: ignore
Expand Down Expand Up @@ -73,8 +74,38 @@ def get_transport_class(
class RecaptchaEnterpriseServiceClient(metaclass=RecaptchaEnterpriseServiceClientMeta):
"""Service to determine the likelihood an event is legitimate."""

DEFAULT_OPTIONS = ClientOptions.ClientOptions(
api_endpoint="recaptchaenterprise.googleapis.com"
@staticmethod
def _get_default_mtls_endpoint(api_endpoint):
"""Convert api endpoint to mTLS endpoint.
Convert "*.sandbox.googleapis.com" and "*.googleapis.com" to
"*.mtls.sandbox.googleapis.com" and "*.mtls.googleapis.com" respectively.
Args:
api_endpoint (Optional[str]): the api endpoint to convert.
Returns:
str: converted mTLS api endpoint.
"""
if not api_endpoint:
return api_endpoint

mtls_endpoint_re = re.compile(
r"(?P<name>[^.]+)(?P<mtls>\.mtls)?(?P<sandbox>\.sandbox)?(?P<googledomain>\.googleapis\.com)?"
)

m = mtls_endpoint_re.match(api_endpoint)
name, mtls, sandbox, googledomain = m.groups()
if mtls or not googledomain:
return api_endpoint

if sandbox:
return api_endpoint.replace(
"sandbox.googleapis.com", "mtls.sandbox.googleapis.com"
)

return api_endpoint.replace(".googleapis.com", ".mtls.googleapis.com")

DEFAULT_ENDPOINT = "recaptchaenterprise.googleapis.com"
DEFAULT_MTLS_ENDPOINT = _get_default_mtls_endpoint.__func__( # type: ignore
DEFAULT_ENDPOINT
)

@classmethod
Expand Down Expand Up @@ -102,19 +133,33 @@ def key_path(project: str, key: str) -> str:
"""Return a fully-qualified key string."""
return "projects/{project}/keys/{key}".format(project=project, key=key)

@staticmethod
def parse_key_path(path: str) -> Dict[str, str]:
"""Parse a key path into its component segments."""
m = re.match(r"^projects/(?P<project>.+?)/keys/(?P<key>.+?)$", path)
return m.groupdict() if m else {}

@staticmethod
def assessment_path(project: str, assessment: str) -> str:
"""Return a fully-qualified assessment string."""
return "projects/{project}/assessments/{assessment}".format(
project=project, assessment=assessment
)

@staticmethod
def parse_assessment_path(path: str) -> Dict[str, str]:
"""Parse a assessment path into its component segments."""
m = re.match(
r"^projects/(?P<project>.+?)/assessments/(?P<assessment>.+?)$", path
)
return m.groupdict() if m else {}

def __init__(
self,
*,
credentials: credentials.Credentials = None,
transport: Union[str, RecaptchaEnterpriseServiceTransport] = None,
client_options: ClientOptions = DEFAULT_OPTIONS,
client_options: ClientOptions = None,
) -> None:
"""Instantiate the recaptcha enterprise service client.
Expand All @@ -128,6 +173,17 @@ def __init__(
transport to use. If set to None, a transport is chosen
automatically.
client_options (ClientOptions): Custom options for the client.
(1) The ``api_endpoint`` property can be used to override the
default endpoint provided by the client.
(2) If ``transport`` argument is None, ``client_options`` can be
used to create a mutual TLS transport. If ``client_cert_source``
is provided, mutual TLS transport will be created with the given
``api_endpoint`` or the default mTLS endpoint, and the client
SSL credentials obtained from ``client_cert_source``.
Raises:
google.auth.exceptions.MutualTlsChannelError: If mutual TLS transport
creation failed for any reason.
"""
if isinstance(client_options, dict):
client_options = ClientOptions.from_dict(client_options)
Expand All @@ -136,18 +192,46 @@ def __init__(
# Ordinarily, we provide the transport, but allowing a custom transport
# instance provides an extensibility point for unusual situations.
if isinstance(transport, RecaptchaEnterpriseServiceTransport):
# transport is a RecaptchaEnterpriseServiceTransport instance.
if credentials:
raise ValueError(
"When providing a transport instance, "
"provide its credentials directly."
)
self._transport = transport
else:
elif client_options is None or (
client_options.api_endpoint is None
and client_options.client_cert_source is None
):
# Don't trigger mTLS if we get an empty ClientOptions.
Transport = type(self).get_transport_class(transport)
self._transport = Transport(
credentials=credentials, host=self.DEFAULT_ENDPOINT
)
else:
# We have a non-empty ClientOptions. If client_cert_source is
# provided, trigger mTLS with user provided endpoint or the default
# mTLS endpoint.
if client_options.client_cert_source:
api_mtls_endpoint = (
client_options.api_endpoint
if client_options.api_endpoint
else self.DEFAULT_MTLS_ENDPOINT
)
else:
api_mtls_endpoint = None

api_endpoint = (
client_options.api_endpoint
if client_options.api_endpoint
else self.DEFAULT_ENDPOINT
)

self._transport = RecaptchaEnterpriseServiceGrpcTransport(
credentials=credentials,
host=client_options.api_endpoint
or "recaptchaenterprise.googleapis.com",
host=api_endpoint,
api_mtls_endpoint=api_mtls_endpoint,
client_cert_source=client_options.client_cert_source,
)

def create_assessment(
Expand Down
Expand Up @@ -15,10 +15,12 @@
# limitations under the License.
#

from typing import Callable, Dict
from typing import Callable, Dict, Tuple

from google.api_core import grpc_helpers # type: ignore
from google.auth import credentials # type: ignore
from google.auth.transport.grpc import SslCredentials # type: ignore


import grpc # type: ignore

Expand Down Expand Up @@ -46,7 +48,9 @@ def __init__(
*,
host: str = "recaptchaenterprise.googleapis.com",
credentials: credentials.Credentials = None,
channel: grpc.Channel = None
channel: grpc.Channel = None,
api_mtls_endpoint: str = None,
client_cert_source: Callable[[], Tuple[bytes, bytes]] = None
) -> None:
"""Instantiate the transport.
Expand All @@ -60,20 +64,55 @@ def __init__(
This argument is ignored if ``channel`` is provided.
channel (Optional[grpc.Channel]): A ``Channel`` instance through
which to make calls.
api_mtls_endpoint (Optional[str]): The mutual TLS endpoint. If
provided, it overrides the ``host`` argument and tries to create
a mutual TLS channel with client SSL credentials from
``client_cert_source`` or applicatin default SSL credentials.
client_cert_source (Optional[Callable[[], Tuple[bytes, bytes]]]): A
callback to provide client SSL certificate bytes and private key
bytes, both in PEM format. It is ignored if ``api_mtls_endpoint``
is None.
Raises:
google.auth.exceptions.MutualTlsChannelError: If mutual TLS transport
creation failed for any reason.
"""
# Sanity check: Ensure that channel and credentials are not both
# provided.
if channel:
# Sanity check: Ensure that channel and credentials are not both
# provided.
credentials = False

# If a channel was explicitly provided, set it.
self._grpc_channel = channel
elif api_mtls_endpoint:
host = (
api_mtls_endpoint
if ":" in api_mtls_endpoint
else api_mtls_endpoint + ":443"
)

# Create SSL credentials with client_cert_source or application
# default SSL credentials.
if client_cert_source:
cert, key = client_cert_source()
ssl_credentials = grpc.ssl_channel_credentials(
certificate_chain=cert, private_key=key
)
else:
ssl_credentials = SslCredentials().ssl_credentials

# create a new channel. The provided one is ignored.
self._grpc_channel = grpc_helpers.create_channel(
host,
credentials=credentials,
ssl_credentials=ssl_credentials,
scopes=self.AUTH_SCOPES,
)

# Run the base constructor.
super().__init__(host=host, credentials=credentials)
self._stubs = {} # type: Dict[str, Callable]

# If a channel was explicitly provided, set it.
if channel:
self._grpc_channel = channel

@classmethod
def create_channel(
cls,
Expand Down
2 changes: 1 addition & 1 deletion mypy.ini
@@ -1,3 +1,3 @@
[mypy]
python_version = 3.5
python_version = 3.6
namespace_packages = True
4 changes: 1 addition & 3 deletions setup.py
Expand Up @@ -40,9 +40,7 @@
platforms="Posix; MacOS X; Windows",
include_package_data=True,
install_requires=(
"google-api-core >= 1.8.0, < 2.0.0dev",
"googleapis-common-protos >= 1.5.8",
"grpcio >= 1.10.0",
"google-api-core[grpc] >= 1.17.0, < 2.0.0dev",
"proto-plus >= 0.4.0",
),
python_requires=">=3.6",
Expand Down
3 changes: 2 additions & 1 deletion synth.metadata
Expand Up @@ -3,7 +3,8 @@
{
"git": {
"name": ".",
"remote": "sso://devrel/cloud/libraries/python/python-recaptcha-enterprise"
"remote": "https://github.com/googleapis/python-recaptcha-enterprise.git",
"sha": "4292038216cb9e2cf20194189f49f22e0c06cb41"
}
},
{
Expand Down

0 comments on commit c20fa3f

Please sign in to comment.