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

feat: add mtls support and resource path parse methods (via synth) #4

Merged
merged 3 commits into from May 28, 2020
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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