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