Random logouts with MVC4 asp.net - c#

This will be my first question here!
Im having problems with my mvc4 app and random occurring logouts.
i use sessions to store my company id and id of the user.
private void SetSessionData(string UserName)
{
Employee data = (from employee in _db.Employees where employee.Email == UserName select employee).First();
Session.Add("Comp_ID", data.Comp_ID);
Session.Add("Company", data.Company.Name);
Session.Add("User_ID", data.ID);
}
i have set the timeout value to 600 for the session (10 hours) this is even set 2 places to be sure:
[AllowAnonymous]
public ActionResult Login(LoginModel model, string returnUrl)
{
if (ModelState.IsValid && WebSecurity.Login(model.UserName, model.Password, persistCookie: model.RememberMe))
{
//FormsAuthentication.SetAuthCookie(model.UserName, model.RememberMe); //sørger for at remember me virker!
SetSessionData(model.UserName);
Session.Timeout = 600;
if (model.RememberMe)
{
Response.Cookies.Add(new HttpCookie("CookieUserName", model.UserName) { Expires = DateTime.Now.AddDays(30), Value = model.UserName });
Response.Cookies.Add(new HttpCookie("CookieRememberMe", model.RememberMe.ToString()) { Expires = DateTime.Now.AddDays(30), Value = model.RememberMe.ToString() });//sætter den nye cookie
}
else
{
Response.Cookies.Set(new HttpCookie("CookieUserName") { Expires = DateTime.Now.AddDays(-1) });
Response.Cookies.Set(new HttpCookie("CookieRememberMe") { Expires = DateTime.Now.AddDays(-1) });
}
if (string.IsNullOrEmpty(returnUrl))
{
return RedirectToLocal(returnUrl);
}
return RedirectToAction("Index", "Home");
}
// If we got this far, something failed, redisplay form
ModelState.AddModelError("", "Vi har enten ikke brugernavnet eller koden i kartoteket.");
return View(model);
}
and here in the web.config:
<system.web>
<machineKey validationKey="MyKeyGoesHere" validation="SHA1" decryption="AES" />
<sessionState timeout="600" />
<compilation debug="true" targetFramework="4.5">
<assemblies>
<add assembly="System.Data.Entity, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
</assemblies>
</compilation>
<httpRuntime targetFramework="4.5" />
<authentication mode="Forms">
<forms loginUrl="~/Account/Login" timeout="600" />
</authentication>
My cookies seem to be saved for 10 hours, and my session_id cookie expiration seems to be set to "when the browser closes".
Server side i have set the app pool to recycle at 1am.
Even though all this is set my users still get random logouts form everything between 2 min after login to 1 hour after login.
to counter some of the random half login state problems i have had i included this:
#if(Session == null || Session["User_ID"] == null || !WebSecurity.Initialized){
//Makes sure the session data is cleared and user logged out if session dies.
try
{
if(Session != null) {Session.Clear();}
if (WebSecurity.Initialized){WebSecurity.Logout();}
FormsAuthentication.SignOut();
//dette er til at stoppe cache.
Response.Cache.SetExpires(DateTime.UtcNow.AddMinutes(-1));
Response.Cache.SetCacheability(HttpCacheability.NoCache);
Response.Cache.SetNoStore();
}catch{ <p>Error Clearing Login Cache</p>}
}
Im pretty lost by now and hopes a guru out there might know what beginners mistake im making here!
Thanks for ALL response in advance!
Edit:
I also tried this: http://www.windowsitpro.com/article/security-development/create-persistent-id-cookies
(original link from: ASP.NET MVC FormsAuthentication Cookie timeout cannot be increased)
but that just made my app logout every single time i pressed anything after login.
The app is running on windows 2012 server with IIS8.
More adds:
I found out the session_id cookie is still set to when closed in the browser:
cloud.hviidnet.com/image/2X3v2y2e1K1S
The strange thing is its set to 600 min, even when i look in the IIS server:
cloud.hviidnet.com/image/1e3J1g2u3p2M

The solution was to remove all use of "Session." and get all the data from the database instead with WebSecurity.CurrentUserID.
Hope this helps someone else!

Do you only have a single web server? If you have multiple servers load balanced, the session could be getting lost as the user gets routed to different servers between posts, which would explain why it happens at random intervals.

Related

How can I force the login screen to appear when user re-opens their web browser after auto-logged out time?

Good afternoon.
I have a situation with a SSL web application written in C# in that if I log in and navigate to a secure page, close my browser and open it again after the login has expired, the content that was shown when closing the browser still appears.
In other words, if the login cookie expires after 30 minutes, and I close the browser and re-open it (restoring my tabs) after 30 minutes, the page that I was viewing still appears and not the expected login page.
If I click on a link after re-opening the browser that is supposed to take me to another secure location, I am redirected to the login page, but I'd like to prevent the previous page content from being shown again since it could contain sensitive data.
The page content is set to expire after 30 minutes and the user login cookie is set to expire after 30 minutes as well. (See images below)
I'm not sure how to force the login screen to appear when re-opening a browser. Thoughts or help would be greatly appreciated!
EDIT: Relevant content of web.config if it will help.:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.web>
[REMOVED]
<authentication mode="Forms">
<forms path="/" cookieless="UseCookies" loginUrl="~/Account/Login.aspx" name="[REMOVED]" requireSSL="true" timeout="30" />
</authentication>
[REMOVED]
</system.web>
<system.webServer>
<staticContent>
<clientCache cacheControlMode="UseMaxAge" cacheControlMaxAge="00:30:00" />
</staticContent>
[REMOVED]
</system.webServer>
[REMOVED]
</configuration>
OnLoad Method from the Site.Master page:
protected void Page_Load(object sender, EventArgs e)
{
/*
* See if the user has read the service agreement, if not, send the user to the service agreement page.
* Do NOT process this if it is being called from the service agreement page!
* If you do, we will end up with an infinite loop and infinite loops are bad mmmkay?
*/
if (!Profile.IsAnonymous && !Roles.IsUserInRole("Administrator"))
{
if (!Profile.ServiceAgreementStatusOkay())
{
if (Page.Request.RawUrl != #"/Account/KB/SA/")
{
Response.Redirect("/Account/KB/SA/");
}
}
}
// only check messages if the user isn't anonymous
if (!Profile.IsAnonymous)
{
int UnreadMessageCount = 0;
SqlDataSourceMessageCount.SelectParameters["UserId"].DefaultValue = Membership.GetUser().ProviderUserKey.ToString();
SqlDataSourceMessageList.SelectParameters["UserId"].DefaultValue = Membership.GetUser().ProviderUserKey.ToString();
Repeater MessageListRepeater = ((Repeater)LoginViewUserMenu.FindControl("RepeaterMessages"));
SqlDataReader CountReader = null;
DataView MessageListDataView = new DataView();
try
{
CountReader = (SqlDataReader)SqlDataSourceMessageCount.Select(DataSourceSelectArguments.Empty);
if (CountReader.HasRows)
{
CountReader.Read();
UnreadMessageCount = CountReader.SafeGetInt32(0);
if (UnreadMessageCount != 0)
{
((Literal)LoginViewUserMenu.FindControl("LiteralMessageCount")).Text = UnreadMessageCount.ToString();
}
else
{
((Literal)LoginViewUserMenu.FindControl("LiteralMessageCount")).Text = string.Empty;
}
}
SqlDataSourceMessageList.FilterParameters.Clear();
SqlDataSourceMessageList.FilterExpression = string.Empty;
SqlDataSourceMessageList.FilterParameters.Add("IsRead", "false");
SqlDataSourceMessageList.FilterExpression = "IsRead = {0}";
MessageListDataView = (DataView)SqlDataSourceMessageList.Select(DataSourceSelectArguments.Empty);
MessageListRepeater.DataSource = MessageListDataView;
MessageListRepeater.DataBind();
}
catch (Exception ex)
{
ErrorNotifier Err = new ErrorNotifier();
Err.Notify(ex, HttpContext.Current.Request.Url.AbsoluteUri.ToString());
throw;
}
finally
{
if (CountReader != null)
{
if (!CountReader.IsClosed)
{
CountReader.Close();
}
}
}
}
// set the value of the bug report path.
TextBoxPath.Text = Page.Request.RawUrl;
// set footer stuff.
AppCopyrightDate.Text = AppAttributes.GetCopyrightString();
LiteralVersionNumber.Text = AppAttributes.AppVersion.ToString();
// set theme info.
ThemeManager TM = new ThemeManager();
if (Request["ThemePreview"] == null)
{
LiteralTheme.Text = TM.GetThemeLink(Profile.UX.Theme);
}
else
{
LiteralTheme.Text = TM.GetThemeLink(Request["ThemePreview"]);
}
}

Issue with remember me in asp mvc membership

I have https website and I am using membership for logins and
my code in controller:
int timeout = rememberme ? 2880 : 2; // Timeout in minutes,525600 = 365 days
var ticket = new FormsAuthenticationTicket(username, rememberme, timeout);
string encrypted = FormsAuthentication.Encrypt(ticket);
var cookie = new HttpCookie(FormsAuthentication.FormsCookieName, encrypted);
cookie.Expires = DateTime.Now.AddMinutes(timeout);//My Line
Response.Cookies.Add(cookie);
string returnurl = FormsAuthentication.GetRedirectUrl(username, rememberme);
if (string.IsNullOrEmpty(returnurl)) returnurl = "/Panel/Login";
if (string.IsNullOrEmpty(returnurl)) returnurl = "/Panel/Login";
if (rol == "User")
return Redirect("/Panel/Dashboard");
else if (rol == "Admin")
return Redirect("/Panel/DashboardAdmin");
return View();
and in we.config:
<httpRuntime targetFramework="4.6.2" executionTimeout="100000000" maxRequestLength="2147483647" />
<authentication mode="Forms">
<forms loginUrl="~/Panel/Login" requireSSL="true" slidingExpiration="true" />
</authentication>
<httpCookies httpOnlyCookies="true" requireSSL="true" />
so its just keep login for 2 minutes and remember me is not working
what should I do?
we should add this to system.web in web.config file
an U can generate this key in iis but if U can access to iis U can use this code
<machineKey
decryptionKey="1513F567EE75F7FB5AC0AC4D79E1D9F25430E3E2F1BCDD3370BCFC4EFC97A541"
validationKey="32CBA563F26041EE5B5FE9581076C40618DCC1218F5F447634EDE8624508A129"
decryption="AES"
validation="SHA1"
/>

"Remember me" functionality in a Login form

I am using linq to entity connection. I want to keep user logged in once he entered into his account, This is my code. It's not working. Help, please
if (this.ChkRememberme != null && this.ChkRememberme.Checked == true)
{
HttpCookie cookie = new HttpCookie(TxtUserName.Text, TxtPassword.Text);
cookie.Expires.AddYears(1);
Response.Cookies.Add(cookie);
}
if (this.ChkRememberme != null && this.ChkRememberme.Checked == true)
{
int timeout = rememberMe ? 525600 : 30; // Timeout in minutes, 525600 = 365 days.
var ticket = new FormsAuthenticationTicket(TxtUserName.Text, TxtPassword.Text);
string encrypted = FormsAuthentication.Encrypt(ticket);
var cookie = new HttpCookie(FormsAuthentication.FormsCookieName, encrypted);
cookie.Expires = System.DateTime.Now.AddMinutes(timeout);// Not my line
cookie.HttpOnly = true; // cookie not available in javascript.
Response.Cookies.Add(cookie);
}
Go to your web.config and find the authentication element. You can set the cookie expiration time (in minutes) there, like such:
<system.web>
<authentication mode="Forms">
<forms loginUrl="~/Account/Login"
name="myCookie" <!-- optional, if you want to rename it -->
timeout="2880" /> <!-- expires in 48 hours -->
</authentication>
</system.web>
Source: how to apply "Remember Me" in c#
Hope this helps
Happy Coding..!!
I recommend to use MembershipReboot for authentication purposes in your app (samples are included).

No redirect to login page with ajax call

Im having problem with a asp.net mvc site. It seems that the "logging out" part doesnt work properly. I can login, no problem, but when Im logged out my code throws an error instead of redirecting to the login page. Im using the "starterpage" from VisualStudio.
my web.config:
<authentication mode="Forms">
<forms
name="MyCookie"
loginUrl="~/Account/LogOn"
protection="All"
slidingExpiration="false"
path="/"
timeout="1"/>
</authentication>
The login function:
[HttpPost]
public ActionResult LogOn(LogOnModel model, string returnUrl)
{
if (ModelState.IsValid)
{
if (Membership.ValidateUser(model.UserName, model.Password))
{
FormsAuthentication.SetAuthCookie(model.UserName, model.RememberMe);
if (Url.IsLocalUrl(returnUrl) && returnUrl.Length > 1 && returnUrl.StartsWith("/")
&& !returnUrl.StartsWith("//") && !returnUrl.StartsWith("/\\"))
{
return Redirect(returnUrl);
}
else
{
return RedirectToAction("Index", "Home");
}
}
else
{
ModelState.AddModelError("", "The user name or password provided is incorrect.");
}
}
// If we got this far, something failed, redisplay form
return View(model);
}
I have a loop that every three sec. calls a function with ajax and when im logged out ( efter 1 min. as configured in web.config ) I get an error instead of the login page.
The function called with ajax
[ActionName("StudentHelp")]
[Authorize]
[OutputCache(Duration = 3, VaryByParam = "none")]
public ActionResult StudentHelp()
{
var teacher = Membership.GetUser();
using(var db = new DbEntities())
{
var studentUserIds = (from p in db.Help
where p.TeacherId == (Guid) teacher.ProviderUserKey
&& p.IsHelped == false
select p).ToList();
IList<StudentModel> students = studentUserIds.Select(studentUserId => new StudentModel(studentUserId.StudentId)).ToList();
return PartialView("_StudentHelp", students);
}
}
Any clues?
thx /Mike
The reason you are getting an error instead of the login page is because you haven't decorated your StudentHelp action with the [Authorize] attribute meaning that this action can be invoked by unauthenticated users. Except that inside this action you are attempting to fetch the currently logged in user (Membership.GetUser()) which will return null when there's no logged in user anymore (because his authentication cookie expired). And then in your LINQ query you are using teacher.ProviderUserKey but since the teacher variable is null you get a NullReferenceException.
UPDATE:
Due to a known issue you might need to add the follownig key to your web.config:
<appSettings>
<add key="loginUrl" value="~/Account/LogOn" />
<appSettings>
The release notes also suggest adding the following but so far this hasn't worked for me when I tested it:
<add key="autoFormsAuthentication" value="false" />

MVC3 Session timeout after 10 seconds

Need some help with a Session timeout problem in an ASP.Net web app. Essentially the session expires about 10-15 seconds after login.
Side Note: I use a custom combo of FormsAuthentication and basic security
My Session.IsNewSession gets set to true after 3-4 good postbacks after login.
My Web.Config has the following...
<sessionState mode="InProc" timeout="130" regenerateExpiredSessionId="true" stateNetworkTimeout="120" compressionEnabled="true" cookieless="UseCookies" />
<authentication mode="Forms">
<forms timeout="120" ticketCompatibilityMode="Framework40" enableCrossAppRedirects="true" />
</authentication>
Where I believe the timeout refers to minutes....
I have an MVC 3 application with an ActionFilter registered
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new MyActionFilterAttribute());
}
Inside the OnActionExecuting I check for a Current Session to prevent access to controller actions which an unauthorized user shouldn't be able to access.
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
HttpContext ctx = HttpContext.Current;
Player player = SessionHelper.GetCurrentPlayer(filterContext.HttpContext.Session);
if (player == null && ctx != null)
{
player = SessionHelper.GetCurrentPlayer(ctx.Session);
}
if (player == null ||
(player.IsAdministrator == false && player.IsCoach == false && player.IsCommittee == false))
{
if (filterContext.Controller is HomeController || filterContext.Controller is AccountController)
{
base.OnActionExecuting(filterContext);
return;
}
string ctxError = ctx != null ? "Context Exists" : "Context Doesnt Exist";
string sessionError = filterContext.HttpContext.Session != null ? "filterContext.HttpContext.Session Exists" : "filterContext.HttpContext.Session Doesnt Exist";
string requestSessionError = filterContext.RequestContext.HttpContext.Session != null ? "filterContext.RequestContext.HttpContext.Session Exists" : "filterContext.RequestContext.HttpContext.Session Doesnt Exist";
throw new SecurityException(string.Format("Attempt to access {0} by user at {1} - {2} ({3}, {4}, {5})",
filterContext.HttpContext.Request.RawUrl,
filterContext.HttpContext.Request.UserHostAddress,
filterContext.HttpContext.Session,
ctxError,
sessionError,
requestSessionError));
}
base.OnActionExecuting(filterContext);
}
So I've determined that the Web Server was refreshing its AppPool faster than my session lifespan. This would result in the same SessionId to be used, but the IsNewSession flag to be set also.
As I have no control over the AppPool lifespan I was able to keep the session in the InProc mode in IIS.
I resolved the issue by moving Session State persistance to a hosted SqlServer database, thereby allowing the session to persist despite the AppPool being recycled.
I'd recommend the solution for any other person seeing their otherwise stable website losing their session state when hosted on a server which they do not have administrative access to.
Oh, and I found that IIS logs were pretty useless here. The best diagnosis logging here, I found, was my own manual logging to determine that this was the scenario.

Categories