Repository: privacyidea/privacyidea

Issue:
Set `g.logged_in_user` during successful `/auth` request
When an authentication is successful we could set the `g.logged_in_user` to be able to use it in a POST-event handler (See #3676 )


Discussion:
OK, I see that `g.logged_in_user` is only set when the JWT auth token is verified successfully:

https://github.com/privacyidea/privacyidea/blob/752a1f95bfc9e052f73ab021483b422a351578ec/privacyidea/api/auth.py#L438

This of course does not occur in the /auth request itself.
The even handler could also check (as a condition) for the JWT, or we add the `g.logged_in_user` to the request object here, when we also create the JWT:

https://github.com/privacyidea/privacyidea/blob/752a1f95bfc9e052f73ab021483b422a351578ec/privacyidea/api/auth.py#L379

~~~~Python
    token = jwt.encode({"username": loginname,
                        "realm": realm,
                        "nonce": nonce,
                        "role": role,
                        "authtype": authtype,
                        "exp": datetime.utcnow() + validity,
                        "rights": rights},
                       secret, algorithm='HS256')
    g.logged_in_user = {"username": loginname, "realm": realm, "role": role}
~~~~

This should be simple, since all data is actually available for the JWT and later it is actually read from the JWT.

I think we can add this one-liner still to 3.9.



Resolving patch:
diff --git a/privacyidea/api/auth.py b/privacyidea/api/auth.py
--- a/privacyidea/api/auth.py
+++ b/privacyidea/api/auth.py
@@ -62,7 +62,7 @@
 from privacyidea.lib.user import User, split_user, log_used_user
 from privacyidea.lib.policy import PolicyClass, REMOTE_USER
 from privacyidea.lib.realm import get_default_realm, realm_is_defined
-from privacyidea.api.lib.postpolicy import (postpolicy, get_webui_settings, add_user_detail_to_response, check_tokentype, 
+from privacyidea.api.lib.postpolicy import (postpolicy, get_webui_settings, add_user_detail_to_response, check_tokentype,
                                             check_tokeninfo, check_serial, no_detail_on_fail, no_detail_on_success,
                                             get_webui_settings)
 from privacyidea.api.lib.prepolicy import (is_remote_user_allowed, prepolicy,
@@ -385,6 +385,11 @@ def get_auth_token():
                         "rights": rights},
                        secret, algorithm='HS256')
 
+    # set the logged-in user for post-policies and post-events
+    g.logged_in_user = {"username": loginname,
+                        "realm": realm,
+                        "role": role}
+
     # Add the role to the response, so that the WebUI can make decisions
     # based on this (only show selfservice, not the admin part)
     return send_result({"token": to_unicode(token),


Test patch:
diff --git a/tests/test_api_auth.py b/tests/test_api_auth.py
--- a/tests/test_api_auth.py
+++ b/tests/test_api_auth.py
@@ -1,5 +1,8 @@
 # -*- coding: utf-8 -*-
 """ Test for the '/auth' API-endpoint """
+import logging
+
+from testfixtures import log_capture
 from .base import MyApiTestCase, OverrideConfigTestCase
 import mock
 from privacyidea.lib.config import set_privacyidea_config, SYSCONF
@@ -789,9 +792,9 @@ def test_01_admin_and_user_same_name(self):
             mock_log.assert_called_with("user uid 1004 failed to authenticate")
 
 
-class PreEventHandlerTest(MyApiTestCase):
+class EventHandlerTest(MyApiTestCase):
 
-    def test_01_setup_eventhandlers(self):
+    def test_01_pre_eventhandlers(self):
         # This test create an HOTP token with C/R with a pre-event handler
         # and the user uses this HOTP token to directly login to /auth
 
@@ -822,7 +825,7 @@ def test_01_setup_eventhandlers(self):
                         options={"tokentype": "hotp", "user": "1",
                                  "additional_params": {
                                      'otpkey': self.otpkey,
-                                     # We need to set gekey=0, otherwise the Tokenhandler will
+                                     # We need to set genkey=0, otherwise the Tokenhandler will
                                      # generate a random otpkey
                                      'genkey': 0}})
         # cleanup tokens
@@ -875,3 +878,28 @@ def test_01_setup_eventhandlers(self):
         delete_policy("crhotp")
         delete_event(eid)
         remove_token(hotptoken.token.serial)
+
+    @log_capture
+    def test_02_post_eventhandler(self, capture):
+        self.setUp_user_realms()
+        # Create an event handler, that creates HOTP token on /auth with default OTP key
+        eid = set_event("post_event_log", event=["auth"], handlermodule="Logging",
+                        action="logging", position="post",
+                        options={"level": logging.INFO,
+                                 "message": "User: {user} Event: {action}"})
+
+        with self.app.test_request_context('/auth',
+                                           method='POST',
+                                           data={"username": "someuser",
+                                                 "password": "test"}):
+            res = self.app.full_dispatch_request()
+            self.assertEqual(200, res.status_code, res)
+            result = res.json.get("result")
+            self.assertTrue(result.get("status"), result)
+
+        capture.check_present(
+            ('pi-eventlogger', 'INFO',
+             'User: someuser Event: /auth')
+        )
+
+        delete_event(eid)