Repository: privacyidea/privacyidea

Issue:
Audit log does take administrative realms into account
The policy ``auditlog`` in scope admin does not honor the administrative realms.

https://github.com/privacyidea/privacyidea/blob/4b8832dfa99d54d8c790cc3b682f08d9c23388fd/privacyidea/api/lib/prepolicy.py#L1313


Discussion:

Resolving patch:
diff --git a/privacyidea/api/lib/prepolicy.py b/privacyidea/api/lib/prepolicy.py
--- a/privacyidea/api/lib/prepolicy.py
+++ b/privacyidea/api/lib/prepolicy.py
@@ -1301,6 +1301,7 @@ def allowed_audit_realm(request=None, action=None):
         action=ACTION.AUDIT,
         scope=SCOPE.ADMIN,
         user=admin_user.get("username"),
+        adminrealm=admin_user.get("realm"),
         client=g.client_ip,
         active=True)
 


Test patch:
diff --git a/tests/test_api_audit.py b/tests/test_api_audit.py
--- a/tests/test_api_audit.py
+++ b/tests/test_api_audit.py
@@ -5,6 +5,8 @@
 import datetime
 from dateutil.parser import parse as parse_time_string
 from dateutil.tz import tzlocal
+from privacyidea.lib.resolver import save_resolver
+from privacyidea.lib.realm import set_realm
 
 PWFILE = "tests/testdata/passwords"
 POLICYFILE = "tests/testdata/policy.cfg"
@@ -68,7 +70,6 @@ def test_01_get_statistics(self):
             d = parse_time_string(json_response.get("result").get("value").get("time_end"))
             self.assertEqual(d, end)
 
-
     def test_02_get_allowed_audit_realm(self):
         # Check that an administrator is only allowed to see log entries of
         # the defined realms.
@@ -91,17 +92,17 @@ def test_02_get_allowed_audit_realm(self):
             self.assertEqual(json_response.get("result").get("value").get(
                 "count"), 2)
 
-            with self.app.test_request_context('/audit/',
-                                               method='GET',
-                                               data={"realm": "realm2B"},
-                                               headers={
-                                                   'Authorization': self.at}):
-                res = self.app.full_dispatch_request()
-                self.assertTrue(res.status_code == 200, res)
-                json_response = json.loads(res.data)
-                self.assertTrue(json_response.get("result").get("status"), res)
-                self.assertEqual(json_response.get("result").get("value").get(
-                    "count"), 3)
+        with self.app.test_request_context('/audit/',
+                                           method='GET',
+                                           data={"realm": "realm2B"},
+                                           headers={
+                                               'Authorization': self.at}):
+            res = self.app.full_dispatch_request()
+            self.assertTrue(res.status_code == 200, res)
+            json_response = json.loads(res.data)
+            self.assertTrue(json_response.get("result").get("status"), res)
+            self.assertEqual(json_response.get("result").get("value").get(
+                "count"), 3)
 
         # set policy for audit realms
         set_policy("audit01", scope=SCOPE.ADMIN, action=ACTION.AUDIT,
@@ -122,12 +123,99 @@ def test_02_get_allowed_audit_realm(self):
         # delete policy
         delete_policy("audit01")
 
+    def test_03_get_allowed_audit_realm(self):
+        # Check than an internal admin is allowed to see all realms
+        # A helpdesk user in "adminrealm" is only allowerd to see realm1A
+        Audit(action="enroll", success=1, realm="realm1A").save()
+        Audit(action="enroll", success=1, realm="realm1A").save()
+        Audit(action="enroll", success=1, realm="realm2B").save()
+        Audit(action="enroll", success=1, realm="realm2B").save()
+        Audit(action="enroll", success=1, realm="realm2B").save()
+
+        # check, that we see all audit entries
+        with self.app.test_request_context('/audit/',
+                                           method='GET',
+                                           data={"realm": "realm1A"},
+                                           headers={'Authorization': self.at}):
+            res = self.app.full_dispatch_request()
+            self.assertTrue(res.status_code == 200, res)
+            json_response = json.loads(res.data)
+            self.assertTrue(json_response.get("result").get("status"), res)
+            self.assertEqual(json_response.get("result").get("value").get(
+                "count"), 5)
+
+        with self.app.test_request_context('/audit/',
+                                           method='GET',
+                                           data={"realm": "realm2B"},
+                                           headers={
+                                               'Authorization': self.at}):
+            res = self.app.full_dispatch_request()
+            self.assertTrue(res.status_code == 200, res)
+            json_response = json.loads(res.data)
+            self.assertTrue(json_response.get("result").get("status"), res)
+            self.assertEqual(json_response.get("result").get("value").get(
+                "count"), 7)
+
+        # set policy: helpdesk users in adminrealm are only allowed to
+        # view "realm1A".
+        set_policy("audit01", scope=SCOPE.ADMIN, action=ACTION.AUDIT,
+                   adminrealm="adminrealm", realm="realm1A")
+        # Test admin is allowed to view unrestricted logs!
+        set_policy("audit02", scope=SCOPE.ADMIN, action=ACTION.AUDIT,
+                   user="testadmin")
+
+        rid = save_resolver({"resolver": self.resolvername1,
+                             "type": "passwdresolver",
+                             "fileName": PWFILE})
+        self.assertTrue(rid > 0, rid)
+
+        (added, failed) = set_realm("adminrealm",
+                                    [self.resolvername1])
+        self.assertTrue(len(failed) == 0)
+        self.assertTrue(len(added) == 1)
+
+        helpdesk_authorization = None
+        with self.app.test_request_context('/auth',
+                                           method='POST', data={'username': 'selfservice@adminrealm',
+                                                                'password': 'test'}):
+            res = self.app.full_dispatch_request()
+            self.assertTrue(res.status_code == 200, res)
+            json_response = json.loads(res.data)
+            value = json_response.get("result").get("value")
+            # Helpdesk user is allowed to view the audit log.
+            self.assertTrue("auditlog" in value.get("rights"))
+            helpdesk_authorization = value.get("token")
+
+        # check, that we only see allowed audit realms
+        with self.app.test_request_context('/audit/',
+                                           method='GET',
+                                           headers={'Authorization': helpdesk_authorization}):
+            res = self.app.full_dispatch_request()
+            self.assertTrue(res.status_code == 200, res)
+            json_response = json.loads(res.data)
+            self.assertTrue(json_response.get("result").get("status"), res)
+            # We now have 3 entries, as we added one by the search in line #43
+            count = json_response.get("result").get("value").get("count")
+            auditdata = json_response.get("result").get("value").get("auditdata")
+            self.assertEqual(count, 6)
+            # All entries are in realm1A!
+            for ad  in auditdata:
+                self.assertEqual(ad.get("realm"), "realm1A")
+
+        # Now check, that the testadmin (self.at) see all entries!
+        with self.app.test_request_context('/audit/',
+                                           method='GET',
+                                           headers={'Authorization': self.at}):
+            res = self.app.full_dispatch_request()
+            self.assertTrue(res.status_code == 200, res)
+            json_response = json.loads(res.data)
+            self.assertTrue(json_response.get("result").get("status"), res)
+            # We now have 3 entries, as we added one by the search in line #43
+            count = json_response.get("result").get("value").get("count")
+            auditdata = json_response.get("result").get("value").get("auditdata")
+            self.assertEqual(count, 25)
+
+        # delete policy
+        delete_policy("audit01")
+        delete_policy("audit02")
 
-    #def test_01_download_audit(self):
-    #    with self.app.test_request_context('/audit/auditfile.csv',
-    #                                       method='GET',
-    #                                       headers={'Authorization': self.at}):
-    #        res = self.app.full_dispatch_request()
-    #        self.assertTrue(res.status_code == 200, res)
-    #        self.assertTrue(res.mimetype == "text/csv", res.mimetype)
-    #        self.assertTrue(res.stream)