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