asp.net forms authentication Global.asax and ajax calls - asp.net

I'm using forms authentication in my current asp.net web forms application "not MVC" and wondering if Global.asax [Application_AuthenticateRequest] and [Application_PostAuthenticateRequest] invoked on every request to the server or Not? i mean does ajax calls count for Global.asax handling or some bugs might occur! because i found in this link conflict:
http://channel9.msdn.com/forums/TechOff/256322-Strangeness-between-ASPNET-AJAX-and-Globalasax/
so please advice if its good or bad to handle custom authentication for ajax calls through Global.asax
thanks,

AJAX calls back to your application are just the same as hitting the site with the browser so yes these events will be fired.
The article you link to concerns the scenario where you have more than one request made within the same session.
http://msdn.microsoft.com/en-us/library/ms178581.aspx
Access to ASP.NET session state is
exclusive per session, which means
that if two different users make
concurrent requests, access to each
separate session is granted
concurrently. However, if two
concurrent requests are made for the
same session (by using the same
SessionID value), the first request
gets exclusive access to the session
information. The second request
executes only after the first request
is finished.
So if you made two requests back to your application from ajax code running in the browser they would be executed one after the other, not in parallel.
There is no way to turn this feature off.
In ASP.NET MVC3 it is possible to create sessionless controllers that do permit multiple ajax requests in the same session to be serviced at the same time by decorating the controller with this attribute:
[SessionState(SessionStateBehavior.Disabled)]

Related

Access all ongoing ASP.NET Session States

What we have is an ASP.NET web app that also does some signalR notifications. Since SignalR cannot access ASP.NET session states we need some other way to validate they are a client logged in on the web app.
In most situations you would think a static dictionary would help. As long as one of the ASP.NET Controllers made sure to keep a cache of key client info (via IP/browser info, or some generated token the client send up to signalR later) -- as long as this was done, then SignalR could validate the client connection before adding it to its pool.
However we are working in a server-farm situation, with SessionState backed by SQL. What this means is that a given server instance, even if it had a static cache of all its clients, may not know about Client C. Of course if Client C made a normal web request, it would find out about Client C when it fetched the SessionState. So the question is, IF work is handed over to a second server instance (Machine B) at just the right/wrong time, where Machine B does not know about client C (except via a context-dependent SessionState fetch, inaccessible from SignalR), HOW could we validate the client on the SignalR side?
All it would require is for some static means of getting ALL clients, OR, simply a "static" context for SessionState (i.e. a server-Session State). Because either way, we could sift through the individual client SessionStates and validate "yes, this client had a session state on a previous machine".
Is there any other way than for the client to reload the page, so that ASP.NEt can "cache up" its info locally? That is the only way I see so far.
I think it's a perfect scenario for "SignalR Backplane", it's designed for a webfarm situation to Scaleout SignalR. Lots of articles available, please search.

Lifetime and multiple use of an AntiForgeryToken?

I'm trying to implement antiforgerytokens to an angular application's ajax requests.
Is there a lifetime attached with the antiforgerytoken? If I have the app open for a long while in a web browser whithout touching it, say for a month. Will the ajax requests fail due to a stale token?
Can the token be reused for multiple calls? Can I keep one token somewhere in the page and retrieve it for all ajax calls?
Indeed API are supposed to be consumed by 3rd parties, but what's regarding Single Page interfaces with AFT?
I'm concerned they still require AFT in order to prevent CSRF atacks. And here is a good way to use them in Ajax requests.
Antiforgery token is generated per Session, and remains in session data till it's expired. For new session new token will be generated. And yes, single token can be reused multiple times within the same session.
Please check the link I've added, there is example of how token might be obtained for Ajax requests.
Will the ajax requests fail due to a stale token? Yes
Can the token be reused for multiple calls? No
However, the better question to ask yourself is why are you using antiforgery tokens with AJAX in the first place. If you're using AJAX, you're using an API, even if you haven't formalized it as such (just a collection of actions/controllers that are using for AJAX/other headless communication). Antiforgery tokens don't work well with APIs because 1) APIs typically allow third-party access and 2) even if they don't, there's better ways to secure them.
If you want to ensure that only your site can access your "API", then implement HTTP authentication or some other scheme to authenticate your requests to your "API". That is how you allow long running sessions that will not fail.

add asp.net pages to an asp classic website

I have an asp classic web site and I want to add some new code. I would want to begin to code with .net. Is there an easy way of doing this.
I was thinking an iframe that call my .net pages, but how will I share my user that need to be logged in my asp classic web site.
If I would use an iframe, what would be the best technique to share my user. I was thinking of passing the crypted info in query: test.com?users=[mycrypteduser]. But how would I encrypt it?
I'm pretty sure you can mix aspx and asp files in a single web project. So, create web-proj, then drop your existing website files to it (from within VS). Then, slowly start to refactor your existing site to aspx, as you can, page by page, and create new pages as aspx, of course.
Using IFRAME over this approach will be a lot more work that one may anticipate. But, regardless, you're hitting the problem of 2 unrelated websites in the need to trust each other authenticated sessions - and, this is primarily solved by those websites communicating such information to each other in the background, without the direct involvement of the browser. You need to be able to change the code at both sites (so, you must own both sites). So, if you want to go that route, typically it'd be done this way:
User logs in to your asp site
Your ASP site calls a webservice at your ASP.NET site and informs it that the user will be coming with a particular one-time auth-token in query and that it should be trusted. The emphases here are: the webservice must be well protected by authentication mechanism (otherwise you're risking a huge security issue); the auth-token mentioned should expire after it's used once and only once (otherwise, you're opening your asp.net site for abuse). Typically, your ASP app would call a service at ASP.NET with a signature like this: string GetAuthToken(string username). ASP.NET app should store this info as a record in a database: username, some random and unique string value (e.g. guid), create time (with the precision of at least a second), and time used.
Your ASP app receives a one-time auth token from ASP.NET app.
Your ASP app would need to include this token into the URL used on the frame to a page at ASP.NET site.
Your ASP app would then serve the page with a frame to the browser.
The browser starts displaying the page, then it gets to displaying the frame to external asp.net page
The browser requests the asp.net url, which contains the auth-token
ASP.NET site receives the request and it assumes that the auth token is present and valid; otherwise, exception. Valid token is: never used (time-used in db mentioned in step 2), and valid (its existence in db). As the receiving page validates this token, it immediately checks it off as used. It's the best to put this logic as one atomic operation (e.g. a stored procedure, if you're using MS SQL Server). This way, you can execute both get-token and mark-token-used in a single step. This URL must be anonymous; you must have forms-auth on this site anyways, and this particular handler should be reachable by anon user. If you dislike making that exception, then maybe create an HttpModule, which would inspect every request, and act only on those that are anonymous and are containing the auth-token (by validating the token, and then, as appropriate, interrupting the request or letting it execute); this way, your framed page doesn't have to care about authentication, but it must be forms-auth protected also. I personally would do this that way (http module). Also, if you're sure that relatively short period of time will pass between step 1 and step 2 here (e.g. few seconds max), then do include token expiration in your token-validation logic (validation time must not be later than token-create-time + some number of seconds, e.g. 30) - just for extra security. Otherwise, if you don't implement expiration - imagine a user logging in today, which generates this never-expiring token, and a malicious user somehow getting a hold of the token string. Then, if the authenticated user never visited the page with the asp.net frame, then the token would be usable days, months, years from the moment it's issued, even after the real user closed their account. You don't want this risk. If the login page doesn't redirect to the page with the frame, then make the service call from that page instead (once per session). Ideally, the token should expire 30 seconds or so max after it's created.
If the token is valid, the part of your ASP.NET app that is validating the token would then be responsible for issuing forms-auth cookie. You'll find a ton of examples out there; keywords: FormsAuthentication, create cookie, authenticate user. Make sure that besides inserting the cookie into the response (which is done by default by FormsAuthentication module), you also set the identity of that current/particular request immediately, as until you do, your request is still considered anonymous. If you don't do that (and people do this, but I don't think it's necessary), you will have to redirect that request (which would force the browser to send up the auth-cookie that it just received in the 302 response).
Finally, your framed page receives an ok that the user checks out and that they may view the content that that page generates. Your page streams HTML down to the browser, and the browser shows that content in the frame.
Note that you will not be able to have any sort of client-side scripting (javascript) going on between the page and the frame (security reasons), and that would be another way why I'd rather mix asp with asp.net files (and slowly upgrading the asp part to asp.net), provided that makes sense in other business-related aspects.
Beware of shared-hosting issues related to outbound requests. Some hosts block all outbound traffic; so, if your asp app is in such environment, you won't be able to make that webservice call to asp.net. If you have the asp app making other/unrelated http calls across the internet (e.g. it talks to 3rd-party web services), you're good (it'll work); otherwise, do test this somehow, as you can never be sure. Also, even if your site runs in your own environment, companies often have outbound firewalls in place, so, you might have to request an exception for this.
Remember that the page-refresh will not be an issue, and you do not need to make the get-token call more then once per authenticated session. This is because the browser will, after the first frame load, have an auth-cookie from asp.net site, and the token (even if present in subsequent frame url), will not be validated (remember, the module validates token on anonymous session only; see step 8).
Do think about adjusting cookie expiration settings between the 2 sites. Imagine asp.net auth cookie expiring before the asp auth cookie expires: user reloads the page, and the iframe shows the login page on asp.net - ugly. So, your asp.net auth cookie should probably be set up to expire longer than asp auth cookie (however long you set it as, you won't fix the problem, as it's either wrong to set the cookie to not expire for extremely long time, e.g. 7 days, or it's theoretically possible that a user of your asp site will sit through all that time without touching the page with the frame after they saw it once, and your asp.net cookie will expire). So, do something like this maybe: set asp.net auth cookie to expire in 20/30 minutes (one of those is the default timeout value). Then, have asp app be aware of this timeout value. So, correction to my previous statement of one get-taken call per session. Instead, have the asp call the get-token service every time that you know the asp.net cookie already expired or might expiring soon. In other words, keep track of when you made the last get-token call for each user, and if 15 min (for example, where asp.net cookie expires in 20) has passed since last get-token call, make it again, change the frame url, and the frame will be authenticated once the existing asp.net cookie expires (which would be approx 5 min from that moment, in this example).
I keep coming back to edit this answer :) So, cookie expiration problem - assuming asp.net cookie expires in 20 min, and I told you to set the url on the frame every 15 min, while I also told you to make the token expire in 30 sec - so, those 2 things are conflicting. Hm, I wonder what's the best solution here... Maybe set the get-token to happen closer to asp.net cookie expiration (as in, e.g, at 18 min, but still less than 20), and set the token to be valid for, I don't know, 3 minutes). This would result in 18 + 3 = 21 to overlap the asp.net cookie expiration. All this because the user already has asp.net cookie. So, 18 min after that first cookie was issued, they visit the page with the frame, and the page decides to get another token. This starts token-ticker on asp.net site, and it sets the iframe url with new token. But, since existing asp.net cookie is still valid, the new token will not even be validated (remember the module only validating anon requests with token? Otherwise, you'll have too many db hits if you do it on every request), so the new token will not be used immediately. Eventually, asp.net cookie will expire (in 2 min), and the new token will be validated. If this is a problem (if I omitted some use case that essentially results in the login page displayed within the frame), then maybe you can implement some other mechanism to keep these cookies in place: maybe add code to the login page at asp.net to look for the token in ReturnUrl (decode, then load into NameValueCollection, then look for it as a normal querystring lookup), and maybe communicate back to the asp site something that would signal it to re-request the token when the frame comes back (and what I mean by this, redirect the framed login page, in this case only, back to a special asp script at asp site, which would re-request the token, and then redirect the frame back to asp.net with new token.
I told you it'd be a lot of work. Perhaps there is a standard that involves all this. Check out OAuth (http://oauth.net/) and OpenID (http://openid.net/); those methods are similar to what StackOverflow is offering as login alternate to SO accounts (Google, Yahoo, etc). However, that implies that you actually send the user to the asp.net site to login, then come back to the page that displays content from asp.net site. Perhaps you can combine this with the webservice call that I suggested (get-token ws, redirect top window with token in url to asp.net, asp.net will authenticate and redirect back, then page with frame will display). However, you still have the cookie expiration problem, as you need to constantly be able to get content from asp.net site (whereas, StackOverflow, for example, talks to Google on my behalf only once, during login, and never again during the session), but instead of that messy iframe redirect path that I send you, maybe you can simply repeat the login-to-asp.net-site routine every 15 min (get token, redirect there, validate token, redirect back). If you do this every 15 min at the whole asp site level, you should be fine - and, the user won't even notice this in most cases, as those redirects will be quick.
I'm sorry if this is a difficult read. I hope it helps, though. +1 if it does :)
You can create a new ASP.NET web application, and pull all of your classic ASP pages. Then when you deploy, the ASP.NET web application will overlay your classic ASP.
If you are using some sort of integrated authentication, both the ASP and ASP.NET pages will have access to the same identity. If you created your own authentication layer in the ASP application, you will need to recreate this in ASP.NET (for example, create classes that read/write the same authentication cookies that the ASP pages are using).
However, long term this will introduce some development friction switching between ASP and ASP.NET all the time, so I would really only suggest this approach if you are planning to incrementally convert your entire application from classic ASP to ASP.NET.
You can use NSession http://nsession.codeplex.com/ an open source project with objective to allow ASP Classic to access ASP.NET out-of-process session stores in the same way that ASP.NET accesses them, and thus share the session state with ASP.NET.
I have tried it out and it really works.
Happy Coding!!
When i face this issue, i have found the best solution is usually to use .NET as a web service, and use HTTPRequests in the ASP page to pull the data into your ASP page.
When sharing sessions with ASP and Classic ASP, the most common way is to NOT USE SESSIONS IN ASP, and Use Cookies, Database Cookies actually for the actual session verification, by GUID usually.

Where in the Web Forms lifecycle can I re-authenticate a user?

Here's the situation - Most of this ASP.NET Web Forms application (which uses a single master page for all pages) with Forms Authentication, has a standard session timeout, but there are some "modes" where we store an encoded cookie that links the user to their account.
I would like to manually check early on in the page lifecycle for the cookie, and if certain conditions are met, manually re-establish the user's authentication ticket/session.
Where's the best place to do this? Master page Page_Init? Global.asax BeginRequest?
An HttpModule would be the best place.
BeginRequest is probably the right place (either in Global.asax or in a custom HttpModule), since from your description it sounds like it should run before AuthenticateRequest, which is the next event in the life cycle.
If you wait until Page_Init, or any other events associated with the Page, the authentication step in the life cycle has already happened.

Does jQuery's $.ajax() function handle ASP.NET authentication correctly?

I have a web app protected by ASP.NET Forms Authentication. The site uses jQuery's $.ajax() functionality to call a web service in the same app.
Browsing to the web service .asmx does cause forms authentication to kick in and I once authenticated and make a $.ajax() call to the server I also see the ASP.NET session cookie and forms auth cookie being posted back to the server in Fiddler.
So...although all appears to be well, I'd like to put my mind at rest that indeed the web service will be protected by ASP.NET forms authentication when called from any of the pages in the web app using $.ajax().
From the server's perspective, an ajax request is not very different from normal GET/POST request - just some extra headers added on in the request. It passes through your normal authentication routine, the same as any other request - if that was not the case, you should be much more worried about the overall security of your application as requests can be forged very easily by people who know what they are doing.
You can easily setup a test to see if a resource requiring authentication successfully blocks out unauthorized requests arriving by Ajax. That should put your mind at ease.
As long as your checking on the server that the user is authenticated then yes you should be protected. I am using $ajax to call both PageMethods and to call an ASP.Net WCF service, and things look good.
It'll be protected, but watch out for what happens when your auth expires and the forms auth redirects back to the login url with a 302 FOUND response.

Resources