Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit c2c39bd

Browse filesBrowse files
feat: add api key support (#116)
* chore: upgrade gapic-generator-java, gax-java and gapic-generator-python PiperOrigin-RevId: 423842556 Source-Link: googleapis/googleapis@a616ca0 Source-Link: googleapis/googleapis-gen@29b938c 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 9f543df commit c2c39bd
Copy full SHA for c2c39bd

File tree

Expand file treeCollapse file tree

3 files changed

+249
-44
lines changed
Filter options
Expand file treeCollapse file tree

3 files changed

+249
-44
lines changed

‎packages/google-area120-tables/google/area120/tables_v1alpha1/services/tables_service/async_client.py

Copy file name to clipboardExpand all lines: packages/google-area120-tables/google/area120/tables_v1alpha1/services/tables_service/async_client.py
+37-1Lines 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
@@ -125,6 +125,42 @@ def from_service_account_file(cls, filename: str, *args, **kwargs):
125125

126126
from_service_account_json = from_service_account_file
127127

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

‎packages/google-area120-tables/google/area120/tables_v1alpha1/services/tables_service/client.py

Copy file name to clipboardExpand all lines: packages/google-area120-tables/google/area120/tables_v1alpha1/services/tables_service/client.py
+84-43Lines changed: 84 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,73 @@ def parse_common_location_path(path: str) -> Dict[str, str]:
264264
m = re.match(r"^projects/(?P<project>.+?)/locations/(?P<location>.+?)$", path)
265265
return m.groupdict() if m else {}
266266

267+
@classmethod
268+
def get_mtls_endpoint_and_cert_source(
269+
cls, client_options: Optional[client_options_lib.ClientOptions] = None
270+
):
271+
"""Return the API endpoint and client cert source for mutual TLS.
272+
273+
The client cert source is determined in the following order:
274+
(1) if `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is not "true", the
275+
client cert source is None.
276+
(2) if `client_options.client_cert_source` is provided, use the provided one; if the
277+
default client cert source exists, use the default one; otherwise the client cert
278+
source is None.
279+
280+
The API endpoint is determined in the following order:
281+
(1) if `client_options.api_endpoint` if provided, use the provided one.
282+
(2) if `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is "always", use the
283+
default mTLS endpoint; if the environment variabel is "never", use the default API
284+
endpoint; otherwise if client cert source exists, use the default mTLS endpoint, otherwise
285+
use the default API endpoint.
286+
287+
More details can be found at https://google.aip.dev/auth/4114.
288+
289+
Args:
290+
client_options (google.api_core.client_options.ClientOptions): Custom options for the
291+
client. Only the `api_endpoint` and `client_cert_source` properties may be used
292+
in this method.
293+
294+
Returns:
295+
Tuple[str, Callable[[], Tuple[bytes, bytes]]]: returns the API endpoint and the
296+
client cert source to use.
297+
298+
Raises:
299+
google.auth.exceptions.MutualTLSChannelError: If any errors happen.
300+
"""
301+
if client_options is None:
302+
client_options = client_options_lib.ClientOptions()
303+
use_client_cert = os.getenv("GOOGLE_API_USE_CLIENT_CERTIFICATE", "false")
304+
use_mtls_endpoint = os.getenv("GOOGLE_API_USE_MTLS_ENDPOINT", "auto")
305+
if use_client_cert not in ("true", "false"):
306+
raise ValueError(
307+
"Environment variable `GOOGLE_API_USE_CLIENT_CERTIFICATE` must be either `true` or `false`"
308+
)
309+
if use_mtls_endpoint not in ("auto", "never", "always"):
310+
raise MutualTLSChannelError(
311+
"Environment variable `GOOGLE_API_USE_MTLS_ENDPOINT` must be `never`, `auto` or `always`"
312+
)
313+
314+
# Figure out the client cert source to use.
315+
client_cert_source = None
316+
if use_client_cert == "true":
317+
if client_options.client_cert_source:
318+
client_cert_source = client_options.client_cert_source
319+
elif mtls.has_default_client_cert_source():
320+
client_cert_source = mtls.default_client_cert_source()
321+
322+
# Figure out which api endpoint to use.
323+
if client_options.api_endpoint is not None:
324+
api_endpoint = client_options.api_endpoint
325+
elif use_mtls_endpoint == "always" or (
326+
use_mtls_endpoint == "auto" and client_cert_source
327+
):
328+
api_endpoint = cls.DEFAULT_MTLS_ENDPOINT
329+
else:
330+
api_endpoint = cls.DEFAULT_ENDPOINT
331+
332+
return api_endpoint, client_cert_source
333+
267334
def __init__(
268335
self,
269336
*,
@@ -314,57 +381,22 @@ def __init__(
314381
if client_options is None:
315382
client_options = client_options_lib.ClientOptions()
316383

317-
# Create SSL credentials for mutual TLS if needed.
318-
if os.getenv("GOOGLE_API_USE_CLIENT_CERTIFICATE", "false") not in (
319-
"true",
320-
"false",
321-
):
322-
raise ValueError(
323-
"Environment variable `GOOGLE_API_USE_CLIENT_CERTIFICATE` must be either `true` or `false`"
324-
)
325-
use_client_cert = (
326-
os.getenv("GOOGLE_API_USE_CLIENT_CERTIFICATE", "false") == "true"
384+
api_endpoint, client_cert_source_func = self.get_mtls_endpoint_and_cert_source(
385+
client_options
327386
)
328387

329-
client_cert_source_func = None
330-
is_mtls = False
331-
if use_client_cert:
332-
if client_options.client_cert_source:
333-
is_mtls = True
334-
client_cert_source_func = client_options.client_cert_source
335-
else:
336-
is_mtls = mtls.has_default_client_cert_source()
337-
if is_mtls:
338-
client_cert_source_func = mtls.default_client_cert_source()
339-
else:
340-
client_cert_source_func = None
341-
342-
# Figure out which api endpoint to use.
343-
if client_options.api_endpoint is not None:
344-
api_endpoint = client_options.api_endpoint
345-
else:
346-
use_mtls_env = os.getenv("GOOGLE_API_USE_MTLS_ENDPOINT", "auto")
347-
if use_mtls_env == "never":
348-
api_endpoint = self.DEFAULT_ENDPOINT
349-
elif use_mtls_env == "always":
350-
api_endpoint = self.DEFAULT_MTLS_ENDPOINT
351-
elif use_mtls_env == "auto":
352-
if is_mtls:
353-
api_endpoint = self.DEFAULT_MTLS_ENDPOINT
354-
else:
355-
api_endpoint = self.DEFAULT_ENDPOINT
356-
else:
357-
raise MutualTLSChannelError(
358-
"Unsupported GOOGLE_API_USE_MTLS_ENDPOINT value. Accepted "
359-
"values: never, auto, always"
360-
)
388+
api_key_value = getattr(client_options, "api_key", None)
389+
if api_key_value and credentials:
390+
raise ValueError(
391+
"client_options.api_key and credentials are mutually exclusive"
392+
)
361393

362394
# Save or instantiate the transport.
363395
# Ordinarily, we provide the transport, but allowing a custom transport
364396
# instance provides an extensibility point for unusual situations.
365397
if isinstance(transport, TablesServiceTransport):
366398
# transport is a TablesServiceTransport instance.
367-
if credentials or client_options.credentials_file:
399+
if credentials or client_options.credentials_file or api_key_value:
368400
raise ValueError(
369401
"When providing a transport instance, "
370402
"provide its credentials directly."
@@ -376,6 +408,15 @@ def __init__(
376408
)
377409
self._transport = transport
378410
else:
411+
import google.auth._default # type: ignore
412+
413+
if api_key_value and hasattr(
414+
google.auth._default, "get_api_key_credentials"
415+
):
416+
credentials = google.auth._default.get_api_key_credentials(
417+
api_key_value
418+
)
419+
379420
Transport = type(self).get_transport_class(transport)
380421
self._transport = Transport(
381422
credentials=credentials,

‎packages/google-area120-tables/tests/unit/gapic/tables_v1alpha1/test_tables_service.py

Copy file name to clipboardExpand all lines: packages/google-area120-tables/tests/unit/gapic/tables_v1alpha1/test_tables_service.py
+128Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -399,6 +399,87 @@ def test_tables_service_client_mtls_env_auto(
399399
)
400400

401401

402+
@pytest.mark.parametrize(
403+
"client_class", [TablesServiceClient, TablesServiceAsyncClient]
404+
)
405+
@mock.patch.object(
406+
TablesServiceClient,
407+
"DEFAULT_ENDPOINT",
408+
modify_default_endpoint(TablesServiceClient),
409+
)
410+
@mock.patch.object(
411+
TablesServiceAsyncClient,
412+
"DEFAULT_ENDPOINT",
413+
modify_default_endpoint(TablesServiceAsyncClient),
414+
)
415+
def test_tables_service_client_get_mtls_endpoint_and_cert_source(client_class):
416+
mock_client_cert_source = mock.Mock()
417+
418+
# Test the case GOOGLE_API_USE_CLIENT_CERTIFICATE is "true".
419+
with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "true"}):
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 == mock_client_cert_source
429+
430+
# Test the case GOOGLE_API_USE_CLIENT_CERTIFICATE is "false".
431+
with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "false"}):
432+
mock_client_cert_source = mock.Mock()
433+
mock_api_endpoint = "foo"
434+
options = client_options.ClientOptions(
435+
client_cert_source=mock_client_cert_source, api_endpoint=mock_api_endpoint
436+
)
437+
api_endpoint, cert_source = client_class.get_mtls_endpoint_and_cert_source(
438+
options
439+
)
440+
assert api_endpoint == mock_api_endpoint
441+
assert cert_source is None
442+
443+
# Test the case GOOGLE_API_USE_MTLS_ENDPOINT is "never".
444+
with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "never"}):
445+
api_endpoint, cert_source = client_class.get_mtls_endpoint_and_cert_source()
446+
assert api_endpoint == client_class.DEFAULT_ENDPOINT
447+
assert cert_source is None
448+
449+
# Test the case GOOGLE_API_USE_MTLS_ENDPOINT is "always".
450+
with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "always"}):
451+
api_endpoint, cert_source = client_class.get_mtls_endpoint_and_cert_source()
452+
assert api_endpoint == client_class.DEFAULT_MTLS_ENDPOINT
453+
assert cert_source is None
454+
455+
# Test the case GOOGLE_API_USE_MTLS_ENDPOINT is "auto" and default cert doesn't exist.
456+
with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "true"}):
457+
with mock.patch(
458+
"google.auth.transport.mtls.has_default_client_cert_source",
459+
return_value=False,
460+
):
461+
api_endpoint, cert_source = client_class.get_mtls_endpoint_and_cert_source()
462+
assert api_endpoint == client_class.DEFAULT_ENDPOINT
463+
assert cert_source is None
464+
465+
# Test the case GOOGLE_API_USE_MTLS_ENDPOINT is "auto" and default cert exists.
466+
with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "true"}):
467+
with mock.patch(
468+
"google.auth.transport.mtls.has_default_client_cert_source",
469+
return_value=True,
470+
):
471+
with mock.patch(
472+
"google.auth.transport.mtls.default_client_cert_source",
473+
return_value=mock_client_cert_source,
474+
):
475+
(
476+
api_endpoint,
477+
cert_source,
478+
) = client_class.get_mtls_endpoint_and_cert_source()
479+
assert api_endpoint == client_class.DEFAULT_MTLS_ENDPOINT
480+
assert cert_source == mock_client_cert_source
481+
482+
402483
@pytest.mark.parametrize(
403484
"client_class,transport_class,transport_name",
404485
[
@@ -2835,6 +2916,23 @@ def test_credentials_transport_error():
28352916
transport=transport,
28362917
)
28372918

2919+
# It is an error to provide an api_key and a transport instance.
2920+
transport = transports.TablesServiceGrpcTransport(
2921+
credentials=ga_credentials.AnonymousCredentials(),
2922+
)
2923+
options = client_options.ClientOptions()
2924+
options.api_key = "api_key"
2925+
with pytest.raises(ValueError):
2926+
client = TablesServiceClient(client_options=options, transport=transport,)
2927+
2928+
# It is an error to provide an api_key and a credential.
2929+
options = mock.Mock()
2930+
options.api_key = "api_key"
2931+
with pytest.raises(ValueError):
2932+
client = TablesServiceClient(
2933+
client_options=options, credentials=ga_credentials.AnonymousCredentials()
2934+
)
2935+
28382936
# It is an error to provide scopes and a transport instance.
28392937
transport = transports.TablesServiceGrpcTransport(
28402938
credentials=ga_credentials.AnonymousCredentials(),
@@ -3463,3 +3561,33 @@ def test_client_ctx():
34633561
with client:
34643562
pass
34653563
close.assert_called()
3564+
3565+
3566+
@pytest.mark.parametrize(
3567+
"client_class,transport_class",
3568+
[
3569+
(TablesServiceClient, transports.TablesServiceGrpcTransport),
3570+
(TablesServiceAsyncClient, transports.TablesServiceGrpcAsyncIOTransport),
3571+
],
3572+
)
3573+
def test_api_key_credentials(client_class, transport_class):
3574+
with mock.patch.object(
3575+
google.auth._default, "get_api_key_credentials", create=True
3576+
) as get_api_key_credentials:
3577+
mock_cred = mock.Mock()
3578+
get_api_key_credentials.return_value = mock_cred
3579+
options = client_options.ClientOptions()
3580+
options.api_key = "api_key"
3581+
with mock.patch.object(transport_class, "__init__") as patched:
3582+
patched.return_value = None
3583+
client = client_class(client_options=options)
3584+
patched.assert_called_once_with(
3585+
credentials=mock_cred,
3586+
credentials_file=None,
3587+
host=client.DEFAULT_ENDPOINT,
3588+
scopes=None,
3589+
client_cert_source_for_mtls=None,
3590+
quota_project_id=None,
3591+
client_info=transports.base.DEFAULT_CLIENT_INFO,
3592+
always_use_jwt_access=True,
3593+
)

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.