Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Weird AJAX redirect 401 issue with IIS

Should I remove this question? I figured out what the issue was and it wasn't IIS... See my answer below for the outcome.

Original Question I'm working on an ASP.Net MVC app and run in to a weird issue with URL Rewrite redirects and AJAX requests.

I've added the following rewrite rule to my Web.config in the root site.

<rewrite>
    <rules>
        <rule name="Account" stopProcessing="true">
            <match url="^SubApp/Account/(.*)$" />
            <action type="Redirect" url="Account/{R:1}" redirectType="Found" />
        </rule>
    </rules>
</rewrite>

Everything seems to work ok if I use a Permanent or Temporary redirectType in the config but fails with a HTTP Error 401.0 - Unauthorized IIS error page .

When I make an normal GET request via the browser to an action that would trigger this rule e.g. https://some-site/SubApp/Account/Settings then I get a 302 Found and the location header is set to the expected URL https://some-site/Account/Settings and the appropriate page is rendered.

However when I make a GET request via JQuery's AJAX i.e. $.get('https://some-site/SubApp/Account/Settings') the returned Response status code is 401 Unauthorized but it still has the appropriate location header.

The content of the response is a standard IIS HTTP Error 401.0 - Unauthorized error page.

Weirdly everything seems to work ok if I use either the Permanent or Temporary redirect types in the config but fails only with Found.

/SubApp is a separate application that sits below the root site at /.

What's going on?

Screenshots

redirectType="Permanent" Permanent Redirect

redirectType="Found" Found Redirect

redirectType="Temporary" Temporary Redirect

As you can see from the screenshots the only difference is the redirectType specified in the Web.config.

As you can see the redirects are happening as expected with exception to the Found redirect type which I would expect to get a 302 - Found response redirecting to the same URL as the others.

like image 384
phuzi Avatar asked Apr 23 '15 09:04

phuzi


1 Answers

Ahhhh, you know when you don't think about something for a while and you get hit with sudden inspiration... Well it happened last night and I found this little nugget put in place to "fix" MVC's insistance on redirecting AJAX requests when authentication fails...

protected void Application_EndRequest()
{
    var context = new HttpContextWrapper(Context);
    // MVC retuns a 302 for unauthorized ajax requests so alter to request status to be a 401
    if (context.Response.StatusCode == 302 && context.Request.IsAjaxRequest() && !context.Request.IsAuthenticated)
    {   
        context.Response.Clear();
        context.Response.StatusCode = 401;
    }
}

And, unsuprisingly, context.Request.IsAuthenticated is always false as it appears to get reset by the redirect .

Updated this, with a little help from Branislav Abadjimarinov's blog post on the subject.

protected void Application_EndRequest()
{
    var context = new HttpContextWrapper(Context);
    // MVC returns a 302 for unauthorized ajax requests so alter to request status to be a 401

    if (context.Response.StatusCode == 302 && context.Request.IsAjaxRequest())
    {
        //Unfortunately the redirect also clears the results of any authentication
        //Try to manually authenticate the user...
        var authCookie = HttpContext.Current.Request.Cookies[FormsAuthentication.FormsCookieName];
        if (authCookie != null)
        {
            var authTicket = FormsAuthentication.Decrypt(authCookie.Value);
            if (authTicket != null && !authTicket.Expired)
            {
                var roles = authTicket.UserData.Split(',');
                HttpContext.Current.User = new System.Security.Principal.GenericPrincipal(new FormsIdentity(authTicket), roles);
            }
        }

        if (!context.Request.IsAuthenticated)
        {
            context.Response.Clear();
            context.Response.StatusCode = 401;
        }

    }
}

And it all works as expected.

Only question is should I remove this question?

like image 138
phuzi Avatar answered Nov 02 '22 21:11

phuzi