Repository: privacyidea/privacyidea

Issue:
adding client_mode to pin reset
By the server response with a prompt for a new PIN, token type is still `webauthn`. That forces us to adjust the code to avoid triggering webauthn tokens if there is no sign request.

Maybe this can be a good idea:
if the server has an unordinary challenge for a specific token, type changes to: e.g. `newPIN`.

That seems more useful because only one thing that is telling us what the server expects is the message, which can differ by the language.

-- edit be @jonna-samuel --

we just added the missing client_mode to pin reset. For more information: https://github.com/privacyidea/privacyidea/issues/3261#issuecomment-1471974091

**Old Idea**

We have the problem that the PIN_reset challenges only can be identified by the massage and this massage can be in different languages.

The solution I wot suggest is to add an extra dictionary entry with the challenge_type. The challenge_type wot be 'None' for a normal challenge and for PIN_reset challenge it wot be 'pi_reset'

for example
a 'normal' challenge:
~~~python~~~
"multi_challenge": [
   {
      "client_mode": "interactive",
      "message": "Bitte geben Sie einen OTP-Wert ein: ",
      "serial": "TOTP00129442",
      "challenge_type": "generic_challenge", 
      "transaction_id": "01294272308714424797",
      "type": "totp"
   },
~~~

a pin_reset challenge:
~~~python~~~
"multi_challenge": [
   {
      "attributes": "null",
      "message": "Vergeben Sie bitter eine neuen PIN ",
      "serial": "WAN0005544C",
      "challenge_type": "generic_pin_reset", 
      "transaction_id": "09816253255958777777",
      "type": "webauthn"
   },
~~~
**Top-level requirements and scenarios**

It is necessary to add the challenge_type to the multi_challeng in the reply.
- [x] getting the challenge_type in the reply
- [x] test that it’s the correct challenge_type

**Implementation**
- add the new entry to the multi_challenge in the reply_dict
- test that it has the correct entry
- test that it does not break old tests



Discussion:
Thank you for filing an issue and sharing your observations or ideas. Please be sure to provide as many information as possible to help us working on this issue.
![grafik](https://user-images.githubusercontent.com/77617779/183588100-db2712eb-80e7-44e4-b5f3-7d9b7977a7d6.png)

OK, in such a case we could remove the tokentype, or move the "type" so s.th. like "old_type", and -- as you said -- fill the "type" with s.th. other (None).
Another way could be, that we allow including the challenge_type to the challenge.
After looking at it closer we just need to set the client mode to "interactive" in the second step.
This must be added to the returned multi-challenge dictionary here:
https://github.com/privacyidea/privacyidea/blob/28f138522618915950769a0fe196720f3b417393/privacyidea/lib/challengeresponsedecorators.py#L62
since all other challenges are dismissed in case of a challenge-response decorator.
The Plug-In must not use the token type to "guess" the current flow.

Resolving patch:
diff --git a/privacyidea/lib/challengeresponsedecorators.py b/privacyidea/lib/challengeresponsedecorators.py
--- a/privacyidea/lib/challengeresponsedecorators.py
+++ b/privacyidea/lib/challengeresponsedecorators.py
@@ -35,6 +35,7 @@
 from privacyidea.models import Challenge
 from privacyidea.lib.challenge import get_challenges
 from privacyidea.lib import _
+from privacyidea.lib.tokenclass import CLIENTMODE
 
 
 log = logging.getLogger(__name__)
@@ -60,6 +61,7 @@ def _create_challenge(token_obj, challenge_type, message, challenge_data=None):
     token_obj.challenge_janitor()
     reply_dict = {}
     reply_dict["multi_challenge"] = [{"transaction_id": db_challenge.transaction_id,
+                                      "client_mode": CLIENTMODE.INTERACTIVE,
                                       "message": message,
                                       "attributes": None,
                                       "serial": token_obj.token.serial,


Test patch:
diff --git a/tests/test_lib_token.py b/tests/test_lib_token.py
--- a/tests/test_lib_token.py
+++ b/tests/test_lib_token.py
@@ -1935,6 +1935,7 @@ def test_01_successfully_change_pin(self):
         self.assertFalse(r)
         self.assertEqual("Please enter a new PIN", reply_dict.get("message"))
         transaction_id = reply_dict.get("transaction_id")
+        self.assertEqual("interactive", reply_dict.get('multi_challenge')[0].get('client_mode'))
 
         # Now send a new PIN
         newpin = "test2"