Sessions ASP.NET Timeout - asp.net

I have problems with sessions in asp.net. I searched the web for a while, but couldn't find the reason why it doesn't works. The session disappears after some minutes. It is a project that isn't created by myself, i'm not a hero in aspx. But I'm trying to solve this problem.
Web.config
<system.web>
<authentication mode="Forms">
<forms loginUrl="~/Default.aspx" timeout="120" slidingExpiration="true" />
</authentication>
<customErrors mode="RemoteOnly"/>
<httpRuntime requestValidationMode="2.0"/>
<pages validateRequest="false" />
<sessionState mode="InProc" cookieless="false" timeout="120" />
</system.web>
Checking if Logged in on the pages that you have to be logged in
if (!functions.isLoggedIn(Session))
{
Response.Redirect("Default.aspx");
}
Functions
public static bool isLoggedIn(HttpSessionState session)
{
return session["user"] != null;
}
Not logged in ? Showing login form, filling in the form and then send it to server to check
protected void Page_Load(object sender, EventArgs e)
{
if (Request["do"] != null)
{
switch (Request["do"])
{
case "logout":
Session.Abandon();
break;
}
}
if (Request.ServerVariables["REQUEST_METHOD"].ToLower() == "post")
{
//get username en password
string username = Request["username"];
string password = Request["password"];
if (String.IsNullOrWhiteSpace(username) || String.IsNullOrWhiteSpace(password))
{
LoginMessage.Text = "Please fill in all the fields...";
}
else
{
password = FormsAuthentication.HashPasswordForStoringInConfigFile(
password,
"SHA1");
UserService gs = new UserService();
user g = gs.getUserByLogin(username, password);
if (g == null)
{
//wrong login
LoginMessage.Text = "Invalid username/password.";
}
else
{
//good login
Session["user"] = g;
System.Diagnostics.Debug.WriteLine("timeout:" + Session.Timeout);
Response.Redirect("Home.aspx");
}
}
}
}
GetUserByLogin function in userservice
public user getUserByLogin(string username, string password)
{
user g;
var db = new projectName.Db.Models.projectnetContext();
IQueryable<user> query = from gb in db.users
where gb.username.Equals(username)
&& gb.Passwoord.Equals(password.ToLower())
&& gb.Status == 1
select gb;
if (!query.Any())
g = null;
else
g = query.First();
return g;
}
After login in, creating the session
Session["user"] = g;
My problem is that I have set the time-out. But it doesn't seems to work. If I check the timeout on the server, it is set to 120. But after 2 minutes, I'm redirected to the login form. Can I solve this? If I debug on localhost, It seems to work, but not online.
The login works. The session is set (otherwise I couldn't enter the next pages). If I go to another page (faster then +-5minutes), then I'm still logged in. So the problem is reproductive.
Or if it isn't possible, Cookies? Normally I work with cookies in PHP,.. But is there a way to do it in ASP.NET on a safe way?

Hmm I Recommend you to use profile instead of session in asp .net .

There is two aspects in your scenario. You have the authentication and the session. These are two different things.
Session that you are manage in your web.config stored a value with a timeout of 120 minutes (2 hours)
But Authentication also have a configuration section in web.config.
https://msdn.microsoft.com/en-us/library/532aee0e%28v=vs.85%29.aspx
So what do you want to do exactly first ?

Please find this MVC controller action method sample.
// POST: /Secure/Login
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public ActionResult Login(LoginFormModel model, string returnUrl)
{
if (ModelState.IsValid)
{
if (Membership.ValidateUser(model.Login, model.Password))
{
using (var db = new DatabaseEntities())
{
var user = db.Users.Single(u => u.Login == model.Login);
Membership.UpdateUser(new MembershipUser("UserMembershipProvider", user.Login, null, null, null, null, true, false, DateTime.MinValue, DateTime.Now, DateTime.MinValue, DateTime.MinValue, DateTime.MinValue));
#region Create Authentication Cookie
Response.Cookies.Add(MyAppFormAuthenticationCookie.Create(user, model.RememberMe));
#endregion
if (!string.IsNullOrWhiteSpace(returnUrl))
{
return Redirect(HttpUtility.UrlDecode(returnUrl));
}
if (model.UserFormType == UserType.Candidate)
{
return RedirectToAction("Index", "Dashboard", new { area = "Candidate" });
}
if (model.UserFormType == UserType.Recruiter)
{
return RedirectToAction("Index", "Dashboard", new { area = "Recruiter" });
}
if (model.UserFormType == UserType.SuperAdmin || model.UserFormType == UserType.Admin)
{
return RedirectToAction("Index", "Dashboard", new { area = "Admin" });
}
}
}
ModelState.AddModelError("", "Incorrect username and/or password");
return View("Index", model);
}
return RedirectToAction("Index", "Home");
}
In this sample, you have :
UPDATE of the user profile to set the last connection date and others if you want ...
CREATION of the authentication cookie in a custom way for this sample
REDIRECTION to the homepage according to the type of user
So, do you have a similar approach to authenticate user in your application ?
EDIT1:
Normally you must finalize authentication process something like this :
var authTicket = new FormsAuthenticationTicket("MyAuthTicket", rememberMe, timeout: 120);
var encryptAuthTicket = FormsAuthentication.Encrypt(authTicket);
Response.Cookies.Add(new HttpCookie(FormsAuthentication.FormsCookieName, encryptAuthTicket) { Expires = authTicket.Expiration });

Just an advice... do you have any re-directions(Response.Redierct) to diff. sites or trying to access the resources for which you don't have access? Session will expire in these cases.

Related

Logging out of ASP.NET MVC application with windows authentication and being able to login again with same user

I am building an application in ASP.NET MVC with windows authentication.
I need a way to logout the logged in user such that a new user can log into the same application without having to close the browser.
For this, I found a neat solution which is as below:
public ActionResult LogOut()
{
HttpCookie cookie = Request.Cookies["TSWA-Last-User"];
if(User.Identity.IsAuthenticated == false || cookie == null || StringComparer.OrdinalIgnoreCase.Equals(User.Identity.Name, cookie.Value))
{
string name = string.Empty;
if(Request.IsAuthenticated)
{
name = User.Identity.Name;
}
cookie = new HttpCookie("TSWA-Last-User", name);
Response.Cookies.Set(cookie);
Response.AppendHeader("Connection", "close");
Response.StatusCode = 0x191;
Response.Clear();
//should probably do a redirect here to the unauthorized/failed login page
//if you know how to do this, please tap it on the comments below
Response.Write("Unauthorized. Reload the page to try again...");
Response.End();
return RedirectToAction("Index");
}
cookie = new HttpCookie("TSWA-Last-User", string.Empty)
{
Expires = DateTime.Now.AddYears(-5)
};
Response.Cookies.Set(cookie);
return RedirectToAction("Index");
}
The problem with this approach however is that the same user cannot login again. It always needs to be a different user to the current one.
I am thinking I should be able to do this this by changing the if clause.
I tried removing the StringComparer.OrdinalIgnoreCase.Equals(User.Identity.Name, cookie.Value) condition as well but it fails to work since cookie value could be not null.
Please, check this post! It worked for me!
https://stackoverflow.com/a/3889441
Just in case, i'm pasting here the code:
#Palantir said:
That's strange... I make one single call to:
FormsAuthentication.SignOut(); and it works...
public ActionResult Logout() {
FormsAuthentication.SignOut();
return Redirect("~/");
}

Site redirecting to login page on every navigate action

I've got an MVC app that's an API documentation site, sitting behind forms auth There are really only two pages in the site... home, which lists (at a high level) all the endpoints on the site, as well as the data objects. You can click on any one of these data objects/endpoints, and be taken to a details page.
Each of my pages are decorated with the [Authorize(Roles="role,names,here")] attribute. As expected, when you enter the site, you're redirected to the login page, and any subsequent requests simply work.
However, yesterday the site started acting up and I'm not sure why. After initial login, the page you requested loads just fine. However, any time you click a link to navigate to any of the other pages, users are redirected to the login page, and credentials no longer work.
Any thoughts as to what's caused this, and how I can fix it?
[Edit]
I don't know why, but my sessionState config was commented out in my web.config (I didn't do that, and as I said, this was working 48 hrs ago), but it appears uncommenting this fixed it:
<sessionState mode="InProc" customProvider="DefaultSessionProvider">
<providers>
<add name="DefaultSessionProvider" type="System.Web.Providers.DefaultSessionStateProvider, System.Web.Providers, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" connectionStringName="dbConn"/>
</providers>
</sessionState>
It was better to show us your class providing session.But use this:
you will have an account controller like this:
UserApplication userApp = new UserApplication();
SessionContext context = new SessionContext();
public ActionResult Login()
{
return View();
}
[HttpPost]
public ActionResult Login(User user)
{
var authenticatedUser = userApp.GetByUsernameAndPassword(user);//you get the user from your application and repository here
if (authenticatedUser != null)
{
context.SetAuthenticationToken(authenticatedUser.UserId.ToString(),false, authenticatedUser);
return RedirectToAction("Index", "Home");
}
return View();
}
public ActionResult Logout()
{
FormsAuthentication.SignOut();
return RedirectToAction("Index", "Home");
}
And your SessionContext will be like this:
public class SessionContext
{
public void SetAuthenticationToken(string name, bool isPersistant, User userData)
{
string data = null;
if (userData != null)
data = new JavaScriptSerializer().Serialize(userData);
FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(1, name, DateTime.Now, DateTime.Now.AddYears(1), isPersistant, userData.UserId.ToString());
string cookieData = FormsAuthentication.Encrypt(ticket);
HttpCookie cookie = new HttpCookie(FormsAuthentication.FormsCookieName, cookieData)
{
HttpOnly = true,
Expires = ticket.Expiration
};
HttpContext.Current.Response.Cookies.Add(cookie);
}
public User GetUserData()
{
User userData = null;
try
{
HttpCookie cookie = HttpContext.Current.Request.Cookies[FormsAuthentication.FormsCookieName];
if (cookie != null)
{
FormsAuthenticationTicket ticket = FormsAuthentication.Decrypt(cookie.Value);
userData = new JavaScriptSerializer().Deserialize(ticket.UserData, typeof(User)) as User;
}
}
catch (Exception ex)
{
}
return userData;
}
}

Basic authentication IHttpModule unexpected behaviour

I have enabled Basic Authentication in IIS7 for my site and followed this link to create handler for basic authentication requests.
The problem is that no matter what credentials user enters, the site keeps returning 401, even if entering correct credentials. This is just a test and credentials are checked against hardcoded values.
Here is relevant code:
public class BasicAuthenticationHttpModule : IHttpModule
{
public void Init(HttpApplication context)
{
context.BeginRequest+=context_BeginRequest;
context.AuthenticateRequest += context_AuthenticateRequest;
}
void context_AuthenticateRequest(object sender, EventArgs e)
{
HttpApplication application = (HttpApplication)sender;
TryAuthenticate(application);
}
private void context_BeginRequest(object sender, EventArgs e)
{
HttpApplication application = (HttpApplication)sender;
TryAuthenticate(application);
}
private static void TryAuthenticate(HttpApplication application)
{
if (!Authenticate(application.Context))
{
application.Context.Response.Status = "401 Unauthorized";
application.Context.Response.StatusCode = 401;
application.Context.Response.AddHeader("WWW-Authenticate", "Basic");
application.CompleteRequest();
}
}
private static bool Authenticate(HttpContext context)
{
if (context.User!=null && context.User.Identity.IsAuthenticated)
{
return true;
}
if (!context.Request.Headers.AllKeys.Contains("Authorization"))
return false;
string authHeader = HttpContext.Current.Request.Headers["Authorization"];
IPrincipal principal;
if (TryGetPrincipal(authHeader, out principal))
{
context.User = principal;
return true;
}
return false;
}
private static bool TryGetPrincipal(string[] creds, out IPrincipal principal)
{
if (creds[0] == "Administrator" && creds[1] == "SecurePassword")
{
principal = new GenericPrincipal(
new GenericIdentity("Administrator"),
new string[] { "Administrator", "User" }
);
return true;
}
if (creds[0] == "BasicUser" && creds[1] == "Password")
{
principal = new GenericPrincipal(
new GenericIdentity("BasicUser"),
new string[] { "User", "SystemUser" }
);
return true;
}
else
{
principal = null;
return false;
}
}
When client enters correct credentials (i.e. "BasicUser", "Password"), GenericPrincipal object is created and assigned to HttpContext's User property. Looking into Request.IsAuthenticated tells that it's true.
And this is why I don't understand is why client receives 401 again and again and again.
I'm not sure how all the pipeline works - may be basic authentication goes further to some IIS HttpModule which also serves the request? Or may be code is incomplete and context_BeginRequest needs to be extended? (I know that in case of Forms authentication type, you do something like Response.Redirect(goodguy.aspx))
Anyway, any help/questions are appreciated.
Forgot to mention that in web.config I also placed
<system.webServer>
<modules>
<add name="BasicAuthenticationHttpModule" type="Analytics.BasicAuthenticationHttpModule" />
</modules>
</system.webServer>
Apparently implemements it's own Basic authentication. Thus our module could authenticate request succussfully, it would get passed to built-in IIS module, which rejected authentication. It is really helpful not to copy paste, but also to think yourself indeed. So to answer my question - disable all authentication on IIS except Anonymous.

Forcing .net Login control to make the user logout if a cookie is null

I have a code base web application that is connected to 2 databases. Depending on which login control a user uses to login, a different database is connected to the code. I am doing all of this by a cookie. This cookie is in a public class called AuthenticatedUser. The class looks like this:
public class AuthenticatedUser : System.Web.UI.Page
{
public static string ConnectionString
{
get
{
HttpCookie myCookie = HttpContext.Current.Request.Cookies["connectionString"];
return GetConnectionStringFromName(myCookie);
}
set
{
if (HttpContext.Current.Request.Cookies["connectionString"] != null)
{
ExpireCookies(HttpContext.Current);
}
var allCookies = HttpContext.Current.Request.Cookies.AllKeys;
HttpCookie cookie = new HttpCookie("connectionString");
cookie.Value = value;
cookie.Expires = DateTime.Now.AddYears(100);
HttpContext.Current.Response.Cookies.Add(cookie);
}
}
private static string GetConnectionStringFromName(HttpCookie myCookie)
{
try
{
string connectionStringName = myCookie.Value;
return ConfigurationManager.ConnectionStrings[connectionStringName].ConnectionString;
}
catch
{
FormsAuthentication.SignOut();
}
finally
{
HttpContext.Current.Response.Redirect("/default.aspx");
}
return "";
} private static void ExpireCookies(HttpContext current)
{
var allCookies = current.Request.Cookies.AllKeys;
foreach (var cook in allCookies.Select(c => current.Response.Cookies[c]).Where(cook => cook != null))
{
cook.Value = "";
cook.Expires = DateTime.Now.AddDays(-1);
current.Request.Cookies.Remove(cook.Name);
cook.Name = "";
}
}
}
This seems to be working on my development machine, but when I tried to deploy it, any user that was using the "remember me" option on the site was getting a null reference error because they did not use the login control to obtain the cookie.
What is the best method to get around this? I was thinking if a user was logged in but the AuthenticatedUser class could not get a Connectionstring to log out the user to force them to use the login control again. What should I do?
Try use:
try
{
FormsAuthentication.SignOut();
}
finally
{
Response.Redirect("~/Home.aspx");
}
This way is preferable, for example if in some time you will decide not- cookie auth, but URL based - the FormsAuthentication will manage it gracefully.

ASP .NET Custom RoleProvider not respecting cacheRolesInCookie="true"

I've implemented a custom role provider, and configured it in my web.config file like this:
<roleManager enabled="true" defaultProvider="TDRoleProvider" cacheRolesInCookie="true">
<providers>
<clear/>
<add name="TDRoleProvider" type="TDRoleProvider"/>
</providers>
</roleManager>
I've overridden the GetRolesForUser function in my custom role provider, and I've stepped into it, and it works just fine - loads up 60 roles for the user I'm testing with. However, I've noticed that the GetRolesForUser gets called on every request that calls User.IsInRole. In other apps I've written, it only calls it once, then caches the result in the cookie. For some reason, the caching is not working for this app. Any ideas as to why?
https://web.archive.org/web/20101123220352/http://connect.microsoft.com/VisualStudio/feedback/details/104688/rolemanager-cacherolesincookie-option-does-not-work
"The issue of when to cache (or not cache) in RolePrincipal went through a number of design iterations, and we finally settled on only caching for the method exposed by the IPrincipal interface (i.e. IsInRole). "
I was having the same problem. In my case the issue was that I was setting Context.User to GenericPrincipal and not RolePrincipal. So instead of:
this.Context.User = new GenericPrincipal(customIdentity, roles);
this fixed for me:
HttpCookie roleCookie = this.Context.Request.Cookies[Roles.CookieName];
if (IsValidAuthCookie(roleCookie))
{
this.Context.User = new RolePrincipal(customIdentity, roleCookie.Value);
}
else
{
this.Context.User = new RolePrincipal(customIdentity);
var x = this.Context.User.IsInRole("Visitor"); // do this to cache the results in the cookie
}
The IsValidAuthCookie method checks for null and empty:
private static bool IsValidAuthCookie(HttpCookie authCookie)
{
return authCookie != null && !String.IsNullOrEmpty(authCookie.Value);
}
UPDATE: After upgrading to MVC5 .NET 4.5 roleManager stopped working (not saving roles in cookie) so had to save it myself:
HttpCookie roleCookie = filterContext.HttpContext.Request.Cookies[Roles.CookieName];
if (IsValidAuthCookie(roleCookie))
{
filterContext.Principal = new RolePrincipal(customIdentity, roleCookie.Value);
RolePrincipal rp = (RolePrincipal)filterContext.Principal;
if (!rp.IsRoleListCached) // check if roles loaded properly (if loads old cookie from another user for example, roles won't be loaded/cached).
{
// roles not loaded. Delete and save new
Roles.DeleteCookie();
rp.IsInRole("Visitor"); // load Roles
SaveRoleCookie(rp, filterContext);
}
}
else
{
filterContext.Principal = new RolePrincipal(customIdentity);
filterContext.Principal.IsInRole("Visitor"); // do this to cache the results in the cookie.
SaveRoleCookie(filterContext.Principal as RolePrincipal, filterContext);
}
Save the roleCookie
private void SaveRoleCookie(RolePrincipal rp, AuthenticationContext filterContext)
{
string s = rp.ToEncryptedTicket();
const int MAX_COOKIE_LENGTH = 4096;
if (string.IsNullOrEmpty(s) || s.Length > MAX_COOKIE_LENGTH)
{
Roles.DeleteCookie();
}
else
{
HttpCookie cookie = new HttpCookie(Roles.CookieName, s);
cookie.HttpOnly = true;
cookie.Path = Roles.CookiePath;
cookie.Domain = Roles.Domain;
if (Roles.CreatePersistentCookie)
cookie.Expires = rp.ExpireDate;
cookie.Secure = Roles.CookieRequireSSL;
filterContext.HttpContext.Response.Cookies.Add(cookie);
}
}
Place this code on AuthenticationFilter and register it globally. See here.
Same is true for me. It keeps calling GetRolesForUser()

Resources