privacyidea / privacyidea

:closed_lock_with_key: multi factor authentication system (2FA, MFA, OTP Server)
http://www.privacyidea.org
GNU Affero General Public License v3.0
1.45k stars 314 forks source link

rollover does not work with tokens which are in clientwait state #2763

Closed laclaro closed 2 years ago

laclaro commented 3 years ago

A token rollover is an token/init request using the serial of an existing token.

In case of a token with tokeninfo "clientwait", this will fail with "ERR905: 2stepinit is only to be used in the first initialization step."

This affects hotp, totp and push tokens.

cornelinux commented 3 years ago

This is probably due to the tokeninfo, that contains the information that the token is in the 2nd enrollment step. This info is not deleted/removed after the token is enrolled.

So before rolling over such a token, this tokeninfo has to be deleted.

cornelinux commented 3 years ago

Hm, I was actually able to rollover an HOTP token with 2step enrollment (via "allow", did not test "force", yet). It also makes sense to me. Since while investigating for #2784 I saw in the code and checked in the database, that the rollout_state is reset after the token is successfully enrolled. So I am not sure, what the problem actually is.

@laclaro can you please explain, what you are trying to do here? (Or course you can not rollover a token, where the 2step enrollment was not finished in the first place, since the rollover starts at the beginning of the enrollment process. It is not ment to finalize an interrupted rollout process - also see #2158 - we currently do not allow/support pending enrollments).

cornelinux commented 2 years ago

I think what we might try to do here is, to rollover a token that is actually in "client_wait", since it was not readily enrolled.

Like: The user forgot to enter the client component and now has a not-working token. Thus the user goes to "rollover" to reenroll the token. This would actually be a scenario, which also makes sense.

In tokenclass.py in line 545 we have the check

        if twostep_init:
            if self.token.rollout_state == ROLLOUTSTATE.CLIENTWAIT:
                # We do not do 2stepinit in the second step
                raise ParameterError("2stepinit is only to be used in the "
                                     "first initialization step.")

that acts as a failsafe to avoid running the first 2step step two times.

We could either

Add a parameter "rollover=1"

By adding such a parameter we can signal a 2step token, that it is ok, to do 2stepinit altouth the token is in rolloutstate "clientwait".

    rollover = getParam(param, "rollover", optional)
    if twostep_init:
        if self.token.rollout_state == ROLLOUTSTATE.CLIENTWAIT and not rollver:
            # Only raise the exception, if we do NOT do rollover

In the tokenEnrollControler in the UI we need to add the rollover parameter when the "rollover"-button is pressed.