Repository: jazzband/django-axes
Pull request #783 (2021-09-02 12:57:51)

feat(helpers): update get_client_str to accept request object
Relating to this feature request: https://github.com/jazzband/django-axes/issues/782


Patch:
diff --git a/axes/handlers/cache.py b/axes/handlers/cache.py
index 1769a4a..e1f21ef 100644
--- a/axes/handlers/cache.py
+++ b/axes/handlers/cache.py
@@ -91,6 +91,7 @@ class AxesCacheHandler(AbstractAxesHandler, AxesBaseHandler):
             request.axes_ip_address,
             request.axes_user_agent,
             request.axes_path_info,
+            request,
         )
 
         if self.is_whitelisted(request, credentials):
@@ -148,6 +149,7 @@ class AxesCacheHandler(AbstractAxesHandler, AxesBaseHandler):
             request.axes_ip_address,
             request.axes_user_agent,
             request.axes_path_info,
+            request,
         )
 
         log.info("AXES: Successful login by %s.", client_str)
@@ -170,6 +172,7 @@ class AxesCacheHandler(AbstractAxesHandler, AxesBaseHandler):
             request.axes_ip_address,
             request.axes_user_agent,
             request.axes_path_info,
+            request,
         )
 
         log.info("AXES: Successful logout by %s.", client_str)
diff --git a/axes/handlers/database.py b/axes/handlers/database.py
index caec843..aa01c00 100644
--- a/axes/handlers/database.py
+++ b/axes/handlers/database.py
@@ -106,6 +106,7 @@ class AxesDatabaseHandler(AbstractAxesHandler, AxesBaseHandler):
             request.axes_ip_address,
             request.axes_user_agent,
             request.axes_path_info,
+            request,
         )
 
         # This replaces null byte chars that crash saving failures.
@@ -202,6 +203,7 @@ class AxesDatabaseHandler(AbstractAxesHandler, AxesBaseHandler):
             request.axes_ip_address,
             request.axes_user_agent,
             request.axes_path_info,
+            request,
         )
 
         log.info("AXES: Successful login by %s.", client_str)
@@ -242,6 +244,7 @@ class AxesDatabaseHandler(AbstractAxesHandler, AxesBaseHandler):
             request.axes_ip_address,
             request.axes_user_agent,
             request.axes_path_info,
+            request,
         )
 
         log.info("AXES: Successful logout by %s.", client_str)
diff --git a/axes/helpers.py b/axes/helpers.py
index 4fa0154..9c31310 100644
--- a/axes/helpers.py
+++ b/axes/helpers.py
@@ -241,7 +241,11 @@ def get_client_cache_key(
 
 
 def get_client_str(
-    username: str, ip_address: str, user_agent: str, path_info: str
+    username: str,
+    ip_address: str,
+    user_agent: str,
+    path_info: str,
+    request: HttpRequest,
 ) -> str:
     """
     Get a readable string that can be used in e.g. logging to distinguish client requests.
@@ -255,11 +259,11 @@ def get_client_str(
 
         if callable(settings.AXES_CLIENT_STR_CALLABLE):
             return settings.AXES_CLIENT_STR_CALLABLE(
-                username, ip_address, user_agent, path_info
+                username, ip_address, user_agent, path_info, request
             )
         if isinstance(settings.AXES_CLIENT_STR_CALLABLE, str):
             return import_string(settings.AXES_CLIENT_STR_CALLABLE)(
-                username, ip_address, user_agent, path_info
+                username, ip_address, user_agent, path_info, request
             )
         raise TypeError(
             "settings.AXES_CLIENT_STR_CALLABLE needs to be a string, callable or None."


Test patch:
diff --git a/tests/test_handlers.py b/tests/test_handlers.py
index b2f557d..d797c9d 100644
--- a/tests/test_handlers.py
+++ b/tests/test_handlers.py
@@ -120,7 +120,11 @@ class AxesHandlerBaseTestCase(AxesTestCase):
                 sender=None, request=self.request, credentials=self.credentials
             )
             client_str = get_client_str(
-                self.username, self.ip_address, self.user_agent, self.path_info
+                self.username,
+                self.ip_address,
+                self.user_agent,
+                self.path_info,
+                self.request,
             )
             log.info.assert_called_with(
                 "AXES: Login failed from whitelisted client %s.", client_str
@@ -135,7 +139,7 @@ class AxesHandlerBaseTestCase(AxesTestCase):
 
 @override_settings(AXES_HANDLER="axes.handlers.database.AxesDatabaseHandler")
 class ResetAttemptsTestCase(AxesHandlerBaseTestCase):
-    """ Resetting attempts is currently implemented only for database handler """
+    """Resetting attempts is currently implemented only for database handler"""
 
     USERNAME_1 = "foo_username"
     USERNAME_2 = "bar_username"
@@ -340,7 +344,7 @@ class AxesDatabaseHandlerTestCase(AxesHandlerBaseTestCase):
 
 @override_settings(AXES_HANDLER="axes.handlers.cache.AxesCacheHandler")
 class ResetAttemptsCacheHandlerTestCase(AxesHandlerBaseTestCase):
-    """ Test reset attempts for the cache handler """
+    """Test reset attempts for the cache handler"""
 
     USERNAME_1 = "foo_username"
     USERNAME_2 = "bar_username"
diff --git a/tests/test_helpers.py b/tests/test_helpers.py
index ffac679..05b4c0f 100644
--- a/tests/test_helpers.py
+++ b/tests/test_helpers.py
@@ -95,9 +95,11 @@ class ClientStringTestCase(AxesTestCase):
         path_info = "/admin/"
 
         expected = self.get_expected_client_str(
-            username, ip_address, user_agent, path_info
+            username, ip_address, user_agent, path_info, self.request
+        )
+        actual = get_client_str(
+            username, ip_address, user_agent, path_info, self.request
         )
-        actual = get_client_str(username, ip_address, user_agent, path_info)
 
         self.assertEqual(expected, actual)
 
@@ -109,9 +111,11 @@ class ClientStringTestCase(AxesTestCase):
         path_info = "/admin/"
 
         expected = self.get_expected_client_str(
-            username, ip_address, user_agent, path_info
+            username, ip_address, user_agent, path_info, self.request
+        )
+        actual = get_client_str(
+            username, ip_address, user_agent, path_info, self.request
         )
-        actual = get_client_str(username, ip_address, user_agent, path_info)
 
         self.assertEqual(expected, actual)
 
@@ -123,9 +127,11 @@ class ClientStringTestCase(AxesTestCase):
         path_info = ("admin", "login")
 
         expected = self.get_expected_client_str(
-            username, ip_address, user_agent, path_info[0]
+            username, ip_address, user_agent, path_info[0], self.request
+        )
+        actual = get_client_str(
+            username, ip_address, user_agent, path_info, self.request
         )
-        actual = get_client_str(username, ip_address, user_agent, path_info)
 
         self.assertEqual(expected, actual)
 
@@ -137,7 +143,9 @@ class ClientStringTestCase(AxesTestCase):
         path_info = "/admin/"
 
         expected = '{ip_address: "127.0.0.1", path_info: "/admin/"}'
-        actual = get_client_str(username, ip_address, user_agent, path_info)
+        actual = get_client_str(
+            username, ip_address, user_agent, path_info, self.request
+        )
 
         self.assertEqual(expected, actual)
 
@@ -150,9 +158,11 @@ class ClientStringTestCase(AxesTestCase):
         path_info = "/admin/"
 
         expected = self.get_expected_client_str(
-            username, ip_address, user_agent, path_info
+            username, ip_address, user_agent, path_info, self.request
+        )
+        actual = get_client_str(
+            username, ip_address, user_agent, path_info, self.request
         )
-        actual = get_client_str(username, ip_address, user_agent, path_info)
 
         self.assertEqual(expected, actual)
 
@@ -165,7 +175,9 @@ class ClientStringTestCase(AxesTestCase):
         path_info = "/admin/"
 
         expected = '{username: "test@example.com", path_info: "/admin/"}'
-        actual = get_client_str(username, ip_address, user_agent, path_info)
+        actual = get_client_str(
+            username, ip_address, user_agent, path_info, self.request
+        )
 
         self.assertEqual(expected, actual)
 
@@ -178,9 +190,11 @@ class ClientStringTestCase(AxesTestCase):
         path_info = "/admin/"
 
         expected = self.get_expected_client_str(
-            username, ip_address, user_agent, path_info
+            username, ip_address, user_agent, path_info, self.request
+        )
+        actual = get_client_str(
+            username, ip_address, user_agent, path_info, self.request
         )
-        actual = get_client_str(username, ip_address, user_agent, path_info)
 
         self.assertEqual(expected, actual)
 
@@ -193,7 +207,9 @@ class ClientStringTestCase(AxesTestCase):
         path_info = "/admin/"
 
         expected = '{username: "test@example.com", ip_address: "127.0.0.1", path_info: "/admin/"}'
-        actual = get_client_str(username, ip_address, user_agent, path_info)
+        actual = get_client_str(
+            username, ip_address, user_agent, path_info, self.request
+        )
 
         self.assertEqual(expected, actual)
 
@@ -206,9 +222,11 @@ class ClientStringTestCase(AxesTestCase):
         path_info = "/admin/"
 
         expected = self.get_expected_client_str(
-            username, ip_address, user_agent, path_info
+            username, ip_address, user_agent, path_info, self.request
+        )
+        actual = get_client_str(
+            username, ip_address, user_agent, path_info, self.request
         )
-        actual = get_client_str(username, ip_address, user_agent, path_info)
 
         self.assertEqual(expected, actual)
 
@@ -221,21 +239,46 @@ class ClientStringTestCase(AxesTestCase):
         path_info = "/admin/"
 
         expected = '{ip_address: "127.0.0.1", user_agent: "Googlebot/2.1 (+http://www.googlebot.com/bot.html)", path_info: "/admin/"}'
-        actual = get_client_str(username, ip_address, user_agent, path_info)
+        actual = get_client_str(
+            username, ip_address, user_agent, path_info, self.request
+        )
 
         self.assertEqual(expected, actual)
 
-    @override_settings(AXES_CLIENT_STR_CALLABLE="tests.test_helpers.get_dummy_client_str")
+    @override_settings(
+        AXES_CLIENT_STR_CALLABLE="tests.test_helpers.get_dummy_client_str"
+    )
+    def test_get_client_str_callable(self):
+        self.assertEqual(
+            get_client_str(
+                "username", "ip_address", "user_agent", "path_info", self.request
+            ),
+            "client string",
+        )
+
+    @override_settings(
+        AXES_CLIENT_STR_CALLABLE="tests.test_helpers.get_dummy_client_str_using_request"
+    )
     def test_get_client_str_callable(self):
+        self.request.user = self.user
         self.assertEqual(
-            get_client_str("username", "ip_address", "user_agent", "path_info"),
-            "client string"
+            get_client_str(
+                "username", "ip_address", "user_agent", "path_info", self.request
+            ),
+            self.email,
         )
 
+
 def get_dummy_client_str(username, ip_address, user_agent, path_info):
     return "client string"
 
 
+def get_dummy_client_str_using_request(
+    username, ip_address, user_agent, path_info, request
+):
+    return f"{request.user.email}"
+
+
 class ClientParametersTestCase(AxesTestCase):
     @override_settings(AXES_ONLY_USER_FAILURES=True)
     def test_get_filter_kwargs_user(self):
diff --git a/tests/test_login.py b/tests/test_login.py
index 3903521..bb0468a 100644
--- a/tests/test_login.py
+++ b/tests/test_login.py
@@ -590,7 +590,7 @@ class DatabaseLoginTestCase(AxesTestCase):
     def test_lockout_by_user_or_ip_allows_when_diff_user_same_ip_using_cache_multiple_failed_attempts(
         self,
     ):
-        """ Test, if the failed attempts make also impact on the attempt count """
+        """Test, if the failed attempts make also impact on the attempt count"""
         # User 1 is locked out from IP 1.
         response = self._login(self.USER_1, self.WRONG_PASSWORD, self.IP_1)
         self.assertEqual(response.status_code, self.ATTEMPT_NOT_BLOCKED)