NullReferenceException in Microsoft.Web.Administration when adding https binding

I am trying to programmatically add a binding to my default website, but I am constantly getting a null-link exception in the Microsoft.Web.Administration dll. Initially, I wanted to assign a certificate along with the binding. I was able to request the certificate I need:

var store = new X509Store(StoreName.Root, StoreLocation.LocalMachine); store.Open(OpenFlags.OpenExistingOnly | OpenFlags.ReadWrite); var certificate = store.Certificates.Find(X509FindType.FindByIssuerName, "TEST_SELF_SIGNED", true) .OfType<X509Certificate>().FirstOrDefault(); 

This correctly gave me the certificate that I wanted, it was not null and had the information that I expected.

 Site site = GetSite("Default Web Site"); var binding = site.Bindings.Add("*:443", certificate.GetCertHash(), "https"); 

Given that none of my variables or any other elements in the sample code are null (including GetCertHash, which returns an array of 20 bytes), I am confused about why I get null here. I even tried the following overload:

 site.Bindings.Add("*:443", "https"); 

And I still get the same zero ref stack:

  System.NullReferenceException was unhandled
   Message = Object reference not set to an instance of an object.
   Source = Microsoft.Web.Administration
   Stacktrace:
        at Microsoft.Web.Administration.Configuration.SetDirty ()
        at Microsoft.Web.Administration.ConfigurationElement.SetDirty ()
        at Microsoft.Web.Administration.ConfigurationElement.SetAttributeValue (String attributeName, Object value)
        at Microsoft.Web.Administration.Binding.SetBindingProperty (String attributeName, String value)
        at Microsoft.Web.Administration.BindingCollection.Add (String bindingInformation, Byte [] certificateHash, String certificateStoreName)
        at TestApp.Program.Main (String [] args) in C: \ Projects \ Cube \ trunk \ src \ AutoUpdate \ TestApp \ Program.cs: line 33
        at System.AppDomain._nExecuteAssembly (RuntimeAssembly assembly, String [] args)
        at System.AppDomain.ExecuteAssembly (String assemblyFile, Evidence assemblySecurity, String [] args)
        at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly ()
        at System.Threading.ThreadHelper.ThreadStart_Context (Object state)
        at System.Threading.ExecutionContext.Run (ExecutionContext executionContext, ContextCallback callback, Object state, Boolean ignoreSyncCtx)
        at System.Threading.ExecutionContext.Run (ExecutionContext executionContext, ContextCallback callback, Object state)
        at System.Threading.ThreadHelper.ThreadStart ()
   InnerException: 

Here is a complete test application that demonstrates the problem, as well as the selfssl command line arguments that I used to create the sample certificate:

selfssl.exe / T / N: CN = TEST_SELF_SIGNED / K: 512 / V: 9999 / Q

 class Program { static void Main(string[] args) { using (ServerManager manager = new ServerManager()) { var store = new X509Store(StoreName.Root, StoreLocation.LocalMachine); store.Open(OpenFlags.OpenExistingOnly | OpenFlags.ReadWrite); var certificate = store.Certificates.Find(X509FindType.FindByIssuerName, "TEST_SELF_SIGNED", true).OfType<X509Certificate>().FirstOrDefault(); Site site = GetSite("Default Web Site"); site.Bindings.Add("*:443", certificate.GetCertHash(), store.Name); store.Close(); manager.CommitChanges(); } } public static Site GetSite(string siteName) { using (var serverManager = new ServerManager()) { return serverManager.Sites.Where(p => p.Name.ToLower() == siteName.ToLower()).FirstOrDefault(); } } } 

Just to cover my bases, Iis is installed and manually assigning a certificate works fine.

+6
source share
1 answer

So, I found the answer by decompiling the Microsoft.Web.Administration dll and popping it onto the stack. It turns out that if you get a site with a helper function, it does not set the ServerManager internal property on your site.

The dll function that caused the problem was in Microsoft.Web.Administration :: Configuration

 internal void SetDirty() { if (this._hasBeenCommitted || this._configurationManager.Owner.ReadOnly) throw new InvalidOperationException(Resources.ObjectHasBeenCommited); this._isDirty = true; } 

The only thing that could be null here is either _configurationManager or _configurationManager.Owner . I checked that there was Owner , and it was the ServerManager that upset me that I should probably request Site from the server manager use block. As soon as I did this, the null ref disappeared and everything worked. Unfortunately, they do not check for null, but it is possible that no one will act on the site object without the context of the server manager.

Anyway, here is the updated code:

 class Program { static void Main(string[] args) { using (var serverManager = new ServerManager()) { var selfSignedCnName = "TEST_SELF_SIGNED"; var websiteName = "Default Web Site"; var site = serverManager.Sites.Where(p => p.Name.ToLower() == websiteName.ToLower()).FirstOrDefault(); var store = new X509Store(StoreName.Root, StoreLocation.LocalMachine); store.Open(OpenFlags.OpenExistingOnly | OpenFlags.ReadWrite); var certificate = store.Certificates.Find(X509FindType.FindByIssuerName, selfSignedCnName, true).OfType<X509Certificate>().FirstOrDefault(); site.Bindings.Add("*:443:", certificate.GetCertHash(), store.Name); store.Close(); serverManager.CommitChanges(); } } } 

It’s also clear from my initial message that moving the entire block of code in the server manager doesn’t mean anything, they are not cascaded. You must act on the site using the server manager from which it came.

+7
source

Source: https://habr.com/ru/post/914545/


All Articles