Redirecting http to https in SharePoint with AAM

There is a common mistake in redirecting http to https on any SharePoint site that thinking that AAM configuration is enough. Well thats not true !

Let’s assume we have following settings on AAM.

HTTPS -> HTTPS : https://www.contoso.com  zone:default  public url: https://www.contoso.com
HTTP -> HTTPS   : http://www.contoso.com  zone:default public url: https://www.contoso.com

And having correspoinding IIS binding:
http://www.contoso.com:*:80 (http)
*:443 (https)

In most of the cases this works fine. like
http://www.contoso.com
http://www.contoso.com/subsite
http://www.contoso.com/pages/home.aspx

but the problem happens when you try to land a one of the default layout pages ,
For example that you have sending a workflow emails pointing an item in a library
with querystrings:

http://www.contoso.com/SubSite/Lists/TestList/DispForm.aspx?ID=1
&Source=http%3A%2F%2Fwww%2Econtoso%2Ecom%2FSub1%2FLists%2FTestSub%2FAllItems%2Easpx
&ContentTypeId=0x0100AFA0B78F421E78408D29FBEA2D5EF4F9

Unfortunately this doesn’t work as expected , Either you can get 404 not found or the related page loads as http instead of https (depends on how you configure bindings on IIS). Well this is  a production design problem that we can not fix at that moment.
Valid for all SharePoint versions (2013,2016,2019)

Suggested solution:
A simple workaround is using another dummy IIS site with binding that intercepting all port 80 requests with host header of your site (www.contoso.com)
and use HTTPRedirect functionality (module) on IIS to redirect to correct IIS site as HTTPS:

Complex Solution:
That you may use URLRewrite module.

 

Fixing Form Action on UrlRewrite

IF you’re rewriting URL’s, you’ve probably come across the same problem I had.

When posting back on the page, the real URL is used.. this is a real pain if you’re writing a page which uses the RawUrl to serve up relevant content.

I had a good look around the web for a solution. These ranged from creating a custom HtmlForm control to replacing the form tag in the App_Browsers folder.

The following is simple and worked for me.

Place the following code in the Page_Load of the page you’re serving up.

HttpContext.Current.RewritePath(HttpContext.Current.Request.RawUrl);

Orginal : http://www.geekzilla.co.uk/View0472D2E7-4653-46B1-AC36-5EA246B17D22.htm

Another and good way to do this using adding a browserfile to App_Browser and write an adapter.
If you do this you dont need to add any code in your pages Page_Load’s

Browser file content:

<browsers>
  <browser refID="Default">
    <controlAdapters>
      <adapter controlType="System.Web.UI.HtmlControls.HtmlForm"
               adapterType="FormRewriterControlAdapter" />
    </controlAdapters>
  </browser>
</browsers>

Rewriter.cs code:

using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
 
/// <summary>
/// Summary description for FormRewriter
/// </summary>
public class FormRewriterControlAdapter : System.Web.UI.Adapters.ControlAdapter
{
 
    protected override void Render(System.Web.UI.HtmlTextWriter writer)
    {
        base.Render(new RewriteFormHtmlTextWriter(writer));
    }
 
}
 
public class RewriteFormHtmlTextWriter : HtmlTextWriter
{
 
    public RewriteFormHtmlTextWriter(HtmlTextWriter writer)
        : base(writer)
    {
        this.InnerWriter = writer.InnerWriter;
    }
 
    public RewriteFormHtmlTextWriter(System.IO.TextWriter writer)
        : base(writer)
    {
        base.InnerWriter = writer;
    }
 
    public override void WriteAttribute(string name, string value, bool fEncode)
    {
 
        // If the attribute we are writing is the "action" attribute, and we are not on a sub-control,
        // then replace the value to write with the raw URL of the request - which ensures that we'll
        // preserve the PathInfo value on postback scenarios
 
        if ((name == "action"))
        {
 
            HttpContext Context;
            Context = HttpContext.Current;
 
            if (Context.Items["ActionAlreadyWritten"] == null)
            {
 
                // Because we are using the UrlRewriting.net HttpModule, we will use the
                // Request.RawUrl property within ASP.NET to retrieve the origional URL
                // before it was re-written. You'll want to change the line of code below
                // if you use a different URL rewriting implementation.
 
                value = Context.Request.RawUrl;
 
                // Indicate that we've already rewritten the <form>'s action attribute to prevent
                // us from rewriting a sub-control under the <form> control
 
                Context.Items["ActionAlreadyWritten"] = true;
 
            }
 
        }
 
        base.WriteAttribute(name, value, fEncode);
 
    }
 
}
Based on : http://aspalliance.com/1234_TipTrick_Url_Rewriting_with_ASPNET.all#Page4