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

Commit a72a4fe

Browse files
feat: add api key support (#29)
* 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 869ec67 commit a72a4fe

File tree

3 files changed

+254
-44
lines changed

3 files changed

+254
-44
lines changed

google/cloud/filestore_v1/services/cloud_filestore_manager/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
@@ -140,6 +140,42 @@ def from_service_account_file(cls, filename: str, *args, **kwargs):
140140

141141
from_service_account_json = from_service_account_file
142142

143+
@classmethod
144+
def get_mtls_endpoint_and_cert_source(
145+
cls, client_options: Optional[ClientOptions] = None
146+
):
147+
"""Return the API endpoint and client cert source for mutual TLS.
148+
149+
The client cert source is determined in the following order:
150+
(1) if `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is not "true", the
151+
client cert source is None.
152+
(2) if `client_options.client_cert_source` is provided, use the provided one; if the
153+
default client cert source exists, use the default one; otherwise the client cert
154+
source is None.
155+
156+
The API endpoint is determined in the following order:
157+
(1) if `client_options.api_endpoint` if provided, use the provided one.
158+
(2) if `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is "always", use the
159+
default mTLS endpoint; if the environment variabel is "never", use the default API
160+
endpoint; otherwise if client cert source exists, use the default mTLS endpoint, otherwise
161+
use the default API endpoint.
162+
163+
More details can be found at https://google.aip.dev/auth/4114.
164+
165+
Args:
166+
client_options (google.api_core.client_options.ClientOptions): Custom options for the
167+
client. Only the `api_endpoint` and `client_cert_source` properties may be used
168+
in this method.
169+
170+
Returns:
171+
Tuple[str, Callable[[], Tuple[bytes, bytes]]]: returns the API endpoint and the
172+
client cert source to use.
173+
174+
Raises:
175+
google.auth.exceptions.MutualTLSChannelError: If any errors happen.
176+
"""
177+
return CloudFilestoreManagerClient.get_mtls_endpoint_and_cert_source(client_options) # type: ignore
178+
143179
@property
144180
def transport(self) -> CloudFilestoreManagerTransport:
145181
"""Returns the transport used by the client instance.

google/cloud/filestore_v1/services/cloud_filestore_manager/client.py

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

285+
@classmethod
286+
def get_mtls_endpoint_and_cert_source(
287+
cls, client_options: Optional[client_options_lib.ClientOptions] = None
288+
):
289+
"""Return the API endpoint and client cert source for mutual TLS.
290+
291+
The client cert source is determined in the following order:
292+
(1) if `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is not "true", the
293+
client cert source is None.
294+
(2) if `client_options.client_cert_source` is provided, use the provided one; if the
295+
default client cert source exists, use the default one; otherwise the client cert
296+
source is None.
297+
298+
The API endpoint is determined in the following order:
299+
(1) if `client_options.api_endpoint` if provided, use the provided one.
300+
(2) if `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is "always", use the
301+
default mTLS endpoint; if the environment variabel is "never", use the default API
302+
endpoint; otherwise if client cert source exists, use the default mTLS endpoint, otherwise
303+
use the default API endpoint.
304+
305+
More details can be found at https://google.aip.dev/auth/4114.
306+
307+
Args:
308+
client_options (google.api_core.client_options.ClientOptions): Custom options for the
309+
client. Only the `api_endpoint` and `client_cert_source` properties may be used
310+
in this method.
311+
312+
Returns:
313+
Tuple[str, Callable[[], Tuple[bytes, bytes]]]: returns the API endpoint and the
314+
client cert source to use.
315+
316+
Raises:
317+
google.auth.exceptions.MutualTLSChannelError: If any errors happen.
318+
"""
319+
if client_options is None:
320+
client_options = client_options_lib.ClientOptions()
321+
use_client_cert = os.getenv("GOOGLE_API_USE_CLIENT_CERTIFICATE", "false")
322+
use_mtls_endpoint = os.getenv("GOOGLE_API_USE_MTLS_ENDPOINT", "auto")
323+
if use_client_cert not in ("true", "false"):
324+
raise ValueError(
325+
"Environment variable `GOOGLE_API_USE_CLIENT_CERTIFICATE` must be either `true` or `false`"
326+
)
327+
if use_mtls_endpoint not in ("auto", "never", "always"):
328+
raise MutualTLSChannelError(
329+
"Environment variable `GOOGLE_API_USE_MTLS_ENDPOINT` must be `never`, `auto` or `always`"
330+
)
331+
332+
# Figure out the client cert source to use.
333+
client_cert_source = None
334+
if use_client_cert == "true":
335+
if client_options.client_cert_source:
336+
client_cert_source = client_options.client_cert_source
337+
elif mtls.has_default_client_cert_source():
338+
client_cert_source = mtls.default_client_cert_source()
339+
340+
# Figure out which api endpoint to use.
341+
if client_options.api_endpoint is not None:
342+
api_endpoint = client_options.api_endpoint
343+
elif use_mtls_endpoint == "always" or (
344+
use_mtls_endpoint == "auto" and client_cert_source
345+
):
346+
api_endpoint = cls.DEFAULT_MTLS_ENDPOINT
347+
else:
348+
api_endpoint = cls.DEFAULT_ENDPOINT
349+
350+
return api_endpoint, client_cert_source
351+
285352
def __init__(
286353
self,
287354
*,
@@ -332,57 +399,22 @@ def __init__(
332399
if client_options is None:
333400
client_options = client_options_lib.ClientOptions()
334401

335-
# Create SSL credentials for mutual TLS if needed.
336-
if os.getenv("GOOGLE_API_USE_CLIENT_CERTIFICATE", "false") not in (
337-
"true",
338-
"false",
339-
):
340-
raise ValueError(
341-
"Environment variable `GOOGLE_API_USE_CLIENT_CERTIFICATE` must be either `true` or `false`"
342-
)
343-
use_client_cert = (
344-
os.getenv("GOOGLE_API_USE_CLIENT_CERTIFICATE", "false") == "true"
402+
api_endpoint, client_cert_source_func = self.get_mtls_endpoint_and_cert_source(
403+
client_options
345404
)
346405

347-
client_cert_source_func = None
348-
is_mtls = False
349-
if use_client_cert:
350-
if client_options.client_cert_source:
351-
is_mtls = True
352-
client_cert_source_func = client_options.client_cert_source
353-
else:
354-
is_mtls = mtls.has_default_client_cert_source()
355-
if is_mtls:
356-
client_cert_source_func = mtls.default_client_cert_source()
357-
else:
358-
client_cert_source_func = None
359-
360-
# Figure out which api endpoint to use.
361-
if client_options.api_endpoint is not None:
362-
api_endpoint = client_options.api_endpoint
363-
else:
364-
use_mtls_env = os.getenv("GOOGLE_API_USE_MTLS_ENDPOINT", "auto")
365-
if use_mtls_env == "never":
366-
api_endpoint = self.DEFAULT_ENDPOINT
367-
elif use_mtls_env == "always":
368-
api_endpoint = self.DEFAULT_MTLS_ENDPOINT
369-
elif use_mtls_env == "auto":
370-
if is_mtls:
371-
api_endpoint = self.DEFAULT_MTLS_ENDPOINT
372-
else:
373-
api_endpoint = self.DEFAULT_ENDPOINT
374-
else:
375-
raise MutualTLSChannelError(
376-
"Unsupported GOOGLE_API_USE_MTLS_ENDPOINT value. Accepted "
377-
"values: never, auto, always"
378-
)
406+
api_key_value = getattr(client_options, "api_key", None)
407+
if api_key_value and credentials:
408+
raise ValueError(
409+
"client_options.api_key and credentials are mutually exclusive"
410+
)
379411

380412
# Save or instantiate the transport.
381413
# Ordinarily, we provide the transport, but allowing a custom transport
382414
# instance provides an extensibility point for unusual situations.
383415
if isinstance(transport, CloudFilestoreManagerTransport):
384416
# transport is a CloudFilestoreManagerTransport instance.
385-
if credentials or client_options.credentials_file:
417+
if credentials or client_options.credentials_file or api_key_value:
386418
raise ValueError(
387419
"When providing a transport instance, "
388420
"provide its credentials directly."
@@ -394,6 +426,15 @@ def __init__(
394426
)
395427
self._transport = transport
396428
else:
429+
import google.auth._default # type: ignore
430+
431+
if api_key_value and hasattr(
432+
google.auth._default, "get_api_key_credentials"
433+
):
434+
credentials = google.auth._default.get_api_key_credentials(
435+
api_key_value
436+
)
437+
397438
Transport = type(self).get_transport_class(transport)
398439
self._transport = Transport(
399440
credentials=credentials,

tests/unit/gapic/filestore_v1/test_cloud_filestore_manager.py

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -422,6 +422,87 @@ def test_cloud_filestore_manager_client_mtls_env_auto(
422422
)
423423

424424

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

3334+
# It is an error to provide an api_key and a transport instance.
3335+
transport = transports.CloudFilestoreManagerGrpcTransport(
3336+
credentials=ga_credentials.AnonymousCredentials(),
3337+
)
3338+
options = client_options.ClientOptions()
3339+
options.api_key = "api_key"
3340+
with pytest.raises(ValueError):
3341+
client = CloudFilestoreManagerClient(
3342+
client_options=options, transport=transport,
3343+
)
3344+
3345+
# It is an error to provide an api_key and a credential.
3346+
options = mock.Mock()
3347+
options.api_key = "api_key"
3348+
with pytest.raises(ValueError):
3349+
client = CloudFilestoreManagerClient(
3350+
client_options=options, credentials=ga_credentials.AnonymousCredentials()
3351+
)
3352+
32533353
# It is an error to provide scopes and a transport instance.
32543354
transport = transports.CloudFilestoreManagerGrpcTransport(
32553355
credentials=ga_credentials.AnonymousCredentials(),
@@ -3878,3 +3978,36 @@ def test_client_ctx():
38783978
with client:
38793979
pass
38803980
close.assert_called()
3981+
3982+
3983+
@pytest.mark.parametrize(
3984+
"client_class,transport_class",
3985+
[
3986+
(CloudFilestoreManagerClient, transports.CloudFilestoreManagerGrpcTransport),
3987+
(
3988+
CloudFilestoreManagerAsyncClient,
3989+
transports.CloudFilestoreManagerGrpcAsyncIOTransport,
3990+
),
3991+
],
3992+
)
3993+
def test_api_key_credentials(client_class, transport_class):
3994+
with mock.patch.object(
3995+
google.auth._default, "get_api_key_credentials", create=True
3996+
) as get_api_key_credentials:
3997+
mock_cred = mock.Mock()
3998+
get_api_key_credentials.return_value = mock_cred
3999+
options = client_options.ClientOptions()
4000+
options.api_key = "api_key"
4001+
with mock.patch.object(transport_class, "__init__") as patched:
4002+
patched.return_value = None
4003+
client = client_class(client_options=options)
4004+
patched.assert_called_once_with(
4005+
credentials=mock_cred,
4006+
credentials_file=None,
4007+
host=client.DEFAULT_ENDPOINT,
4008+
scopes=None,
4009+
client_cert_source_for_mtls=None,
4010+
quota_project_id=None,
4011+
client_info=transports.base.DEFAULT_CLIENT_INFO,
4012+
always_use_jwt_access=True,
4013+
)

0 commit comments

Comments
 (0)