Search code examples
c#asp.net-mvcentity-frameworkasp.net-identityowin

EF throws AspNetUsers error after Owin Authorization timeout


I have overridden the authorization in my AccountController for an MVC5 app. It works fine logging in and logging out, getting the context, etc. However, if the authorization times out, instead of redirecting me back to the Login page, it throws the error:

Invalid object name 'dbo.AspNetUsers'.

I'm not using EF in authentication, but rather a service, so I do not have these tables. However, I can't find where it is hitting this code to throw the error.

AccountController.cs:

    public async Task<ActionResult> Login(LoginViewModel model, string returnUrl)
    {
        if (!ModelState.IsValid)
        {
            return View(model);
        }

        var userRequest = new RequestObject
        {
            Name = model.Username,
            Password = model.Password
        };

        try
        {                
            var result = await client.LoginUserAsync(userRequest);

            if (result == 0)
            {
                var user = new User
                {
                    Name = model.Username
                };

                OwinSignIn(user);

                return RedirectToAction("Index", "Home");
            }
        }
        catch (Exception)
        {
            // TODO: log error
        }

        ModelState.AddModelError("", "Invalid login attempt.");
        return View(model);
    }


    private void OwinSignIn(User user, bool isPersistence = false)
    {
        var claims = new[] {
            new Claim(ClaimTypes.Name, user.Name)
        };

        var identity = new ClaimsIdentity(claims, DefaultAuthenticationTypes.ApplicationCookie);

        var result = client.GetUserRoles(userRequest);
        var roles = result.Roles.ToList();

        if (roles.Any())
        {
            var roleClaims = roles.Select(r => new Claim(ClaimTypes.Role, r.Name));
            identity.AddClaims(roleClaims);
        }

        AuthenticationManager.SignIn(new AuthenticationProperties { IsPersistent = isPersistence }, identity);
    }

Again, this only happens if I am signed in and wait for that authorization to expire. I'm not sure what method I have not updated in order to make sure it just goes back to the Login page - I suspect there is something that is checking the session is still valid somewhere but I'm not sure where.

Thanks.

UPDATE:

If I remove the OnValidateIdentity call, the problem goes away. I'm not sure if this can be fixed or if removing it is ok...

        app.UseCookieAuthentication(new CookieAuthenticationOptions
        {
            AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
            LoginPath = new PathString("/Account/Login"),
            Provider = new CookieAuthenticationProvider
            {
                // Enables the application to validate the security stamp when the user logs in.
                // This is a security feature which is used when you change a password or add an external login to your account.  
                OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<ApplicationUserManager, ApplicationUser>(
                    validateInterval: TimeSpan.FromMinutes(30),
                    regenerateIdentity: (manager, user) => user.GenerateUserIdentityAsync(manager))
            }
        });     

Solution

  • I understand that you've already found a solution to your problem. If you are not using EF to persist your users data, then it will be safe to remove most of Identity packages from your solution and only leave required OWIN ones.

    Reason you see this effect is because this bit:

    OnValidateIdentity =     
        SecurityStampValidator.OnValidateIdentity<ApplicationUserManager, ApplicationUser>(
                            validateInterval: TimeSpan.FromMinutes(30),
                            regenerateIdentity: (manager, user) => user.GenerateUserIdentityAsync(manager))
    

    It is executed on a request every 30 minutes and checks if the current cookie is the same as data in the database. Is actually calling default ApplicationUserManager that is by default wired into the EF and by default expect AspNetUsers table to be present. No, you won't find this string in your solution - this table is defined on IdentityDbContext and is provided by EF part of Identity.

    I suspect it will be safe to make your ApplicationDbContext to inherit from DbContext rather than from IdentityDbContext - this will remove any possibility to hit missing tables that you don't need. Following that you can remove ApplicationUserManager (as it expects IdentityDbContext).

    I've blogged about using AD as a service for setting OWIN cookie - some of this might be useful for you.