I've put a custom authorize attribute into my MVC application, which does
if (!this.Roles.Split(',').Any(filterContext.HttpContext.User.IsInRole))
and if true it will redirect you to unauthorised.
I put this attribute on my controller at controller level.
One action works fine, and in one action I get unauthorised.
Is there some bug or problem in the role system? I've read that logging out and in can force some cache to refresh or something, however the system I am using authenticates with your domain credentials so there is no way to log out.
I've tried restarting the app pool and deleting my session cookie but nothing has worked.
Has anyone experienced this specific issue before or has some guidance on perhaps flushing any caching related to it (assuming it's a caching issue)?
ETA: Another user on the system gave himself the role required for the controller and both actions work fine for him. So perhaps my user is somehow bugged. This is on UAT so slightly more difficult to debug than running on my local machine (which works fine).
ETA2: I'm pretty sure this is a caching issue, as going to the URL with ?1=1 in the query string, it works. I'm unable to invalidate the cache though. This may be a problem in the future when assigning roles to people.
First, we need more code before we could possibly give you any definitive answers. However:
Caching could be a problem. If you're using anything like OutputCache, you should ensure that you're using VaryByCustom and somehow including the user's id or other identifying token in the custom string returned.
If you're adding roles to users, you must either log the user out and sign them back in, or otherwise invalidate their authorization. In Identity, for example, you can simply invalidate the security stamp, which will cause the user to be reauthorized, updating things like claims or roles that have changed since they signed in.
Related
I'm experiencing some trouble with an ASP.NET MVC 5 application that has been buggering me for a few days.
The application is using Forms Authentication to control whether a user is Authenticated, and Session to keep track of the user's data.
A few of our users are unable to log in, and I have been able to recreate the problem on a collegue's device. We don't know much about the devices with the problems, except that they all seem to be running iOS. I can't seem to nail down the pattern, though, as one user who reported the problem was running 11.2.5, which I am also running myself without trouble. The collegue's device is running 11.3 beta, but I haven't yet heard of any other users with this version, so I'm unable to pin point that as the problem - which also seems unlikely when one of the users with the problem is running 11.2.5.
The issue happens after the users try logging in. After a successful login, the user is redirected to a specific section of the site, where Authentication is required. Requesting any page in this section redirects you to the login page if you are not Authenticated.
Some of the resources that are requested on this page expect to retrieve some data from Session. For some reason, the Session cookie may sometimes be missing, and other times the Authorization cookie is missing.
For the past few days while I have been hunting this, my collegue's device happened to leave out the Session cookie when requesting our Cachemanifest, in which we expect to be able to generate a specific part based on some data from the Session. This caused the generation to fail, which in turn caused the request to fail.
After changing the generation logic to work around this, with a different solution if the Session cookie is missing, my collegue's device has changed its approach; Now, it includes the Session cookie when requesting this resource, but instead leaves out the Authorization cookie in a subsequent request to a different resource, which is still in the section that requires Authorization. This resource happens to be mentioned in the Cachemanifest, and because this next request does not include the Authorizaiton cookie, that request is redirected to the login page, which is interpreted by the Cachemanifest as an error.
As far as I recall, I haven't changed anything else, so I'm really at a loss as to why this devices' behaviour has changed.
Both of these cookies are included in other requests before and after the failing request, and there doesn't seem to be a pattern between what requests is chooses to leave these two cookies out of, or which cookies to leave out. The only thing that is consistent is that the behaviour doesn't change when retrying after clearing the browser data (only after I made my change, which I still don't see how could result in this behaviour).
The site is forcing HTTPS, so I tried setting the Session cookie to Secure, but that didn't seem to make a difference.
I still need to try setting the Authorization cookie to Secure, but I'm not very optimistic there. I also still need to try reverting my changes to see if the old behaviour reappears.
Has anybody experienced similar problems before, or does anybody have any further suggestions? I know I might be a bit sparse on the details, I'd be happy to provide any further details if I'm able.
Thank you in advance :)
I've got a ASP.NET MVC web app which uses forms authentication.
I'm using ActiveDirectoryMembershipProvider to validate users against our domain.
if (Membership.ValidateUser(m.Username, m.Password))
{
FormsAuthentication.SetAuthCookie(m.Username, true);
....
This means the user gets validated only when they log in.
Problem with that is ofcourse that if the user's password changes they still remain logged in. Or worse, user leaves our company with a grudge, and they still have access.
I would have thought such a simple use case would have an obvious answer but I've been stuck on this for a while now.
I could put the users password in the session and then validate it every time, but that doesn't feel right.
What is the suggested/correct way of handling this?
The typical solution is to force log out when users unsubscribes from the service or less commonly when they change password. Use this method:
FormsAuthentication.SignOut();
FormsAuthentication.RedirectToLoginPage();
If the user can be deactivated outside of the app (i.e. Active Directory), the typical practice is to rely on the session time-out and perhaps ask for the credentials once more for critical operations. If you absolutely cannot allow the deactivated user to work while the session is still active, then yes, you'll have to check the credentials on every request. Since storing the password in the app is a very bad idea, it means you'll have to ask for credentials on each request which arguably is an even worse idea.
As for the password change, it normally doesn't modify the user's permissions so it should be harmless to allow for them to continue working.
The answer is to periodically (every 30 minutes or so) check User.IsApproved and User.LastPasswordChangedDate to make sure the users credentials are still valid.
To do this you need to manually create the FormsAuthenticationTicket and cookie, rather than using FormsAuthentication.SetAuthCookie.
Put the date you validated the user inside UserData and compare this against LastPasswordChangedDate.
I've implemented this and it works perfectly.
More information here
Check if Active Directory password is different from cookie
Specifically, I have written a Rails app in which I'm using the default (in Rails 2.3.5) CookieStore session store and I've spotted an odd problem in development.
Myself and a few others had been using the site for a few weeks and we each had a login based on a username and password (each user registered themselves and I stored the (salted and hashed) data in the database). I was storing the user ID in the Rails session object (and, therefore, in the cookie that is passed back and forth between browser and server).
One important point here: since this is an intranet site, I set the cookies to stay alive for up to 2 weeks to avoid users having to log in all the time.
Today I reset the database, wiping all user records (and all other data, intentionally). A few users started registering themselves again and then one user found that the first time they went to the site since the wipe they were automatically logged-in as a different user!
I think I can see why this happened: the user ID passed from that user's browser to the server now matched a different user-record in my database. My initial thought was "oh dear, I wasn't expecting that!" but the more I thought about it the more I realised this was probably expected behaviour.
I realise I can change my Rails app to user ActiveRecordStore but before I did that I wanted to make sure I understand what's going on here. Specifically, does the combination of using CookieStore sessions and having the sessions stay alive for some time really create such a gaping security hole? Or am I missing something? Should the session_id be providing a little more security here?
The big security hole in this setup isn't the cookie length, it's setting the user_id in a cookie. This means that anyone who logs into your site can log in as anyone else just by changing that cookie! A hacker would just sequentially walk through user_id's, logging in and seeing if there's anything they want to steal or abuse.
If you want to roll your own authentication, try this instead: add a "token" string field to your user table. When somebody logs in, set this token to a random set of numbers and letters, and pass that as the cookie back to the user. The token should be at least 32 characaters, alphanumeric, upper and lower case.
Now when a user goes to a page, their account is looked up by that hash instead of their user_id. The value is that the hash is much harder to guess, and will never be repeated. Your user_id's were actually repeated when you reset the database, causing people to be logged in as each other.
UPDATE
#shingara is right that the cookie store does handle the security part already, my mistake. The user_id mixup is therefore a one-time occurrence because you reset the database. This is not a problem you'll face in a production environment, unless you reset the database again. If resetting is ever a possibility, then still do the token creation as I recommended. Otherwise, you're fine.
The simplest solution to the problem you had here would be to have changed the cookie name when you reset the database. The cookie name should be in config/initializers/session_store.rb
ActionController::Base.session = {
:key => '_your_app_session_v2',
You could also change the secret, but that may generate errors for your users if they request the site with an old cookie.
You case arrived only if you have 2 differents user with the same user_id. So it's not possible if you define the user_id like unique.
Another case, you can add in session, an hash with an unique key by user. when you check the session you get the user_id and check if the user_token is same . If not, the user is not authorized.
Thankyou for all the responses. They all answered my question in a way: yes, my setup (and my not setting a new session key after wiping the users) creates a security hole.
Lots of Rails tutorials advocate this setup without mentioning the fact that all you need is to monkey with your cookie to be fully authenticated as another user.
So, to summarise, I asked the question because I couldn't find anything discussing the danger of CookieStore session + long cookie lifetimes, and I found that surprising so thought I might be missing something obvious.
I had a similar issue and resolved it using a code snippet similar to
this comment by mdesantis on managing Rails secret token
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)
I'm trying to use forms.signout but sometimes it does not log out the user and he still can navegates through the website.
How can I resolve this? I also configured web.config forms authentication, but it's still not working.
I'm using FormsAuthentication to autenticate an user passing he's login.
Thanks!!
I don't know what the cause is but a few things you might consider/try
are they actually able to still visit pages generated by the server or are they just going back to locally cached versions? What happens when they cause a postback that has code to check if they are authenticated does that work or does it fail? I think the later meaning they are signed out but viewing cached versions of the logged in page in which case you want to instruct the client not to cache the pages using for instances:
Response.Cache.SetExpires(DateTime.UtcNow.AddMinutes(-1));
Response.Cache.SetCacheability(HttpCacheability.NoCache);
Response.Cache.SetNoStore();
You can try manually setting the cookie to be expired but this is a hack
FormsAuthentication.SignOut();
Context.Response.Cookies.Item(FormsAuthentication.FormsCookieName).Expires = Date.Now;
Response.Redirect("~/Somewhere.aspx");
Does the user have the domain (or a parent domain) in their trusted sites or intranet sites? I've run into some issues recently where a user is authenticated, but anonymous under circumstances where this is true. In my case it could also be that a parent site was, at one time, configured to allow windows integrated authentication. I've removed since removed that, but it didn't seem to help the problem. I haven't yet restarted IIS to see if this would have an effect. I've resorted to checking both that the user is authenticated and non-anonymous to ensure that the proper parts of the view are rendered. This is actually more accurate even though my login code should prevent having an anonymous login.