After searching a lot i did not get any answers and finally i had to get back to you. Below i am explaining my problem in detail. It's too long, so please don't quit reading. I have explained my problem in simple language.
I have been developing an asp.net mvc project.
I am using standard ASP.NET roles and membership.
Everything is working fine but the remember me functionality doesn't work at all.
I am listing all the details of work. Hope you guys can help me out solve this problem.
I simply need this:
I need user to login to web application. During login they can either login with remember me or without it.
If user logs in with remember me, i want browser to remember them for long time, let's say atleast one year or considerably long time. The way they do it in www.dotnetspider.com,www.codeproject.com,www.daniweb.com and many other sites.
If user logs in without remember me, then browser should allow access to website for some 20 -30 minutes and after that their session should expire. Their session should also expire when user logs in and shuts down the browser without logging out.
Note: I have succesfully implemented above functionality without using standard asp.net roles and membership by creating my own talbes for user and authenticating against my database table, setting cookie and sessions in my other projects. But for this project we starting from the beginning used standard asp.net roles and membership. We thought it will work and after everything was build at the time of testing it just didn't work. and now we cannot replace the existing functionality with standard asp.net roles and membership with my own custom user tables and all the stuff, you understand what i am taling about.
Either there is some kind of bug with standard asp.net roles and membership functionality or i have the whole concept of standard asp.net roles and membership wrong. i have stated what i want above. I think it's very simple and reasonable.
What i did
Login form with username,password and remember me field.
My setting in web.config:
<authentication mode="Forms">
<forms loginUrl="~/Account/LogOn" timeout="2880"/>
</authentication>
in My controller action, i have this:
FormsAuth.SignIn(userName, rememberMe);
public void SignIn(string userName, bool createPersistentCookie)
{
FormsAuthentication.SetAuthCookie(userName, createPersistentCookie);
}
Now the problems are following:
I have already stated in above section "I simply need this".
user can successfully log in to the system. Their session exists for as much minutes as specified in timeout value in web.config. I have also given a sample of my web.config. In my samplem if i set the timeout to 5 minutes,then user session expires after 5 minutes, that's ok. But if user closes the browser and reopen the browser, user can still enter the website without loggin in untill time specified in "timeout" has not passed out. The sliding expiration for timeout value is also working fine. Now if user logs in to the system with remember me checked, user session still expires after 5 minutes. This is not good behaviour, is it?. I mean to say that if user logs in to the system with remember me checked he should be remembered for a long time untill he doesn't logs out of the system or user doesn't manually deletes all the cookies from the browser. If user logs in to the system without remember me checked his session should expire after the timeout period values specified in web.config and also if users closes the browser. The problem is that if user closes the browser and reopens it he can still enter the website without logging in.
I search internet a lot on this topic, but i could not get the solution. In the blog post(http://weblogs.asp.net/scottgu/archive/2005/11/08/430011.aspx) made by Scott Gu on exactly the same topic. The users are complaining about the same thing in their comments ut there is no easy solution given in by Mr. Scott.
I read it at following places:
http://weblogs.asp.net/scottgu/archive/2005/11/08/430011.aspx
http://geekswithblogs.net/vivek/archive/2006/09/14/91191.aspx
I guess this is a problem of lot's of users. As seem from blog post made by Mr. Scott Gu.
Your help will be really appreciated.
Thanks in advance.
What you want to do is have a different timeout when the RememberMe option is checked, than when it is unchecked. Unfortunately, the SetAuthCookie method does not allow you to set the expiration manually, so you'll have to do that yourself.
The problem is then, how to do that?
ASP.NET MVC uses the FormsAuthentication class of System.Web.Security to do that, because it's not trivial if you also want to support the configuration settings and cookieless browsing and SSL, but I think that if you simply do this:
int timeout = rememberMe ? 525600 : 30; // 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 = System.DateTime.Now.AddMinutes(timeout);// Not my line
cookie.HttpOnly = true; // cookie not available in javascript.
Response.Cookies.Add(cookie);
...you'll get a basic version of what you need.
NOTE: I did not test this code.
Kevin and Dave,you guys rock, man.
Dave, in addition to your code i had to add one more line to make it work. I mean to make it remember for at least one year. I had to assign value to cookie.Expires in addition to your code to make it work. If this line cookie.Expires is not set the cookie is lost after computer restart i mean at the end of the session. I noticed this in FireFox. I Went through the details of cookie and i found: If cookie.Expires is not set then value for "Expires:" attribute in Firefox is "At the end of the session" but if cookie.Expires is set then the value for "Expires:" attribute in Firefox is to the datetime the cookie.Expires value was set.
Here is the code:
int timeout = createPersistentCookie ? 525600 : 2; // Timeout in minutes,525600 = 365 days
var ticket = new FormsAuthenticationTicket(userName,createPersistentCookie,timeout);
string encrypted = FormsAuthentication.Encrypt(ticket);
var cookie = new HttpCookie(FormsAuthentication.FormsCookieName, encrypted);
cookie.Expires = System.DateTime.Now.AddMinutes(timeout);//My Line
HttpContext.Current.Response.Cookies.Add(cookie);
Thank you guys, that was really a great solution.
Just a quick note about using membership auth ticket in a shared environment for anyone who may land here with that issue. I've got an mvc site runnig at godaddy and had trouble with remember me. This was the solution:
<system.web>
<machineKey
validationKey="4C6404A3B305CD6E8CFEAC258F042FB95E45E9C3C2CEC3AAB838996CFBE661E41DF1A1BAC75B9B45E02147612FD9B71CA74DDA50B0D0D6ED11F0BB8E31048953"
decryptionKey="BC471CF17A97B08A9DF85C7B502AD95680E3BE4418FD9C6CEA57E7F97ED64291"
validation="SHA1" decryption="AES"
/>
Thanks to :
http://www.geekfreeq.com/aspnet-remember-me-option-forms-authentication-not-working/
That's not a problem, it's a feature :)
The user's session hasn't expired yet so, even if they close and reopen the browser, the cookie is still good.
It's the cookie's expiration that invalidates the user's session.
I had implemented same thing and when i test it it works fine in Mozila but not working in IE8 for all pc, i also had updated setting to accept cookies in IE but still not working.
Internet Explorer 8.x
Click on the Tools-menu.
Select Internet Options in the menu - a new window opens.
Click on the Privacy tab near the top of the window.
Click on the Default button of the window.
Move the slider so that it is on one of the levels below Medium High (including Medium, Low, Accept All Cookies).
Save changes by clicking OK.
You should be able to add items to your shopping cart now.
Related
I had the same issue like this guy. Because I am lucky, his solution also worked for me.
But I think it's a bit dirty and I was wondering if there isn't a better one.
I've set up this configuration on IIS, but the cookies will always expire when the user closes her browser (if I don't use he "cookie hack")
Any Ideas?
EDIT: To clearify: It not the Server side session that is lost, it's only the "ASP.NET_SessionId" cookie lifetime, which is incorrect.
EDIT2: After some Research, I was wondering when the ASP.NET_SessionId cookie is actually set. If I delete it (using Firefox) and refreshing the page (even several times) a new one won't appear ... What's going on here?
EDIT3: I just found out, that the session id cookie will be set if I put something into the session, so that question (EDIT2) is off.
The session cookie will exire as soon as possible for security reasons. One should not extent it's lifetime due to session hijacking.
If you need "the old session back", then use ASP.NET authentication and generate a new session after the users comes back to the site. This will safe memory and also increase overall security.
Im using autologin on my MVC 3 website.
How do I best handle this problem:
A user signs in at his own computer (and gets a 30 day cookie)
Same user signs in at a friends computer (and gets a 30 day cookie)
Its now possible to autologin in at both computers. The user realizes this and changes his password but his friend is still able to autologin from his computer until the cookie expires.
How do I best handle this?
I could of course set at date on the user when password changed and check this up against the date in the cookie.
Or am I missing something?
I know what you're saying, but I think you're implying an association between the "remember me" function and the "password change" function which in practice, isn't there. The auth token you get when authenticating is not generally tied to the value of the password (i.e. when using the membership provider), after all, you're logically keeping the identity authenticated across sessions and in this regard, it works just fine.
To be honest, this sounds like more of a user behaviour problem than a technology problem. In your use case, someone is consciously asking the browser to allow them to remain authenticated for a long period of time and doing so on a machine which they have no control over. Of course I'm assuming you have a "remember me" checkbox and if you don't, there's your answer right there.
The other thing you might want to look at is what OWASP talks about in part 3 of the Top 10 - Broken authentication and session management. This link will put it in a .NET context for you but in short, it talks a lot about reducing the opportunity for exactly what you're describing to happen by things like eager session expiration, disabling sliding sessions and obviously giving end users the control to expire the token at session expiration and log out at any time.
Don't yo have Remember me checkbox on your login form. The value of this checkbox will dictate whether you are going to create persistent cookie or not. if you don't create persistent cookie, it will expire as soon as session ends. In this scenario you user can leave Remember me checkbox unchecked when logging in on his friends computer. If he doesn't he is calling for trouble himself.
We are attempting to integrate an ASP.NET MVC site with our client's SSO system using PingFederate. I would like to use the built in FormsAuthentication framework to do this. The way I've gone about it so far is:
Set up my Web.config so that my FormsAuthentication LoginURL goes to my site's "BeginAuthentication" action on a "Security" controller. From this action, I set up some session variables (what URL was being accessed, for example, since Ping won't send this info back to me), and then redirect to our client's login page on an external site (www.client.com/Login for example).
From here, the authentication takes place and a cookie is generated on the same domain as the one that our application is running on which contains the unique identifier of the authenticated user, I've set it up so that once this happens, the Ping server will redirect to my "EndAuthentication" action on my "Security" controller.
In this action, I call my membership class's "ValidateUser" method which takes this unique identifier from the cookie and loads in the user on our application that this ID refers to. I save that logged in user in our Session (Session["LoggedInAs"], for example) and expire the cookie that contains the id of the authenticated user that the SSO system provided for me.
All of this works well. The issue I'm wondering about is what happens after our user has already authenticated and manually goes back to our client's login page (www.client.com/login) and logs in as another user. If they do that, then the flow from #2 above to number 3 happens as normal - but since there already exists an authenticated user on our site, it seems as though the FormsAuthentication system doesn't bother kicking off anything so I don't get a chance to check for the cookie I'm looking for to login as this new user. What I'd like to do is, somewhere in my Global.asax file (probably FormsAuthenticate_OnAuthenticate), check to see if the cookie that the SSO system sends to me exists, and if so, sign out of the application using FormsAuthentication.SignOut().
Another issue that seems to be related is that if I let my Session expire, the FormsAuthentication still seems to think I am authenticated and it lets me access a page even though no currently logged in user exists in my Session, so the page doesn't render correctly. Should I tap into the Session_End event and do FormsAuthentication.SignOut() here as well?
Basically, I want to know when the authentication ticket created by
System.Web.Security.FormsAuthentication.SetAuthCookie(..) gets checked in the flow of a request so that I can determine whether I need to SignOut() and force revalidation or not.
Thanks for any help. Sorry for the length of this message, trying to be as detailed as possible.
Mustafa
Welcome to the small section of Hades that is mixing session with formsauth.
If your needs are as complex as presented, you would get more sleep if you implement a full provider stack to share amongst the participating sites. Easier said than done, I know.
But to address your question:
from http://www.codeproject.com/Articles/39026/Exploring-Web-config-system-web-httpModules.aspx
On the way in....Check ticket and set identity #
app.AuthenticateRequest += System.Web.Security.FormsAuthenticationModule.OnEnter-->OnAuthenticate
On the way out... set the ticket and redirect as necessary
app.EndRequest += System.Web.Security.FormsAuthenticationModule.OnLeave
Reflector is your friend. ;-)
I don't know about a specific event for when the cookie is checked, but you could place the appropriate logic in Application_BeginRequest() and check the user's authentication state there.
Another issue that seems to be related
is that if I let my Session expire,
the FormsAuthentication still seems to
think I am authenticated and it lets
me access a page even though no
currently logged in user exists in my
Session, so the page doesn't render
correctly.
The life of the cookie (how long until ASP.NET feels it needs to ask for a password again) and how you are managing state are unrelated. The ASP.NET authentication is cookie based so that, should a developer want to, he could turn off viewstate, session, use no query strings or hidden fields and authentication still works.
If you want to tie the interval at which you request the password to how you are persisting data, then you will want your session expiration to be roughly the same as the cookie expiration, but they will never quite match up. It would be better to have two policies (one for how fast you throw away a users session data and one for how long you are willing to wait before you need to reask for a password)
As a user, when I see a "remember me" checkbox, I expect it to remember me -- not just when I close my browser, but when I come back to the site after a week.
So in my ASP.NET MVC application I am considering the following web.config values:
<authentication mode="Forms">
<forms defaultUrl="/" loginUrl="/account/login" name=".ASPXAUTH" timeout="50000000" />
</authentication>
I plan to also have userIsOnlineTimeWindow="20" to still have decent stats about who is online. I also plan to setup a machineKey so that the user isn't kicked off when IIS recycles.
Thoughts on this setup? My biggest concern is that it will hog up resources -- but will it in a stateless MVC app? Isn't that actually related to the sessionState timeout variable as opposed to authentication timeout? And sessionState is no longer relevant in MVC? I've seen conflicting information and am trying to get to the bottom of it.
Also, if I take this approach, I assume that this should also take care of the user who fills out a form for a long time before hitting submit and they lose their work. I've seen posts related to that, but am trying to solve two problems at once (keep alive while viewing the page plus also keep alive for days if I said 'remember me'.
One issue I see is that even if the user doesn't say "remember me" it will still remember them until they close the browser. (To me that's within user expectations.) The other issue is that I may need to perform extra checks on IsApproved and IsLockedOut per http://scottonwriting.net/sowblog/posts/11167.aspx.
Thoughts? Particularly on the system resources issue. Thanks.
FormsAuthentication is stored as a cookie in the client's browser and will not use up any resources by itself. The timeout setting there does not change how long something will be kept in the server's memory or anything to do with the regular session storage.
If you rely solely on the user ID/name you get from FormsAuthentication (HttpContext.User) then yes, there will probably be issues with administering user accounts like you point out. It would be a good practice to look up the actual current user data once per request.
Using DotNetOpenAuth 3 in ASP.NET MVC and implementing a RememberMe facility ...
I'm finding that even if I set createPersistentCookie to true in FormsAuthentication.RedirectFromLoginPage and FormsAuthentication.SetAuthCookie the user is not remembered once the ASP.NET session times out.
If I inspect the cookie I find it is marked as persistent and does have an expiry date way in the future, I assume because I set my web.config FORMS timeout to a few years away. Anyhow, if the user closes the browser and re-opens it they are remembered correctly - as long as the ASP session hasn't timed out.
An older post of Scott Hanselmann's makes me wonder if it is because FormsAuthentication tries to renew the authentication ticket and maybe in an OpenId model that doesn't work but I have set FORMS SlidingExpiration="false" in web.config and anyway I thought that forcing a persistent cookie would make that stuff irrelevant.
I'm also wondering why the DotNetOpenId MVC sample doesn't include a RememberMe checkbox - maybe there's something tricky about it?
On the other hand, here at StackOverflow I see I am automatically remembered across sessions. Wondering whether they used something other than DotNetOpenId to do their OpenId authentication.
Anybody else done RememberMe successfully with DotNetOpenId in ASP.NET MVC? Any tricks?
[Update]
Thanks for trying to help, Andrew. Turns out this was not about DotNetOpenId.
I gather, after reading this, that my hosting provider is probably recycling the app pool regularly and that's causing the authentication ticket encryption to be done with a new machine key.
As per the preceding linked article I added the following under System.Web in my Web.Config and it resolved the issue:
<machineKey
validationKey="(generated a new key to place here)"
decryptionKey="(generated a new key to place here)"
validation="SHA1"
decryption="AES" />
I still think the cookie name should match... but here's something else.
It sounds like you're saying as long as your timeout in the web.config file is large, then things work. But that once you shorten it, your persistent cookie doesn't outlast the timeout value. This forum topic helped answer this for me:
http://forums.asp.net/p/1010241/1347970.aspx#1347970
It seems that the timeout in web.config affects all cookies. It says how long the authentication ticket lasts. All auth cookies have this 'time to live' timeout whether they are 'persistent' or not. So the difference between persistent cookies and non-persistent cookies are that the former will last across different browser sessions and the latter will die (early) if the browser is closed.
Does that make sense?
Does the cookie name match in your web.config file and your controller's call to FormsAuthentication.SetAuthCookie? This may be a bug in the DNOI sample, but I suspect if you have a cookie name in your web.config file (as the DNOI sample does), then you probably have to set the cookie name as the third parameter to SetAuthCookie or RedirectFromLoginPage. Otherwise, forms auth doesn't recognize the persistent cookie you set as the login cookie.