From 878d7c70d0fbaf14141f805037a87fce75201c16 Mon Sep 17 00:00:00 2001 From: ohmayr Date: Mon, 3 Mar 2025 20:05:03 +0000 Subject: [PATCH 1/2] chore: add request-response log helpers --- google/auth/_helpers.py | 44 +++++++++++++++++----- google/auth/aio/transport/aiohttp.py | 7 ++++ google/auth/transport/_aiohttp_requests.py | 8 +++- google/auth/transport/_http_client.py | 5 ++- google/auth/transport/requests.py | 5 ++- google/auth/transport/urllib3.py | 5 ++- 6 files changed, 61 insertions(+), 13 deletions(-) diff --git a/google/auth/_helpers.py b/google/auth/_helpers.py index 1c2790a10..f67f54014 100644 --- a/google/auth/_helpers.py +++ b/google/auth/_helpers.py @@ -19,7 +19,9 @@ import datetime from email.message import Message import hashlib +import logging import sys +from typing import Optional, Dict, Any import urllib from google.auth import exceptions @@ -28,15 +30,8 @@ # expiry. REFRESH_THRESHOLD = datetime.timedelta(minutes=3, seconds=45) -_SENSITIVE_FIELDS = { - "accessToken", - "access_token", - "id_token", - "client_id", - "refresh_token", - "client_secret", -} - +# TODO(https://github.com/googleapis/google-auth-library-python/issues/1684): Audit and update the list below. +_SENSITIVE_FIELDS = {"accessToken", "access_token", "id_token", "client_id", "refresh_token", "client_secret"} def copy_docstring(source_class): """Decorator that copies a method's docstring from another class. @@ -311,3 +306,34 @@ def _hash_value(value, field_name: str) -> str: hash_object.update(encoded_value) hex_digest = hash_object.hexdigest() return f"hashed_{field_name}-{hex_digest}" + + +def request_log(logger: logging.Logger, method: str, url: str, body: Optional[Any], headers: Optional[Dict[str, str]]) -> None: + """ + Logs an HTTP request at the DEBUG level. + + Args: + logger: The logging.Logger instance to use. + method: The HTTP method (e.g., "GET", "POST"). + url: The URL of the request. + body: The request body (can be None). + headers: The request headers (can be None). + """ + # TODO(https://github.com/googleapis/google-auth-library-python/issues/1680): Log only if enabled. + # TODO(https://github.com/googleapis/google-auth-library-python/issues/1682): Add httpRequest extra to log event. + # TODO(https://github.com/googleapis/google-auth-library-python/issues/1681): Hash sensitive information. + logger.debug("Making request: %s %s", method, url) + + +def response_log(logger: logging.Logger, response: Any) -> None: + """ + Logs an HTTP response at the DEBUG level. + + Args: + logger: The logging.Logger instance to use. + response: The HTTP response object to log. + """ + # TODO(https://github.com/googleapis/google-auth-library-python/issues/1680): Log only if enabled. + # TODO(https://github.com/googleapis/google-auth-library-python/issues/1683): Add httpResponse extra to log event. + # TODO(https://github.com/googleapis/google-auth-library-python/issues/1681): Hash sensitive information. + logger.debug("Response received...") diff --git a/google/auth/aio/transport/aiohttp.py b/google/auth/aio/transport/aiohttp.py index 074d1491c..f232974e8 100644 --- a/google/auth/aio/transport/aiohttp.py +++ b/google/auth/aio/transport/aiohttp.py @@ -16,6 +16,7 @@ """ import asyncio +import logging from typing import AsyncGenerator, Mapping, Optional try: @@ -29,6 +30,10 @@ from google.auth import exceptions from google.auth.aio import transport +from _helpers import request_log, response_log + +_LOGGER = logging.getLogger(__name__) + class Response(transport.Response): """ @@ -155,6 +160,7 @@ async def __call__( self._session = aiohttp.ClientSession() client_timeout = aiohttp.ClientTimeout(total=timeout) + request_log(_LOGGER, method, url, body, headers) response = await self._session.request( method, url, @@ -163,6 +169,7 @@ async def __call__( timeout=client_timeout, **kwargs, ) + response_log(_LOGGER, response) return Response(response) except aiohttp.ClientError as caught_exc: diff --git a/google/auth/transport/_aiohttp_requests.py b/google/auth/transport/_aiohttp_requests.py index bc4d9dc69..73a060839 100644 --- a/google/auth/transport/_aiohttp_requests.py +++ b/google/auth/transport/_aiohttp_requests.py @@ -24,12 +24,17 @@ import functools import aiohttp # type: ignore +import logging import urllib3 # type: ignore from google.auth import exceptions from google.auth import transport from google.auth.transport import requests +from _helpers import request_log, response_log + +_LOGGER = logging.getLogger(__name__) + # Timeout can be re-defined depending on async requirement. Currently made 60s more than # sync timeout. _DEFAULT_TIMEOUT = 180 # in seconds @@ -182,10 +187,11 @@ async def __call__( self.session = aiohttp.ClientSession( auto_decompress=False ) # pragma: NO COVER - requests._LOGGER.debug("Making request: %s %s", method, url) + request_log(_LOGGER, method, url, body, headers) response = await self.session.request( method, url, data=body, headers=headers, timeout=timeout, **kwargs ) + response_log(_LOGGER, response) return _CombinedResponse(response) except aiohttp.ClientError as caught_exc: diff --git a/google/auth/transport/_http_client.py b/google/auth/transport/_http_client.py index cec0ab73f..6a2f5c74f 100644 --- a/google/auth/transport/_http_client.py +++ b/google/auth/transport/_http_client.py @@ -22,6 +22,8 @@ from google.auth import exceptions from google.auth import transport +from _helpers import request_log, response_log + _LOGGER = logging.getLogger(__name__) @@ -99,10 +101,11 @@ def __call__( connection = http_client.HTTPConnection(parts.netloc, timeout=timeout) try: - _LOGGER.debug("Making request: %s %s", method, url) + request_log(_LOGGER, method, url, body, headers) connection.request(method, path, body=body, headers=headers, **kwargs) response = connection.getresponse() + response_log(_LOGGER, response) return Response(response) except (http_client.HTTPException, socket.error) as caught_exc: diff --git a/google/auth/transport/requests.py b/google/auth/transport/requests.py index 23a69783d..121e496e4 100644 --- a/google/auth/transport/requests.py +++ b/google/auth/transport/requests.py @@ -40,6 +40,8 @@ import google.auth.transport._mtls_helper from google.oauth2 import service_account +from _helpers import request_log, response_log + _LOGGER = logging.getLogger(__name__) _DEFAULT_TIMEOUT = 120 # in seconds @@ -182,10 +184,11 @@ def __call__( google.auth.exceptions.TransportError: If any exception occurred. """ try: - _LOGGER.debug("Making request: %s %s", method, url) + request_log(_LOGGER, method, url, body, headers) response = self.session.request( method, url, data=body, headers=headers, timeout=timeout, **kwargs ) + response_log(_LOGGER, response) return _Response(response) except requests.exceptions.RequestException as caught_exc: new_exc = exceptions.TransportError(caught_exc) diff --git a/google/auth/transport/urllib3.py b/google/auth/transport/urllib3.py index 63144f5ff..fd3fb9964 100644 --- a/google/auth/transport/urllib3.py +++ b/google/auth/transport/urllib3.py @@ -52,6 +52,8 @@ else: # pragma: NO COVER RequestMethods = urllib3.request.RequestMethods # type: ignore +from _helpers import request_log, response_log + _LOGGER = logging.getLogger(__name__) @@ -136,10 +138,11 @@ def __call__( kwargs["timeout"] = timeout try: - _LOGGER.debug("Making request: %s %s", method, url) + request_log(_LOGGER, method, url, body, headers) response = self.http.request( method, url, body=body, headers=headers, **kwargs ) + response_log(_LOGGER, response) return _Response(response) except urllib3.exceptions.HTTPError as caught_exc: new_exc = exceptions.TransportError(caught_exc) From 03905876883b5640fad0bf25ea2121b01d9d9f6c Mon Sep 17 00:00:00 2001 From: ohmayr Date: Mon, 3 Mar 2025 20:29:12 +0000 Subject: [PATCH 2/2] fix presubmit --- google/auth/aio/transport/aiohttp.py | 6 ++---- google/auth/transport/_aiohttp_requests.py | 6 +++--- google/auth/transport/_http_client.py | 7 +++---- google/auth/transport/requests.py | 7 +++---- google/auth/transport/urllib3.py | 7 +++---- 5 files changed, 14 insertions(+), 19 deletions(-) diff --git a/google/auth/aio/transport/aiohttp.py b/google/auth/aio/transport/aiohttp.py index f232974e8..9b09f4cda 100644 --- a/google/auth/aio/transport/aiohttp.py +++ b/google/auth/aio/transport/aiohttp.py @@ -30,8 +30,6 @@ from google.auth import exceptions from google.auth.aio import transport -from _helpers import request_log, response_log - _LOGGER = logging.getLogger(__name__) @@ -160,7 +158,7 @@ async def __call__( self._session = aiohttp.ClientSession() client_timeout = aiohttp.ClientTimeout(total=timeout) - request_log(_LOGGER, method, url, body, headers) + _helpers.request_log(_LOGGER, method, url, body, headers) response = await self._session.request( method, url, @@ -169,7 +167,7 @@ async def __call__( timeout=client_timeout, **kwargs, ) - response_log(_LOGGER, response) + _helpers.response_log(_LOGGER, response) return Response(response) except aiohttp.ClientError as caught_exc: diff --git a/google/auth/transport/_aiohttp_requests.py b/google/auth/transport/_aiohttp_requests.py index 73a060839..fed951d14 100644 --- a/google/auth/transport/_aiohttp_requests.py +++ b/google/auth/transport/_aiohttp_requests.py @@ -29,9 +29,9 @@ from google.auth import exceptions from google.auth import transport +from google.auth import _helpers from google.auth.transport import requests -from _helpers import request_log, response_log _LOGGER = logging.getLogger(__name__) @@ -187,11 +187,11 @@ async def __call__( self.session = aiohttp.ClientSession( auto_decompress=False ) # pragma: NO COVER - request_log(_LOGGER, method, url, body, headers) + _helpers.request_log(_LOGGER, method, url, body, headers) response = await self.session.request( method, url, data=body, headers=headers, timeout=timeout, **kwargs ) - response_log(_LOGGER, response) + _helpers.response_log(_LOGGER, response) return _CombinedResponse(response) except aiohttp.ClientError as caught_exc: diff --git a/google/auth/transport/_http_client.py b/google/auth/transport/_http_client.py index 6a2f5c74f..bedceac58 100644 --- a/google/auth/transport/_http_client.py +++ b/google/auth/transport/_http_client.py @@ -21,8 +21,7 @@ from google.auth import exceptions from google.auth import transport - -from _helpers import request_log, response_log +from google.auth import _helpers _LOGGER = logging.getLogger(__name__) @@ -102,10 +101,10 @@ def __call__( try: - request_log(_LOGGER, method, url, body, headers) + _helpers.request_log(_LOGGER, method, url, body, headers) connection.request(method, path, body=body, headers=headers, **kwargs) response = connection.getresponse() - response_log(_LOGGER, response) + _helpers.response_log(_LOGGER, response) return Response(response) except (http_client.HTTPException, socket.error) as caught_exc: diff --git a/google/auth/transport/requests.py b/google/auth/transport/requests.py index 121e496e4..b3b9fadb0 100644 --- a/google/auth/transport/requests.py +++ b/google/auth/transport/requests.py @@ -37,11 +37,10 @@ from google.auth import environment_vars from google.auth import exceptions from google.auth import transport +from google.auth import _helpers import google.auth.transport._mtls_helper from google.oauth2 import service_account -from _helpers import request_log, response_log - _LOGGER = logging.getLogger(__name__) _DEFAULT_TIMEOUT = 120 # in seconds @@ -184,11 +183,11 @@ def __call__( google.auth.exceptions.TransportError: If any exception occurred. """ try: - request_log(_LOGGER, method, url, body, headers) + _helpers.request_log(_LOGGER, method, url, body, headers) response = self.session.request( method, url, data=body, headers=headers, timeout=timeout, **kwargs ) - response_log(_LOGGER, response) + _helpers.response_log(_LOGGER, response) return _Response(response) except requests.exceptions.RequestException as caught_exc: new_exc = exceptions.TransportError(caught_exc) diff --git a/google/auth/transport/urllib3.py b/google/auth/transport/urllib3.py index fd3fb9964..f41d36bf0 100644 --- a/google/auth/transport/urllib3.py +++ b/google/auth/transport/urllib3.py @@ -45,6 +45,7 @@ from google.auth import environment_vars from google.auth import exceptions from google.auth import transport +from google.auth import _helpers from google.oauth2 import service_account if version.parse(urllib3.__version__) >= version.parse("2.0.0"): # pragma: NO COVER @@ -52,8 +53,6 @@ else: # pragma: NO COVER RequestMethods = urllib3.request.RequestMethods # type: ignore -from _helpers import request_log, response_log - _LOGGER = logging.getLogger(__name__) @@ -138,11 +137,11 @@ def __call__( kwargs["timeout"] = timeout try: - request_log(_LOGGER, method, url, body, headers) + _helpers.request_log(_LOGGER, method, url, body, headers) response = self.http.request( method, url, body=body, headers=headers, **kwargs ) - response_log(_LOGGER, response) + _helpers.response_log(_LOGGER, response) return _Response(response) except urllib3.exceptions.HTTPError as caught_exc: new_exc = exceptions.TransportError(caught_exc)