Pourquoi « Invalid Token » lors de la réinitialisation de mot de passe avec ASP.Net Identity ?

Ceci est plus une note à moi-même qu’un article mais il vaut la peine de le partager.

Si vous avez cherché comme moi à comprendre le pourquoi du comment le code généré par ASP.Net Identity (~ le token de sécurité) était invalide lors de la réinitialisation du mot de passe, eh bien sachez que vous n’avez plus à chercher, il s’agit probablement de la même raison que moi.

Le SecurityStamp est NULL dans la base de données !

mais pourquoi tant de haine ?

Tout simplement pour une raison de sécurité certainement et quand on a vu le code on comprend alors pourquoi ça fait du « mercredi ».

public async Task GenerateAsync(string purpose, UserManager<tuser, tkey=""> manager, TUser user)
{
    if (user == null)
    {
        throw new ArgumentNullException("user");
    }
    var ms = new MemoryStream();
    using (var writer = ms.CreateWriter())
    {
        writer.Write(DateTimeOffset.UtcNow);
        writer.Write(Convert.ToString(user.Id, CultureInfo.InvariantCulture));
        writer.Write(purpose ?? "");
        string stamp = null;
        if (manager.SupportsUserSecurityStamp)
        {
            stamp = await manager.GetSecurityStampAsync(user.Id).WithCurrentCulture();
        }
        writer.Write(stamp ?? "");
    }
    var protectedBytes = Protector.Protect(ms.ToArray());
    return Convert.ToBase64String(protectedBytes);
}

OK ET ?

Cela ne vous saute pas aux yeux ? Ce n’est pas grave, je vous explique :-).

En fait, dans la génération du token si votre SecurityStamp en base est NULL alors il est remplacé par rien. Sauf que de l’autre côté quand il s’agit de vérifier, il faut bien comparer ce que l’on a mis dans le token avec ce qui existe sauf que rien == NULL c’est FAUX.

Mais si la raison même de la non-validation du token est au final différente. Elle vient du décodage du token dans le MemoryStream lors du ReadString() qui provoque une erreur.

public async Task ValidateAsync(string purpose, string token, UserManager<tuser, tkey=""> manager, TUser user)
{
    try
    {
        var unprotectedData = Protector.Unprotect(Convert.FromBase64String(token));
        var ms = new MemoryStream(unprotectedData);
        using (var reader = ms.CreateReader())
        {
            var creationTime = reader.ReadDateTimeOffset();
            var expirationTime = creationTime + TokenLifespan;
            if (expirationTime < DateTimeOffset.UtcNow)
            {
                return false;
            }

            var userId = reader.ReadString();
            if (!String.Equals(userId, Convert.ToString(user.Id, CultureInfo.InvariantCulture)))
            {
                return false;
            }
            var purp = reader.ReadString();
            if (!String.Equals(purp, purpose))
            {
                return false;
            }
            var stamp = reader.ReadString();
            if (reader.PeekChar() != -1)
            {
                return false;
            }

            if (manager.SupportsUserSecurityStamp)
            {
                var expectedStamp = await manager.GetSecurityStampAsync(user.Id).WithCurrentCulture();
                return stamp == expectedStamp;
            }
            return stamp == "";
        }
    }
    catch
    {
        // Do not leak exception
    }
    return false;
}

Conclusion

Donc pour conclure, on ne met pas NULL dans le SecurityStamp :-). C’est tout bête mais fallait le savoir.

Publicités
Pourquoi « Invalid Token » lors de la réinitialisation de mot de passe avec ASP.Net Identity ?

Laisser un commentaire

Entrez vos coordonnées ci-dessous ou cliquez sur une icône pour vous connecter:

Logo WordPress.com

Vous commentez à l'aide de votre compte WordPress.com. Déconnexion / Changer )

Image Twitter

Vous commentez à l'aide de votre compte Twitter. Déconnexion / Changer )

Photo Facebook

Vous commentez à l'aide de votre compte Facebook. Déconnexion / Changer )

Photo Google+

Vous commentez à l'aide de votre compte Google+. Déconnexion / Changer )

Connexion à %s