Home > Blockchain >  MVC5 Azure web app incorrectly redirecting using OIDC & FrontDoor
MVC5 Azure web app incorrectly redirecting using OIDC & FrontDoor

Time:10-06

I've got an MVC5 Azure web app, which has been working fine with OIDC, using Azure AD as the identity provider.

I'm now trying to put the app behind FrontDoor, but something isn't configured correctly, as the initial request (the one that triggers authenticatation) always redirects to the underlying web app address (app.azurewebsites.net), instead of the FrontDoor (app.azurefd.net). Subsequent requests to the FrontDoor address (that don't need authenticating) work fine.

  • The web app has an access restriction rule to prevent any access except via the FrontDoor.
  • The redirect URI configured in the app is set to the FrontDoor address (app.azurefd.net/signin-oidc).
  • The Azure app registration also has the FrontDoor version (app.azurefd.net/signin-oidc).

The SecurityTokenValidated notification is firing which, if I understand correctly, means that the request from the identity provider back to the redirect URI (app.azurefd.net/signin-oidc) has worked fine, but the final step where it redirects to the URL originally requested is not using the FrontDoor address.

I've tried using FrontDoor Classic and Standard and have tried (with both) having the origin host header match the host name, or being blank. When they match, the behaviour is as described above. Using a blank origin host header is suggested in various places but appears to no-longer work - it now results in a 404.

This Origin

And the origin group looks like this:

Origin Group

I'm happy to post more config screenshots if that might help, but I'm not sure which bits would be useful.

CodePudding user response:

As far as I can work out, the problem is that the OWIN middleware doesn't use the X-Forwarded-Host from the request, and there doesn't seem to be any option to change this. The .NET Core version makes it easy to configure how headers like this are handled using UseForwardedHeaders (docs), but I couldn't find any equivalent in .NET Framework, so I wrote my own, based on this answer to a similar problem.

public static class UseForwardedHeadersExtension
{
    private const string ForwardedHeadersAdded = "ForwardedHeadersAdded";

    /// <summary>
    /// Checks for the presence of <c>X-Forwarded-Host</c> header, and if present updates the <c>HTTP_HOST</c> header.
    /// </summary>
    /// <remarks>
    /// This extension method is required for running behind FrontDoor. FrontDoor adds the <c>X-Forwarded-Host</c> headers to indicate the host from the original request.
    /// </remarks>
    public static IAppBuilder UseForwardedHeaders(this IAppBuilder app)
    {
        if (app == null)
        {
            throw new ArgumentNullException(nameof(app));
        }

        // no need to add more than one instance of this middleware to the pipeline.
        if (app.Properties.ContainsKey(ForwardedHeadersAdded)) return app;

        app.Properties[ForwardedHeadersAdded] = true;

        app.Use(async (context, next) =>
        {
            var request = context.Request;

            if (request.Headers.ContainsKey("X-Forwarded-Host"))
            {
                var httpContext = context.Get<HttpContextBase>(typeof(HttpContextBase).FullName);
                var serverVars = httpContext.Request.ServerVariables;
                serverVars["HTTP_HOST"] = request.Headers["X-Forwarded-Host"];
            }

            await next.Invoke().ConfigureAwait(false);
        });

        return app;
    }
}

This is hugely simplistic compared to the .NET Core implementation in ForwardedHeadersExtensions.cs and ForwardedHeadersMiddleware.cs, but given that access to the app is limited to FrontDoor (it can't be accessed directly) it should be safe, as the header will always be set by FrontDoor. There's a great explanation of the security implications in this blog post, which links to this tweet.

  • Related