Skip to content
This repository was archived by the owner on Jul 6, 2023. It is now read-only.

Commit aaa957f

Browse files
feat: add api key support (#35)
* chore: upgrade gapic-generator-java, gax-java and gapic-generator-python PiperOrigin-RevId: 423842556 Source-Link: googleapis/googleapis@a616ca0 Source-Link: https://github.com/googleapis/googleapis-gen/commit/29b938c58c1e51d019f2ee539d55dc0a3c86a905 Copy-Tag: eyJwIjoiLmdpdGh1Yi8uT3dsQm90LnlhbWwiLCJoIjoiMjliOTM4YzU4YzFlNTFkMDE5ZjJlZTUzOWQ1NWRjMGEzYzg2YTkwNSJ9 * 🦉 Updates from OwlBot See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md Co-authored-by: Owl Bot <gcf-owl-bot[bot]@users.noreply.github.com>
1 parent 612dba0 commit aaa957f

File tree

3 files changed

+245
-44
lines changed

3 files changed

+245
-44
lines changed

google/cloud/deploy_v1/services/cloud_deploy/async_client.py

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
from collections import OrderedDict
1717
import functools
1818
import re
19-
from typing import Dict, Sequence, Tuple, Type, Union
19+
from typing import Dict, Optional, Sequence, Tuple, Type, Union
2020
import pkg_resources
2121

2222
from google.api_core.client_options import ClientOptions
@@ -126,6 +126,42 @@ def from_service_account_file(cls, filename: str, *args, **kwargs):
126126

127127
from_service_account_json = from_service_account_file
128128

129+
@classmethod
130+
def get_mtls_endpoint_and_cert_source(
131+
cls, client_options: Optional[ClientOptions] = None
132+
):
133+
"""Return the API endpoint and client cert source for mutual TLS.
134+
135+
The client cert source is determined in the following order:
136+
(1) if `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is not "true", the
137+
client cert source is None.
138+
(2) if `client_options.client_cert_source` is provided, use the provided one; if the
139+
default client cert source exists, use the default one; otherwise the client cert
140+
source is None.
141+
142+
The API endpoint is determined in the following order:
143+
(1) if `client_options.api_endpoint` if provided, use the provided one.
144+
(2) if `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is "always", use the
145+
default mTLS endpoint; if the environment variabel is "never", use the default API
146+
endpoint; otherwise if client cert source exists, use the default mTLS endpoint, otherwise
147+
use the default API endpoint.
148+
149+
More details can be found at https://google.aip.dev/auth/4114.
150+
151+
Args:
152+
client_options (google.api_core.client_options.ClientOptions): Custom options for the
153+
client. Only the `api_endpoint` and `client_cert_source` properties may be used
154+
in this method.
155+
156+
Returns:
157+
Tuple[str, Callable[[], Tuple[bytes, bytes]]]: returns the API endpoint and the
158+
client cert source to use.
159+
160+
Raises:
161+
google.auth.exceptions.MutualTLSChannelError: If any errors happen.
162+
"""
163+
return CloudDeployClient.get_mtls_endpoint_and_cert_source(client_options) # type: ignore
164+
129165
@property
130166
def transport(self) -> CloudDeployTransport:
131167
"""Returns the transport used by the client instance.

google/cloud/deploy_v1/services/cloud_deploy/client.py

Lines changed: 84 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -364,6 +364,73 @@ def parse_common_location_path(path: str) -> Dict[str, str]:
364364
m = re.match(r"^projects/(?P<project>.+?)/locations/(?P<location>.+?)$", path)
365365
return m.groupdict() if m else {}
366366

367+
@classmethod
368+
def get_mtls_endpoint_and_cert_source(
369+
cls, client_options: Optional[client_options_lib.ClientOptions] = None
370+
):
371+
"""Return the API endpoint and client cert source for mutual TLS.
372+
373+
The client cert source is determined in the following order:
374+
(1) if `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is not "true", the
375+
client cert source is None.
376+
(2) if `client_options.client_cert_source` is provided, use the provided one; if the
377+
default client cert source exists, use the default one; otherwise the client cert
378+
source is None.
379+
380+
The API endpoint is determined in the following order:
381+
(1) if `client_options.api_endpoint` if provided, use the provided one.
382+
(2) if `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is "always", use the
383+
default mTLS endpoint; if the environment variabel is "never", use the default API
384+
endpoint; otherwise if client cert source exists, use the default mTLS endpoint, otherwise
385+
use the default API endpoint.
386+
387+
More details can be found at https://google.aip.dev/auth/4114.
388+
389+
Args:
390+
client_options (google.api_core.client_options.ClientOptions): Custom options for the
391+
client. Only the `api_endpoint` and `client_cert_source` properties may be used
392+
in this method.
393+
394+
Returns:
395+
Tuple[str, Callable[[], Tuple[bytes, bytes]]]: returns the API endpoint and the
396+
client cert source to use.
397+
398+
Raises:
399+
google.auth.exceptions.MutualTLSChannelError: If any errors happen.
400+
"""
401+
if client_options is None:
402+
client_options = client_options_lib.ClientOptions()
403+
use_client_cert = os.getenv("GOOGLE_API_USE_CLIENT_CERTIFICATE", "false")
404+
use_mtls_endpoint = os.getenv("GOOGLE_API_USE_MTLS_ENDPOINT", "auto")
405+
if use_client_cert not in ("true", "false"):
406+
raise ValueError(
407+
"Environment variable `GOOGLE_API_USE_CLIENT_CERTIFICATE` must be either `true` or `false`"
408+
)
409+
if use_mtls_endpoint not in ("auto", "never", "always"):
410+
raise MutualTLSChannelError(
411+
"Environment variable `GOOGLE_API_USE_MTLS_ENDPOINT` must be `never`, `auto` or `always`"
412+
)
413+
414+
# Figure out the client cert source to use.
415+
client_cert_source = None
416+
if use_client_cert == "true":
417+
if client_options.client_cert_source:
418+
client_cert_source = client_options.client_cert_source
419+
elif mtls.has_default_client_cert_source():
420+
client_cert_source = mtls.default_client_cert_source()
421+
422+
# Figure out which api endpoint to use.
423+
if client_options.api_endpoint is not None:
424+
api_endpoint = client_options.api_endpoint
425+
elif use_mtls_endpoint == "always" or (
426+
use_mtls_endpoint == "auto" and client_cert_source
427+
):
428+
api_endpoint = cls.DEFAULT_MTLS_ENDPOINT
429+
else:
430+
api_endpoint = cls.DEFAULT_ENDPOINT
431+
432+
return api_endpoint, client_cert_source
433+
367434
def __init__(
368435
self,
369436
*,
@@ -414,57 +481,22 @@ def __init__(
414481
if client_options is None:
415482
client_options = client_options_lib.ClientOptions()
416483

417-
# Create SSL credentials for mutual TLS if needed.
418-
if os.getenv("GOOGLE_API_USE_CLIENT_CERTIFICATE", "false") not in (
419-
"true",
420-
"false",
421-
):
422-
raise ValueError(
423-
"Environment variable `GOOGLE_API_USE_CLIENT_CERTIFICATE` must be either `true` or `false`"
424-
)
425-
use_client_cert = (
426-
os.getenv("GOOGLE_API_USE_CLIENT_CERTIFICATE", "false") == "true"
484+
api_endpoint, client_cert_source_func = self.get_mtls_endpoint_and_cert_source(
485+
client_options
427486
)
428487

429-
client_cert_source_func = None
430-
is_mtls = False
431-
if use_client_cert:
432-
if client_options.client_cert_source:
433-
is_mtls = True
434-
client_cert_source_func = client_options.client_cert_source
435-
else:
436-
is_mtls = mtls.has_default_client_cert_source()
437-
if is_mtls:
438-
client_cert_source_func = mtls.default_client_cert_source()
439-
else:
440-
client_cert_source_func = None
441-
442-
# Figure out which api endpoint to use.
443-
if client_options.api_endpoint is not None:
444-
api_endpoint = client_options.api_endpoint
445-
else:
446-
use_mtls_env = os.getenv("GOOGLE_API_USE_MTLS_ENDPOINT", "auto")
447-
if use_mtls_env == "never":
448-
api_endpoint = self.DEFAULT_ENDPOINT
449-
elif use_mtls_env == "always":
450-
api_endpoint = self.DEFAULT_MTLS_ENDPOINT
451-
elif use_mtls_env == "auto":
452-
if is_mtls:
453-
api_endpoint = self.DEFAULT_MTLS_ENDPOINT
454-
else:
455-
api_endpoint = self.DEFAULT_ENDPOINT
456-
else:
457-
raise MutualTLSChannelError(
458-
"Unsupported GOOGLE_API_USE_MTLS_ENDPOINT value. Accepted "
459-
"values: never, auto, always"
460-
)
488+
api_key_value = getattr(client_options, "api_key", None)
489+
if api_key_value and credentials:
490+
raise ValueError(
491+
"client_options.api_key and credentials are mutually exclusive"
492+
)
461493

462494
# Save or instantiate the transport.
463495
# Ordinarily, we provide the transport, but allowing a custom transport
464496
# instance provides an extensibility point for unusual situations.
465497
if isinstance(transport, CloudDeployTransport):
466498
# transport is a CloudDeployTransport instance.
467-
if credentials or client_options.credentials_file:
499+
if credentials or client_options.credentials_file or api_key_value:
468500
raise ValueError(
469501
"When providing a transport instance, "
470502
"provide its credentials directly."
@@ -476,6 +508,15 @@ def __init__(
476508
)
477509
self._transport = transport
478510
else:
511+
import google.auth._default # type: ignore
512+
513+
if api_key_value and hasattr(
514+
google.auth._default, "get_api_key_credentials"
515+
):
516+
credentials = google.auth._default.get_api_key_credentials(
517+
api_key_value
518+
)
519+
479520
Transport = type(self).get_transport_class(transport)
480521
self._transport = Transport(
481522
credentials=credentials,

tests/unit/gapic/deploy_v1/test_cloud_deploy.py

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -390,6 +390,83 @@ def test_cloud_deploy_client_mtls_env_auto(
390390
)
391391

392392

393+
@pytest.mark.parametrize("client_class", [CloudDeployClient, CloudDeployAsyncClient])
394+
@mock.patch.object(
395+
CloudDeployClient, "DEFAULT_ENDPOINT", modify_default_endpoint(CloudDeployClient)
396+
)
397+
@mock.patch.object(
398+
CloudDeployAsyncClient,
399+
"DEFAULT_ENDPOINT",
400+
modify_default_endpoint(CloudDeployAsyncClient),
401+
)
402+
def test_cloud_deploy_client_get_mtls_endpoint_and_cert_source(client_class):
403+
mock_client_cert_source = mock.Mock()
404+
405+
# Test the case GOOGLE_API_USE_CLIENT_CERTIFICATE is "true".
406+
with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "true"}):
407+
mock_api_endpoint = "foo"
408+
options = client_options.ClientOptions(
409+
client_cert_source=mock_client_cert_source, api_endpoint=mock_api_endpoint
410+
)
411+
api_endpoint, cert_source = client_class.get_mtls_endpoint_and_cert_source(
412+
options
413+
)
414+
assert api_endpoint == mock_api_endpoint
415+
assert cert_source == mock_client_cert_source
416+
417+
# Test the case GOOGLE_API_USE_CLIENT_CERTIFICATE is "false".
418+
with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "false"}):
419+
mock_client_cert_source = mock.Mock()
420+
mock_api_endpoint = "foo"
421+
options = client_options.ClientOptions(
422+
client_cert_source=mock_client_cert_source, api_endpoint=mock_api_endpoint
423+
)
424+
api_endpoint, cert_source = client_class.get_mtls_endpoint_and_cert_source(
425+
options
426+
)
427+
assert api_endpoint == mock_api_endpoint
428+
assert cert_source is None
429+
430+
# Test the case GOOGLE_API_USE_MTLS_ENDPOINT is "never".
431+
with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "never"}):
432+
api_endpoint, cert_source = client_class.get_mtls_endpoint_and_cert_source()
433+
assert api_endpoint == client_class.DEFAULT_ENDPOINT
434+
assert cert_source is None
435+
436+
# Test the case GOOGLE_API_USE_MTLS_ENDPOINT is "always".
437+
with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "always"}):
438+
api_endpoint, cert_source = client_class.get_mtls_endpoint_and_cert_source()
439+
assert api_endpoint == client_class.DEFAULT_MTLS_ENDPOINT
440+
assert cert_source is None
441+
442+
# Test the case GOOGLE_API_USE_MTLS_ENDPOINT is "auto" and default cert doesn't exist.
443+
with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "true"}):
444+
with mock.patch(
445+
"google.auth.transport.mtls.has_default_client_cert_source",
446+
return_value=False,
447+
):
448+
api_endpoint, cert_source = client_class.get_mtls_endpoint_and_cert_source()
449+
assert api_endpoint == client_class.DEFAULT_ENDPOINT
450+
assert cert_source is None
451+
452+
# Test the case GOOGLE_API_USE_MTLS_ENDPOINT is "auto" and default cert exists.
453+
with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "true"}):
454+
with mock.patch(
455+
"google.auth.transport.mtls.has_default_client_cert_source",
456+
return_value=True,
457+
):
458+
with mock.patch(
459+
"google.auth.transport.mtls.default_client_cert_source",
460+
return_value=mock_client_cert_source,
461+
):
462+
(
463+
api_endpoint,
464+
cert_source,
465+
) = client_class.get_mtls_endpoint_and_cert_source()
466+
assert api_endpoint == client_class.DEFAULT_MTLS_ENDPOINT
467+
assert cert_source == mock_client_cert_source
468+
469+
393470
@pytest.mark.parametrize(
394471
"client_class,transport_class,transport_name",
395472
[
@@ -4949,6 +5026,23 @@ def test_credentials_transport_error():
49495026
transport=transport,
49505027
)
49515028

5029+
# It is an error to provide an api_key and a transport instance.
5030+
transport = transports.CloudDeployGrpcTransport(
5031+
credentials=ga_credentials.AnonymousCredentials(),
5032+
)
5033+
options = client_options.ClientOptions()
5034+
options.api_key = "api_key"
5035+
with pytest.raises(ValueError):
5036+
client = CloudDeployClient(client_options=options, transport=transport,)
5037+
5038+
# It is an error to provide an api_key and a credential.
5039+
options = mock.Mock()
5040+
options.api_key = "api_key"
5041+
with pytest.raises(ValueError):
5042+
client = CloudDeployClient(
5043+
client_options=options, credentials=ga_credentials.AnonymousCredentials()
5044+
)
5045+
49525046
# It is an error to provide scopes and a transport instance.
49535047
transport = transports.CloudDeployGrpcTransport(
49545048
credentials=ga_credentials.AnonymousCredentials(),
@@ -5724,3 +5818,33 @@ def test_client_ctx():
57245818
with client:
57255819
pass
57265820
close.assert_called()
5821+
5822+
5823+
@pytest.mark.parametrize(
5824+
"client_class,transport_class",
5825+
[
5826+
(CloudDeployClient, transports.CloudDeployGrpcTransport),
5827+
(CloudDeployAsyncClient, transports.CloudDeployGrpcAsyncIOTransport),
5828+
],
5829+
)
5830+
def test_api_key_credentials(client_class, transport_class):
5831+
with mock.patch.object(
5832+
google.auth._default, "get_api_key_credentials", create=True
5833+
) as get_api_key_credentials:
5834+
mock_cred = mock.Mock()
5835+
get_api_key_credentials.return_value = mock_cred
5836+
options = client_options.ClientOptions()
5837+
options.api_key = "api_key"
5838+
with mock.patch.object(transport_class, "__init__") as patched:
5839+
patched.return_value = None
5840+
client = client_class(client_options=options)
5841+
patched.assert_called_once_with(
5842+
credentials=mock_cred,
5843+
credentials_file=None,
5844+
host=client.DEFAULT_ENDPOINT,
5845+
scopes=None,
5846+
client_cert_source_for_mtls=None,
5847+
quota_project_id=None,
5848+
client_info=transports.base.DEFAULT_CLIENT_INFO,
5849+
always_use_jwt_access=True,
5850+
)

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy