I want to allow admins to be logged in for longer than normal users. I don't see a hook for setting the cookie timeout programmatically or in a role-based way. Is this possible in ASP using Forms Authentication?
Yes, you could do that. You would need to generate the authentication ticket manually instead of letting the framework generate it automatically.
Depending the user role, the expiration you assign to the ticket.
This tutorial show how to generate the ticket manually.
SNIPPET:
switch Role:
Case A: VARIABLE X = Y; BREAK;
CASE B: VARIABLE X = Y2; BREAK;
..
End switch
FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(
1, // Ticket version
Username.Value, // Username associated with ticket
DateTime.Now, // Date/time issued
DateTime.Now.AddMinutes(VARIABLE X), // Date/time to expire
true, // "true" for a persistent user cookie
reader.GetString(0), // 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
// Set the cookie's expiration time to the tickets expiration time
if (ticket.IsPersistent) cookie.Expires = ticket.Expiration;
Response.Cookies.Add(cookie);
Related
I am working on permanent login in MVC.net application, i have tried using IsPersistent = true in FormAuthantication, but if i restart iis then it logs out the uses
below is the code which is responsible for loging in.
public void SetLoginData(UserLoginInfo userLoginInfo)
{
HttpContext .Current.Session[SessionUserEmailIdKey] = userLoginInfo.Email;
HttpContext.Current.Session[SessionWelcomeNameKey] = userLoginInfo.FirstName;
HttpContext.Current.Session[SessionWelcomeRegistrationIdKey] = userLoginInfo.RegistrationId;
HttpContext.Current.Session[SessionLoginInfoKey] = userLoginInfo;
const bool isPersistent = true;
const string userData = "user";
var ticket = new FormsAuthenticationTicket(1,
userLoginInfo.RegistrationId.ToString(
CultureInfo.InvariantCulture),
DateTime.UtcNow,
DateTime.UtcNow.AddMinutes(180),
isPersistent,
userData,
FormsAuthentication.FormsCookiePath);
string encTicket = FormsAuthentication.Encrypt(ticket);
HttpContext.Current.Request.Cookies.Add(new HttpCookie(FormsAuthentication.FormsCookieName, encTicket));
HttpContext.Current.Response.Cookies.Add(new HttpCookie(FormsAuthentication.FormsCookieName, encTicket));
}
please tell me how can i implement login so that even though app restarts, users will not e logged out.
In order to create perpetual logins, you will need to make sure two things are in place (since you are using FormsAuthentication).
First - ensure your ticket expiration time is set to sometime way out in the future
= new FormsAuthenticationTicket(1,
userLoginInfo.RegistrationId.ToString(CultureInfo.InvariantCulture),
DateTime.UtcNow,
DateTime.UtcNow.AddYears(20),
isPersistent,
userData,
FormsAuthentication.FormsCookiePath);
Second (and most likely why users are getting kicked out of the site when you reboot IIS) is to create a machineKey section in your web.config with a static key pair set. By default, IIS autogenerates a machineKey per app. This is what is used to encrypt/decrypt your forms authentication tickets. If IIS restarts, you will most likely get a new machine key in this instance, which means that the ticket cannot be decrypted.... meaning user has to log in again. By creating/defining a static key, you can prevent a key change when IIS recycles. Information on setting the machine key can be found on MSDN here.
Lastly, forms authentication has ZERO to do with sessions and session management. They are mutually exclusive and do not impact each other in typical scenarios. When a user logs in, they are given an encrypted cookie containing the expiration time and user name. This is NOT stored in session, so adjusting session settings will have no impact on user logins.
I create some cookies in logon.aspx.cscodebehind thatc read and contain user info from DB with data reader .
HttpCookie UID = new HttpCookie("ID");
Response.Cookies["UID"].Value = Recordset[0].ToString();
Response.Cookies.Add(UID);
HttpCookie UName = new HttpCookie("Username");
Response.Cookies["Username"].Value = Recordset[3].ToString();
Response.Cookies.Add(UName);
HttpCookie Pass = new HttpCookie("Pass");
Response.Cookies["Pass"].Value = Recordset[4].ToString();
Response.Cookies.Add(Pass);
HttpCookie Admins = new HttpCookie("Admin");
Response.Cookies["Admin"].Value = Recordset[12].ToString();
Response.Cookies.Add(Admins);
HttpCookie Mails = new HttpCookie("Emails");
Response.Cookies["Emails"].Value = Recordset[9].ToString();
Response.Cookies.Add(Mails);
Response.Redirect("../default.aspx");
when i trace the code every thing is good and data hold by cookies.
Now when i read these cookies in master page or other content page, i can't.
in other worlds the cookies not recognize by their names(or keys)
if (Request.Cookies["Username"] !=null)
{
lblWelcomeUser.Text = Server.HtmlEncode(Request.Cookies["Username"].Value);
pnlUsersNavigation.Visible = true;
LoginMenu.Visible = false;
RegisterMenu.Visible = false;
lblWelcomeUser.Text = Server.HtmlEncode(Request.Cookies["Username"].Value);
//lblWelcomeUser.Text = Request.Cookies["Username"].Value.ToString();
if (Request.Cookies["Admin"].Value.ToString()=="True")
{
lblWelcomeUser.Text = "WELCOME ADMIN";
// Show Menu that is only for Admin
}
where is the problem in this code?
It appears that you might be overwriting the cookie with a good value, with a new empty cookie.
// new cookie created - empty
HttpCookie UName = new HttpCookie("Username");
// new cookie created with a value
Response.Cookies["Username"].Value = Recordset[3].ToString();
// overwrite new cookie with value with new empty cookie
Response.Cookies.Add(UName);
Create the cookie, set the value, then add the cookie to the response.
HttpCookie UName = new HttpCookie("Username");
UName.Value = Recordset[3].ToString();
Response.Cookies.Add(UName);
Also note that as Paul Grimshaw pointed out, you can add multiple values to the same cookie.
Download Fiddler to check request/response to ensure your cookies contain the correct values and such... http://fiddler2.com/get-fiddler
Also be careful about Man-in-the-middle attacks. Storing usernames and passwords in plain text is not such a good idea to begin with.
This doesn't look like a very secure way of securing access to your application. Try looking at ASP.NET membership.
Otherwise try setting an expiry date. Also, as this example shows, you may want to store all the above info in one cookie:
HttpCookie myCookie = new HttpCookie("UserSettings");
myCookie["UID"] = Recordset[0].ToString();
myCookie["Username"] = Recordset[3].ToString();
//...etc...
myCookie.Expires = DateTime.Now.AddDays(1);
Response.Cookies.Add(myCookie);
Also, from MSDN:
By default, cookies are shared by all pages that are in the same
domain, but you can limit cookies to specific subfolders in a Web site
by setting their Path property. To allow a cookie to be retrieved by
all pages in all folders of your application, set it from a page that
is in the root folder of your application and do not set the Path
property. If you do not specify an expiration limit for the cookie,
the cookie is not persisted to the client computer and it expires when
the user session expires. Cookies can store values only of type
String. You must convert any non-string values to strings before you
can store them in a cookie. For many data types, calling the ToString
method is sufficient. For more information, see the ToString method
for the data type you wish to persist.
When a valid user logs into the system and closes the browser without logging out, it occasionally (i.e. not immediately after but in the next day) prevents the user to login back into the system throwing the following:
Error: 403 - Forbidden: Access is denied. You do not have permission to view this directory or page using the credentials that you supplied.
This question refers to the same problem but in his solution, he decided not to use persistent cookies by passing false as a parameter when creating the FormsAuthenticationTicket, which is not the desired solution.
This is how I am creating the cookie:
private void createCookie(string username, int customerID, bool persist)
{
HttpCookie cookie = FormsAuthentication.GetAuthCookie(username, persist);
cookie.Expires = DateTime.Now.AddHours(12);
var ticket = FormsAuthentication.Decrypt(cookie.Value);
var userData = customerID.ToString();
var newTicket = new FormsAuthenticationTicket(ticket.Version, ticket.Name, ticket.IssueDate, ticket.Expiration, ticket.IsPersistent, userData);
cookie.Value = FormsAuthentication.Encrypt(newTicket);
Response.Cookies.Add(cookie);
}
Any ideas on how to solve this?
When a valid user logs into the system and closes the browser without
logging out, it occasionally (i.e. not immediately after but in the
next day) prevents the user to login back into the system...
I could be dense but isn't the code working like the way you implemented it?
Namely, in createCookie(): you specify cookie.Expires = DateTime.Now.AddHours(12);, which marks the cookie to expire 12 hours after it is issued.
In Asp.net 1.0, if FormsAuthenticationTicket.IsPersistent is set, the ticket will automatically have a valid duration of 50 years from the time issued.
However in Asp.net 2.0 this is no longer the case. If FormsAuthenticationTicket.IsPersistent is set to false, the ticket will have a valid duration identical to the Session timeout period. If FormsAuthenticationTicket.IsPersistent is set to true, the valid duration will default to the Forms Authentication timeout attribute. You have the expiration time set to issue time plus 12 hours, so I would expect the ticket to stop working after 12 hours. Assuming you are using Asp.net 2.0+, hopefully this should explain the hehavior your are seeing. I would suggest try increasing the expiration time to a longer duration and see if the problem goes away.
There is no inherent problem with including your own userData in the auth cookie.
In one of our websites we use the asp.net login control, and add the following event listener with much success:
protected void Login1_LoggedIn(object sender, EventArgs e)
{
//... unimportant code left out
//Update the users ticket with custom userInfo object
string userData = userInfo.Id.ToString("N");
HttpCookie cookie = Response.Cookies.Get(FormsAuthentication.FormsCookieName);
FormsAuthenticationTicket oldTicket = FormsAuthentication.Decrypt(cookie.Value);
FormsAuthenticationTicket newTicket =
new FormsAuthenticationTicket(
oldTicket.Version,
oldTicket.Name,
oldTicket.IssueDate,
oldTicket.Expiration,
oldTicket.IsPersistent,
userData,
oldTicket.CookiePath);
cookie.Value = FormsAuthentication.Encrypt(newTicket);
}
I have the form authentication work fine with expiry 3 months cookie setting:
FormsAuthentication.Initialize();
FormsAuthenticationTicket authTicket = new FormsAuthenticationTicket(1, this.txtUsername.Text, DateTime.Now
, DateTime.Now.AddMonths(3), true, string.Empty);
so even if IIS restarted or project rebuild occur the user still authenitaced until he choose to log out our 3 months passed.
as for the custom role provider [authorizing part] when the user login isValid() i add session variable:
HttpContext.Current.Session.Add("userinfo", userInfo);
but as we know the session expire after web.config change, project build, IIS reboot or 20 mins passed by default.
all what I want is to make the system save Session["userinfo"] same as authentication [cookie] do but ofcourse without setting userinfo in cookie because that's not secure even the userId is considered security breach to be stored in cookie!
so how to accomplish that? i thought to store the user id in cookie but encrypted then if i found session expired but user still authenticated I'll reload the userInfo from DB but is that good enough or better approach available? and what about storing userInfo in authTicked in (string.Empty) in above code segment, is at accessible later and how to use it?
ok, sounds no body responded! so i choose to store the userId in the user-data section of the auth ticket:
FormsAuthenticationTicket authTicket = new FormsAuthenticationTicket(1, this.txtUsername.Text, DateTime.Now
, DateTime.Now.AddMonths(3), true, UserInfo.UserId.ToString());
then when I need to check the userInfo I use the following property:
public UserInformation UserInfo
{
get
{
if (Session["userinfo"] == null)
{
FormsIdentity id = (FormsIdentity)User.Identity;
FormsAuthenticationTicket ticket = id.Ticket;
long userId = Convert.ToInt64(ticket.UserData);
Session["userinfo"]=new MySqlMembershipProvider().LoadUserInfo(userId);
}
return (UserInformation)Session["userinfo"];
}
}
that's all. i thought of profile provider but i didn't like the idea of fetching the user permissions from db [9 tables structure] then re-store them under on record in sessions tables [its like circulating around yourself] beside if user perms or prefs updated more db hits required!!
Is it possible to update an ASP.NET cookies value without also having to update the expiration time? I have found that if I try and update a Cookie without also updating the expiration, that cookie no longer exists. I have the following code which I am try to modify. What's the point of having an expiration, if every time the cookie value is updated, so is the expiration?
HttpCookie cookie = HttpContext.Current.Request.Cookies[constantCookie];
if (cookie == null)
cookie = new HttpCookie(constantCookie);
cookie.Expires = DateTime.Now.AddYears(1);
cookie.Value = openClose;
HttpContext.Current.Response.Cookies.Set(cookie);
The ASP.NET HttpCookie class can not initialize the Expires property upon reading in a cookie from an HTTP request (since the HTTP specification doesn't require the client to even send the Expiration value to the server in the first place). And if you don't set the Expires property before you set the cookie back in the HTTP Response, than it turns it into a session cookie instead of a persistent one.
If you really must keep the expiration, than you could set the initial expiration date as part of the cookie value, then when you read the cookie in, parse out the value and set the new expiration to match.
An example that doesn't include any other data so the cookie isn't really helpful -- you would have to serialize it somehow with the actual data you want to store:
HttpCookie cookie = HttpContext.Current.Request.Cookies[constantCookie];
DateTime expires = DateTime.Now.AddYears(1);
if (cookie == null) {
cookie = new HttpCookie(constantCookie);
} else {
// cookie.Value would have to be deserialized if it had real data
expires = DateTime.Parse(cookie.Value);
}
cookie.Expires = expires;
// save the original expiration back to the cookie value; if you want to store
// more than just that piece of data, you would have to serialize this with the
// actual data to store
cookie.Value = expires.ToString();
HttpContext.Current.Response.Cookies.Set(cookie);