Cookie value expiring before the cookie expires - asp.net-mvc

I have an asp.net MVC app that i am working on and I wrote a custom actionfilter in order to filter out certain controller actions based on authorization levels which are set on login and stored in an encrypted cookie along side the formsauthentication cookie, both cookies are set to have the same expiration time but for some reason after awhile of idle time the authorization cookie value becomes blank, i haven't been able to debug and catch it in the act but it just disappears
my actionfilter code looks like this:
string usersRole = "";
if (filterContext.HttpContext.Session["role"] != null)
usersRole = filterContext.HttpContext.Session["role"].ToString();
else if (filterContext.HttpContext.Response.Cookies["ArisPortalCookie"].Value != null)
{
usersRole = filterContext.HttpContext.Response.Cookies["ArisPortalCookie"].Value;
filterContext.HttpContext.Session["role"] = usersRole;
}
string encryptedRole = EncryptionHelper.Encrypt(RoleToCheckFor);
if (encryptedRole == usersRole || usersRole == EncryptionHelper.Encrypt("Admin")) //if the user's role and role required match, we have success
{
//now we break down the response action based on what role was required
if (RoleToCheckFor == "Admin")
{
}
else if (RoleToCheckFor == "Tech" || RoleToCheckFor == "Admin")
{
}
else if (RoleToCheckFor == "Physician" || RoleToCheckFor == "Admin")
{
}
}
else
{
filterContext.Result = new ViewResult
{
ViewName = "NoAuth",
ViewData = filterContext.Controller.ViewData,
TempData = filterContext.Controller.TempData
};
}

I do the same to store Roles. Why have them side by side?
I assume you're doing something like this:
FormsAuthenticationTicket authTicket =
new FormsAuthenticationTicket(1,
username,
DateTime.Now,
DateTime.Now.AddMinutes(60),
rememberMe,
roles);
string encTicket = FormsAuthentication.Encrypt(authTicket);
HttpCookie authenticationCookie = new HttpCookie(FormsAuthentication.FormsCookieName, encTicket);
authenticationCookie.HttpOnly = true;
contextBase.Response.Cookies.Add(authenticationCookie);
If you are using FormsAuthentication.SetAuthCookie as well, which I don't think you need to and I don't, then make sure your config has timeout set to 60 minutes as well or equivalent to your time of above.
Reading values (piped format) from cookie (as requested)
private static void ReadCookieForPrincipal()
{
string cookieName = FormsAuthentication.FormsCookieName;
HttpCookie authCookie = HttpContext.Current.Request.Cookies[cookieName];
// If the cookie can't be found, don't issue the ticket
if (authCookie == null) return;
// Get the authentication ticket and rebuild the principal & identity
FormsAuthenticationTicket authTicket = FormsAuthentication.Decrypt(authCookie.Value);
string[] roles = authTicket.UserData.Split(new Char[] { '|' });
GenericIdentity userIdentity = new GenericIdentity(authTicket.Name);
GenericPrincipal userPrincipal = new GenericPrincipal(userIdentity, roles);
HttpContext.Current.User = userPrincipal;
}

Related

mvc 5 Set Cookie Expire, but expiration back to 01/01/0001

I set cookie when login success like this :
public JsonResult LoginWithPassword(String password)
{
Response.Cookies.Remove("Auth");
string CookieName = "Auth";
long UserId = 4;
HttpCookie myCookie = HttpContext.Response.Cookies[CookieName] ?? new HttpCookie(CookieName);
myCookie.Values["UserId"] = UserId.ToString();
myCookie.Values["LastVisit"] = DateTime.Now.ToString();
myCookie.Expires = DateTime.Now.AddDays(1);
HttpContext.Response.Cookies.Add(myCookie);
return Json(new { IsSuccess = true, ReturnUrl = returnUrl });
}
else
{
return Json(new { IsSuccess = false, Message = "Login fail, Wrong Password" });
}
}
and i read it in next page/action :
public ActionResult Index()
{
if (HttpContext.Request.Cookies["Auth"] == null)
return RedirectToAction("Login", "Access");
return View();
}
Really strange the cookie of "Auth" always empty. When i check the expiration date in debugging breakpoint, i get expiration date : 01/01/0001.
why this happend and how to solve this?
This action in two differents controller
I have tried to implement your code to create cookie. Same code is working fine in MVC5 at my end in firefox browser.
I have used code as below to create cookie -
Response.Cookies.Remove("Auth");
string CookieName = "Auth";
HttpCookie cookie = HttpContext.Response.Cookies[CookieName] ?? new HttpCookie(CookieName);
//HttpCookie cookie = new HttpCookie("Cookie");
cookie.Value = "Hello Cookie! CreatedOn: " + DateTime.Now.ToShortTimeString();
cookie.Expires = DateTime.Now.AddDays(5);
this.ControllerContext.HttpContext.Response.Cookies.Add(cookie);
In addition the check on "Auth" cookie is successful on Index page as -
public ActionResult Index()
{
if (HttpContext.Request.Cookies["Cookie"] == null)
return RedirectToAction("Login", "Account");
return View();
}
Alternatively I suggest to
1) Set Expiry after cookie is created in login page OR
2) add decimal in expiry days eg. 1.0 or 5.0. See article at link -
http://forums.asp.net/t/1982279.aspx?MVC5+Application+Cookie+expires+when+session+ends
Let me know if this helps you.

FormsAuthentication and Ajax Requests

I have a problem knowing whether a user is authenticated or not when ajax requests are sent from jQuery.
HttpContext.User.Identity is not empty when a user does a regular request from their browser and the aspxauth cookie is set. When a user tries doing a ajax request from jQuery, the aspxauth is not set at all.
My Web.Config
<authentication mode="Forms">
<forms loginUrl="~/" />
</authentication>
Setting the FormsAuthentication Cookie
var cookie = new AuthCookie
{
UserId = user.UserId,
Email = user.Email,
Name = user.Name,
RememberMe = createPersistentCookie,
TimeZone = user.TimeZone,
CompanyId = user.CompanyId,
Roles = new List<string> { user.Role ?? "user" }
};
string userData = JsonConvert.SerializeObject(cookie);
var ticket = new FormsAuthenticationTicket(1, cookie.Email, DateTime.Now,
DateTime.Now.Add(FormsAuthentication.Timeout),
createPersistentCookie, userData);
string encTicket = FormsAuthentication.Encrypt(ticket);
var httpCookie = new HttpCookie(FormsAuthentication.FormsCookieName, encTicket) { Expires = DateTime.Now.Add(FormsAuthentication.Timeout) };
_httpContext.Response.Cookies.Add(httpCookie);
When I make requests through my broser, the auth cookie appears:
Whenever I make a request through javascript using $.get() or loading javascript scripts / Any other request through javascript, I get:
The odd thing is that on another ASP application I am using WebSecurity and that works perfectly. The auth cookie is always being sent back from client to server. For this ASP MVC 5 application, when I try to use the FormAuthentication, I cannot get the AuthCookie to proceed through all requests.
you are still able to decorate your class/method with [Authorize] and the like. If you're looking to check inside the controller method you have access to the User Property inherited from System.Web.Mvc.Controller or System.Web.Http.ApiController depending on your controller flavor :
//
// Summary:
// Returns the current principal associated with this request.
//
// Returns:
// The current principal associated with this request.
public IPrincipal User { get; set; }
it can be used like so:
if (User != null && User.Identity != null && User.Identity.IsAuthenticated)
{
// user has access - process request
}
Edit:
Here is an example of an [Api]Controller with an ajax[able] method that uses the controller's User property instead of HttpContext's:
public class HelloController : ApiController
{
[HttpGet]
public IHttpActionResult HelloWorld()
{
try
{
if (User != null && User.Identity != null && User.Identity.IsAuthenticated)
{
return Ok("Hello There " + User.Identity.Name + "!");
}
else
{
return Ok("Hello There Anonymous!");
}
}
catch { throw; }
}
}

Set cookie value before view loaded in MVC?

I need to set a cookie value before my view called. otherwise I have to refresh the page to get cookie value in the view. The problem here is the value of cookie will get in controller.
[HttpGet]
[Route("Abstract/{meetingCode}")]
[AllowAnonymous]
public ActionResult Index(string meetingCode)
{
var meetingAbstract = new MeetingAbstract();
meetingAbstract.Meeting = _abstractContext.GetMeetingWithMeetingCode(meetingCode);
if (meetingAbstract.Meeting != null)
{
var cookie = new HttpCookie("_culture");
cookie.Value = meetingAbstract.Meeting.language.language_locale_code;//"en-US";
cookie.Expires = DateTime.Now.AddDays(365);
cookie.Path = "/";
this.ControllerContext.HttpContext.Response.Cookies.Add(cookie);
...
Any other way without refresh the page again to set cookie value?
Cookies have some peculiar behaviour, I mean you create them in the Response stream, to be sent to the client, but they are not available in the Request stream until they are sent from the client.
I mean, you cannot access the cookie unless it is being sent from the client.
Anyway, why you need to refresh your page to access the cookie you just created? Is not easier to use the same variable?
[HttpGet]
[Route("Abstract/{meetingCode}")]
[AllowAnonymous]
public ActionResult Index(string meetingCode)
{
var meetingAbstract = new MeetingAbstract();
meetingAbstract.Meeting = _abstractContext.GetMeetingWithMeetingCode(meetingCode);
var cookie;
if (meetingAbstract.Meeting != null)
{
cookie = new HttpCookie("_culture");
cookie.Value = meetingAbstract.Meeting.language.language_locale_code;//"en-US";
cookie.Expires = DateTime.Now.AddDays(365);
cookie.Path = "/";
this.ControllerContext.HttpContext.Response.Cookies.Add(cookie);
} else {
cookie = this.ControllerContext.HttpContext.Request.Cookies["_culture"];
}
...

HttpContext.Current.User.IsInRole not working

in my controller AuthController/signin i have this code:
entities.UserAccount user = (new BLL.GestionUserAccount()).authentifier(email, password);
//storing the userId in a cookie
string roles = (new BLL.GestionUserAccount()).GetUserRoles(user.IdUser);
// Initialize FormsAuthentication, for what it's worth
FormsAuthentication.Initialize();
//
FormsAuthentication.SetAuthCookie(user.IdUser.ToString(), false);
FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(
1, // Ticket version
user.IdUser.ToString(), // Username associated with ticket
DateTime.Now, // Date/time issued
DateTime.Now.AddMinutes(30), // Date/time to expire
true, // "true" for a persistent user cookie
roles, // User-data, in this case the roles
FormsAuthentication.FormsCookiePath);// Path cookie valid for
// Encrypt the cookie using the machine key for secure transport
string hash = FormsAuthentication.Encrypt(ticket);
HttpCookie cookie = new HttpCookie(
FormsAuthentication.FormsCookieName, // Name of auth cookie
hash); // Hashed ticket
// Get the stored user-data, in this case, our roles
// Set the cookie's expiration time to the tickets expiration time
if (ticket.IsPersistent) cookie.Expires = ticket.Expiration;
// Add the cookie to the list for outgoing response
Response.Cookies.Add(cookie);
return RedirectToAction("index", "Home");
in the master page i have a menu ,in that menu there is an item that is meant to be seen only by admin role.
<% if (HttpContext.Current.User.IsInRole("admin")){ %>
<%=Html.ActionLink("Places", "Places", "Places")%>
<%} %>
even with HttpContext.Current.User conatining the right roles,i can't see the item:
globalx asax:
protected void Application_AuthenticateRequest(Object sender, EventArgs e)
{
if (HttpContext.Current.User != null)
{
if (HttpContext.Current.User.Identity.IsAuthenticated)
{
if (HttpContext.Current.User.Identity is FormsIdentity)
{
FormsIdentity id =
(FormsIdentity)HttpContext.Current.User.Identity;
FormsAuthenticationTicket ticket = id.Ticket;
// Get the stored user-data, in this case, our roles
string userData = ticket.UserData;
string[] roles = userData.Split(',');
HttpContext.Current.User = new GenericPrincipal(id, roles);
}
}
}
}
Instead of using User.IsInRole(), try the static method Roles.IsUserInRole().
I know it sounds silly but from your image I can only see your userData from your ticket.
The only thing I can think if is if the userData is not going into the principal. (Possibly a problem with the last three lines of glabal.asax.cs)
Something is wrong here:
string userData = ticket.UserData;
string[] roles = userData.Split(',');
HttpContext.Current.User = new GenericPrincipal(id, roles);
You will need a custom Authorize attribute which will parse the user data portion of the authentication ticket and manually create the IPrincipal. Take a look at this post which illustrates the way I would recommend you to do this in ASP.NET MVC. Never use HttpContext.Current in an ASP.NET MVC application. Not even in your views. Use <% if (User.IsInRole("admin")) { %> instead.
One statement is missing.
After this line:
FormsAuthenticationTicket ticket = id.Ticket;
You need to put this line:
ticket = FormsAuthentication.Decrypt(ticket.Name);
In global.asax assign principal on 2 objects like that:
private static void SetPrincipal(IPrincipal principal)
{
Thread.CurrentPrincipal = principal;
if (HttpContext.Current != null)
{
HttpContext.Current.User = principal;
}
}
I found it here ASP.NET documentation

Asp.Net MVC FormsAuthenticationTicket

Im setting FormsAuthenticationTicket in the Logon method to manually create an authentication cookie. How do I validate that authentication cookie and assign it the Current.User object. Is it done in the Global.asax page?
Logon code:
FormsAuthenticationTicket Authticket = new
FormsAuthenticationTicket(1,
model.UserName,
DateTime.Now,
DateTime.Now.AddYears(1),
true,
"",
FormsAuthentication.FormsCookiePath);
string hash = FormsAuthentication.Encrypt(Authticket);
HttpCookie Authcookie = new HttpCookie(FormsAuthentication.FormsCookieName, hash);
if (Authticket.IsPersistent) Authcookie.Expires = Authticket.Expiration;
Response.Cookies.Add(Authcookie);
if (!String.IsNullOrEmpty(returnUrl))
{
return Redirect(returnUrl);
}
return RedirectToAction("Index", "Home");
How do i read this cookie and validate the user?
my code so far in the global.asax file:
HttpCookie authCookie = Request.Cookies[FormsAuthentication.FormsCookieName];
if (authCookie != null)
{
FormsAuthenticationTicket authTicket = FormsAuthentication.Decrypt(authCookie.Value);
FormsIdentity id = new FormsIdentity(authTicket);
GenericPrincipal principal = new GenericPrincipal(id,null);
Context.User = principal;
}
I moved this type of code into a base controller. There is a method called "OnAuthorization" in the Controller class that can be overridden.
It's been a little while, but I believe all requests (images, css... etc) where going through the OnAuthorization method in the Global.asax. By pushing the authorization down to the controller you are only getting the request to your controller/actions

Resources