Extending Forms Authentication Timeout When Making AJAX Calls With jQuery - asp.net

I'm looking to rewrite a pretty intensive CRUD type ASP.NET page to utilize ajax calls (specifically jQuery ajax). My concern in doing this is that the user may be on this page longer than the forms authentication timeout. Because of this, I'm thinking that I should extend the forms authentication ticket with each ajax call (basically how it does in a normal web forms submit model). So the questions:
Is this even a valid concern? If so, would writing a jQuery plugin to extend the forms authentication timeout be possible? Does one already exist? Would using ASP.NET AJAX be a better approach?
Any comments\help would be appreciated.

I can confirm that making a web service or page method call through jQuery will extend an ASP.NET session expiration in the same way that a regular postback will.
I often use a five minute setInterval() to call a "keep-alive" service, which will preserve the user's session indefinitely even if they leave the application idle.

You should be able to use MS Ajax without the Script manager and use jQuery to consume the WebMethods. More info doing so here
As far as I know, calling a WebMethod will extend the user's session timeout. So this approach may be a best of both worlds.

I use this for my keepalive webservice.
Modify this to your liking and let me know if it works...
Note: session("UID") is a variable I setup at login. I name my ticket the same
<WebMethod(CacheDuration:=0, EnableSession:=True)> _
Public Function keepSessionAlive() As String
If Session("UID") Is Nothing OrElse Session("UID") = 0 Then
Throw New ApplicationException("Login")
End If
Session("lastKeepSessionAlive") = DateTime.Now
If Not (Context.Request.Cookies(System.Web.Security.FormsAuthentication.FormsCookieName) Is Nothing) Then
Dim ticket As System.Web.Security.FormsAuthenticationTicket
Try
ticket = System.Web.Security.FormsAuthentication.Decrypt(Context.Request.Cookies(System.Web.Security.FormsAuthentication.FormsCookieName).Value)
If ticket.Name = Context.Session("UID") Then
System.Web.Security.FormsAuthentication.SetAuthCookie(Context.Session("UID"), False)
Debug.WriteLine("keepAlive:AuthenticationReset")
End If
Catch ex As Exception
Debug.WriteLine("keepAlive:AuthenticationReset FAILED!!!")
Throw New ApplicationException("Login")
End Try
Else
Debug.WriteLine("keepAlive.Load: No Authentication Cookie. Error")
Throw New ApplicationException("Login")
End If
Return Session.SessionID.ToString
End Function

Use Fiddler or some other utility to see if Microsoft was smart enough to make sure the cookie gets updated between AJAX calls. You may have better luck (with regard to automatic updating of the forms auth tickeet) if you use Microsoft's baked-in asp.net AJAX (which is substantially similar).

Forms auth works via a cookie. Cookies are sent with XMLHttpRequest requests, so I don't think there's a problem here.
Note that there is an issue related to the FormsAuthTicket expiring, and being forced to redirect to login.aspx or some such. But that's an entirely different scenario than what you're talking about.

I don't think I completely understand what it is you're asking but in terms of the jquery ajax timeout, you can set the local timeout in the ajax call.
Example:
$.ajax('ajax.php',{timeout: 60000},function (data) {
alert(data);
}

Related

Implement a Simple Authorization Function in ASP.NET Without Using ASP.NET Identity

I'm building a simple CMS using ASP.NET MVC 5 and Entity Framework 6. I have 2 sites: Public and Admin. Public site to diplay all the content and Admin site to manage all the content.
I only need a single Admin account to handle all the content in the Admin site.
I'm thinking to use a session to keep the logged in user data and check for the session details when accessing an authorized page.
Keep the user data in a session.
var obj = db.UserProfiles.Where(a => a.UserName.Equals(objUser.UserName) && a.Password.Equals(objUser.Password)).FirstOrDefault();
if (obj != null)
{
Session["UserID"] = obj.UserId.ToString();
Session["UserName"] = obj.UserName.ToString();
return RedirectToAction("UserDashBoard");
}
Check before accessing an authorized page.
public ActionResult UserDashBoard()
{
if (Session["UserID"] != null)
{
return View();
} else
{
return RedirectToAction("Login");
}
}
So with this approach I wouldn't need to implement advance ASP Identity functions for the authorization.
Is this approach correct and would there be any downsides using this approach?
NEVER EVER EVER EVER EVER use session for authentication. It's insecure for starters, and it won't survive a loss of session (which IIS can kill at any time, for any reason). Session cookies are not encrypted, so they can be grabbed and used easily (assuming a non-encrypted link, even if you use HTTPS for authentication pages).
Another issue is that you are doing your authentication way too late in the pipeline. OnAuthenticate runs at the very beginning of the pipeline, while you action methods are towards the end. This means that the site is doing a lot of work it doesn't have to do if the user is not authorized.
I'm not sure why you are so against using Identity, the MVC basic templates already roll a full identity implementation for you. You don't have to do much.
The downside is that you have to write it all yourself anyway. You already need role-based authorisation and have to write cludges. Identity already have this implemented and tested for you. Also keeping information in session is not very secure.
And you don't need to implement much yourself anyway. Yes, there are lot of functionality that you'll probably won't need, but just don't use it.
Don't build your own authorisation system. Since you ask this question, you are probably not qualified enough to make it secure.

Handle session timeout in asp.net using Javascript

Essentially I want to be able to catch when a user lets their session timeout and then clicks on something that ends up causing an Async postback. I figured out that if I put this code in my Session_Start (in Global.asax) then I can catch a postback that occurred during a session timeout:
With HttpContext.Current
If TypeOf .Handler Is Page Then
Dim page As Page = CType(.Handler, Page)
If page IsNot Nothing AndAlso page.IsPostBack Then
'Session timeout
End If
End If
End With
This works fine. My question is, I would like to be able to inject some javascript into the Response and then call Response.End() so that the rest of the application does not get finish executing. The problem is that when I try Response.Write("<script ... ") followed by Response.End() then javascript does not get written to the response stream. I'm sure there are other places in the application that I can safely write Javascript to the Response but I can't let the rest of the application execute because it will error when it tries to access the session objects.
To sum up: I need to inject javascript into the response in the Session_Start event in Global.asax
Note: You may be wondering why I'm not doing this in Session_End...we don't use InProc sessions and so Session_End doesn't get called...but that's beside the point...just wanted to make it clear why I'm doing this in Session_Start.
Writing to the response stream outside of an HttpHandler is generally not a good idea; it may work in some corner cases, but it's not how things are intended to work.
Have you considered using either a Page base class or a Page Adapter to do this? That way, you would only need one copy of the code, and it could be applied to either all pages or just the ones you select.
Another option would be to use URL rewriting to redirect the incoming request to a page that generates the script output you need.

ASP.net web services

I am using a web service which sets the Thread.CurrentPrincipal object while logging in and soon later when another webmethod of the same web service accesses Thread.CurrentPrincipal, its different/resets
Can someone tell me if this is expected or can different webmethod calls from the same client can access the same Thread.CurrentPrincipal object
Thanks
As soon as you stop using a thread it goes back into the thread pool.
The next call will take a thread from the thread pool, but you have no control which one you get.
You need to send information about which user is making the call, with each request.
This is expected, every new web request is actually new thread. And every web request reset stuff like CurrentThread, CurrentCulture and so on.
What are you trying to do is authentication session. There are many possible solutions. But to suggest something I have to specify technology you use.
For example, ASP.NET ASMX Services can use Forms Authentication. Also they are aware about ASP.NET Session.
With WCF, you can enable ASP.NET support, so you will have same stuff like for ASP.NET ASMX Services. But you also can leverage on Windows Communication Foundation Authentication Service.
Anyways need more info from you.
If you are using the built-in ASP .NET authentication for your website and then just calling the web service from a web page, you may be able to enable session variables and user context information in the methods of the web service with a decoration. Like this:
[WebMethod(EnableSession=true)]
public void MyWebMethod()
{
string mySessionVar = HttpContext.Current.Session["sessionVar"].ToString();
IPrincipal currentUser = HttpContext.Current.User;
...
}
If that doesn't solve your problem, tell us what are you using the Thread.CurrentPrincipal object for (what you are pulling out of the Thread.CurrentPrincipal object). Perhaps there is another solution.

ASP.NET Access current session using jQuery

Is there a way to modify the current Session() variable using jQuery? If it involves deconstructing the ViewState then I'm not really interested. Just curious if there was some easy way to do it.
Thanks!
If you need to pass a per session property between jQuery and the server you could try using cookies instead.
Otherwise you'll have to create a custom handler (ashx) file or a WebMethod or similar that lets you access it with Ajax calls.
jQuery
$.get("http://somewhere/page.aspx",
{sessionVar: "something"},
function(data)
{
alert("Session(\"something\") = " + data);
}
);
page.aspx:
Response.Write(Session[Request.QueryString["sessionVar"]]);
That's with no error checking or anything...
Session is stored on the server and you can't access it from jQuery unless you make an ajax call and get the session details from server.
Other than the fact that both ViewState and Session helps developer maintain state in their web application, they have nothing to do with each other.
EDIT:
If you want to modify the session using Ajax. Create an HTTP handler SessionHelper.ashx. This session handler can take 'SessionVariableName' and 'SessionVariableValue' as Query String parameters and modify the session state on the server. You can call this handler from jQuery using $.ajax method.
Please keep in mind that if you expose an handler like that, you will have to protect it against misuse as any person can call the handler directly and modify the Session variables. [e.g. If you store User role/privileges in session, a hacker can modify this role/privileges through this handler.]

Is there a browser equivalent to IE's ClearAuthenticationCache?

I have a few internal .net web application here that require users to "log out" of them. I know this may seem moot on an Intranet application, but nonetheless it is there.
We are using Windows authentication for our Intranet apps, so we tie in to our Active Directory with Basic Authentication and the credentials get stored in the browser cache, as opposed to a cookie when using .net forms authentication.
In IE6+ you can leverage a special JavaScript function they created by doing the following:
document.execCommand("ClearAuthenticationCache", "false")
However, for the other browsers that are to be supported (namely Firefox at the moment, but I strive for multi-browser support), I simply display message to the user that they need to close their browser to log out of the application, which effectively flushes the application cache.
Does anybody know of some commands/hacks/etc. that I can use in other browsers to flush the authentication cache?
I've come up with a fix that seems fairly consistent but is hacky and I'm still not happy with it.
It does work though :-)
1) Redirect them to a Logoff page
2) On that page fire a script to ajax load another page with dummy credentials (sample in jQuery):
$j.ajax({
url: '<%:Url.Action("LogOff401", new { id = random })%>',
type: 'POST',
username: '<%:random%>',
password: '<%:random%>',
success: function () { alert('logged off'); }
});
3) That should always return 401 the first time (to force the new credentials to be passed) and then only accept the dummy credentials (sample in MVC):
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult LogOff401(string id)
{
// if we've been passed HTTP authorisation
string httpAuth = this.Request.Headers["Authorization"];
if (!string.IsNullOrEmpty(httpAuth) &&
httpAuth.StartsWith("basic", StringComparison.OrdinalIgnoreCase))
{
// build the string we expect - don't allow regular users to pass
byte[] enc = Encoding.UTF8.GetBytes(id + ':' + id);
string expected = "basic " + Convert.ToBase64String(enc);
if (string.Equals(httpAuth, expected, StringComparison.OrdinalIgnoreCase))
{
return Content("You are logged out.");
}
}
// return a request for an HTTP basic auth token, this will cause XmlHttp to pass the new header
this.Response.StatusCode = 401;
this.Response.StatusDescription = "Unauthorized";
this.Response.AppendHeader("WWW-Authenticate", "basic realm=\"My Realm\"");
return Content("Force AJAX component to sent header");
}
4) Now the random string credentials have been accepted and cached by the browser instead. When they visit another page it will try to use them, fail, and then prompt for the right ones.
A couple of notes. A few people have said that you need to fire off a ajax request with invalid credentials to get the browser to drop it's own credentials.
This is true but as Keith pointed out, it is essential that the server page claims to accept these credentials for this method to work consistently.
On a similar note: It is NOT good enough for your page to just bring up the login dialog via a 401 error. If the user cancels out of the dialog then their cached credentials are also unaffected.
Also if you can please poke MOZILLA at https://bugzilla.mozilla.org/show_bug.cgi?id=287957 to add a proper fix for FireFox. A webkit bug was logged at https://bugs.webkit.org/show_bug.cgi?id=44823. IE implements a poor but functional solution with the method:
document.execCommand("ClearAuthenticationCache", "false");
It is unfortunate that we need to go to these lengths just to log out a user.
Mozilla implemented the crypto object, available via the DOM window object, which has the logout function (Firefox 1.5 upward) to clear the SSL session state at the browser level so that "the next private operation on any token will require the user password again" (see this).
The crypto object seems to be an implementation of the Web Crypto API, and according to this document, the DOMCrypt API will add even more functions.
As stated above Microsoft IE (6 upward) has:
document.execCommand("ClearAuthenticationCache", "false")
I have found no way of clearing the SLL cache in Chrome (see this and this bug reports).
In case the browser does not offer any API to do this, I think the better we can do is to instruct the user to close the browser.
Here's what I do:
var agt=navigator.userAgent.toLowerCase();
if (agt.indexOf("msie") !== -1) {
document.execCommand("ClearAuthenticationCache","false");
}
//window.crypto is defined in Chrome, but it has no logout function
else if (window.crypto && typeof window.crypto.logout === "function"){
window.crypto.logout();
}
else{
window.location = "/page/to/instruct/the/user/to/close/the/browser";
}
I've been searching for a similar solution and came across a patch for Trac (an issue management system) that does this.
I've looked through the code (and I'm tired, so I'm not explaining everything); basically you need to do an AJAX call with guaranteed invalid credentials to your login page. The browser will get a 401 and know it needs to ask you for the right credentials next time you go there. You use AJAX instead of a redirect so that you can specify incorrect credentials and the browser doesn't popup a dialog.
On the patch (http://trac-hacks.org/wiki/TrueHttpLogoutPatch) page they use very rudimentary AJAX; something better like jQuery or Prototype, etc. is probably better, although this gets the job done.
Why not use FormsAuth, but against ActiveDirectory instead as per the info in this thread. It's just as (in)secure as Basic Auth, but logging out is simply a matter of blanking a cookie (or rather, calling FormsAuthentication.SignOut)
Well, I've been browsing around Bugzilla for a bit now and seemingly the best way you can go for clearing the authentication would be to send non-existant credentials.
Read more here: https://bugzilla.mozilla.org/show_bug.cgi?id=287957
Hopefully this will be useful until someone actually comes along with an explicit answer - this issue was discussed two years ago on a message board.
HTH

Resources