1

Some days ago i published my code into a "production" environment just for testing purposes. So this website i've been developing it's online. The issue is that no matter what changes i do to the cookie settings.

I tried changing the sliding expiration to true and to false, both using:

        options.ExpireTimeSpan = TimeSpan.FromDays(30);                
        options.Cookie.Expiration = TimeSpan.FromDays(30);

Also setting the expiration to 1 year. Nothing seems to be working.

This is my setup from Startup.cs:

public void ConfigureServices(IServiceCollection services)
        {
            services.Configure<ForwardedHeadersOptions>(options =>
            {
                options.ForwardedHeaders = ForwardedHeaders.All;
                options.RequireHeaderSymmetry = false;
            });

            services.AddDbContext<IdentityDataContext>();

            services.AddIdentity<PinchilaIdentityUser, IdentityRole>()
                .AddEntityFrameworkStores<IdentityDataContext>()
                .AddUserManager<PinchilaUserManager>()
                .AddDefaultTokenProviders();
                services.Configure<SecurityStampValidatorOptions>(options => options.ValidationInterval = TimeSpan.FromSeconds(10));
                services.AddAuthentication()
                    .Services.ConfigureApplicationCookie(options =>
                    {
                        options.SlidingExpiration = true;
                        options.ExpireTimeSpan = TimeSpan.FromMinutes(30);
                    });
}

        //COOKIE
            services.ConfigureApplicationCookie(options => {
                if (!String.IsNullOrEmpty(PinchilaSettings.Instance.CookieDomain))
                {
                    options.Cookie.Domain = PinchilaSettings.Instance.CookieDomain;
                }
                if (!String.IsNullOrEmpty(PinchilaSettings.Instance.CookieName))
                {
                    options.Cookie.Name = PinchilaSettings.Instance.CookieName;
                }
                options.AccessDeniedPath = new PathString("/error/default");
                options.ExpireTimeSpan = TimeSpan.FromDays(30);
                options.Cookie.Expiration = TimeSpan.FromDays(30);
            });

            var mvcBuilder = services.AddMvc();

            services.Configure<RazorViewEngineOptions>(options => {
                options.ViewLocationExpanders.Add(new ViewLocationExpander());
            });

            mvcBuilder.AddMvcOptions(o => {
                o.Filters.Add(typeof(GlobalExceptionFilter));
                o.Filters.Add(typeof(RuntimeStateFilter));
                o.Filters.Add(typeof(RouteLoggerFilter));
            });

            services.AddAntiforgery(options => {
                options.HeaderName = Utilities.CONSTANTS.REQUEST_VERIFICATION_HEADER_NAME;
                options.FormFieldName = Utilities.CONSTANTS.REQUEST_VERIFICATION_HEADER_NAME;
            });


            services.AddScoped<IViewRenderService, ViewRenderService>();
            services.AddLogging(loggingBuilder =>
            {
                var filter = new LoggingFilter();
                loggingBuilder.AddFilter(filter.Filter);
            });
        }

And this is my login part from my AccountController:

[HttpPost]
[AllowAnonymous]
[PinchilaValidateAntiForgeryToken]
public async Task<ActionResult> Login(LoginViewModel model, string returnUrl)
{
    ViewData["ReturnUrl"] = returnUrl;
    if (ModelState.IsValid)
    {
        model.UserName = model.UserName.TrimSafe();
        model.Password = model.Password.TrimSafe();
        var user = await _userManager.FindByNameAsync(model.UserName);
        if (user != null)
        {
            var result = await _signInManager.PasswordSignInAsync(user, model.Password, model.RememberMe, lockoutOnFailure: true);
            if (result.Succeeded)
            {

                var cookie = HttpContext.Request.Cookies["theme"];
                if (cookie != null && !String.IsNullOrEmpty(cookie))
                {
                    Response.Cookies.Append("theme", "", new Microsoft.AspNetCore.Http.CookieOptions() { Expires = DateTime.UtcNow.AddDays(30) });
                }

                return RedirectToLocal(returnUrl);
            }
            if (result.IsLockedOut)
            {
                ModelState.AddModelError(string.Empty, "This account has been locked out for security reasons. Try again later.");
                return View(model);
            }
            else
            {
                ModelState.AddModelError(string.Empty, "Invalid login attempt");
                return View(model);
            }
        }
        else
        {
            ModelState.AddModelError(string.Empty, "Invalid login attempt");
        }
    }

    return View(model);

}

If any of you can give me some different point of view i'll be very grateful.

Edit: this is how the cookies looks like on the Chrome console: enter image description here

emboole
  • 501
  • 6
  • 23
  • 1
    Use your browser's developer tools to inspect the cookies (and HTTP headers that set cookies) to look for anything going wrong. I recommend you post the full `Set-Cookie` header which would have some useful clues. – Dai Jan 31 '19 at 23:28
  • I just edited it with the info. Something that looks wrong is the value of the "notfirsttime" cookie. – emboole Jan 31 '19 at 23:33
  • Have you checked if IIS is being recycled? If someone recycles your AppPoll or IIS, the users lose their authentications. – Tiago B Feb 01 '19 at 00:43
  • @emboole `keeps logging out users`-When it logs out user? you added a lot thing but did specify that clearly? – TanvirArjel Feb 01 '19 at 02:29
  • @TanvirArjel title edited! they log in and within an hour they are logged out – emboole Feb 01 '19 at 02:53
  • 2
    I'm confused. You're saying that they're logged out within an hour, but your expiration is 30 minutes. Even with sliding expiration, if the user is inactive for 30 minutes, they'll be logged out, and of course with absolute expiration, they'll be logged out within 30 minutes regardless. Both cases fall under "within an hour", so what is the exact issue here? – Chris Pratt Feb 01 '19 at 14:50
  • 2
    Oh I see. In most places you changed it to 30 days. Perhaps you missed this line: `options.ExpireTimeSpan = TimeSpan.FromMinutes(30);` in `AddAuthentication`? – Chris Pratt Feb 01 '19 at 14:51
  • Has sense to me, let me check it! – emboole Feb 01 '19 at 18:46
  • Hi @ChrisPratt. I changed it and just checked. unfortunately I have been logged out. Checked with phone, 2 computers. – emboole Feb 01 '19 at 20:50
  • @Dai i noticed that the domain in the identity cookie is different. All cookies have the domain, but that one, which is preceded with a ".". I changed the cookie domain and will check again – emboole Feb 01 '19 at 21:15

1 Answers1

0

Thanks to @TiagoBrenck comment i started looking for an answer on the server side.

I found out this post. Please look at the @dantey89 answer. It fixed my issue.

Basically, inside startup.cs, on ConfigureServices method you need to put this:

        public void ConfigureServices(IServiceCollection services)
    {

        var environment = services.BuildServiceProvider().GetRequiredService<IHostingEnvironment>();


        services.AddDataProtection()
                .SetApplicationName($"my-app-{environment.EnvironmentName}")
                .PersistKeysToFileSystem(new DirectoryInfo($@"{environment.ContentRootPath}\keys"));

       ...

    }

This will create a folder. It needs permissions from the app pool or will have error 500.

Hope this help others.

emboole
  • 501
  • 6
  • 23