Prevent XmlHttpRequest redirect response in .Net MVC WS-Federation Site

血红的双手。 提交于 2019-12-04 06:40:27

I think I've found an answer to this problem and want to circle back and leave an answer for anyone else in the world that might encounter this.

My problem was that the HttpContext.Current.Items wasn't matching up between my ActionFilterAttribute and the WSFederationAuthenticationModule so I ended up inspecting the context and adding some checks similar to Phil Haacks Forms Redirect Suppress Example

Here is what my updated custom WSFederationAuthenticationModule looks like:

public class WSFederationServiceAuthenticationModule : WSFederationAuthenticationModule
{
    private static Log4NetLoggingService logger = new Log4NetLoggingService();

    protected override void OnAuthorizationFailed(AuthorizationFailedEventArgs e)
    {
        base.OnAuthorizationFailed(e);            

        var context = HttpContext.Current;
        var req = context.Request;
        var resp = context.Response;

        if (req == null || resp == null)
        {
            logger.Info("WSFedService: Did not find Request or Response");
            return;
        }

        if ((resp.StatusCode == 302 || resp.StatusCode == 401) && req.Headers["X-Requested-With"] == "XMLHttpRequest")
        {
            logger.Info("WSFedService: Found Redirect and Header");
            e.RedirectToIdentityProvider = false;
        }
        else
        {
            logger.Info(string.Format("WSFedService: Did not find redirect status code or XMLHttpRequest Header: {0}", resp.StatusCode));
        }

    }
}

And of course, you'll need to add this to your web.config in place of the default authentication module:

<system.web>
    <httpModules>
        <!-- Old and Busted...
        <add name="WSFederationAuthenticationModule"
           type="Microsoft.IdentityModel.Web.WSFederationAuthenticationModule, Microsoft.IdentityModel, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
        -->

        <!-- New Hotness... -->
        <add name="WSFederationAuthenticationModule"
           type="MyApp.Web.Authentication.WSFederationServiceAuthenticationModule, MyApp.Web" />
    </httpModules>
</system.web>

<system.webServer>
    <modules>
        <!-- Old and Busted...
        <add name="WSFederationAuthenticationModule"
           type="Microsoft.IdentityModel.Web.WSFederationAuthenticationModule, Microsoft.IdentityModel, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
           preCondition="managedHandler"/>
        -->

        <!-- New Hotness... -->
        <add name="WSFederationAuthenticationModule"
           type="MyApp.Web.Authentication.WSFederationServiceAuthenticationModule, MyApp.Web"
           preCondition="managedHandler"/>

    </modules>
</system.webServer>

I realize this thread is ancient, but I came across it while trying to solve the same problem (I have web apis that I want to use with active clients, and I want to send down a 401 if authentication goes south instead of redirecting.)

..And, depending on your situation, it might be easier/less involved to handle the authorization failed event in Global.asax and do your checking there.

This link is what I've been following: http://msdn.microsoft.com/en-us/library/system.identitymodel.services.wsfederationauthenticationmodule.authorizationfailed.aspx

..And it seems straightforward.

In my case i have hosted my api's under path "/api" in website which are secured using JWT authentication.

For fix this issue, following overrides were done in WSFederationAuthenticationModule(ofcourse register this custom module in web.config, System.WebServer).

public class CustomWSFederationAuthenticationModule : System.IdentityModel.Services.WSFederationAuthenticationModule
{
    protected override void OnAuthorizationFailed(AuthorizationFailedEventArgs e)
    {
        if (!IsApiCall())
            e.RedirectToIdentityProvider = false;
        base.OnAuthorizationFailed(e);
    }

    protected override void OnEndRequest(object sender, EventArgs args)
    {
        if (!IsApiCall())
            base.OnEndRequest(sender, args);
    }

    private bool IsApiCall()
    {
        return (HttpContext.Current.Request.Path.ToLowerInvariant().Contains("/api/"));
    }
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!