Search code examples
asp.net-coreasp.net-identity

ASP.NET Identity - forcing the Normalized Email & Username to lower case


This is really weird.

I call the following (in a unit test hence the calling async methods as sync):

    var identityUser = new IdentityUser(email)
    {
        Email = email,
        PhoneNumber = phone
    };
    identityUser.NormalizedEmail = identityUser.Email.Normalize().ToUpperInvariant();
    identityUser.NormalizedUserName = identityUser.UserName?.Normalize().ToUpperInvariant();
    // activate user
    identityUser.EmailConfirmed = true;
    identityUser.PhoneNumberConfirmed = true;
    identityUser.LockoutEnabled = false;

    var result = _store.SetUserNameAsync(identityUser, identityUser.Email, CancellationToken.None);
    result.Wait();
    if (!result.IsCompletedSuccessfully)
        throw new Exception($"Failed to create username {identityUser.UserName}: {result.Exception?.Message}");
    var identityCreateResult = _userManager.CreateAsync(identityUser, password).Result;
    if (!identityCreateResult.Succeeded)
        throw new Exception($"Failed to create user {identityUser.UserName}: {identityCreateResult.Errors.First().Description}");

And on exit from _userManager.CreateAsync(identityUser, password) the NormalizedEmail and NormalizedUserName in identityUser are now lowercase. And in the database they are lower case.

Ok, so I then "fix" it with the following:

    identityUser = identityContext.Users.First(x => x.Id == identityUser.Id);
    identityUser.NormalizedEmail = identityUser.Email.ToUpperInvariant();
    identityUser.NormalizedUserName = identityUser.UserName?.ToUpperInvariant();
    // activate user
    identityUser.EmailConfirmed = true;
    identityUser.PhoneNumberConfirmed = true;
    identityUser.LockoutEnabled = false;
    identityContext.SaveChanges();

And now the identityUser object and the database has them in upper case until I call the following:

    var claim = new Claim("Manager", "_states");
    _ = _userManager.AddClaimAsync(identityUser, claim).Result;

On exit from _userManager.AddClaimAsync(identityUser, claim).Result both the identityUser object and the database now have them as lower case.

What in the world is going on here? All the documentation says the Normalized properties are the regular property with Normalize().ToUpperInvariant() applied to them. This makes no sense.


Solution

  • Turned out to be a simple fix:

    _userManager.KeyNormalizer = new UpperInvariantLookupNormalizer();
    

    That is set when you access the UserManager in your web app. But when you create a UserManager for unit tests KeyNormalizer is null.