Repository: privacyidea/privacyidea

Issue:
2303/user obj in auth
@laclaro, please review this pull request, since you orginally posted the issue.
I added exactly the test case of a user with now token, who gets a token enrolled by a pre-event handler when logging in against /auth.


Discussion:
# [Codecov](https://codecov.io/gh/privacyidea/privacyidea/pull/2346?src=pr&el=h1) Report
> Merging [#2346](https://codecov.io/gh/privacyidea/privacyidea/pull/2346?src=pr&el=desc) into [master](https://codecov.io/gh/privacyidea/privacyidea/commit/a9f3f8d7cc25a68ad39af961e03cf135bac7edf7?el=desc) will **increase** coverage by `0.00%`.
> The diff coverage is `100.00%`.

[![Impacted file tree graph](https://codecov.io/gh/privacyidea/privacyidea/pull/2346/graphs/tree.svg?width=650&height=150&src=pr&token=7nHLZki60B)](https://codecov.io/gh/privacyidea/privacyidea/pull/2346?src=pr&el=tree)

```diff
@@           Coverage Diff           @@
##           master    #2346   +/-   ##
=======================================
  Coverage   96.57%   96.57%           
=======================================
  Files         160      160           
  Lines       20615    20605   -10     
=======================================
- Hits        19909    19900    -9     
+ Misses        706      705    -1     
```


| [Impacted Files](https://codecov.io/gh/privacyidea/privacyidea/pull/2346?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [privacyidea/lib/tokens/webauthn.py](https://codecov.io/gh/privacyidea/privacyidea/pull/2346/diff?src=pr&el=tree#diff-cHJpdmFjeWlkZWEvbGliL3Rva2Vucy93ZWJhdXRobi5weQ==) | `69.71% <ø> (-0.06%)` | :arrow_down: |
| [privacyidea/api/auth.py](https://codecov.io/gh/privacyidea/privacyidea/pull/2346/diff?src=pr&el=tree#diff-cHJpdmFjeWlkZWEvYXBpL2F1dGgucHk=) | `97.20% <100.00%> (+0.16%)` | :arrow_up: |
| [privacyidea/lib/challengeresponsedecorators.py](https://codecov.io/gh/privacyidea/privacyidea/pull/2346/diff?src=pr&el=tree#diff-cHJpdmFjeWlkZWEvbGliL2NoYWxsZW5nZXJlc3BvbnNlZGVjb3JhdG9ycy5weQ==) | `100.00% <100.00%> (+1.17%)` | :arrow_up: |
| [privacyidea/lib/tokens/webauthntoken.py](https://codecov.io/gh/privacyidea/privacyidea/pull/2346/diff?src=pr&el=tree#diff-cHJpdmFjeWlkZWEvbGliL3Rva2Vucy93ZWJhdXRobnRva2VuLnB5) | `92.13% <100.00%> (ø)` | |

------

[Continue to review full report at Codecov](https://codecov.io/gh/privacyidea/privacyidea/pull/2346?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/privacyidea/privacyidea/pull/2346?src=pr&el=footer). Last update [bd9f54f...2fc1137](https://codecov.io/gh/privacyidea/privacyidea/pull/2346?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).


Resolving patch:
diff --git a/privacyidea/lib/challengeresponsedecorators.py b/privacyidea/lib/challengeresponsedecorators.py
--- a/privacyidea/lib/challengeresponsedecorators.py
+++ b/privacyidea/lib/challengeresponsedecorators.py
@@ -62,7 +62,9 @@ def _create_pin_reset_challenge(token_obj, message, challenge_data=None):
                                       "serial": token_obj.token.serial,
                                       "type": token_obj.token.tokentype}]
     reply_dict["message"] = message
+    reply_dict["messages"] = [message]
     reply_dict["transaction_id"] = db_challenge.transaction_id
+    # TODO: This line is deprecated: Add the information for the old administrative triggerchallenge
     reply_dict["transaction_ids"] = [db_challenge.transaction_id]
 
     return reply_dict


Test patch:
diff --git a/tests/test_api_validate.py b/tests/test_api_validate.py
--- a/tests/test_api_validate.py
+++ b/tests/test_api_validate.py
@@ -3027,6 +3027,45 @@ def test_01_pin_change_via_validate_single_shot(self):
         delete_policy("via_validate")
         delete_policy("hotp_chalresp")
 
+    def test_02_challenge_text_header(self):
+        # Test PIN change after authentication with a single shot authentication
+        # Create policy change pin on first use
+        set_policy("first_use", scope=SCOPE.ENROLL, action=ACTION.CHANGE_PIN_FIRST_USE)
+        set_policy("via_validate", scope=SCOPE.AUTH, action=ACTION.CHANGE_PIN_VIA_VALIDATE)
+        set_policy("hotp_chalresp", scope=SCOPE.AUTH, action="{0!s}=hotp".format(ACTION.CHALLENGERESPONSE))
+        challenge_header = "Choose one: <ul>"
+        set_policy("challenge_header", scope=SCOPE.AUTH,
+                   action="{0!s}={1!s}".format(ACTION.CHALLENGETEXT_HEADER, challenge_header))
+
+        with self.app.test_request_context('/token/init', method='POST',
+                                           data={"user": "cornelius", "pin": "test",
+                                                 "serial": self.serial, "otpkey": self.otpkey},
+                                           headers={"Authorization": self.at}):
+            res = self.app.full_dispatch_request()
+            self.assertEqual(res.status_code, 200)
+            result = res.json['result']
+            self.assertTrue(result.get("value"))
+
+        # 1st authentication creates a PIN change challenge via challenge response
+        with self.app.test_request_context('/validate/check', method='POST',
+                                           data={"user": "cornelius",
+                                                 "pass": "test{0!s}".format(self.valid_otp_values[1])}):
+            res = self.app.full_dispatch_request()
+            self.assertEqual(res.status_code, 200)
+            result = res.json['result']
+            self.assertFalse(result.get("value"))
+            details = res.json['detail']
+            transaction_id = details.get("transaction_id")
+            # check that the challenge header is contained in the message
+            self.assertEqual("{0!s}<li>Please enter a new PIN</li>\n".format(challenge_header),
+                             details.get("message"))
+
+        remove_token(self.serial)
+        delete_policy("first_use")
+        delete_policy("via_validate")
+        delete_policy("hotp_chalresp")
+        delete_policy("challenge_header")
+
 
 class AChallengeResponse(MyApiTestCase):