Sunday, 12 May 2013

Set IIS website https binding programmatically (add certificate too)

I found myself needing to set a website's https binding for a few servers, this week and I wondered whether this could be done programmatically.

Although in this case the method, see below, is used to set https as a binding it can be easily modified to add any binding type to any website. I kind of did it as halfway house, I might modify it later to make it a little bit more robust and generic.

private static void SetBinding(string siteName, string bindingInfo, string fileName,string password)
{
    using (ServerManager serverManager = new ServerManager())
    {
        Site site = serverManager.Sites.Where(x => x.Name == siteName).SingleOrDefault();

        X509Store store = new X509Store(StoreName.My, StoreLocation.LocalMachine);
        store.Open(OpenFlags.OpenExistingOnly | OpenFlags.ReadWrite);

        X509Certificate2 certificate = new X509Certificate2(fileName, password);

        store.Add(certificate);

        if (site.Bindings.Any(x => x.Protocol.ToLower() != binding.ToLower()))
        {
            Binding binding = site.Bindings.Add(bindingInfo, certificate.GetCertHash(), store.Name);

            binding.Protocol = "https";
        }

        store.Close();
    }
}

Note that bindingInfo should be of this form "*:443:" if you want your website to listen on all ip addresses of your server.

The certificate needs to be of PKCS #12 vintage, i.e. with a .pfx or .p12  extension (don't just change the filename extenstion to .pfx if you have a .cer or .der certificate, it won't work.)

Don't forget to add the following namespaces (the library for the Microsoft.Web.Administration namespace is called the same as the namespace).

System.Security.Cryptography.X509Certificates;
Microsoft.Web.Administration;

2 comments:

  1. Is it binding.ToLower() is bindingInfo or...?

    ReplyDelete
  2. It's wrong anyways. The if statement will always try to rebind https if there are any additional existing protocols as well, such as http. Should be something like this instead;

    if (site.Bindings.Where(x => x.Protocol == "https").Count() == 0)

    ReplyDelete