@@ -238,6 +238,73 @@ def parse_common_location_path(path: str) -> Dict[str, str]:
238238 m = re .match (r"^projects/(?P<project>.+?)/locations/(?P<location>.+?)$" , path )
239239 return m .groupdict () if m else {}
240240
241+ @classmethod
242+ def get_mtls_endpoint_and_cert_source (
243+ cls , client_options : Optional [client_options_lib .ClientOptions ] = None
244+ ):
245+ """Return the API endpoint and client cert source for mutual TLS.
246+
247+ The client cert source is determined in the following order:
248+ (1) if `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is not "true", the
249+ client cert source is None.
250+ (2) if `client_options.client_cert_source` is provided, use the provided one; if the
251+ default client cert source exists, use the default one; otherwise the client cert
252+ source is None.
253+
254+ The API endpoint is determined in the following order:
255+ (1) if `client_options.api_endpoint` if provided, use the provided one.
256+ (2) if `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is "always", use the
257+ default mTLS endpoint; if the environment variabel is "never", use the default API
258+ endpoint; otherwise if client cert source exists, use the default mTLS endpoint, otherwise
259+ use the default API endpoint.
260+
261+ More details can be found at https://google.aip.dev/auth/4114.
262+
263+ Args:
264+ client_options (google.api_core.client_options.ClientOptions): Custom options for the
265+ client. Only the `api_endpoint` and `client_cert_source` properties may be used
266+ in this method.
267+
268+ Returns:
269+ Tuple[str, Callable[[], Tuple[bytes, bytes]]]: returns the API endpoint and the
270+ client cert source to use.
271+
272+ Raises:
273+ google.auth.exceptions.MutualTLSChannelError: If any errors happen.
274+ """
275+ if client_options is None :
276+ client_options = client_options_lib .ClientOptions ()
277+ use_client_cert = os .getenv ("GOOGLE_API_USE_CLIENT_CERTIFICATE" , "false" )
278+ use_mtls_endpoint = os .getenv ("GOOGLE_API_USE_MTLS_ENDPOINT" , "auto" )
279+ if use_client_cert not in ("true" , "false" ):
280+ raise ValueError (
281+ "Environment variable `GOOGLE_API_USE_CLIENT_CERTIFICATE` must be either `true` or `false`"
282+ )
283+ if use_mtls_endpoint not in ("auto" , "never" , "always" ):
284+ raise MutualTLSChannelError (
285+ "Environment variable `GOOGLE_API_USE_MTLS_ENDPOINT` must be `never`, `auto` or `always`"
286+ )
287+
288+ # Figure out the client cert source to use.
289+ client_cert_source = None
290+ if use_client_cert == "true" :
291+ if client_options .client_cert_source :
292+ client_cert_source = client_options .client_cert_source
293+ elif mtls .has_default_client_cert_source ():
294+ client_cert_source = mtls .default_client_cert_source ()
295+
296+ # Figure out which api endpoint to use.
297+ if client_options .api_endpoint is not None :
298+ api_endpoint = client_options .api_endpoint
299+ elif use_mtls_endpoint == "always" or (
300+ use_mtls_endpoint == "auto" and client_cert_source
301+ ):
302+ api_endpoint = cls .DEFAULT_MTLS_ENDPOINT
303+ else :
304+ api_endpoint = cls .DEFAULT_ENDPOINT
305+
306+ return api_endpoint , client_cert_source
307+
241308 def __init__ (
242309 self ,
243310 * ,
@@ -288,57 +355,22 @@ def __init__(
288355 if client_options is None :
289356 client_options = client_options_lib .ClientOptions ()
290357
291- # Create SSL credentials for mutual TLS if needed.
292- if os .getenv ("GOOGLE_API_USE_CLIENT_CERTIFICATE" , "false" ) not in (
293- "true" ,
294- "false" ,
295- ):
296- raise ValueError (
297- "Environment variable `GOOGLE_API_USE_CLIENT_CERTIFICATE` must be either `true` or `false`"
298- )
299- use_client_cert = (
300- os .getenv ("GOOGLE_API_USE_CLIENT_CERTIFICATE" , "false" ) == "true"
358+ api_endpoint , client_cert_source_func = self .get_mtls_endpoint_and_cert_source (
359+ client_options
301360 )
302361
303- client_cert_source_func = None
304- is_mtls = False
305- if use_client_cert :
306- if client_options .client_cert_source :
307- is_mtls = True
308- client_cert_source_func = client_options .client_cert_source
309- else :
310- is_mtls = mtls .has_default_client_cert_source ()
311- if is_mtls :
312- client_cert_source_func = mtls .default_client_cert_source ()
313- else :
314- client_cert_source_func = None
315-
316- # Figure out which api endpoint to use.
317- if client_options .api_endpoint is not None :
318- api_endpoint = client_options .api_endpoint
319- else :
320- use_mtls_env = os .getenv ("GOOGLE_API_USE_MTLS_ENDPOINT" , "auto" )
321- if use_mtls_env == "never" :
322- api_endpoint = self .DEFAULT_ENDPOINT
323- elif use_mtls_env == "always" :
324- api_endpoint = self .DEFAULT_MTLS_ENDPOINT
325- elif use_mtls_env == "auto" :
326- if is_mtls :
327- api_endpoint = self .DEFAULT_MTLS_ENDPOINT
328- else :
329- api_endpoint = self .DEFAULT_ENDPOINT
330- else :
331- raise MutualTLSChannelError (
332- "Unsupported GOOGLE_API_USE_MTLS_ENDPOINT value. Accepted "
333- "values: never, auto, always"
334- )
362+ api_key_value = getattr (client_options , "api_key" , None )
363+ if api_key_value and credentials :
364+ raise ValueError (
365+ "client_options.api_key and credentials are mutually exclusive"
366+ )
335367
336368 # Save or instantiate the transport.
337369 # Ordinarily, we provide the transport, but allowing a custom transport
338370 # instance provides an extensibility point for unusual situations.
339371 if isinstance (transport , Controller2Transport ):
340372 # transport is a Controller2Transport instance.
341- if credentials or client_options .credentials_file :
373+ if credentials or client_options .credentials_file or api_key_value :
342374 raise ValueError (
343375 "When providing a transport instance, "
344376 "provide its credentials directly."
@@ -350,6 +382,15 @@ def __init__(
350382 )
351383 self ._transport = transport
352384 else :
385+ import google .auth ._default # type: ignore
386+
387+ if api_key_value and hasattr (
388+ google .auth ._default , "get_api_key_credentials"
389+ ):
390+ credentials = google .auth ._default .get_api_key_credentials (
391+ api_key_value
392+ )
393+
353394 Transport = type (self ).get_transport_class (transport )
354395 self ._transport = Transport (
355396 credentials = credentials ,
0 commit comments