Our SaaS CMS/CRM/AMS product Mition is only $199 a month including licenses and hosting!

Azure Front Door and Kentico Xperience

popupimage

by Brett Andrew 9th April 2021

How to set host name / client IP when you have multiple sites pointing to a single instance. This includes multiple instances coming in via Azure Front Door and also caters for other urls going to that site directly (not using Azure Front Door) incase you have older sites on the same system that are not going to use Azure Front Door.

By default when you setup a backend for Azure Front door, it uses the default URL that the application service has. This is a problem for Kentico Xperience when you have multiple host names that point to that back end application service.

This solution is for K12+ with MVC - the modification is to the Kentico code. The solution is to use a handler file.

Create a file called: AzureHeaderHandler.cs and place it in this folder

CMS\Old_App_Code\Handlers\

Then copy and paste the following into it:

using System;
using System.Web;
using System.Collections.Specialized;

using CMS;
using CMS.DataEngine;
using CMS.Base;
using CMS.Helpers;
using CMS.EventLog;

// Registers the custom module into the system
[assembly: RegisterModule(typeof(SSLRequestModule))]

public class SSLRequestModule : Module
{
    // Module class constructor, the system registers the module under the name "SSLRequests"
    public SSLRequestModule()
        : base("SSLRequests")
    {
    }

    // Contains initialization code that is executed when the application starts
    protected override void OnInit()
    {
        base.OnInit();

        // Assigns handlers called before each request is processed

        //No need to handle non-ssl as we do this through Azure now-a-days
        //RequestEvents.Prepare.Execute += HandleSSLRequests;

        // we do need to cater for proxied front door host and client ip, which are provided by headers from an azure front door,
        // if this did not go through an azure front door and the protocols are not set and it wont try to override it
        RequestEvents.Prepare.Execute += HandleFrontDoorHostAddress;
        RequestEvents.Prepare.Execute += HandleUserHostAddress;
        

        // Sets the URL port used for HTTPS requests
        //URLHelper.SSLUrlPort = 443;
    }

    // Checks if requests are forwarded as SSL
    private static void HandleSSLRequests(object sender, EventArgs e)
    {
        try
        {
            if ((HttpContext.Current != null) && (HttpContext.Current.Request != null))
        {
            // Loads the request headers as a collection
            NameValueCollection headers = HttpContext.Current.Request.Headers;

            // Gets the value from the X-Forwarded-Ssl header
            string forwardedSSL = headers.Get("X-Forwarded-Proto").ToLower();
            RequestContext.IsSSL = false;
            
            // Checks if the original request used HTTPS
            if (String.Equals(forwardedSSL, "https", StringComparison.OrdinalIgnoreCase))
            {
                RequestContext.IsSSL = true;
            }
        }
        }
        catch (Exception ex)
        {
            EventLogProvider.LogException("AzureHeaderHandler", "HandleSSLRequests", ex);
        }
    }

    
    /// <summary>
    /// Provides Kentico with the correct Host Address if the original address is hidden by using a Reverse proxy
    /// </summary>    
    private static void HandleUserHostAddress(object sender, EventArgs e)
    {
        try
        {
            if (HttpContext.Current != null)
            {
                // Gets the value from the X-forwarded-for header and pass it to the request context
                var xForwardFor = HttpContext.Current.Request.Headers.Get("X-Forwarded-For");

                if (!string.IsNullOrEmpty(xForwardFor))
                    if (xForwardFor.Contains(","))
                    {
                        RequestContext.UserHostAddress = xForwardFor.Split(',')[0];
                    }
                else
                    {
                        RequestContext.UserHostAddress = xForwardFor;
                    }

            }
        }
        catch (Exception ex)
        {
            EventLogProvider.LogException("AzureHeaderHandler", "HandleUserHostAddress", ex);
        }
    }

    private static void HandleFrontDoorHostAddress(object sender, EventArgs e)
    {
        try
        {
            if (HttpContext.Current != null)
            {
                // Gets the value from the X-forwarded-for header and pass it to the request context
                var xForwardHost = HttpContext.Current.Request.Headers.Get("X-Forwarded-Host");

                if (!string.IsNullOrEmpty(xForwardHost))
                {
                    if (xForwardHost.Contains(","))
                    {
                        xForwardHost = xForwardHost.Split(',')[0];
                    }


                    string currentdomain = RequestContext.CurrentDomain;
                    RequestContext.CurrentURL = RequestContext.CurrentURL.Replace(currentdomain, xForwardHost);
                }
            }
        }
        catch (Exception ex)
        {
            EventLogProvider.LogException("AzureHeaderHandler", "HandleFrontDoorHostAddress", ex);
        }
    }
}



Xperience will then receive the URL from the host header and load the correct site and also show the users correct IP address (without that section it shows the front door IP address)

Any questions or comments let me know.



Contact us