From 260eac93162601f58ef0d794bca7354f805093b5 Mon Sep 17 00:00:00 2001 From: Andre Engelbrecht Date: Wed, 14 Apr 2021 10:07:29 +0100 Subject: [PATCH] different username files (#18) * login failed receiver will check in allowed fields [#17] * Cleanup - We don't use multiple user fields here These two receivers don't check for credentials dictionary, but rather just uses the user object directly. --- auditing/__init__.py | 15 +++++++++-- auditing/tests.py | 64 +++++++++++++++++++++++--------------------- 2 files changed, 46 insertions(+), 33 deletions(-) diff --git a/auditing/__init__.py b/auditing/__init__.py index c4b88c1..ac82479 100644 --- a/auditing/__init__.py +++ b/auditing/__init__.py @@ -22,9 +22,20 @@ def login_logger(sender, **kwargs): @receiver(user_login_failed) def login_failed_logger(sender, **kwargs): - USER_FIELD = getattr(settings, 'AUDIT_USERNAME_FIELD', 'username') + + def get_username_in(credentials: dict): + """ + Find the username in credentials dict based on list of valid username + keys. + """ + USER_FIELDS = getattr(settings, 'AUDIT_USERNAME_FIELDS', ['username']) + for key in USER_FIELDS: + if key in credentials.keys(): + return credentials[key] + raise KeyError("Valid username not found in credentials.") + msg_data = get_request_info(kwargs['request']) - msg_data['username'] = kwargs['credentials'][USER_FIELD] + msg_data['username'] = get_username_in(kwargs['credentials']) logger.warn('"Django Login failed", {}'.format( format_log_message(msg_data))) diff --git a/auditing/tests.py b/auditing/tests.py index 6521531..0b8bc3e 100644 --- a/auditing/tests.py +++ b/auditing/tests.py @@ -159,21 +159,6 @@ def test_ignored_fields(self): self.assertNotIn('"password1":', out) self.assertNotIn('"password2":', out) - @override_settings(AUDIT_USERNAME_FIELD='email') - def test_message_custom_user_field(self): - req = self._post(data={ - "email": "user@example.com", - "password": "secret", - }) - - with self.assertLogs('auditing', level='INFO') as cm: - login_logger( - self.mock_sender, - user=MockUser(username='user@example.com'), - request=req) - - self.assertIn('"username": "user@example.com"', cm.output[0]) - class LoginFailedLoggerReceiverTestCase(SignalsBaseTestCase): @@ -218,7 +203,7 @@ def test_ignored_fields(self): self.assertNotIn('"password1": ', out) self.assertNotIn('"password2": ', out) - @override_settings(AUDIT_USERNAME_FIELD='email') + @override_settings(AUDIT_USERNAME_FIELDS=['email']) def test_message_custom_user_field(self): req = self._post(data={ "email": "user@example.com", @@ -233,6 +218,38 @@ def test_message_custom_user_field(self): self.assertIn('"username": "wrong"', cm.output[0]) + @override_settings(AUDIT_USERNAME_FIELDS=['email', 'username']) + def test_message_fallback_user_field(self): + req = self._post(data={ + "username": "tester", + "password": "secret", + }) + + with self.assertLogs('auditing', level='INFO') as cm: + login_failed_logger( + self.mock_sender, + credentials={'username': 'wrong', 'password': '************'}, + request=req) + + self.assertIn('"username": "wrong"', cm.output[0]) + + @override_settings(AUDIT_USERNAME_FIELDS=['email']) + def test_user_field_not_found_raises_error(self): + req = self._post(data={ + "username": "tester", + "password": "secret", + }) + + with self.assertRaises(KeyError) as err: + login_failed_logger( + self.mock_sender, + credentials={'username': 'wrong', 'password': '************'}, + request=req) + + self.assertEqual( + "'Valid username not found in credentials.'", + str(err.exception)) + class LogoutLoggerReceiverTestCase(SignalsBaseTestCase): @@ -282,21 +299,6 @@ def test_ignored_fields(self): self.assertNotIn('"password1":', out) self.assertNotIn('"password2":', out) - @override_settings(AUDIT_USERNAME_FIELD='email') - def test_message_custom_user_field(self): - req = self._post(data={ - "email": "user@example.com", - "password": "secret", - }) - - with self.assertLogs('auditing', level='INFO') as cm: - logout_logger( - self.mock_sender, - user=MockUser('user@example.com'), - request=req) - - self.assertIn('"username": "user@example.com"', cm.output[0]) - class HTTPHeadersLoggingMiddlewareTestCase(TestCase):