@@ -299,6 +299,73 @@ def parse_common_location_path(path: str) -> Dict[str, str]:
299299 m = re .match (r"^projects/(?P<project>.+?)/locations/(?P<location>.+?)$" , path )
300300 return m .groupdict () if m else {}
301301
302+ @classmethod
303+ def get_mtls_endpoint_and_cert_source (
304+ cls , client_options : Optional [client_options_lib .ClientOptions ] = None
305+ ):
306+ """Return the API endpoint and client cert source for mutual TLS.
307+
308+ The client cert source is determined in the following order:
309+ (1) if `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is not "true", the
310+ client cert source is None.
311+ (2) if `client_options.client_cert_source` is provided, use the provided one; if the
312+ default client cert source exists, use the default one; otherwise the client cert
313+ source is None.
314+
315+ The API endpoint is determined in the following order:
316+ (1) if `client_options.api_endpoint` if provided, use the provided one.
317+ (2) if `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is "always", use the
318+ default mTLS endpoint; if the environment variabel is "never", use the default API
319+ endpoint; otherwise if client cert source exists, use the default mTLS endpoint, otherwise
320+ use the default API endpoint.
321+
322+ More details can be found at https://google.aip.dev/auth/4114.
323+
324+ Args:
325+ client_options (google.api_core.client_options.ClientOptions): Custom options for the
326+ client. Only the `api_endpoint` and `client_cert_source` properties may be used
327+ in this method.
328+
329+ Returns:
330+ Tuple[str, Callable[[], Tuple[bytes, bytes]]]: returns the API endpoint and the
331+ client cert source to use.
332+
333+ Raises:
334+ google.auth.exceptions.MutualTLSChannelError: If any errors happen.
335+ """
336+ if client_options is None :
337+ client_options = client_options_lib .ClientOptions ()
338+ use_client_cert = os .getenv ("GOOGLE_API_USE_CLIENT_CERTIFICATE" , "false" )
339+ use_mtls_endpoint = os .getenv ("GOOGLE_API_USE_MTLS_ENDPOINT" , "auto" )
340+ if use_client_cert not in ("true" , "false" ):
341+ raise ValueError (
342+ "Environment variable `GOOGLE_API_USE_CLIENT_CERTIFICATE` must be either `true` or `false`"
343+ )
344+ if use_mtls_endpoint not in ("auto" , "never" , "always" ):
345+ raise MutualTLSChannelError (
346+ "Environment variable `GOOGLE_API_USE_MTLS_ENDPOINT` must be `never`, `auto` or `always`"
347+ )
348+
349+ # Figure out the client cert source to use.
350+ client_cert_source = None
351+ if use_client_cert == "true" :
352+ if client_options .client_cert_source :
353+ client_cert_source = client_options .client_cert_source
354+ elif mtls .has_default_client_cert_source ():
355+ client_cert_source = mtls .default_client_cert_source ()
356+
357+ # Figure out which api endpoint to use.
358+ if client_options .api_endpoint is not None :
359+ api_endpoint = client_options .api_endpoint
360+ elif use_mtls_endpoint == "always" or (
361+ use_mtls_endpoint == "auto" and client_cert_source
362+ ):
363+ api_endpoint = cls .DEFAULT_MTLS_ENDPOINT
364+ else :
365+ api_endpoint = cls .DEFAULT_ENDPOINT
366+
367+ return api_endpoint , client_cert_source
368+
302369 def __init__ (
303370 self ,
304371 * ,
@@ -349,57 +416,22 @@ def __init__(
349416 if client_options is None :
350417 client_options = client_options_lib .ClientOptions ()
351418
352- # Create SSL credentials for mutual TLS if needed.
353- if os .getenv ("GOOGLE_API_USE_CLIENT_CERTIFICATE" , "false" ) not in (
354- "true" ,
355- "false" ,
356- ):
357- raise ValueError (
358- "Environment variable `GOOGLE_API_USE_CLIENT_CERTIFICATE` must be either `true` or `false`"
359- )
360- use_client_cert = (
361- os .getenv ("GOOGLE_API_USE_CLIENT_CERTIFICATE" , "false" ) == "true"
419+ api_endpoint , client_cert_source_func = self .get_mtls_endpoint_and_cert_source (
420+ client_options
362421 )
363422
364- client_cert_source_func = None
365- is_mtls = False
366- if use_client_cert :
367- if client_options .client_cert_source :
368- is_mtls = True
369- client_cert_source_func = client_options .client_cert_source
370- else :
371- is_mtls = mtls .has_default_client_cert_source ()
372- if is_mtls :
373- client_cert_source_func = mtls .default_client_cert_source ()
374- else :
375- client_cert_source_func = None
376-
377- # Figure out which api endpoint to use.
378- if client_options .api_endpoint is not None :
379- api_endpoint = client_options .api_endpoint
380- else :
381- use_mtls_env = os .getenv ("GOOGLE_API_USE_MTLS_ENDPOINT" , "auto" )
382- if use_mtls_env == "never" :
383- api_endpoint = self .DEFAULT_ENDPOINT
384- elif use_mtls_env == "always" :
385- api_endpoint = self .DEFAULT_MTLS_ENDPOINT
386- elif use_mtls_env == "auto" :
387- if is_mtls :
388- api_endpoint = self .DEFAULT_MTLS_ENDPOINT
389- else :
390- api_endpoint = self .DEFAULT_ENDPOINT
391- else :
392- raise MutualTLSChannelError (
393- "Unsupported GOOGLE_API_USE_MTLS_ENDPOINT value. Accepted "
394- "values: never, auto, always"
395- )
423+ api_key_value = getattr (client_options , "api_key" , None )
424+ if api_key_value and credentials :
425+ raise ValueError (
426+ "client_options.api_key and credentials are mutually exclusive"
427+ )
396428
397429 # Save or instantiate the transport.
398430 # Ordinarily, we provide the transport, but allowing a custom transport
399431 # instance provides an extensibility point for unusual situations.
400432 if isinstance (transport , BigtableInstanceAdminTransport ):
401433 # transport is a BigtableInstanceAdminTransport instance.
402- if credentials or client_options .credentials_file :
434+ if credentials or client_options .credentials_file or api_key_value :
403435 raise ValueError (
404436 "When providing a transport instance, "
405437 "provide its credentials directly."
@@ -411,6 +443,15 @@ def __init__(
411443 )
412444 self ._transport = transport
413445 else :
446+ import google .auth ._default # type: ignore
447+
448+ if api_key_value and hasattr (
449+ google .auth ._default , "get_api_key_credentials"
450+ ):
451+ credentials = google .auth ._default .get_api_key_credentials (
452+ api_key_value
453+ )
454+
414455 Transport = type (self ).get_transport_class (transport )
415456 self ._transport = Transport (
416457 credentials = credentials ,
0 commit comments