From 416407fd736f2e8a5e6963c5ec512079ba79c22d Mon Sep 17 00:00:00 2001
From: Feanil Patel <feanil@edx.org>
Date: Thu, 18 Mar 2021 10:31:49 -0400
Subject: [PATCH] fix: Add more info in warning log messages.

If this happens, it's usefule to know what main view code was being
targetd so that we can more easily investigate what might have caused
this issue.

Add a new custom attribute 'safe_sessions.user_mismatch' to find
requests that had this issue in our monitoring system.
---
 .../djangoapps/safe_sessions/middleware.py    | 23 ++++++++++++++-----
 .../safe_sessions/tests/test_middleware.py    |  6 ++---
 .../safe_sessions/tests/test_utils.py         | 18 ++++++++++-----
 3 files changed, 32 insertions(+), 15 deletions(-)

diff --git a/openedx/core/djangoapps/safe_sessions/middleware.py b/openedx/core/djangoapps/safe_sessions/middleware.py
index 612ae6e6f10..ddd21dfb428 100644
--- a/openedx/core/djangoapps/safe_sessions/middleware.py
+++ b/openedx/core/djangoapps/safe_sessions/middleware.py
@@ -54,6 +54,10 @@ to the browser that the cookie should be sent only over an
 SSL-protected channel.  Otherwise, a session hijacker could copy
 the entire cookie and use it to impersonate the victim.
 
+Custom Attributes:
+    safe_sessions.user_mismatch: 'request-response-mismatch' | 'request-session-mismatch'
+        This attribute can be one of the above two values which correspond to the kind of comparison
+        that failed when processing the response. See SafeSessionMiddleware._verify_user
 """
 
 
@@ -72,6 +76,7 @@ from django.http import HttpResponse
 from django.utils.crypto import get_random_string
 from django.utils.deprecation import MiddlewareMixin
 from django.utils.encoding import python_2_unicode_compatible
+from edx_django_utils.monitoring import set_custom_attribute
 
 from six import text_type  # pylint: disable=ungrouped-imports
 
@@ -372,18 +377,24 @@ class SafeSessionMiddleware(SessionMiddleware, MiddlewareMixin):
                 # conditionally set the log level.
                 log_func = log.debug if request.user.id is None else log.warning
                 log_func(
-                    u"SafeCookieData user at request '{0}' does not match user at response: '{1}'".format(
-                        request.safe_cookie_verified_user_id,
-                        request.user.id,
+                    (
+                        "SafeCookieData user at request '{0}' does not match user at response: '{1}' "
+                        "for request path '{2}'"
+                    ).format(
+                        request.safe_cookie_verified_user_id, request.user.id, request.path,
                     ),
                 )
+                set_custom_attribute("safe_sessions.user_mismatch", "request-response-mismatch")
             if request.safe_cookie_verified_user_id != userid_in_session:
                 log.warning(
-                    u"SafeCookieData user at request '{0}' does not match user in session: '{1}'".format(  # pylint: disable=logging-format-interpolation
-                        request.safe_cookie_verified_user_id,
-                        userid_in_session,
+                    (
+                        "SafeCookieData user at request '{0}' does not match user in session: '{1}' "
+                        "for request path '{2}'"
+                    ).format(  # pylint: disable=logging-format-interpolation
+                        request.safe_cookie_verified_user_id, userid_in_session, request.path,
                     ),
                 )
+                set_custom_attribute("safe_sessions.user_mismatch", "request-session-mismatch")
 
     @staticmethod
     def get_user_id_from_session(request):
diff --git a/openedx/core/djangoapps/safe_sessions/tests/test_middleware.py b/openedx/core/djangoapps/safe_sessions/tests/test_middleware.py
index 1dd19e85f23..f24259246ee 100644
--- a/openedx/core/djangoapps/safe_sessions/tests/test_middleware.py
+++ b/openedx/core/djangoapps/safe_sessions/tests/test_middleware.py
@@ -185,10 +185,10 @@ class TestSafeSessionProcessResponse(TestSafeSessionsLogMixin, TestCase):
     def test_different_user_at_step_2_error(self):
         self.request.safe_cookie_verified_user_id = "different_user"
 
-        with self.assert_logged_for_request_user_mismatch("different_user", self.user.id, 'warning'):
+        with self.assert_logged_for_request_user_mismatch("different_user", self.user.id, 'warning', self.request.path):
             self.assert_response(set_request_user=True, set_session_cookie=True)
 
-        with self.assert_logged_for_session_user_mismatch("different_user", self.user.id):
+        with self.assert_logged_for_session_user_mismatch("different_user", self.user.id, self.request.path):
             self.assert_response(set_request_user=True, set_session_cookie=True)
 
     def test_anonymous_user(self):
@@ -196,7 +196,7 @@ class TestSafeSessionProcessResponse(TestSafeSessionsLogMixin, TestCase):
         self.request.user = AnonymousUser()
         self.request.session[SESSION_KEY] = self.user.id
         with self.assert_no_error_logged():
-            with self.assert_logged_for_request_user_mismatch(self.user.id, None, 'debug'):
+            with self.assert_logged_for_request_user_mismatch(self.user.id, None, 'debug', self.request.path):
                 self.assert_response(set_request_user=False, set_session_cookie=True)
 
     def test_update_cookie_data_at_step_3(self):
diff --git a/openedx/core/djangoapps/safe_sessions/tests/test_utils.py b/openedx/core/djangoapps/safe_sessions/tests/test_utils.py
index c4c765be708..529c9efe465 100644
--- a/openedx/core/djangoapps/safe_sessions/tests/test_utils.py
+++ b/openedx/core/djangoapps/safe_sessions/tests/test_utils.py
@@ -116,28 +116,34 @@ class TestSafeSessionsLogMixin(object):
             yield
 
     @contextmanager
-    def assert_logged_for_request_user_mismatch(self, user_at_request, user_at_response, log_level):
+    def assert_logged_for_request_user_mismatch(self, user_at_request, user_at_response, log_level, request_path):
         """
         Asserts that warning was logged when request.user
         was not equal to user at response
         """
         with self.assert_logged_with_message(
-            u"SafeCookieData user at request '{}' does not match user at response: '{}'".format(
-                user_at_request, user_at_response
+            (
+                "SafeCookieData user at request '{}' does not match user at response: '{}' "
+                "for request path '{}'"
+            ).format(
+                user_at_request, user_at_response, request_path
             ),
             log_level=log_level,
         ):
             yield
 
     @contextmanager
-    def assert_logged_for_session_user_mismatch(self, user_at_request, user_in_session):
+    def assert_logged_for_session_user_mismatch(self, user_at_request, user_in_session, request_path):
         """
         Asserts that warning was logged when request.user
         was not equal to user at session
         """
         with self.assert_logged_with_message(
-            u"SafeCookieData user at request '{}' does not match user in session: '{}'".format(
-                user_at_request, user_in_session
+            (
+                "SafeCookieData user at request '{}' does not match user in session: '{}' "
+                "for request path '{}'"
+            ).format(
+                user_at_request, user_in_session, request_path
             ),
             log_level='warning',
         ):
-- 
GitLab