Repository: privacyidea/privacyidea

Issue:
Add transaction_id to GET token/challenges
Certain tokens (like Push, or maybe tiqr) work better, when a service account can fetch the challenges to verify, if the response was answered correctly.

Thus we should add a parameter ``transaction_id`` to the API endpoint.


Discussion:

Resolving patch:
diff --git a/privacyidea/api/token.py b/privacyidea/api/token.py
--- a/privacyidea/api/token.py
+++ b/privacyidea/api/token.py
@@ -307,6 +307,8 @@ def get_challenges_api(serial=None):
     :query sortdir: asc/desc
     :query page: request a certain page
     :query pagesize: limit the number of returned tokens
+    :query transaction_id: only returns challenges for this
+        transaction_id. This is useful when working with push or tiqr tokens.
     :return: json
     """
     param = request.all_data
@@ -314,8 +316,10 @@ def get_challenges_api(serial=None):
     sort = getParam(param, "sortby", optional, default="timestamp")
     sdir = getParam(param, "sortdir", optional, default="asc")
     psize = int(getParam(param, "pagesize", optional, default=15))
+    transaction_id = getParam(param, "transaction_id", optional)
     g.audit_object.log({"serial": serial})
     challenges = get_challenges_paginate(serial=serial, sortby=sort,
+                                         transaction_id=transaction_id,
                                          sortdir=sdir, page=page, psize=psize)
     g.audit_object.log({"success": True})
     return send_result(challenges)


Test patch:
diff --git a/tests/test_api_token.py b/tests/test_api_token.py
--- a/tests/test_api_token.py
+++ b/tests/test_api_token.py
@@ -1188,6 +1188,36 @@ def test_19_get_challenges(self):
             value = result.get("value")
             self.assertEqual(value.get("count"), 0)
 
+        # create a second challenge and a third cahllenge
+        r = check_serial_pass(serial, "pin")
+        r = check_serial_pass(serial, "pin")
+        transaction_ids = []
+        with self.app.test_request_context('/token/challenges/',
+                                           method='GET',
+                                           headers={'Authorization': self.at}):
+            res = self.app.full_dispatch_request()
+            self.assertTrue(res.status_code == 200, res)
+            result = json.loads(res.data.decode('utf8')).get("result")
+            value = result.get("value")
+            self.assertEqual(value.get("count"), 3)
+            challenges = value.get("challenges")
+            for challenge in challenges:
+                # Fill the list of all transaction_ids
+                transaction_ids.append(challenge.get("transaction_id"))
+
+        # Now we only ask for the first transation id. This should return only ONE challenge
+        with self.app.test_request_context('/token/challenges/',
+                                            data={"transaction_id": transaction_ids[0]},
+                                            method='GET',
+                                            headers={'Authorization': self.at}):
+            res = self.app.full_dispatch_request()
+            self.assertTrue(res.status_code == 200, res)
+            result = json.loads(res.data.decode('utf8')).get("result")
+            value = result.get("value")
+            self.assertEqual(value.get("count"), 1)
+            challenges = value.get("challenges")
+            self.assertEqual(challenges[0].get("transaction_id"), transaction_ids[0])
+
         delete_policy("chalresp")
 
     def test_20_init_yubikey(self):