Repository: privacyidea/privacyidea

Issue:
Unable to Enroll Push Token if tokenlabel is configured in policy
# What did you try to do?

Enroll push token for user with **tokenlabel** set to \<u>_\
 within an enrollment policy.   Username is testuser and token serial is PIPU00001234

# What outcome did you expect?

Token enrolled successfully in app.

# What outcome did you experience?

Request was sent to /ttype/push with the serial of testuser_PIPU00001234.  Error message **No token with this serial number in the rollout state 'clientwait'** is logged to audit trail.  App displays a server rollout error.

# Mitigation/Workaround

Changing the policy to be \
 allowed the token to be enrolled successfully.

# Configuration

* privacyIDEA Version: 3.0
* Installation method: ubuntu packages

## more details: 

* OS:  Ubuntu 16.04LTS
* Webserver: Apache
* Tokendatabase: MySql

# Log Sample

```
[2019-04-23 20:41:01,886][privacyidea.api.ttype:185] Entering token with arguments () and keywords {'ttype': u'push'}
[2019-04-23 20:41:01,886][privacyidea.lib.tokens.pushtoken:404] Do the 2nd step of the enrollment.
[2019-04-23 20:41:01,887][privacyidea.lib.token:185] Entering get_tokens with arguments () and keywords {'serial': u'testuser_PIPU00001234', 'rollout_state': 'clientwait', 'tokentype': 'push'}
[2019-04-23 20:41:01,889][privacyidea.lib.token:197] Exiting get_tokens with result []
[2019-04-23 20:41:01,889][privacyidea.lib.auditmodules.base:185] Entering log with arguments ({'info': "No token with this serial number in the rollout state 'clientwait'."}) and keywords {}
[2019-04-23 20:41:01,889][privacyidea.lib.auditmodules.base:197] Exiting log with result None
[2019-04-23 20:41:01,915][privacyidea.api.lib.utils:219] Can not get param: No JSON object could be decoded
[2019-04-23 20:41:01,934][privacyidea.api.lib.utils:219] Can not get param: No JSON object could be decoded
[2019-04-23 20:41:01,937][privacyidea.api.before_after:88] End handling of request u'/ttype/push?'

```


Discussion:
Thanks for the bug report. The error occurs because the enrollment policy modifies the label part of the URL in the QR code to be ``testuser_PIPU00001234``:

```
otpauth://pipush/testuser_PIPU00001234?url=...
```

Then the app uses this label part as the token serial number and sends it back to privacyIDEA during enrollment. But privacyIDEA knows no token with serial number ``testuser_PIPU00001234``, only ``PIPU00001234``, so the above error is raised.

I'm not sure if we need to change the server code, or the app code, or both :) @nilsbehlen @cornelinux any thoughts?
We add an extra parameter "serial", that containes the unchangeable serial number.

The lib/tokens/pushtoken.py will then look like this:

            # this allows to upgrade our crypto
            extra_data["v"] = 1
            extra_data["sslverify"] = sslverify
            extra_data["serial"] = self.get_serial()
            # We display this during the first enrollment step!
            qr_url = create_push_token_url(url=fb_options.get(FIREBASE_CONFIG.REGISTRATION_URL),
                                           user=user.login,
                                           realm=user.realm,
                                           serial=self.get_serial(),
                                           tokenlabel=tokenlabel,
                                           issuer=tokenissuer,
                                           user_obj=user,
                                           extra_data=extra_data,
                                           ttl=fb_options.get(FIREBASE_CONFIG.TTL))

Resolving patch:
diff --git a/privacyidea/lib/tokens/pushtoken.py b/privacyidea/lib/tokens/pushtoken.py
--- a/privacyidea/lib/tokens/pushtoken.py
+++ b/privacyidea/lib/tokens/pushtoken.py
@@ -343,6 +343,7 @@ def get_init_detail(self, params=None, user=None):
                 extra_data[k] = fb_options.get(k)
             # this allows to upgrade our crypto
             extra_data["v"] = 1
+            extra_data["serial"] = self.get_serial()
             extra_data["sslverify"] = sslverify
             # We display this during the first enrollment step!
             qr_url = create_push_token_url(url=fb_options.get(FIREBASE_CONFIG.REGISTRATION_URL),


Test patch:
diff --git a/tests/test_lib_tokens_push.py b/tests/test_lib_tokens_push.py
--- a/tests/test_lib_tokens_push.py
+++ b/tests/test_lib_tokens_push.py
@@ -167,6 +167,8 @@ def test_02_api_enroll(self):
             serial = detail.get("serial")
             self.assertEqual(detail.get("rollout_state"), "clientwait")
             self.assertTrue("pushurl" in detail)
+            # check that the new URL contains the serial number
+            self.assertTrue("&serial=PIPU" in detail.get("pushurl").get("value"))
             self.assertFalse("otpkey" in detail)
             enrollment_credential = detail.get("enrollment_credential")