Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package python-google-auth for 
openSUSE:Factory checked in at 2023-12-09 22:49:03
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-google-auth (Old)
 and      /work/SRC/openSUSE:Factory/.python-google-auth.new.25432 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-google-auth"

Sat Dec  9 22:49:03 2023 rev:36 rq:1131735 version:2.25.1

Changes:
--------
--- /work/SRC/openSUSE:Factory/python-google-auth/python-google-auth.changes    
2023-11-26 19:36:48.805085622 +0100
+++ 
/work/SRC/openSUSE:Factory/.python-google-auth.new.25432/python-google-auth.changes
 2023-12-09 22:49:08.646612520 +0100
@@ -1,0 +2,20 @@
+Thu Dec  7 22:38:03 UTC 2023 - Dirk Müller <[email protected]>
+
+- update to 2.25.1:
+  * Fix vm universe_domain bug (#1433) (8683520)
+  * Add custom tls signer for ECP Provider. (39eb287)
+  * Add custom tls signer for ECP Provider. (#1402) (39eb287)
+  * Add with_universe_domain (#1408) (505910c)
+  * Fixes issue where Python37DeprecationWarning cannot be
+    filtered (#1428) (f22f767)
+  * Remove broken link in Python37DeprecationWarning (#1430)
+  * Add support for Python 3.12 (#1421) (307916c)
+  * Add universe domain support for VM cred (#1409) (7ab0fce)
+  * Modify the token refresh window (#1419) (c6af1d6)
+  * Add missing before request to async oauth2 credentials.
+    (#1420) (8eaa878)
+  * Auto create self signed jwt cred (#1418) (6c610a5)
+  * Migrate datetime.utcnow for python 3.12 (#1413) (e4d9c27)
+  * Update user cred doc (#1414) (3f426bc)
+
+-------------------------------------------------------------------

Old:
----
  google-auth-2.23.4.tar.gz

New:
----
  google-auth-2.25.1.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-google-auth.spec ++++++
--- /var/tmp/diff_new_pack.YHWcoC/_old  2023-12-09 22:49:09.278635337 +0100
+++ /var/tmp/diff_new_pack.YHWcoC/_new  2023-12-09 22:49:09.278635337 +0100
@@ -18,7 +18,7 @@
 
 %{?sle15_python_module_pythons}
 Name:           python-google-auth
-Version:        2.23.4
+Version:        2.25.1
 Release:        0
 Summary:        Google Authentication Library
 License:        Apache-2.0

++++++ google-auth-2.23.4.tar.gz -> google-auth-2.25.1.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/google-auth-2.23.4/PKG-INFO 
new/google-auth-2.25.1/PKG-INFO
--- old/google-auth-2.23.4/PKG-INFO     2023-10-31 20:38:28.224912200 +0100
+++ new/google-auth-2.25.1/PKG-INFO     2023-12-06 02:45:01.775611400 +0100
@@ -1,6 +1,6 @@
 Metadata-Version: 2.1
 Name: google-auth
-Version: 2.23.4
+Version: 2.25.1
 Summary: Google Authentication Library
 Home-page: https://github.com/googleapis/google-auth-library-python
 Author: Google Cloud Platform
@@ -13,6 +13,7 @@
 Classifier: Programming Language :: Python :: 3.9
 Classifier: Programming Language :: Python :: 3.10
 Classifier: Programming Language :: Python :: 3.11
+Classifier: Programming Language :: Python :: 3.12
 Classifier: Development Status :: 5 - Production/Stable
 Classifier: Intended Audience :: Developers
 Classifier: License :: OSI Approved :: Apache Software License
@@ -22,12 +23,23 @@
 Classifier: Operating System :: OS Independent
 Classifier: Topic :: Internet :: WWW/HTTP
 Requires-Python: >=3.7
+License-File: LICENSE
+Requires-Dist: cachetools<6.0,>=2.0.0
+Requires-Dist: pyasn1-modules>=0.2.1
+Requires-Dist: rsa<5,>=3.1.4
 Provides-Extra: aiohttp
+Requires-Dist: aiohttp<4.0.0.dev0,>=3.6.2; extra == "aiohttp"
+Requires-Dist: requests<3.0.0.dev0,>=2.20.0; extra == "aiohttp"
 Provides-Extra: pyopenssl
+Requires-Dist: pyopenssl>=20.0.0; extra == "pyopenssl"
+Requires-Dist: cryptography>=38.0.3; extra == "pyopenssl"
 Provides-Extra: requests
+Requires-Dist: requests<3.0.0.dev0,>=2.20.0; extra == "requests"
 Provides-Extra: reauth
-Provides-Extra: enterprise_cert
-License-File: LICENSE
+Requires-Dist: pyu2f>=0.1.5; extra == "reauth"
+Provides-Extra: enterprise-cert
+Requires-Dist: cryptography==36.0.2; extra == "enterprise-cert"
+Requires-Dist: pyopenssl==22.0.0; extra == "enterprise-cert"
 
 Google Auth Python Library
 ==========================
@@ -51,7 +63,7 @@
 
 For more information on setting up your Python development environment, please 
refer to `Python Development Environment Setup Guide`_ for Google Cloud 
Platform.
 
-.. _`Python Development Environment Setup Guide`: 
https://cloud.google.com/python/setup
+.. _`Python Development Environment Setup Guide`: 
https://cloud.google.com/python/docs/setup
 
 Extras
 ------
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/google-auth-2.23.4/README.rst 
new/google-auth-2.25.1/README.rst
--- old/google-auth-2.23.4/README.rst   2023-10-31 20:35:33.000000000 +0100
+++ new/google-auth-2.25.1/README.rst   2023-12-06 02:42:14.000000000 +0100
@@ -20,7 +20,7 @@
 
 For more information on setting up your Python development environment, please 
refer to `Python Development Environment Setup Guide`_ for Google Cloud 
Platform.
 
-.. _`Python Development Environment Setup Guide`: 
https://cloud.google.com/python/setup
+.. _`Python Development Environment Setup Guide`: 
https://cloud.google.com/python/docs/setup
 
 Extras
 ------
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/google-auth-2.23.4/google/auth/__init__.py 
new/google-auth-2.25.1/google/auth/__init__.py
--- old/google-auth-2.23.4/google/auth/__init__.py      2023-10-31 
20:35:33.000000000 +0100
+++ new/google-auth-2.25.1/google/auth/__init__.py      2023-12-06 
02:42:14.000000000 +0100
@@ -35,8 +35,7 @@
 class Python37DeprecationWarning(DeprecationWarning):  # pragma: NO COVER
     """
     Deprecation warning raised when Python 3.7 runtime is detected.
-    Python 3.7 support will be dropped after January 1, 2024. See
-    https://cloud.google.com/python/docs/python37-sunset/ for more information.
+    Python 3.7 support will be dropped after January 1, 2024.
     """
 
     pass
@@ -46,12 +45,8 @@
 if sys.version_info.major == 3 and sys.version_info.minor == 7:  # pragma: NO 
COVER
     message = (
         "After January 1, 2024, new releases of this library will drop support 
"
-        "for Python 3.7. More details about Python 3.7 support "
-        "can be found at https://cloud.google.com/python/docs/python37-sunset/";
+        "for Python 3.7."
     )
-
-    # Configure the Python37DeprecationWarning warning so that it is only 
emitted once.
-    warnings.simplefilter("once", Python37DeprecationWarning)
     warnings.warn(message, Python37DeprecationWarning)
 
 # Set default logging handler to avoid "No handler found" warnings.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/google-auth-2.23.4/google/auth/_helpers.py 
new/google-auth-2.25.1/google/auth/_helpers.py
--- old/google-auth-2.23.4/google/auth/_helpers.py      2023-10-31 
20:35:33.000000000 +0100
+++ new/google-auth-2.25.1/google/auth/_helpers.py      2023-12-06 
02:42:14.000000000 +0100
@@ -23,11 +23,9 @@
 
 from google.auth import exceptions
 
-# Token server doesn't provide a new a token when doing refresh unless the
-# token is expiring within 30 seconds, so refresh threshold should not be
-# more than 30 seconds. Otherwise auth lib will send tons of refresh requests
-# until 30 seconds before the expiration, and cause a spike of CPU usage.
-REFRESH_THRESHOLD = datetime.timedelta(seconds=20)
+# The smallest MDS cache used by this library stores tokens until 4 minutes 
from
+# expiry.
+REFRESH_THRESHOLD = datetime.timedelta(minutes=3, seconds=45)
 
 
 def copy_docstring(source_class):
@@ -92,7 +90,14 @@
     Returns:
         datetime: The current time in UTC.
     """
-    return datetime.datetime.utcnow()
+    # We used datetime.utcnow() before, since it's deprecated from python 3.12,
+    # we are using datetime.now(timezone.utc) now. "utcnow()" is offset-native
+    # (no timezone info), but "now()" is offset-aware (with timezone info).
+    # This will cause datetime comparison problem. For backward compatibility,
+    # we need to remove the timezone info.
+    now = datetime.datetime.now(datetime.timezone.utc)
+    now = now.replace(tzinfo=None)
+    return now
 
 
 def datetime_to_secs(value):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/google-auth-2.23.4/google/auth/compute_engine/_metadata.py 
new/google-auth-2.25.1/google/auth/compute_engine/_metadata.py
--- old/google-auth-2.23.4/google/auth/compute_engine/_metadata.py      
2023-10-31 20:35:33.000000000 +0100
+++ new/google-auth-2.25.1/google/auth/compute_engine/_metadata.py      
2023-12-06 02:42:14.000000000 +0100
@@ -156,6 +156,7 @@
     recursive=False,
     retry_count=5,
     headers=None,
+    return_none_for_not_found_error=False,
 ):
     """Fetch a resource from the metadata server.
 
@@ -173,6 +174,8 @@
         retry_count (int): How many times to attempt connecting to metadata
             server using above timeout.
         headers (Optional[Mapping[str, str]]): Headers for the request.
+        return_none_for_not_found_error (Optional[bool]): If True, returns None
+            for 404 error instead of throwing an exception.
 
     Returns:
         Union[Mapping, str]: If the metadata server returns JSON, a mapping of
@@ -216,8 +219,17 @@
             "metadata service. Compute Engine Metadata server 
unavailable".format(url)
         )
 
+    content = _helpers.from_bytes(response.data)
+
+    if response.status == http_client.NOT_FOUND and 
return_none_for_not_found_error:
+        _LOGGER.info(
+            "Compute Engine Metadata server call to %s returned 404, reason: 
%s",
+            path,
+            content,
+        )
+        return None
+
     if response.status == http_client.OK:
-        content = _helpers.from_bytes(response.data)
         if (
             _helpers.parse_content_type(response.headers["content-type"])
             == "application/json"
@@ -232,14 +244,14 @@
                 raise new_exc from caught_exc
         else:
             return content
-    else:
-        raise exceptions.TransportError(
-            "Failed to retrieve {} from the Google Compute Engine "
-            "metadata service. Status: {} Response:\n{}".format(
-                url, response.status, response.data
-            ),
-            response,
-        )
+
+    raise exceptions.TransportError(
+        "Failed to retrieve {} from the Google Compute Engine "
+        "metadata service. Status: {} Response:\n{}".format(
+            url, response.status, response.data
+        ),
+        response,
+    )
 
 
 def get_project_id(request):
@@ -259,6 +271,29 @@
     return get(request, "project/project-id")
 
 
+def get_universe_domain(request):
+    """Get the universe domain value from the metadata server.
+
+    Args:
+        request (google.auth.transport.Request): A callable used to make
+            HTTP requests.
+
+    Returns:
+        str: The universe domain value. If the universe domain endpoint is not
+        not found, return the default value, which is googleapis.com
+
+    Raises:
+        google.auth.exceptions.TransportError: if an error other than
+            404 occurs while retrieving metadata.
+    """
+    universe_domain = get(
+        request, "universe/universe_domain", 
return_none_for_not_found_error=True
+    )
+    if not universe_domain:
+        return "googleapis.com"
+    return universe_domain
+
+
 def get_service_account_info(request, service_account="default"):
     """Get information about a service account from the metadata server.
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/google-auth-2.23.4/google/auth/compute_engine/credentials.py 
new/google-auth-2.25.1/google/auth/compute_engine/credentials.py
--- old/google-auth-2.23.4/google/auth/compute_engine/credentials.py    
2023-10-31 20:35:33.000000000 +0100
+++ new/google-auth-2.25.1/google/auth/compute_engine/credentials.py    
2023-12-06 02:42:14.000000000 +0100
@@ -28,6 +28,7 @@
 from google.auth import jwt
 from google.auth import metrics
 from google.auth.compute_engine import _metadata
+from google.auth.transport import requests as google_auth_requests
 from google.oauth2 import _client
 
 
@@ -73,6 +74,8 @@
         self._quota_project_id = quota_project_id
         self._scopes = scopes
         self._default_scopes = default_scopes
+        self._universe_domain_cached = False
+        self._universe_domain_request = google_auth_requests.Request()
 
     def _retrieve_info(self, request):
         """Retrieve information about the service account.
@@ -131,6 +134,16 @@
     def requires_scopes(self):
         return not self._scopes
 
+    @property
+    def universe_domain(self):
+        if self._universe_domain_cached:
+            return self._universe_domain
+        self._universe_domain = _metadata.get_universe_domain(
+            self._universe_domain_request
+        )
+        self._universe_domain_cached = True
+        return self._universe_domain
+
     @_helpers.copy_docstring(credentials.CredentialsWithQuotaProject)
     def with_quota_project(self, quota_project_id):
         return self.__class__(
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/google-auth-2.23.4/google/auth/external_account.py 
new/google-auth-2.25.1/google/auth/external_account.py
--- old/google-auth-2.23.4/google/auth/external_account.py      2023-10-31 
20:35:33.000000000 +0100
+++ new/google-auth-2.25.1/google/auth/external_account.py      2023-12-06 
02:42:14.000000000 +0100
@@ -415,6 +415,22 @@
         new_cred._metrics_options = self._metrics_options
         return new_cred
 
+    def with_universe_domain(self, universe_domain):
+        """Create a copy of these credentials with the given universe domain.
+
+        Args:
+            universe_domain (str): The universe domain value.
+
+        Returns:
+            google.auth.external_account.Credentials: A new credentials
+                instance.
+        """
+        kwargs = self._constructor_args()
+        kwargs.update(universe_domain=universe_domain)
+        new_cred = self.__class__(**kwargs)
+        new_cred._metrics_options = self._metrics_options
+        return new_cred
+
     def _initialize_impersonated_credentials(self):
         """Generates an impersonated credentials.
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/google-auth-2.23.4/google/auth/transport/_custom_tls_signer.py 
new/google-auth-2.25.1/google/auth/transport/_custom_tls_signer.py
--- old/google-auth-2.23.4/google/auth/transport/_custom_tls_signer.py  
2023-10-31 20:35:33.000000000 +0100
+++ new/google-auth-2.25.1/google/auth/transport/_custom_tls_signer.py  
2023-12-06 02:42:14.000000000 +0100
@@ -107,6 +107,22 @@
     return lib
 
 
+def load_provider_lib(provider_lib_path):
+    _LOGGER.debug("loading provider library from %s", provider_lib_path)
+
+    # winmode parameter is only available for python 3.8+.
+    lib = (
+        ctypes.CDLL(provider_lib_path, winmode=0)
+        if sys.version_info >= (3, 8) and os.name == "nt"
+        else ctypes.CDLL(provider_lib_path)
+    )
+
+    lib.ECP_attach_to_ctx.argtypes = [ctypes.c_void_p, ctypes.c_char_p]
+    lib.ECP_attach_to_ctx.restype = ctypes.c_int
+
+    return lib
+
+
 # Computes SHA256 hash.
 def _compute_sha256_digest(to_be_signed, to_be_signed_len):
     from cryptography.hazmat.primitives import hashes
@@ -199,21 +215,31 @@
         self._enterprise_cert_file_path = enterprise_cert_file_path
         self._cert = None
         self._sign_callback = None
+        self._provider_lib = None
 
     def load_libraries(self):
-        try:
-            with open(self._enterprise_cert_file_path, "r") as f:
-                enterprise_cert_json = json.load(f)
-                libs = enterprise_cert_json["libs"]
-                signer_library = libs["ecp_client"]
-                offload_library = libs["tls_offload"]
-        except (KeyError, ValueError) as caught_exc:
-            new_exc = exceptions.MutualTLSChannelError(
-                "enterprise cert file is invalid", caught_exc
-            )
-            raise new_exc from caught_exc
-        self._offload_lib = load_offload_lib(offload_library)
-        self._signer_lib = load_signer_lib(signer_library)
+        with open(self._enterprise_cert_file_path, "r") as f:
+            enterprise_cert_json = json.load(f)
+            libs = enterprise_cert_json.get("libs", {})
+
+            signer_library = libs.get("ecp_client", None)
+            offload_library = libs.get("tls_offload", None)
+            provider_library = libs.get("ecp_provider", None)
+
+        # Using newer provider implementation. This is mutually exclusive to 
the
+        # offload implementation.
+        if provider_library:
+            self._provider_lib = load_provider_lib(provider_library)
+            return
+
+        # Using old offload implementation
+        if offload_library and signer_library:
+            self._offload_lib = load_offload_lib(offload_library)
+            self._signer_lib = load_signer_lib(signer_library)
+            self.set_up_custom_key()
+            return
+
+        raise exceptions.MutualTLSChannelError("enterprise cert file is 
invalid")
 
     def set_up_custom_key(self):
         # We need to keep a reference of the cert and sign callback so it won't
@@ -224,11 +250,22 @@
         )
 
     def attach_to_ssl_context(self, ctx):
-        # In the TLS handshake, the signing operation will be done by the
-        # sign_callback.
-        if not self._offload_lib.ConfigureSslContext(
-            self._sign_callback,
-            ctypes.c_char_p(self._cert),
-            _cast_ssl_ctx_to_void_p(ctx._ctx._context),
-        ):
-            raise exceptions.MutualTLSChannelError("failed to configure SSL 
context")
+        if self._provider_lib:
+            if not self._provider_lib.ECP_attach_to_ctx(
+                _cast_ssl_ctx_to_void_p(ctx._ctx._context),
+                self._enterprise_cert_file_path.encode("ascii"),
+            ):
+                raise exceptions.MutualTLSChannelError(
+                    "failed to configure ECP Provider SSL context"
+                )
+        elif self._offload_lib and self._signer_lib:
+            if not self._offload_lib.ConfigureSslContext(
+                self._sign_callback,
+                ctypes.c_char_p(self._cert),
+                _cast_ssl_ctx_to_void_p(ctx._ctx._context),
+            ):
+                raise exceptions.MutualTLSChannelError(
+                    "failed to configure ECP Offload SSL context"
+                )
+        else:
+            raise exceptions.MutualTLSChannelError("Invalid ECP 
configuration.")
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/google-auth-2.23.4/google/auth/transport/requests.py 
new/google-auth-2.25.1/google/auth/transport/requests.py
--- old/google-auth-2.23.4/google/auth/transport/requests.py    2023-10-31 
20:35:33.000000000 +0100
+++ new/google-auth-2.25.1/google/auth/transport/requests.py    2023-12-06 
02:42:14.000000000 +0100
@@ -274,7 +274,6 @@
 
         self.signer = 
_custom_tls_signer.CustomTlsSigner(enterprise_cert_file_path)
         self.signer.load_libraries()
-        self.signer.set_up_custom_key()
 
         poolmanager = create_urllib3_context()
         poolmanager.load_verify_locations(cafile=certifi.where())
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/google-auth-2.23.4/google/auth/version.py 
new/google-auth-2.25.1/google/auth/version.py
--- old/google-auth-2.23.4/google/auth/version.py       2023-10-31 
20:35:33.000000000 +0100
+++ new/google-auth-2.25.1/google/auth/version.py       2023-12-06 
02:42:14.000000000 +0100
@@ -12,4 +12,4 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-__version__ = "2.23.4"
+__version__ = "2.25.1"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/google-auth-2.23.4/google/oauth2/__init__.py 
new/google-auth-2.25.1/google/oauth2/__init__.py
--- old/google-auth-2.23.4/google/oauth2/__init__.py    2023-10-31 
20:35:33.000000000 +0100
+++ new/google-auth-2.25.1/google/oauth2/__init__.py    2023-12-06 
02:42:14.000000000 +0100
@@ -21,8 +21,7 @@
 class Python37DeprecationWarning(DeprecationWarning):  # pragma: NO COVER
     """
     Deprecation warning raised when Python 3.7 runtime is detected.
-    Python 3.7 support will be dropped after January 1, 2024. See
-    https://cloud.google.com/python/docs/python37-sunset/ for more information.
+    Python 3.7 support will be dropped after January 1, 2024.
     """
 
     pass
@@ -32,9 +31,6 @@
 if sys.version_info.major == 3 and sys.version_info.minor == 7:  # pragma: NO 
COVER
     message = (
         "After January 1, 2024, new releases of this library will drop support 
"
-        "for Python 3.7. More details about Python 3.7 support "
-        "can be found at https://cloud.google.com/python/docs/python37-sunset/";
+        "for Python 3.7."
     )
-    # Configure the Python37DeprecationWarning warning so that it is only 
emitted once.
-    warnings.simplefilter("once", Python37DeprecationWarning)
     warnings.warn(message, Python37DeprecationWarning)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/google-auth-2.23.4/google/oauth2/_credentials_async.py 
new/google-auth-2.25.1/google/oauth2/_credentials_async.py
--- old/google-auth-2.23.4/google/oauth2/_credentials_async.py  2023-10-31 
20:35:33.000000000 +0100
+++ new/google-auth-2.25.1/google/oauth2/_credentials_async.py  2023-12-06 
02:42:14.000000000 +0100
@@ -96,6 +96,12 @@
                     )
                 )
 
+    @_helpers.copy_docstring(credentials.Credentials)
+    async def before_request(self, request, method, url, headers):
+        if not self.valid:
+            await self.refresh(request)
+        self.apply(headers)
+
 
 class 
UserAccessTokenCredentials(oauth2_credentials.UserAccessTokenCredentials):
     """Access token credentials for user account.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/google-auth-2.23.4/google/oauth2/credentials.py 
new/google-auth-2.25.1/google/oauth2/credentials.py
--- old/google-auth-2.23.4/google/oauth2/credentials.py 2023-10-31 
20:35:33.000000000 +0100
+++ new/google-auth-2.25.1/google/oauth2/credentials.py 2023-12-06 
02:42:14.000000000 +0100
@@ -49,13 +49,15 @@
 
 # The Google OAuth 2.0 token endpoint. Used for authorized user credentials.
 _GOOGLE_OAUTH2_TOKEN_ENDPOINT = "https://oauth2.googleapis.com/token";
+_DEFAULT_UNIVERSE_DOMAIN = "googleapis.com"
 
 
 class Credentials(credentials.ReadOnlyScoped, 
credentials.CredentialsWithQuotaProject):
     """Credentials using OAuth 2.0 access and refresh tokens.
 
-    The credentials are considered immutable. If you want to modify the
-    quota project, use :meth:`with_quota_project` or ::
+    The credentials are considered immutable except the tokens and the token
+    expiry, which are updated after refresh. If you want to modify the quota
+    project, use :meth:`with_quota_project` or ::
 
         credentials = credentials.with_quota_project('myproject-123')
 
@@ -84,6 +86,7 @@
         enable_reauth_refresh=False,
         granted_scopes=None,
         trust_boundary=None,
+        universe_domain=_DEFAULT_UNIVERSE_DOMAIN,
     ):
         """
         Args:
@@ -125,6 +128,9 @@
             granted_scopes (Optional[Sequence[str]]): The scopes that were 
consented/granted by the user.
                 This could be different from the requested scopes and it could 
be empty if granted
                 and requested scopes were same.
+            trust_boundary (str): String representation of trust boundary meta.
+            universe_domain (Optional[str]): The universe domain. The default
+                universe domain is googleapis.com.
         """
         super(Credentials, self).__init__()
         self.token = token
@@ -142,6 +148,7 @@
         self.refresh_handler = refresh_handler
         self._enable_reauth_refresh = enable_reauth_refresh
         self._trust_boundary = trust_boundary
+        self._universe_domain = universe_domain or _DEFAULT_UNIVERSE_DOMAIN
 
     def __getstate__(self):
         """A __getstate__ method must exist for the __setstate__ to be called
@@ -272,6 +279,7 @@
             rapt_token=self.rapt_token,
             enable_reauth_refresh=self._enable_reauth_refresh,
             trust_boundary=self._trust_boundary,
+            universe_domain=self._universe_domain,
         )
 
     @_helpers.copy_docstring(credentials.CredentialsWithTokenUri)
@@ -291,6 +299,34 @@
             rapt_token=self.rapt_token,
             enable_reauth_refresh=self._enable_reauth_refresh,
             trust_boundary=self._trust_boundary,
+            universe_domain=self._universe_domain,
+        )
+
+    def with_universe_domain(self, universe_domain):
+        """Create a copy of the credential with the given universe domain.
+
+        Args:
+            universe_domain (str): The universe domain value.
+
+        Returns:
+            google.oauth2.credentials.Credentials: A new credentials instance.
+        """
+
+        return self.__class__(
+            self.token,
+            refresh_token=self.refresh_token,
+            id_token=self.id_token,
+            token_uri=self._token_uri,
+            client_id=self.client_id,
+            client_secret=self.client_secret,
+            scopes=self.scopes,
+            default_scopes=self.default_scopes,
+            granted_scopes=self.granted_scopes,
+            quota_project_id=self.quota_project_id,
+            rapt_token=self.rapt_token,
+            enable_reauth_refresh=self._enable_reauth_refresh,
+            trust_boundary=self._trust_boundary,
+            universe_domain=universe_domain,
         )
 
     def _metric_header_for_usage(self):
@@ -298,6 +334,17 @@
 
     @_helpers.copy_docstring(credentials.Credentials)
     def refresh(self, request):
+        if self._universe_domain != _DEFAULT_UNIVERSE_DOMAIN:
+            raise exceptions.RefreshError(
+                "User credential refresh is only supported in the default "
+                "googleapis.com universe domain, but the current universe "
+                "domain is {}. If you created the credential with an access "
+                "token, it's likely that the provided token is expired now, "
+                "please update your code with a valid token.".format(
+                    self._universe_domain
+                )
+            )
+
         scopes = self._scopes if self._scopes is not None else 
self._default_scopes
         # Use refresh handler if available and no refresh token is
         # available. This is useful in general when tokens are obtained by 
calling
@@ -427,6 +474,7 @@
             expiry=expiry,
             rapt_token=info.get("rapt_token"),  # may not exist
             trust_boundary=info.get("trust_boundary"),  # may not exist
+            universe_domain=info.get("universe_domain"),  # may not exist
         )
 
     @classmethod
@@ -470,6 +518,7 @@
             "client_secret": self.client_secret,
             "scopes": self.scopes,
             "rapt_token": self.rapt_token,
+            "universe_domain": self._universe_domain,
         }
         if self.expiry:  # flatten expiry timestamp
             prep["expiry"] = self.expiry.isoformat() + "Z"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/google-auth-2.23.4/google/oauth2/service_account.py 
new/google-auth-2.25.1/google/oauth2/service_account.py
--- old/google-auth-2.23.4/google/oauth2/service_account.py     2023-10-31 
20:35:33.000000000 +0100
+++ new/google-auth-2.25.1/google/oauth2/service_account.py     2023-12-06 
02:42:14.000000000 +0100
@@ -182,10 +182,7 @@
         self._quota_project_id = quota_project_id
         self._token_uri = token_uri
         self._always_use_jwt_access = always_use_jwt_access
-        if not universe_domain:
-            self._universe_domain = _DEFAULT_UNIVERSE_DOMAIN
-        else:
-            self._universe_domain = universe_domain
+        self._universe_domain = universe_domain or _DEFAULT_UNIVERSE_DOMAIN
 
         if universe_domain != _DEFAULT_UNIVERSE_DOMAIN:
             self._always_use_jwt_access = True
@@ -328,6 +325,22 @@
         cred._always_use_jwt_access = always_use_jwt_access
         return cred
 
+    def with_universe_domain(self, universe_domain):
+        """Create a copy of these credentials with the given universe domain.
+
+        Args:
+            universe_domain (str): The universe domain value.
+
+        Returns:
+            google.auth.service_account.Credentials: A new credentials
+                instance.
+        """
+        cred = self._make_copy()
+        cred._universe_domain = universe_domain
+        if universe_domain != _DEFAULT_UNIVERSE_DOMAIN:
+            cred._always_use_jwt_access = True
+        return cred
+
     def with_subject(self, subject):
         """Create a copy of these credentials with the specified subject.
 
@@ -417,13 +430,11 @@
 
     @_helpers.copy_docstring(credentials.Credentials)
     def refresh(self, request):
-        if (
-            self._universe_domain != _DEFAULT_UNIVERSE_DOMAIN
-            and not self._jwt_credentials
-        ):
-            raise exceptions.RefreshError(
-                "self._jwt_credentials is missing for non-default universe 
domain"
-            )
+        if self._always_use_jwt_access and not self._jwt_credentials:
+            # If self signed jwt should be used but jwt credential is not
+            # created, try to create one with scopes
+            self._create_self_signed_jwt(None)
+
         if self._universe_domain != _DEFAULT_UNIVERSE_DOMAIN and self._subject:
             raise exceptions.RefreshError(
                 "domain wide delegation is not supported for non-default 
universe domain"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/google-auth-2.23.4/google_auth.egg-info/PKG-INFO 
new/google-auth-2.25.1/google_auth.egg-info/PKG-INFO
--- old/google-auth-2.23.4/google_auth.egg-info/PKG-INFO        2023-10-31 
20:38:28.000000000 +0100
+++ new/google-auth-2.25.1/google_auth.egg-info/PKG-INFO        2023-12-06 
02:45:01.000000000 +0100
@@ -1,6 +1,6 @@
 Metadata-Version: 2.1
 Name: google-auth
-Version: 2.23.4
+Version: 2.25.1
 Summary: Google Authentication Library
 Home-page: https://github.com/googleapis/google-auth-library-python
 Author: Google Cloud Platform
@@ -13,6 +13,7 @@
 Classifier: Programming Language :: Python :: 3.9
 Classifier: Programming Language :: Python :: 3.10
 Classifier: Programming Language :: Python :: 3.11
+Classifier: Programming Language :: Python :: 3.12
 Classifier: Development Status :: 5 - Production/Stable
 Classifier: Intended Audience :: Developers
 Classifier: License :: OSI Approved :: Apache Software License
@@ -22,12 +23,23 @@
 Classifier: Operating System :: OS Independent
 Classifier: Topic :: Internet :: WWW/HTTP
 Requires-Python: >=3.7
+License-File: LICENSE
+Requires-Dist: cachetools<6.0,>=2.0.0
+Requires-Dist: pyasn1-modules>=0.2.1
+Requires-Dist: rsa<5,>=3.1.4
 Provides-Extra: aiohttp
+Requires-Dist: aiohttp<4.0.0.dev0,>=3.6.2; extra == "aiohttp"
+Requires-Dist: requests<3.0.0.dev0,>=2.20.0; extra == "aiohttp"
 Provides-Extra: pyopenssl
+Requires-Dist: pyopenssl>=20.0.0; extra == "pyopenssl"
+Requires-Dist: cryptography>=38.0.3; extra == "pyopenssl"
 Provides-Extra: requests
+Requires-Dist: requests<3.0.0.dev0,>=2.20.0; extra == "requests"
 Provides-Extra: reauth
-Provides-Extra: enterprise_cert
-License-File: LICENSE
+Requires-Dist: pyu2f>=0.1.5; extra == "reauth"
+Provides-Extra: enterprise-cert
+Requires-Dist: cryptography==36.0.2; extra == "enterprise-cert"
+Requires-Dist: pyopenssl==22.0.0; extra == "enterprise-cert"
 
 Google Auth Python Library
 ==========================
@@ -51,7 +63,7 @@
 
 For more information on setting up your Python development environment, please 
refer to `Python Development Environment Setup Guide`_ for Google Cloud 
Platform.
 
-.. _`Python Development Environment Setup Guide`: 
https://cloud.google.com/python/setup
+.. _`Python Development Environment Setup Guide`: 
https://cloud.google.com/python/docs/setup
 
 Extras
 ------
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/google-auth-2.23.4/google_auth.egg-info/SOURCES.txt 
new/google-auth-2.25.1/google_auth.egg-info/SOURCES.txt
--- old/google-auth-2.23.4/google_auth.egg-info/SOURCES.txt     2023-10-31 
20:38:28.000000000 +0100
+++ new/google-auth-2.25.1/google_auth.egg-info/SOURCES.txt     2023-12-06 
02:45:01.000000000 +0100
@@ -109,6 +109,7 @@
 tests/data/context_aware_metadata.json
 tests/data/enterprise_cert_invalid.json
 tests/data/enterprise_cert_valid.json
+tests/data/enterprise_cert_valid_provider.json
 tests/data/es256_privatekey.pem
 tests/data/es256_public_cert.pem
 tests/data/es256_publickey.pem
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/google-auth-2.23.4/setup.py 
new/google-auth-2.25.1/setup.py
--- old/google-auth-2.23.4/setup.py     2023-10-31 20:35:33.000000000 +0100
+++ new/google-auth-2.25.1/setup.py     2023-12-06 02:42:14.000000000 +0100
@@ -70,6 +70,7 @@
         "Programming Language :: Python :: 3.9",
         "Programming Language :: Python :: 3.10",
         "Programming Language :: Python :: 3.11",
+        "Programming Language :: Python :: 3.12",
         "Development Status :: 5 - Production/Stable",
         "Intended Audience :: Developers",
         "License :: OSI Approved :: Apache Software License",
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/google-auth-2.23.4/tests/compute_engine/test__metadata.py 
new/google-auth-2.25.1/tests/compute_engine/test__metadata.py
--- old/google-auth-2.23.4/tests/compute_engine/test__metadata.py       
2023-10-31 20:35:33.000000000 +0100
+++ new/google-auth-2.25.1/tests/compute_engine/test__metadata.py       
2023-12-06 02:42:14.000000000 +0100
@@ -325,6 +325,18 @@
     )
 
 
+def test_get_return_none_for_not_found_error():
+    request = make_request("Metadata error", status=http_client.NOT_FOUND)
+
+    assert _metadata.get(request, PATH, return_none_for_not_found_error=True) 
is None
+
+    request.assert_called_once_with(
+        method="GET",
+        url=_metadata._METADATA_ROOT + PATH,
+        headers=_metadata._METADATA_HEADERS,
+    )
+
+
 def test_get_failure_connection_failed():
     request = make_request("")
     request.side_effect = exceptions.TransportError()
@@ -371,6 +383,53 @@
     assert project_id == project
 
 
+def test_get_universe_domain_success():
+    request = make_request(
+        "fake_universe_domain", headers={"content-type": "text/plain"}
+    )
+
+    universe_domain = _metadata.get_universe_domain(request)
+
+    request.assert_called_once_with(
+        method="GET",
+        url=_metadata._METADATA_ROOT + "universe/universe_domain",
+        headers=_metadata._METADATA_HEADERS,
+    )
+    assert universe_domain == "fake_universe_domain"
+
+
+def test_get_universe_domain_not_found():
+    # Test that if the universe domain endpoint returns 404 error, we should
+    # use googleapis.com as the universe domain
+    request = make_request("not found", status=http_client.NOT_FOUND)
+
+    universe_domain = _metadata.get_universe_domain(request)
+
+    request.assert_called_once_with(
+        method="GET",
+        url=_metadata._METADATA_ROOT + "universe/universe_domain",
+        headers=_metadata._METADATA_HEADERS,
+    )
+    assert universe_domain == "googleapis.com"
+
+
+def test_get_universe_domain_other_error():
+    # Test that if the universe domain endpoint returns an error other than 404
+    # we should throw the error
+    request = make_request("unauthorized", status=http_client.UNAUTHORIZED)
+
+    with pytest.raises(exceptions.TransportError) as excinfo:
+        _metadata.get_universe_domain(request)
+
+    assert excinfo.match(r"unauthorized")
+
+    request.assert_called_once_with(
+        method="GET",
+        url=_metadata._METADATA_ROOT + "universe/universe_domain",
+        headers=_metadata._METADATA_HEADERS,
+    )
+
+
 @mock.patch(
     "google.auth.metrics.token_request_access_token_mds",
     return_value=ACCESS_TOKEN_REQUEST_METRICS_HEADER_VALUE,
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/google-auth-2.23.4/tests/compute_engine/test_credentials.py 
new/google-auth-2.25.1/tests/compute_engine/test_credentials.py
--- old/google-auth-2.23.4/tests/compute_engine/test_credentials.py     
2023-10-31 20:35:33.000000000 +0100
+++ new/google-auth-2.25.1/tests/compute_engine/test_credentials.py     
2023-12-06 02:42:14.000000000 +0100
@@ -208,6 +208,30 @@
         assert headers["authorization"] == "Bearer token"
         assert headers["x-goog-api-client"] == "cred-type/mds"
 
+    @mock.patch(
+        "google.auth.compute_engine._metadata.get_universe_domain",
+        return_value="fake_universe_domain",
+    )
+    def test_universe_domain(self, get_universe_domain):
+        self.credentials._universe_domain_cached = False
+        self.credentials._universe_domain = "googleapis.com"
+
+        # calling the universe_domain property should trigger a call to
+        # get_universe_domain to fetch the value. The value should be cached.
+        assert self.credentials.universe_domain == "fake_universe_domain"
+        assert self.credentials._universe_domain == "fake_universe_domain"
+        assert self.credentials._universe_domain_cached
+        get_universe_domain.assert_called_once_with(
+            self.credentials._universe_domain_request
+        )
+
+        # calling the universe_domain property the second time should use the
+        # cached value instead of calling get_universe_domain
+        assert self.credentials.universe_domain == "fake_universe_domain"
+        get_universe_domain.assert_called_once_with(
+            self.credentials._universe_domain_request
+        )
+
 
 class TestIDTokenCredentials(object):
     credentials = None
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/google-auth-2.23.4/tests/data/enterprise_cert_valid_provider.json 
new/google-auth-2.25.1/tests/data/enterprise_cert_valid_provider.json
--- old/google-auth-2.23.4/tests/data/enterprise_cert_valid_provider.json       
1970-01-01 01:00:00.000000000 +0100
+++ new/google-auth-2.25.1/tests/data/enterprise_cert_valid_provider.json       
2023-12-06 02:42:14.000000000 +0100
@@ -0,0 +1,6 @@
+{
+    "libs": {
+        "ecp_client": "/path/to/signer/lib",
+        "ecp_provider": "/path/to/provider/lib"
+    }
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/google-auth-2.23.4/tests/oauth2/test_credentials.py 
new/google-auth-2.25.1/tests/oauth2/test_credentials.py
--- old/google-auth-2.23.4/tests/oauth2/test_credentials.py     2023-10-31 
20:35:33.000000000 +0100
+++ new/google-auth-2.25.1/tests/oauth2/test_credentials.py     2023-12-06 
02:42:14.000000000 +0100
@@ -122,6 +122,17 @@
 
         assert excinfo.match("The provided refresh_handler is not a callable 
or None.")
 
+    def test_refresh_with_non_default_universe_domain(self):
+        creds = credentials.Credentials(
+            token="token", universe_domain="dummy_universe.com"
+        )
+        with pytest.raises(exceptions.RefreshError) as excinfo:
+            creds.refresh(mock.Mock())
+
+        assert excinfo.match(
+            "refresh is only supported in the default googleapis.com universe 
domain"
+        )
+
     @mock.patch("google.oauth2.reauth.refresh_grant", autospec=True)
     @mock.patch(
         "google.auth._helpers.utcnow",
@@ -774,6 +785,12 @@
         creds.apply(headers)
         assert "x-goog-user-project" in headers
 
+    def test_with_universe_domain(self):
+        creds = credentials.Credentials(token="token")
+        assert creds.universe_domain == "googleapis.com"
+        new_creds = creds.with_universe_domain("dummy_universe.com")
+        assert new_creds.universe_domain == "dummy_universe.com"
+
     def test_with_token_uri(self):
         info = AUTH_USER_INFO.copy()
 
@@ -868,6 +885,7 @@
         assert json_asdict.get("scopes") == creds.scopes
         assert json_asdict.get("client_secret") == creds.client_secret
         assert json_asdict.get("expiry") == info["expiry"]
+        assert json_asdict.get("universe_domain") == creds.universe_domain
 
         # Test with a `strip` arg
         json_output = creds.to_json(strip=["client_secret"])
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/google-auth-2.23.4/tests/oauth2/test_service_account.py 
new/google-auth-2.25.1/tests/oauth2/test_service_account.py
--- old/google-auth-2.23.4/tests/oauth2/test_service_account.py 2023-10-31 
20:35:33.000000000 +0100
+++ new/google-auth-2.25.1/tests/oauth2/test_service_account.py 2023-12-06 
02:42:14.000000000 +0100
@@ -205,6 +205,17 @@
         creds_with_new_token_uri = credentials.with_token_uri(new_token_uri)
         assert creds_with_new_token_uri._token_uri == new_token_uri
 
+    def test_with_universe_domain(self):
+        credentials = self.make_credentials()
+
+        new_credentials = 
credentials.with_universe_domain("dummy_universe.com")
+        assert new_credentials.universe_domain == "dummy_universe.com"
+        assert new_credentials._always_use_jwt_access
+
+        new_credentials = credentials.with_universe_domain("googleapis.com")
+        assert new_credentials.universe_domain == "googleapis.com"
+        assert not new_credentials._always_use_jwt_access
+
     def test__with_always_use_jwt_access(self):
         credentials = self.make_credentials()
         assert not credentials._always_use_jwt_access
@@ -557,12 +568,16 @@
         assert jwt_grant.called
         assert not self_signed_jwt_refresh.called
 
-    def test_refresh_non_gdu_missing_jwt_credentials(self):
-        credentials = self.make_credentials(universe_domain="foo")
+    def test_refresh_missing_jwt_credentials(self):
+        credentials = self.make_credentials()
+        credentials = credentials.with_scopes(["foo", "bar"])
+        credentials = credentials.with_always_use_jwt_access(True)
+        assert not credentials._jwt_credentials
+
+        credentials.refresh(mock.Mock())
 
-        with pytest.raises(exceptions.RefreshError) as excinfo:
-            credentials.refresh(None)
-        assert excinfo.match("self._jwt_credentials is missing")
+        # jwt credentials should have been automatically created with scopes
+        assert credentials._jwt_credentials is not None
 
     def test_refresh_non_gdu_domain_wide_delegation_not_supported(self):
         credentials = self.make_credentials(universe_domain="foo")
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/google-auth-2.23.4/tests/test_credentials.py 
new/google-auth-2.25.1/tests/test_credentials.py
--- old/google-auth-2.23.4/tests/test_credentials.py    2023-10-31 
20:35:33.000000000 +0100
+++ new/google-auth-2.25.1/tests/test_credentials.py    2023-12-06 
02:42:14.000000000 +0100
@@ -55,9 +55,7 @@
     # Set the expiration to one second more than now plus the clock skew
     # accomodation. These credentials should be valid.
     credentials.expiry = (
-        datetime.datetime.utcnow()
-        + _helpers.REFRESH_THRESHOLD
-        + datetime.timedelta(seconds=1)
+        _helpers.utcnow() + _helpers.REFRESH_THRESHOLD + 
datetime.timedelta(seconds=1)
     )
 
     assert credentials.valid
@@ -65,7 +63,7 @@
 
     # Set the credentials expiration to now. Because of the clock skew
     # accomodation, these credentials should report as expired.
-    credentials.expiry = datetime.datetime.utcnow()
+    credentials.expiry = _helpers.utcnow()
 
     assert not credentials.valid
     assert credentials.expired
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/google-auth-2.23.4/tests/test_external_account.py 
new/google-auth-2.25.1/tests/test_external_account.py
--- old/google-auth-2.23.4/tests/test_external_account.py       2023-10-31 
20:35:33.000000000 +0100
+++ new/google-auth-2.25.1/tests/test_external_account.py       2023-12-06 
02:42:14.000000000 +0100
@@ -505,6 +505,11 @@
         credentials = self.make_credentials()
         assert credentials.universe_domain == 
external_account._DEFAULT_UNIVERSE_DOMAIN
 
+    def test_with_universe_domain(self):
+        credentials = self.make_credentials()
+        new_credentials = 
credentials.with_universe_domain("dummy_universe.com")
+        assert new_credentials.universe_domain == "dummy_universe.com"
+
     def test_info_workforce_pool(self):
         credentials = self.make_workforce_pool_credentials(
             workforce_pool_user_project=self.WORKFORCE_POOL_USER_PROJECT
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/google-auth-2.23.4/tests/transport/test__custom_tls_signer.py 
new/google-auth-2.25.1/tests/transport/test__custom_tls_signer.py
--- old/google-auth-2.23.4/tests/transport/test__custom_tls_signer.py   
2023-10-31 20:35:33.000000000 +0100
+++ new/google-auth-2.25.1/tests/transport/test__custom_tls_signer.py   
2023-12-06 02:42:14.000000000 +0100
@@ -11,7 +11,6 @@
 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 # See the License for the specific language governing permissions and
 # limitations under the License.
-
 import base64
 import ctypes
 import os
@@ -30,11 +29,19 @@
 ENTERPRISE_CERT_FILE = os.path.join(
     os.path.dirname(__file__), "../data/enterprise_cert_valid.json"
 )
+ENTERPRISE_CERT_FILE_PROVIDER = os.path.join(
+    os.path.dirname(__file__), "../data/enterprise_cert_valid_provider.json"
+)
 INVALID_ENTERPRISE_CERT_FILE = os.path.join(
     os.path.dirname(__file__), "../data/enterprise_cert_invalid.json"
 )
 
 
+def test_load_provider_lib():
+    with mock.patch("ctypes.CDLL", return_value=mock.MagicMock()):
+        _custom_tls_signer.load_provider_lib("/path/to/provider/lib")
+
+
 def test_load_offload_lib():
     with mock.patch("ctypes.CDLL", return_value=mock.MagicMock()):
         lib = _custom_tls_signer.load_offload_lib("/path/to/offload/lib")
@@ -173,62 +180,81 @@
         ) as load_offload_lib:
             load_offload_lib.return_value = offload_lib
             load_signer_lib.return_value = signer_lib
-            signer_object = 
_custom_tls_signer.CustomTlsSigner(ENTERPRISE_CERT_FILE)
-            signer_object.load_libraries()
-    assert signer_object._cert is None
+            with mock.patch(
+                "google.auth.transport._custom_tls_signer.get_cert"
+            ) as get_cert:
+                with mock.patch(
+                    
"google.auth.transport._custom_tls_signer.get_sign_callback"
+                ) as get_sign_callback:
+                    get_cert.return_value = b"mock_cert"
+                    signer_object = _custom_tls_signer.CustomTlsSigner(
+                        ENTERPRISE_CERT_FILE
+                    )
+                    signer_object.load_libraries()
+                    
signer_object.attach_to_ssl_context(create_urllib3_context())
+                    get_cert.assert_called_once()
+                    get_sign_callback.assert_called_once()
+                    offload_lib.ConfigureSslContext.assert_called_once()
     assert signer_object._enterprise_cert_file_path == ENTERPRISE_CERT_FILE
     assert signer_object._offload_lib == offload_lib
     assert signer_object._signer_lib == signer_lib
     load_signer_lib.assert_called_with("/path/to/signer/lib")
     load_offload_lib.assert_called_with("/path/to/offload/lib")
 
-    # Test set_up_custom_key and set_up_ssl_context methods
-    with mock.patch("google.auth.transport._custom_tls_signer.get_cert") as 
get_cert:
-        with mock.patch(
-            "google.auth.transport._custom_tls_signer.get_sign_callback"
-        ) as get_sign_callback:
-            get_cert.return_value = b"mock_cert"
-            signer_object.set_up_custom_key()
-            signer_object.attach_to_ssl_context(create_urllib3_context())
-    get_cert.assert_called_once()
-    get_sign_callback.assert_called_once()
-    offload_lib.ConfigureSslContext.assert_called_once()
 
+def test_custom_tls_signer_provider():
+    provider_lib = mock.MagicMock()
 
-def test_custom_tls_signer_failed_to_load_libraries():
     # Test load_libraries method
+    with mock.patch(
+        "google.auth.transport._custom_tls_signer.load_provider_lib"
+    ) as load_provider_lib:
+        load_provider_lib.return_value = provider_lib
+        signer_object = _custom_tls_signer.CustomTlsSigner(
+            ENTERPRISE_CERT_FILE_PROVIDER
+        )
+        signer_object.load_libraries()
+        signer_object.attach_to_ssl_context(mock.MagicMock())
+
+    assert signer_object._enterprise_cert_file_path == 
ENTERPRISE_CERT_FILE_PROVIDER
+    assert signer_object._provider_lib == provider_lib
+    load_provider_lib.assert_called_with("/path/to/provider/lib")
+
+
+def test_custom_tls_signer_failed_to_load_libraries():
     with pytest.raises(exceptions.MutualTLSChannelError) as excinfo:
         signer_object = 
_custom_tls_signer.CustomTlsSigner(INVALID_ENTERPRISE_CERT_FILE)
         signer_object.load_libraries()
     assert excinfo.match("enterprise cert file is invalid")
 
 
-def test_custom_tls_signer_fail_to_offload():
-    offload_lib = mock.MagicMock()
-    signer_lib = mock.MagicMock()
+def test_custom_tls_signer_failed_to_attach():
+    with pytest.raises(exceptions.MutualTLSChannelError) as excinfo:
+        signer_object = 
_custom_tls_signer.CustomTlsSigner(ENTERPRISE_CERT_FILE)
+        signer_object._offload_lib = mock.MagicMock()
+        signer_object._signer_lib = mock.MagicMock()
+        signer_object._sign_callback = mock.MagicMock()
+        signer_object._cert = b"mock cert"
+        signer_object._offload_lib.ConfigureSslContext.return_value = False
+        signer_object.attach_to_ssl_context(mock.MagicMock())
+    assert excinfo.match("failed to configure ECP Offload SSL context")
 
-    with mock.patch(
-        "google.auth.transport._custom_tls_signer.load_signer_lib"
-    ) as load_signer_lib:
-        with mock.patch(
-            "google.auth.transport._custom_tls_signer.load_offload_lib"
-        ) as load_offload_lib:
-            load_offload_lib.return_value = offload_lib
-            load_signer_lib.return_value = signer_lib
-            signer_object = 
_custom_tls_signer.CustomTlsSigner(ENTERPRISE_CERT_FILE)
-            signer_object.load_libraries()
 
-    # set the return value to be 0 which indicts offload fails
-    offload_lib.ConfigureSslContext.return_value = 0
+def test_custom_tls_signer_failed_to_attach_provider():
+    with pytest.raises(exceptions.MutualTLSChannelError) as excinfo:
+        signer_object = _custom_tls_signer.CustomTlsSigner(
+            ENTERPRISE_CERT_FILE_PROVIDER
+        )
+        signer_object._provider_lib = mock.MagicMock()
+        signer_object._provider_lib.ECP_attach_to_ctx.return_value = False
+        signer_object.attach_to_ssl_context(mock.MagicMock())
+    assert excinfo.match("failed to configure ECP Provider SSL context")
 
+
+def test_custom_tls_signer_failed_to_attach_no_libs():
     with pytest.raises(exceptions.MutualTLSChannelError) as excinfo:
-        with mock.patch(
-            "google.auth.transport._custom_tls_signer.get_cert"
-        ) as get_cert:
-            with mock.patch(
-                "google.auth.transport._custom_tls_signer.get_sign_callback"
-            ):
-                get_cert.return_value = b"mock_cert"
-                signer_object.set_up_custom_key()
-                signer_object.attach_to_ssl_context(create_urllib3_context())
-    assert excinfo.match("failed to configure SSL context")
+        signer_object = 
_custom_tls_signer.CustomTlsSigner(ENTERPRISE_CERT_FILE)
+        signer_object._offload_lib = None
+        signer_object._signer_lib = None
+        signer_object.attach_to_ssl_context(mock.MagicMock())
+    assert excinfo.match("Invalid ECP configuration.")
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/google-auth-2.23.4/tests/transport/test_requests.py 
new/google-auth-2.25.1/tests/transport/test_requests.py
--- old/google-auth-2.23.4/tests/transport/test_requests.py     2023-10-31 
20:35:33.000000000 +0100
+++ new/google-auth-2.25.1/tests/transport/test_requests.py     2023-12-06 
02:42:14.000000000 +0100
@@ -545,16 +545,12 @@
         google.auth.transport._custom_tls_signer.CustomTlsSigner, 
"load_libraries"
     )
     @mock.patch.object(
-        google.auth.transport._custom_tls_signer.CustomTlsSigner, 
"set_up_custom_key"
-    )
-    @mock.patch.object(
         google.auth.transport._custom_tls_signer.CustomTlsSigner,
         "attach_to_ssl_context",
     )
     def test_success(
         self,
         mock_attach_to_ssl_context,
-        mock_set_up_custom_key,
         mock_load_libraries,
         mock_proxy_manager_for,
         mock_init_poolmanager,
@@ -565,7 +561,6 @@
         )
 
         mock_load_libraries.assert_called_once()
-        mock_set_up_custom_key.assert_called_once()
         assert mock_attach_to_ssl_context.call_count == 2
 
         adapter.init_poolmanager()

Reply via email to