feat: add GOOGLE_API_USE_CLIENT_CERTIFICATE support (#592)

diff --git a/google/auth/environment_vars.py b/google/auth/environment_vars.py
index 9c1367f..46a8926 100644
--- a/google/auth/environment_vars.py
+++ b/google/auth/environment_vars.py
@@ -53,3 +53,9 @@
 GCE_METADATA_IP = "GCE_METADATA_IP"
 """Environment variable providing an alternate ip:port to be used for ip-only
 GCE metadata requests."""
+
+GOOGLE_API_USE_CLIENT_CERTIFICATE = "GOOGLE_API_USE_CLIENT_CERTIFICATE"
+"""Environment variable controlling whether to use client certificate or not.
+
+The default value is false. Users have to explicitly set this value to true
+in order to use client certificate to establish a mutual TLS channel."""
diff --git a/google/auth/transport/grpc.py b/google/auth/transport/grpc.py
index 13234a3..ab7d0db 100644
--- a/google/auth/transport/grpc.py
+++ b/google/auth/transport/grpc.py
@@ -17,9 +17,11 @@
 from __future__ import absolute_import
 
 import logging
+import os
 
 import six
 
+from google.auth import environment_vars
 from google.auth import exceptions
 from google.auth.transport import _mtls_helper
 
@@ -96,6 +98,9 @@
 
     This creates a channel with SSL and :class:`AuthMetadataPlugin`. This
     channel can be used to create a stub that can make authorized requests.
+    Users can configure client certificate or rely on device certificates to
+    establish a mutual TLS channel, if the `GOOGLE_API_USE_CLIENT_CERTIFICATE`
+    variable is explicitly set to `true`.
 
     Example::
 
@@ -138,7 +143,9 @@
             ssl_credentials=regular_ssl_credentials)
 
     Option 2: create a mutual TLS channel by calling a callback which returns
-    the client side certificate and the key::
+    the client side certificate and the key (Note that
+    `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable must be explicitly
+    set to `true`)::
 
         def my_client_cert_callback():
             code_to_load_client_cert_and_key()
@@ -155,7 +162,9 @@
 
     Option 3: use application default SSL credentials. It searches and uses
     the command in a context aware metadata file, which is available on devices
-    with endpoint verification support.
+    with endpoint verification support (Note that
+    `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable must be explicitly
+    set to `true`).
     See https://cloud.google.com/endpoint-verification/docs/overview::
 
         try:
@@ -174,7 +183,8 @@
             ssl_credentials=default_ssl_credentials)
 
     Option 4: not setting ssl_credentials and client_cert_callback. For devices
-    without endpoint verification support, a regular TLS channel is created;
+    without endpoint verification support or `GOOGLE_API_USE_CLIENT_CERTIFICATE`
+    environment variable is not `true`, a regular TLS channel is created;
     otherwise, a mutual TLS channel is created, however, the call should be
     wrapped in a try/except block in case of malformed context aware metadata.
 
@@ -205,13 +215,15 @@
             This argument is mutually exclusive with client_cert_callback;
             providing both will raise an exception.
             If ssl_credentials and client_cert_callback are None, application
-            default SSL credentials will be used.
+            default SSL credentials are used if `GOOGLE_API_USE_CLIENT_CERTIFICATE`
+            environment variable is explicitly set to `true`, otherwise one way TLS
+            SSL credentials are used.
         client_cert_callback (Callable[[], (bytes, bytes)]): Optional
             callback function to obtain client certicate and key for mutual TLS
             connection. This argument is mutually exclusive with
             ssl_credentials; providing both will raise an exception.
-            If ssl_credentials and client_cert_callback are None, application
-            default SSL credentials will be used.
+            This argument does nothing unless `GOOGLE_API_USE_CLIENT_CERTIFICATE`
+            environment variable is explicitly set to `true`.
         kwargs: Additional arguments to pass to :func:`grpc.secure_channel`.
 
     Returns:
@@ -235,16 +247,21 @@
 
     # If SSL credentials are not explicitly set, try client_cert_callback and ADC.
     if not ssl_credentials:
-        if client_cert_callback:
+        use_client_cert = os.getenv(
+            environment_vars.GOOGLE_API_USE_CLIENT_CERTIFICATE, "false"
+        )
+        if use_client_cert == "true" and client_cert_callback:
             # Use the callback if provided.
             cert, key = client_cert_callback()
             ssl_credentials = grpc.ssl_channel_credentials(
                 certificate_chain=cert, private_key=key
             )
-        else:
+        elif use_client_cert == "true":
             # Use application default SSL credentials.
             adc_ssl_credentils = SslCredentials()
             ssl_credentials = adc_ssl_credentils.ssl_credentials
+        else:
+            ssl_credentials = grpc.ssl_channel_credentials()
 
     # Combine the ssl credentials and the authorization credentials.
     composite_credentials = grpc.composite_channel_credentials(
@@ -257,17 +274,29 @@
 class SslCredentials:
     """Class for application default SSL credentials.
 
-    For devices with endpoint verification support, a device certificate will be
-    automatically loaded and mutual TLS will be established.
+    The behavior is controlled by `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment
+    variable whose default value is `false`. Client certificate will not be used
+    unless the environment variable is explicitly set to `true`. See
+    https://google.aip.dev/auth/4114
+
+    If the environment variable is `true`, then for devices with endpoint verification
+    support, a device certificate will be automatically loaded and mutual TLS will
+    be established.
     See https://cloud.google.com/endpoint-verification/docs/overview.
     """
 
     def __init__(self):
-        # Load client SSL credentials.
-        metadata_path = _mtls_helper._check_dca_metadata_path(
-            _mtls_helper.CONTEXT_AWARE_METADATA_PATH
+        use_client_cert = os.getenv(
+            environment_vars.GOOGLE_API_USE_CLIENT_CERTIFICATE, "false"
         )
-        self._is_mtls = metadata_path is not None
+        if use_client_cert != "true":
+            self._is_mtls = False
+        else:
+            # Load client SSL credentials.
+            metadata_path = _mtls_helper._check_dca_metadata_path(
+                _mtls_helper.CONTEXT_AWARE_METADATA_PATH
+            )
+            self._is_mtls = metadata_path is not None
 
     @property
     def ssl_credentials(self):
diff --git a/google/auth/transport/requests.py b/google/auth/transport/requests.py
index 4f5af7d..9a2f3af 100644
--- a/google/auth/transport/requests.py
+++ b/google/auth/transport/requests.py
@@ -19,6 +19,7 @@
 import functools
 import logging
 import numbers
+import os
 import time
 
 try:
@@ -40,6 +41,7 @@
 )  # pylint: disable=ungrouped-imports
 import six  # pylint: disable=ungrouped-imports
 
+from google.auth import environment_vars
 from google.auth import exceptions
 from google.auth import transport
 import google.auth.transport._mtls_helper
@@ -249,13 +251,18 @@
     credentials' headers to the request and refreshing credentials as needed.
 
     This class also supports mutual TLS via :meth:`configure_mtls_channel`
-    method. If client_cert_callback is provided, client certificate and private
+    method. In order to use this method, the `GOOGLE_API_USE_CLIENT_CERTIFICATE`
+    environment variable must be explicitly set to `true`, otherwise it does
+    nothing. Assume the environment is set to `true`, the method behaves in the
+    following manner:
+    If client_cert_callback is provided, client certificate and private
     key are loaded using the callback; if client_cert_callback is None,
     application default SSL credentials will be used. Exceptions are raised if
     there are problems with the certificate, private key, or the loading process,
     so it should be called within a try/except block.
 
-    First we create an :class:`AuthorizedSession` instance and specify the endpoints::
+    First we set the environment variable to `true`, then create an :class:`AuthorizedSession`
+    instance and specify the endpoints::
 
         regular_endpoint = 'https://pubsub.googleapis.com/v1/projects/{my_project_id}/topics'
         mtls_endpoint = 'https://pubsub.mtls.googleapis.com/v1/projects/{my_project_id}/topics'
@@ -343,9 +350,11 @@
     def configure_mtls_channel(self, client_cert_callback=None):
         """Configure the client certificate and key for SSL connection.
 
-        If client certificate and key are successfully obtained (from the given
-        client_cert_callback or from application default SSL credentials), a
-        :class:`_MutualTlsAdapter` instance will be mounted to "https://" prefix.
+        The function does nothing unless `GOOGLE_API_USE_CLIENT_CERTIFICATE` is
+        explicitly set to `true`. In this case if client certificate and key are
+        successfully obtained (from the given client_cert_callback or from application
+        default SSL credentials), a :class:`_MutualTlsAdapter` instance will be mounted
+        to "https://" prefix.
 
         Args:
             client_cert_callback (Optional[Callable[[], (bytes, bytes)]]):
@@ -358,6 +367,13 @@
             google.auth.exceptions.MutualTLSChannelError: If mutual TLS channel
                 creation failed for any reason.
         """
+        use_client_cert = os.getenv(
+            environment_vars.GOOGLE_API_USE_CLIENT_CERTIFICATE, "false"
+        )
+        if use_client_cert != "true":
+            self._is_mtls = False
+            return
+
         try:
             import OpenSSL
         except ImportError as caught_exc:
diff --git a/google/auth/transport/urllib3.py b/google/auth/transport/urllib3.py
index 3742f1a..209fc51 100644
--- a/google/auth/transport/urllib3.py
+++ b/google/auth/transport/urllib3.py
@@ -17,6 +17,7 @@
 from __future__ import absolute_import
 
 import logging
+import os
 import warnings
 
 # Certifi is Mozilla's certificate bundle. Urllib3 needs a certificate bundle
@@ -45,6 +46,7 @@
 import six
 import urllib3.exceptions  # pylint: disable=ungrouped-imports
 
+from google.auth import environment_vars
 from google.auth import exceptions
 from google.auth import transport
 
@@ -202,13 +204,18 @@
     credentials' headers to the request and refreshing credentials as needed.
 
     This class also supports mutual TLS via :meth:`configure_mtls_channel`
-    method. If client_cert_callback is provided, client certificate and private
+    method. In order to use this method, the `GOOGLE_API_USE_CLIENT_CERTIFICATE`
+    environment variable must be explicitly set to `true`, otherwise it does
+    nothing. Assume the environment is set to `true`, the method behaves in the
+    following manner:
+    If client_cert_callback is provided, client certificate and private
     key are loaded using the callback; if client_cert_callback is None,
     application default SSL credentials will be used. Exceptions are raised if
     there are problems with the certificate, private key, or the loading process,
     so it should be called within a try/except block.
 
-    First we create an :class:`AuthorizedHttp` instance and specify the endpoints::
+    First we set the environment variable to `true`, then create an :class:`AuthorizedHttp`
+    instance and specify the endpoints::
 
         regular_endpoint = 'https://pubsub.googleapis.com/v1/projects/{my_project_id}/topics'
         mtls_endpoint = 'https://pubsub.mtls.googleapis.com/v1/projects/{my_project_id}/topics'
@@ -282,9 +289,13 @@
 
     def configure_mtls_channel(self, client_cert_callback=None):
         """Configures mutual TLS channel using the given client_cert_callback or
-        application default SSL credentials. Returns True if the channel is
-        mutual TLS and False otherwise. Note that the `http` provided in the
-        constructor will be overwritten.
+        application default SSL credentials. The behavior is controlled by
+        `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable.
+        (1) If the environment variable value is `true`, the function returns True
+        if the channel is mutual TLS and False otherwise. The `http` provided
+        in the constructor will be overwritten.
+        (2) If the environment variable is not set or `false`, the function does
+        nothing and it always return False.
 
         Args:
             client_cert_callback (Optional[Callable[[], (bytes, bytes)]]):
@@ -300,6 +311,12 @@
             google.auth.exceptions.MutualTLSChannelError: If mutual TLS channel
                 creation failed for any reason.
         """
+        use_client_cert = os.getenv(
+            environment_vars.GOOGLE_API_USE_CLIENT_CERTIFICATE, "false"
+        )
+        if use_client_cert != "true":
+            return False
+
         try:
             import OpenSSL
         except ImportError as caught_exc: