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

Commit c1210da

Browse files
feat: add api key support (#149)
* 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 816a364 commit c1210da

File tree

3 files changed

+260
-43
lines changed

3 files changed

+260
-43
lines changed

google/cloud/mediatranslation_v1beta1/services/speech_translation_service/async_client.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import re
1919
from typing import (
2020
Dict,
21+
Optional,
2122
AsyncIterable,
2223
Awaitable,
2324
AsyncIterator,
@@ -117,6 +118,42 @@ def from_service_account_file(cls, filename: str, *args, **kwargs):
117118

118119
from_service_account_json = from_service_account_file
119120

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

google/cloud/mediatranslation_v1beta1/services/speech_translation_service/client.py

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

223+
@classmethod
224+
def get_mtls_endpoint_and_cert_source(
225+
cls, client_options: Optional[client_options_lib.ClientOptions] = None
226+
):
227+
"""Return the API endpoint and client cert source for mutual TLS.
228+
229+
The client cert source is determined in the following order:
230+
(1) if `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is not "true", the
231+
client cert source is None.
232+
(2) if `client_options.client_cert_source` is provided, use the provided one; if the
233+
default client cert source exists, use the default one; otherwise the client cert
234+
source is None.
235+
236+
The API endpoint is determined in the following order:
237+
(1) if `client_options.api_endpoint` if provided, use the provided one.
238+
(2) if `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is "always", use the
239+
default mTLS endpoint; if the environment variabel is "never", use the default API
240+
endpoint; otherwise if client cert source exists, use the default mTLS endpoint, otherwise
241+
use the default API endpoint.
242+
243+
More details can be found at https://google.aip.dev/auth/4114.
244+
245+
Args:
246+
client_options (google.api_core.client_options.ClientOptions): Custom options for the
247+
client. Only the `api_endpoint` and `client_cert_source` properties may be used
248+
in this method.
249+
250+
Returns:
251+
Tuple[str, Callable[[], Tuple[bytes, bytes]]]: returns the API endpoint and the
252+
client cert source to use.
253+
254+
Raises:
255+
google.auth.exceptions.MutualTLSChannelError: If any errors happen.
256+
"""
257+
if client_options is None:
258+
client_options = client_options_lib.ClientOptions()
259+
use_client_cert = os.getenv("GOOGLE_API_USE_CLIENT_CERTIFICATE", "false")
260+
use_mtls_endpoint = os.getenv("GOOGLE_API_USE_MTLS_ENDPOINT", "auto")
261+
if use_client_cert not in ("true", "false"):
262+
raise ValueError(
263+
"Environment variable `GOOGLE_API_USE_CLIENT_CERTIFICATE` must be either `true` or `false`"
264+
)
265+
if use_mtls_endpoint not in ("auto", "never", "always"):
266+
raise MutualTLSChannelError(
267+
"Environment variable `GOOGLE_API_USE_MTLS_ENDPOINT` must be `never`, `auto` or `always`"
268+
)
269+
270+
# Figure out the client cert source to use.
271+
client_cert_source = None
272+
if use_client_cert == "true":
273+
if client_options.client_cert_source:
274+
client_cert_source = client_options.client_cert_source
275+
elif mtls.has_default_client_cert_source():
276+
client_cert_source = mtls.default_client_cert_source()
277+
278+
# Figure out which api endpoint to use.
279+
if client_options.api_endpoint is not None:
280+
api_endpoint = client_options.api_endpoint
281+
elif use_mtls_endpoint == "always" or (
282+
use_mtls_endpoint == "auto" and client_cert_source
283+
):
284+
api_endpoint = cls.DEFAULT_MTLS_ENDPOINT
285+
else:
286+
api_endpoint = cls.DEFAULT_ENDPOINT
287+
288+
return api_endpoint, client_cert_source
289+
223290
def __init__(
224291
self,
225292
*,
@@ -270,57 +337,22 @@ def __init__(
270337
if client_options is None:
271338
client_options = client_options_lib.ClientOptions()
272339

273-
# Create SSL credentials for mutual TLS if needed.
274-
if os.getenv("GOOGLE_API_USE_CLIENT_CERTIFICATE", "false") not in (
275-
"true",
276-
"false",
277-
):
278-
raise ValueError(
279-
"Environment variable `GOOGLE_API_USE_CLIENT_CERTIFICATE` must be either `true` or `false`"
280-
)
281-
use_client_cert = (
282-
os.getenv("GOOGLE_API_USE_CLIENT_CERTIFICATE", "false") == "true"
340+
api_endpoint, client_cert_source_func = self.get_mtls_endpoint_and_cert_source(
341+
client_options
283342
)
284343

285-
client_cert_source_func = None
286-
is_mtls = False
287-
if use_client_cert:
288-
if client_options.client_cert_source:
289-
is_mtls = True
290-
client_cert_source_func = client_options.client_cert_source
291-
else:
292-
is_mtls = mtls.has_default_client_cert_source()
293-
if is_mtls:
294-
client_cert_source_func = mtls.default_client_cert_source()
295-
else:
296-
client_cert_source_func = None
297-
298-
# Figure out which api endpoint to use.
299-
if client_options.api_endpoint is not None:
300-
api_endpoint = client_options.api_endpoint
301-
else:
302-
use_mtls_env = os.getenv("GOOGLE_API_USE_MTLS_ENDPOINT", "auto")
303-
if use_mtls_env == "never":
304-
api_endpoint = self.DEFAULT_ENDPOINT
305-
elif use_mtls_env == "always":
306-
api_endpoint = self.DEFAULT_MTLS_ENDPOINT
307-
elif use_mtls_env == "auto":
308-
if is_mtls:
309-
api_endpoint = self.DEFAULT_MTLS_ENDPOINT
310-
else:
311-
api_endpoint = self.DEFAULT_ENDPOINT
312-
else:
313-
raise MutualTLSChannelError(
314-
"Unsupported GOOGLE_API_USE_MTLS_ENDPOINT value. Accepted "
315-
"values: never, auto, always"
316-
)
344+
api_key_value = getattr(client_options, "api_key", None)
345+
if api_key_value and credentials:
346+
raise ValueError(
347+
"client_options.api_key and credentials are mutually exclusive"
348+
)
317349

318350
# Save or instantiate the transport.
319351
# Ordinarily, we provide the transport, but allowing a custom transport
320352
# instance provides an extensibility point for unusual situations.
321353
if isinstance(transport, SpeechTranslationServiceTransport):
322354
# transport is a SpeechTranslationServiceTransport instance.
323-
if credentials or client_options.credentials_file:
355+
if credentials or client_options.credentials_file or api_key_value:
324356
raise ValueError(
325357
"When providing a transport instance, "
326358
"provide its credentials directly."
@@ -332,6 +364,15 @@ def __init__(
332364
)
333365
self._transport = transport
334366
else:
367+
import google.auth._default # type: ignore
368+
369+
if api_key_value and hasattr(
370+
google.auth._default, "get_api_key_credentials"
371+
):
372+
credentials = google.auth._default.get_api_key_credentials(
373+
api_key_value
374+
)
375+
335376
Transport = type(self).get_transport_class(transport)
336377
self._transport = Transport(
337378
credentials=credentials,

tests/unit/gapic/mediatranslation_v1beta1/test_speech_translation_service.py

Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -422,6 +422,90 @@ def test_speech_translation_service_client_mtls_env_auto(
422422
)
423423

424424

425+
@pytest.mark.parametrize(
426+
"client_class",
427+
[SpeechTranslationServiceClient, SpeechTranslationServiceAsyncClient],
428+
)
429+
@mock.patch.object(
430+
SpeechTranslationServiceClient,
431+
"DEFAULT_ENDPOINT",
432+
modify_default_endpoint(SpeechTranslationServiceClient),
433+
)
434+
@mock.patch.object(
435+
SpeechTranslationServiceAsyncClient,
436+
"DEFAULT_ENDPOINT",
437+
modify_default_endpoint(SpeechTranslationServiceAsyncClient),
438+
)
439+
def test_speech_translation_service_client_get_mtls_endpoint_and_cert_source(
440+
client_class,
441+
):
442+
mock_client_cert_source = mock.Mock()
443+
444+
# Test the case GOOGLE_API_USE_CLIENT_CERTIFICATE is "true".
445+
with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "true"}):
446+
mock_api_endpoint = "foo"
447+
options = client_options.ClientOptions(
448+
client_cert_source=mock_client_cert_source, api_endpoint=mock_api_endpoint
449+
)
450+
api_endpoint, cert_source = client_class.get_mtls_endpoint_and_cert_source(
451+
options
452+
)
453+
assert api_endpoint == mock_api_endpoint
454+
assert cert_source == mock_client_cert_source
455+
456+
# Test the case GOOGLE_API_USE_CLIENT_CERTIFICATE is "false".
457+
with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "false"}):
458+
mock_client_cert_source = mock.Mock()
459+
mock_api_endpoint = "foo"
460+
options = client_options.ClientOptions(
461+
client_cert_source=mock_client_cert_source, api_endpoint=mock_api_endpoint
462+
)
463+
api_endpoint, cert_source = client_class.get_mtls_endpoint_and_cert_source(
464+
options
465+
)
466+
assert api_endpoint == mock_api_endpoint
467+
assert cert_source is None
468+
469+
# Test the case GOOGLE_API_USE_MTLS_ENDPOINT is "never".
470+
with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "never"}):
471+
api_endpoint, cert_source = client_class.get_mtls_endpoint_and_cert_source()
472+
assert api_endpoint == client_class.DEFAULT_ENDPOINT
473+
assert cert_source is None
474+
475+
# Test the case GOOGLE_API_USE_MTLS_ENDPOINT is "always".
476+
with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "always"}):
477+
api_endpoint, cert_source = client_class.get_mtls_endpoint_and_cert_source()
478+
assert api_endpoint == client_class.DEFAULT_MTLS_ENDPOINT
479+
assert cert_source is None
480+
481+
# Test the case GOOGLE_API_USE_MTLS_ENDPOINT is "auto" and default cert doesn't exist.
482+
with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "true"}):
483+
with mock.patch(
484+
"google.auth.transport.mtls.has_default_client_cert_source",
485+
return_value=False,
486+
):
487+
api_endpoint, cert_source = client_class.get_mtls_endpoint_and_cert_source()
488+
assert api_endpoint == client_class.DEFAULT_ENDPOINT
489+
assert cert_source is None
490+
491+
# Test the case GOOGLE_API_USE_MTLS_ENDPOINT is "auto" and default cert exists.
492+
with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "true"}):
493+
with mock.patch(
494+
"google.auth.transport.mtls.has_default_client_cert_source",
495+
return_value=True,
496+
):
497+
with mock.patch(
498+
"google.auth.transport.mtls.default_client_cert_source",
499+
return_value=mock_client_cert_source,
500+
):
501+
(
502+
api_endpoint,
503+
cert_source,
504+
) = client_class.get_mtls_endpoint_and_cert_source()
505+
assert api_endpoint == client_class.DEFAULT_MTLS_ENDPOINT
506+
assert cert_source == mock_client_cert_source
507+
508+
425509
@pytest.mark.parametrize(
426510
"client_class,transport_class,transport_name",
427511
[
@@ -603,6 +687,25 @@ def test_credentials_transport_error():
603687
transport=transport,
604688
)
605689

690+
# It is an error to provide an api_key and a transport instance.
691+
transport = transports.SpeechTranslationServiceGrpcTransport(
692+
credentials=ga_credentials.AnonymousCredentials(),
693+
)
694+
options = client_options.ClientOptions()
695+
options.api_key = "api_key"
696+
with pytest.raises(ValueError):
697+
client = SpeechTranslationServiceClient(
698+
client_options=options, transport=transport,
699+
)
700+
701+
# It is an error to provide an api_key and a credential.
702+
options = mock.Mock()
703+
options.api_key = "api_key"
704+
with pytest.raises(ValueError):
705+
client = SpeechTranslationServiceClient(
706+
client_options=options, credentials=ga_credentials.AnonymousCredentials()
707+
)
708+
606709
# It is an error to provide scopes and a transport instance.
607710
transport = transports.SpeechTranslationServiceGrpcTransport(
608711
credentials=ga_credentials.AnonymousCredentials(),
@@ -1144,3 +1247,39 @@ def test_client_ctx():
11441247
with client:
11451248
pass
11461249
close.assert_called()
1250+
1251+
1252+
@pytest.mark.parametrize(
1253+
"client_class,transport_class",
1254+
[
1255+
(
1256+
SpeechTranslationServiceClient,
1257+
transports.SpeechTranslationServiceGrpcTransport,
1258+
),
1259+
(
1260+
SpeechTranslationServiceAsyncClient,
1261+
transports.SpeechTranslationServiceGrpcAsyncIOTransport,
1262+
),
1263+
],
1264+
)
1265+
def test_api_key_credentials(client_class, transport_class):
1266+
with mock.patch.object(
1267+
google.auth._default, "get_api_key_credentials", create=True
1268+
) as get_api_key_credentials:
1269+
mock_cred = mock.Mock()
1270+
get_api_key_credentials.return_value = mock_cred
1271+
options = client_options.ClientOptions()
1272+
options.api_key = "api_key"
1273+
with mock.patch.object(transport_class, "__init__") as patched:
1274+
patched.return_value = None
1275+
client = client_class(client_options=options)
1276+
patched.assert_called_once_with(
1277+
credentials=mock_cred,
1278+
credentials_file=None,
1279+
host=client.DEFAULT_ENDPOINT,
1280+
scopes=None,
1281+
client_cert_source_for_mtls=None,
1282+
quota_project_id=None,
1283+
client_info=transports.base.DEFAULT_CLIENT_INFO,
1284+
always_use_jwt_access=True,
1285+
)

0 commit comments

Comments
 (0)