@@ -153,6 +153,7 @@ def __init__(
153153 "`auth_request` must either be configured or the external package `aiohttp` must be installed to use the default value."
154154 )
155155 self ._auth_request = _auth_request
156+ self ._mtls_rotation_lock = asyncio .Lock ()
156157
157158 async def configure_mtls_channel (self , client_cert_callback = None ):
158159 """Configure the client certificate and key for SSL connection.
@@ -319,43 +320,54 @@ async def request(
319320 if getattr (self , "is_mtls" , False ) and any (
320321 prefix in url for prefix in MTLS_URL_PREFIXES
321322 ):
322- try :
323- (
324- call_cert_bytes ,
325- call_key_bytes ,
326- cached_fingerprint ,
327- current_cert_fingerprint ,
328- ) = await mtls . _run_in_executor (
329- google . auth . transport . _mtls_helper . check_parameters_for_unauthorized_response ,
330- self . _cached_cert ,
331- )
332- if cached_fingerprint != current_cert_fingerprint :
323+ # Snapshot the stale certificate state BEFORE acquiring the lock.
324+ # This represents the cert that caused the 401 rejection.
325+ stale_cert = self . _cached_cert
326+
327+ # Wait in line to acquire the lock
328+ async with self . _mtls_rotation_lock :
329+ # Check Did another coroutine already reconfigure mTLS
330+ if self . _cached_cert != stale_cert :
331+ # Yes! Another request already updated the channel
332+ pass
333+ else :
333334 try :
334- _LOGGER .info (
335- "Client certificate has changed, reconfiguring mTLS "
336- "channel."
335+ (
336+ call_cert_bytes ,
337+ call_key_bytes ,
338+ cached_fingerprint ,
339+ current_cert_fingerprint ,
340+ ) = await mtls ._run_in_executor (
341+ google .auth .transport ._mtls_helper .check_parameters_for_unauthorized_response ,
342+ self ._cached_cert ,
337343 )
338- if self ._mtls_init_task and self ._mtls_init_task .done ():
339- self ._mtls_init_task = None
340- await self .configure_mtls_channel (
341- lambda : (call_cert_bytes , call_key_bytes )
342- )
343- continue
344+ if cached_fingerprint != current_cert_fingerprint :
345+ try :
346+ _LOGGER .info (
347+ "Client certificate has changed, reconfiguring mTLS "
348+ "channel."
349+ )
350+ if self ._mtls_init_task and self ._mtls_init_task .done ():
351+ self ._mtls_init_task = None
352+ await self .configure_mtls_channel (
353+ lambda : (call_cert_bytes , call_key_bytes )
354+ )
355+ continue
356+ except Exception as e :
357+ _LOGGER .warning (
358+ "Failed to reconfigure mTLS channel: %s. Proceeding with original response." ,
359+ e ,
360+ )
361+ else :
362+ _LOGGER .info (
363+ "Skipping reconfiguration of mTLS channel because the client"
364+ " certificate has not changed."
365+ )
344366 except Exception as e :
345367 _LOGGER .warning (
346- "Failed to reconfigure mTLS channel : %s. Proceeding with original response." ,
368+ "Failed to check client certificate parameters : %s. Proceeding with original response." ,
347369 e ,
348370 )
349- else :
350- _LOGGER .info (
351- "Skipping reconfiguration of mTLS channel because the client"
352- " certificate has not changed."
353- )
354- except Exception as e :
355- _LOGGER .warning (
356- "Failed to check client certificate parameters: %s. Proceeding with original response." ,
357- e ,
358- )
359371
360372 if response .status_code not in transport .DEFAULT_RETRYABLE_STATUS_CODES :
361373 break
0 commit comments