예제 #1
0
 /// <summary>
 /// Find a site with a specific name in a resilient way
 /// </summary>
 /// <param name="manager"></param>
 /// <param name="siteName"></param>
 /// <param name="logger"></param>
 /// <returns></returns>
 public static List <Site> FindSiteWithName(ServerManager manager, string siteName, ILoggerInterface logger)
 {
     return(UtilsSystem.QueryEnumerable(
                manager.Sites,
                (s) => s.Name == siteName,
                (s) => s,
                (s) => s.Name,
                logger));
 }
예제 #2
0
        /// <summary>
        /// Delete a site from the server manager.
        ///
        /// The behaviour has been enhanced to prevent deleting a site from affecting bindings from
        /// other sites. See related article. Doing a simple sites.Remove() call can totally mess up bindings from
        /// other websites, which becomes even worse when using CCS (central certificate store).
        ///
        /// @see https://stackoverflow.com/questions/37792421/removing-secured-site-programmatically-spoils-other-bindings
        /// </summary>
        /// <param name="site"></param>
        /// <param name="manager"></param>
        /// <param name="criteria"></param>
        /// <param name="logger"></param>
        public static void RemoveSiteBindings(
            Site site,
            ServerManager manager,
            Func <Binding, bool> criteria,
            ILoggerInterface logger)
        {
            // Site bindings
            var siteBindingsToRemove = site.Bindings.Where(criteria).ToList();

            // Make sure that this is "resilient"
            var allBindings = UtilsSystem.QueryEnumerable(
                manager.Sites,
                (s) => true,
                (s) => s.Bindings,
                (s) => s.Name,
                logger);

            // We have to collect all existing bindings from other sites, including ourse
            var existingBindings = (from p in allBindings
                                    select p.Where((i) => i.Protocol == "https")).SelectMany((i) => i)
                                   .ToList();

            // Remove all bindings for our site, we only care about SSL bindings,the other onse
            // will be removed with the site itself
            foreach (var b in siteBindingsToRemove)
            {
                existingBindings.Remove(b);

                // The central certificate store
                bool bindingUsedInAnotherSite = (from p in existingBindings
                                                 where (p.Host == b.Host &&
                                                        p.BindingInformation == b.BindingInformation)
                                                 ||

                                                 // A combination of port and usage of CCS is a positive, even if in different IP addresses
                                                 (p.SslFlags.HasFlag(SslFlags.CentralCertStore) && b.SslFlags.HasFlag(SslFlags.CentralCertStore) &&
                                                  p.EndPoint.Port.ToString() == b.EndPoint.Port.ToString())
                                                 select 1).Any();

                site.Bindings.Remove(b, bindingUsedInAnotherSite);
            }
        }
예제 #3
0
 /// <summary>
 /// There is a delay between a serverManager.CommitChanges() and the actual
 /// materialization of the configuration.
 ///
 /// This methods waits for a specific site to be available.
 /// </summary>
 public static void WaitForSiteToBeAvailable(string siteName, ILoggerInterface logger)
 {
     UtilsSystem.RetryWhile(
         () =>
     {
         using (ServerManager sm = new ServerManager())
         {
             // Site is ready when state is available
             var state = UtilsSystem.QueryEnumerable(
                 sm.Sites,
                 (s) => s.Name == siteName,
                 (s) => s,
                 (s) => s.Name,
                 logger).Single().State;
         }
     },
         (e) => true,
         3000,
         logger);
 }
예제 #4
0
        /// <summary>
        /// IIS is very bad at detecting and handling changes in certificates stored in the
        /// central certificate store, use this method to ensure that a hostname bound
        /// to a SSL termination is properly updated throughout IIS
        ///
        /// https://docs.microsoft.com/en-us/iis/get-started/whats-new-in-iis-85/certificate-rebind-in-iis85
        /// https://delpierosysadmin.wordpress.com/2015/02/23/iis-8-5-enable-automatic-rebind-of-renewed-certificate-via-command-line/
        /// </summary>
        public static void EnsureCertificateInCentralCertificateStoreIsRebound(string hostname, ILoggerInterface logger)
        {
            Dictionary <string, List <Binding> > temporaryBindings = new Dictionary <string, List <Binding> >();

            using (var sm = new ServerManager())
            {
                // Al sites that have an SSL termination bound to this hostname
                var sites = UtilsSystem.QueryEnumerable(
                    sm.Sites,
                    (s) => s.Bindings.Any(i => i.Protocol == "https" && hostname.Equals(i.Host, StringComparison.CurrentCultureIgnoreCase)),
                    (s) => s,
                    (s) => s.Name,
                    logger).ToList();

                // Remove temporarily
                foreach (var site in sites)
                {
                    foreach (var binding in site.Bindings.Where((i) => i.Protocol == "https" && hostname.Equals(i.Host, StringComparison.CurrentCultureIgnoreCase)).ToList())
                    {
                        if (!temporaryBindings.ContainsKey(site.Name))
                        {
                            temporaryBindings[site.Name] = new List <Binding>();
                        }

                        logger.LogInfo(true, "Removed binding {0} from site {1}", binding.BindingInformation, site.Name);

                        temporaryBindings[site.Name].Add(binding);
                        site.Bindings.Remove(binding);
                    }
                }

                CommitChanges(sm);
            }

            // This wait here helps...
            Thread.Sleep(2000);

            // Now restore...
            using (var sm = new ServerManager())
            {
                foreach (var siteName in temporaryBindings.Keys)
                {
                    var site = FindSiteWithName(sm, siteName, logger).Single();

                    foreach (var binding in temporaryBindings[siteName])
                    {
                        var b = site.Bindings.Add(binding.BindingInformation, binding.Protocol);
                        b.SslFlags             = binding.SslFlags;
                        b.CertificateStoreName = binding.CertificateStoreName;
                        b.UseDsMapper          = binding.UseDsMapper;

                        logger.LogInfo(true, "Restored binding {0} to site {1}", binding.BindingInformation, site.Name);
                    }
                }

                CommitChanges(sm);
            }

            // This wait here helps also...
            Thread.Sleep(2000);
        }