From 023d3edb3f8ae7044af80f3a1659db76f2471188 Mon Sep 17 00:00:00 2001 From: Nestor Acuna-Blanco Date: Thu, 9 May 2024 16:46:54 +0200 Subject: [PATCH 1/2] fix: auth leakage with basic authentication --- src/RequestsLibrary/log.py | 6 +++++- utests/test_log.py | 41 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+), 1 deletion(-) diff --git a/src/RequestsLibrary/log.py b/src/RequestsLibrary/log.py index 6d3007d..3c9f7c1 100644 --- a/src/RequestsLibrary/log.py +++ b/src/RequestsLibrary/log.py @@ -5,6 +5,7 @@ from RequestsLibrary.utils import is_file_descriptor LOG_CHAR_LIMIT = 10000 +AUTHORIZATION = 'Authorization' def log_response(response): @@ -24,11 +25,14 @@ def log_request(response): else: original_request = request redirected = "" + safe_headers = dict(original_request.headers) + if AUTHORIZATION in safe_headers: + safe_headers[AUTHORIZATION] = '*****' logger.info( "%s Request : " % original_request.method.upper() + "url=%s %s\n " % (original_request.url, redirected) + "path_url=%s \n " % original_request.path_url - + "headers=%s \n " % original_request.headers + + "headers=%s \n " % safe_headers + "body=%s \n " % format_data_to_log_string(original_request.body) ) diff --git a/utests/test_log.py b/utests/test_log.py index 7468463..137965c 100644 --- a/utests/test_log.py +++ b/utests/test_log.py @@ -60,6 +60,47 @@ def test_log_request(mocked_logger): "body=%s \n " % request.body) +@mock.patch('RequestsLibrary.log.logger') +def test_log_request_with_headers(mocked_logger): + headers = {'User-Agent': 'python-requests/2.31.0', + 'Accept-Encoding': 'gzip, deflate', + 'Accept': '*/*', + 'Connection': 'keep-alive'} + request = Request(method='get', url='http://mock.rulezz', headers=headers) + request = request.prepare() + response = mock.MagicMock() + response.history = [] + response.request = request + log_request(response) + assert mocked_logger.info.call_args[0][0] == ("%s Request : " % request.method + + "url=%s \n " % request.url + + "path_url=%s \n " % request.path_url + + "headers=%s \n " % request.headers + + "body=%s \n " % request.body) + + +@mock.patch('RequestsLibrary.log.logger') +def test_log_request_with_headers_auth(mocked_logger): + headers = {'User-Agent': 'python-requests/2.31.0', + 'Accept-Encoding': 'gzip, deflate', + 'Accept': '*/*', + 'Connection': 'keep-alive', + 'Authorization': 'some_token'} + safe_headers = dict(headers) + safe_headers['Authorization'] = '*****' + request = Request(method='get', url='http://mock.rulezz', headers=headers) + request = request.prepare() + response = mock.MagicMock() + response.history = [] + response.request = request + log_request(response) + assert mocked_logger.info.call_args[0][0] == ("%s Request : " % request.method + + "url=%s \n " % request.url + + "path_url=%s \n " % request.path_url + + "headers=%s \n " % safe_headers + + "body=%s \n " % request.body) + + @mock.patch('RequestsLibrary.log.logger') def test_log_request_with_redirect(mocked_logger): request = Request(method='get', url='http://mock.rulezz/redirected') From ba2b7d9a180754539634bc5195d78ec4ca8b02ae Mon Sep 17 00:00:00 2001 From: Nestor Acuna-Blanco Date: Fri, 28 Jun 2024 20:35:10 +0200 Subject: [PATCH 2/2] feat: enable credentials visualization when in debug or trace logging. --- src/RequestsLibrary/log.py | 2 +- utests/test_log.py | 27 ++++++++++++++++++++++++++- 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/src/RequestsLibrary/log.py b/src/RequestsLibrary/log.py index 3c9f7c1..09807f4 100644 --- a/src/RequestsLibrary/log.py +++ b/src/RequestsLibrary/log.py @@ -26,7 +26,7 @@ def log_request(response): original_request = request redirected = "" safe_headers = dict(original_request.headers) - if AUTHORIZATION in safe_headers: + if logger.LOGLEVEL not in ['TRACE', 'DEBUG'] and AUTHORIZATION in safe_headers: safe_headers[AUTHORIZATION] = '*****' logger.info( "%s Request : " % original_request.method.upper() diff --git a/utests/test_log.py b/utests/test_log.py index 137965c..eda6d75 100644 --- a/utests/test_log.py +++ b/utests/test_log.py @@ -1,5 +1,6 @@ import json import os +import pytest from requests import Request @@ -79,8 +80,10 @@ def test_log_request_with_headers(mocked_logger): "body=%s \n " % request.body) +@pytest.mark.parametrize('log_level', ['INFO', 'CONSOLE', 'HTML', 'WARN', 'ERROR']) @mock.patch('RequestsLibrary.log.logger') -def test_log_request_with_headers_auth(mocked_logger): +def test_log_request_with_headers_auth_with_no_debug_trace_logger(mocked_logger, log_level): + mocked_logger.LOGLEVEL = log_level headers = {'User-Agent': 'python-requests/2.31.0', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', @@ -101,6 +104,28 @@ def test_log_request_with_headers_auth(mocked_logger): "body=%s \n " % request.body) +@pytest.mark.parametrize('log_level', ['DEBUG', 'TRACE']) +@mock.patch('RequestsLibrary.log.logger') +def test_log_request_with_headers_auth_with_debug_trace_logger(mocked_logger, log_level): + headers = {'User-Agent': 'python-requests/2.31.0', + 'Accept-Encoding': 'gzip, deflate', + 'Accept': '*/*', + 'Connection': 'keep-alive', + 'Authorization': 'some_token'} + mocked_logger.LOGLEVEL = log_level + request = Request(method='get', url='http://mock.rulezz', headers=headers) + request = request.prepare() + response = mock.MagicMock() + response.history = [] + response.request = request + log_request(response) + assert mocked_logger.info.call_args[0][0] == ("%s Request : " % request.method + + "url=%s \n " % request.url + + "path_url=%s \n " % request.path_url + + "headers=%s \n " % request.headers + + "body=%s \n " % request.body) + + @mock.patch('RequestsLibrary.log.logger') def test_log_request_with_redirect(mocked_logger): request = Request(method='get', url='http://mock.rulezz/redirected')