예제 #1
0
        /// <summary>
        /// Test if the host fits to the binding
        /// 100: full match
        /// 90: partial match (Certificate less specific, e.g. *.example.com cert for sub.example.com binding)
        /// 50,59,48,...: partial match (IIS less specific, e.g. sub.example.com cert for *.example.com binding)
        /// 10: default match (catch-all binding)
        /// 0: no match
        /// </summary>
        /// <param name=""></param>
        /// <param name=""></param>
        /// <returns></returns>
        private int Fits(IIISBinding iis, Identifier certificate, SSLFlags flags)
        {
            // The default (emtpy) binding matches with all hostnames.
            // But it's not supported with Central SSL
            if (string.IsNullOrEmpty(iis.Host) && (!flags.HasFlag(SSLFlags.CentralSsl)))
            {
                return(10);
            }

            // Match sub.example.com (certificate) with *.example.com (IIS)
            if (iis.Host.StartsWith("*.") && !certificate.Value.StartsWith("*."))
            {
                if (certificate.Value.ToLower().EndsWith(iis.Host.ToLower().Replace("*.", ".")))
                {
                    // If there is a binding for *.a.b.c.com (5) and one for *.c.com (3)
                    // then the hostname test.a.b.c.com (5) is a better (more specific)
                    // for the former than for the latter, so we prefer to use that.
                    var hostLevel    = certificate.Value.Split('.').Count();
                    var bindingLevel = iis.Host.Split('.').Count();
                    return(50 - (hostLevel - bindingLevel));
                }
                else
                {
                    return(0);
                }
            }

            // Match *.example.com (certificate) with sub.example.com (IIS)
            if (!iis.Host.StartsWith("*.") && certificate.Value.StartsWith("*."))
            {
                if (iis.Host.ToLower().EndsWith(certificate.Value.ToLower().Replace("*.", ".")))
                {
                    // But it should not match with another.sub.example.com.
                    var hostLevel    = certificate.Value.Split('.').Count();
                    var bindingLevel = iis.Host.Split('.').Count();
                    if (hostLevel == bindingLevel)
                    {
                        return(90);
                    }
                }
                else
                {
                    return(0);
                }
            }

            // Full match
            return(string.Equals(iis.Host, certificate.Value, StringComparison.CurrentCultureIgnoreCase) ? 100 : 0);
        }
예제 #2
0
 /// <summary>
 /// Regular constructor
 /// </summary>
 /// <param name="flags"></param>
 /// <param name="port"></param>
 /// <param name="ip"></param>
 /// <param name="thumbprint"></param>
 /// <param name="store"></param>
 /// <param name="hostName"></param>
 /// <param name="siteId"></param>
 public BindingOptions(
     SSLFlags flags    = SSLFlags.None,
     int port          = IISClient.DefaultBindingPort,
     string ip         = IISClient.DefaultBindingIp,
     byte[] thumbprint = null,
     string store      = null,
     string hostName   = null,
     long?siteId       = null)
 {
     Flags      = flags;
     Port       = port;
     IP         = ip;
     Thumbprint = thumbprint;
     Store      = store;
     Host       = hostName;
     SiteId     = siteId;
 }
        /// <summary>
        /// Create or update a single binding in a single site
        /// </summary>
        /// <param name="site"></param>
        /// <param name="host"></param>
        /// <param name="flags"></param>
        /// <param name="thumbprint"></param>
        /// <param name="store"></param>
        /// <param name="newPort"></param>
        public void AddOrUpdateBindings(Site site, string host, SSLFlags flags, byte[] thumbprint, string store, int newPort = 443, bool allowCreate = true)
        {
            var existingBindings      = site.Bindings.Where(x => string.Equals(x.Host, host, StringComparison.CurrentCultureIgnoreCase)).ToList();
            var existingHttpsBindings = existingBindings.Where(x => x.Protocol == "https").ToList();
            var existingHttpBindings  = existingBindings.Where(x => x.Protocol == "http").ToList();
            var update = existingHttpsBindings.Any();

            if (update)
            {
                // Already on HTTPS, update those bindings to use the Let's Encrypt
                // certificate instead of the existing one. Note that this only happens
                // for the target website, if other websites have bindings using other
                // certificates, they will remain linked to the old ones.
                foreach (var existingBinding in existingHttpsBindings)
                {
                    UpdateBinding(site, existingBinding, flags, thumbprint, store);
                }
            }
            else if (allowCreate)
            {
                _log.Information(true, "Adding new https binding {host}:{port}", host, newPort);
                string IP = "*";
                if (existingHttpBindings.Any())
                {
                    IP = GetIP(existingHttpBindings.First().EndPoint.ToString(), host);
                }
                else
                {
                    _log.Warning("No HTTP binding for {host} on {name}", host, site.Name);
                }
                Binding newBinding = site.Bindings.CreateElement("binding");
                newBinding.Protocol             = "https";
                newBinding.BindingInformation   = $"{IP}:{newPort}:{host}";
                newBinding.CertificateStoreName = store;
                newBinding.CertificateHash      = thumbprint;
                if (flags > 0)
                {
                    newBinding.SetAttributeValue("sslFlags", flags);
                }
                site.Bindings.Add(newBinding);
            }
            else
            {
                _log.Information("Binding not created");
            }
        }
예제 #4
0
        /// <summary>
        /// Make sure the flags are set correctly for updating the binding,
        /// because special conditions apply to the default binding
        /// </summary>
        /// <param name="host"></param>
        /// <param name="flags"></param>
        /// <returns></returns>
        private SSLFlags CheckFlags(bool newBinding, string host, SSLFlags flags)
        {
            // SSL flags are not supported at all by Windows 2008
            if (_client.Version.Major < 8)
            {
                return(SSLFlags.None);
            }

            // Add SNI on Windows Server 2012+ for new bindings
            if (newBinding &&
                !string.IsNullOrEmpty(host) &&
                _client.Version.Major >= 8)
            {
                flags |= SSLFlags.SNI;
            }

            // Modern flags are not supported by IIS versions lower than 10.
            // In fact they are not even supported by all versions of IIS 10,
            // but so far we don't know how to check for these features
            // availability (IIS reports its version as 10.0.0 even on
            // Server 2019).
            if (_client.Version.Major < 10)
            {
                flags &= ~SSLFlags.IIS10_Flags;
            }

            // Some flags cannot be used together with the CentralSsl flag,
            // because when using CentralSsl they are supposedly configured at
            // the server level instead of at the binding level (though the IIS
            // Manager doesn't seem to expose these options).
            if (flags.HasFlag(SSLFlags.CentralSsl))
            {
                // Do not allow CentralSSL flag to be set on the default binding
                // Logic elsewhere in the program should prevent this
                // from happening. This is merely a sanity check
                if (string.IsNullOrEmpty(host))
                {
                    throw new InvalidOperationException("Central SSL is not supported without a hostname");
                }
                flags &= ~SSLFlags.NotWithCentralSsl;
            }

            // All checks passed, return flags
            return(flags);
        }
예제 #5
0
        /// <summary>
        /// Turn on SNI for #915
        /// </summary>
        /// <param name="start"></param>
        /// <param name="match"></param>
        /// <param name="allBindings"></param>
        /// <returns></returns>
        private SSLFlags UpdateFlags(SSLFlags start, Binding match, Binding[] allBindings)
        {
            var updateFlags = start;

            if (Version.Major >= 8 && !match.HasSSLFlags(SSLFlags.SNI))
            {
                if (allBindings
                    .Except(new[] { match })
                    .Where(x => StructuralComparisons.StructuralEqualityComparer.Equals(match.CertificateHash, x.CertificateHash))
                    .Where(x => !x.HasSSLFlags(SSLFlags.SNI))
                    .Any())
                {
                    _log.Warning("Turning on SNI for existing binding to avoid conflict");
                    return(start | SSLFlags.SNI);
                }
            }
            return(start);
        }
예제 #6
0
        public void UpdateFtpSite(Target target, SSLFlags flags, CertificateInfo newCertificate, CertificateInfo oldCertificate)
        {
            var ftpSites      = FtpSites.ToList();
            var oldThumbprint = oldCertificate?.Certificate?.Thumbprint;
            var newThumbprint = newCertificate?.Certificate?.Thumbprint;
            var updated       = 0;

            foreach (var ftpSite in ftpSites)
            {
                var sslElement = ftpSite.GetChildElement("ftpServer").
                                 GetChildElement("security").
                                 GetChildElement("ssl");

                var currentThumbprint = sslElement.GetAttributeValue("serverCertHash").ToString();
                var update            = false;
                if (ftpSite.Id == target.FtpSiteId)
                {
                    if (string.Equals(currentThumbprint, newThumbprint, StringComparison.CurrentCultureIgnoreCase))
                    {
                        _log.Information(true, "No updated need for ftp site {name}", ftpSite.Name);
                    }
                    else
                    {
                        update = true;
                    }
                }
                else if (string.Equals(currentThumbprint, oldThumbprint, StringComparison.CurrentCultureIgnoreCase))
                {
                    update = true;
                }
                if (update)
                {
                    sslElement.SetAttributeValue("serverCertHash", newThumbprint);
                    _log.Information(true, "Updating existing ftp site {name}", ftpSite.Name);
                    updated += 1;
                }
            }
            if (updated > 0)
            {
                _log.Information("Committing {count} {type} site changes to IIS", updated, "ftp");
                Commit();
            }
        }
예제 #7
0
        /// <summary>
        /// Create a new binding
        /// </summary>
        /// <param name="site"></param>
        /// <param name="host"></param>
        /// <param name="flags"></param>
        /// <param name="thumbprint"></param>
        /// <param name="store"></param>
        /// <param name="port"></param>
        /// <param name="IP"></param>
        private void AddBinding(Site site, string host, SSLFlags flags, byte[] thumbprint, string store, int port, string IP)
        {
            flags = CheckFlags(host, flags);
            _log.Information(true, "Adding new https binding {host}:{port}", host, port);
            Binding newBinding = site.Bindings.CreateElement("binding");

            newBinding.Protocol             = "https";
            newBinding.BindingInformation   = $"{IP}:{port}:{host}";
            newBinding.CertificateStoreName = store;
            newBinding.CertificateHash      = thumbprint;
            if (!string.IsNullOrEmpty(host) && Version.Major >= 8)
            {
                flags |= SSLFlags.SNI;
            }
            if (flags > 0)
            {
                newBinding.SetAttributeValue("sslFlags", flags);
            }
            site.Bindings.Add(newBinding);
        }
예제 #8
0
        void IInstallationPlugin.Install(CertificateInfo newCertificate, CertificateInfo oldCertificate)
        {
            SSLFlags flags = 0;

            if (newCertificate.Store == null)
            {
                if (_iisClient.Version.Major < 8)
                {
                    var errorMessage = "Centralized SSL is only supported on IIS8+";
                    _log.Error(errorMessage);
                    throw new InvalidOperationException(errorMessage);
                }
                else
                {
                    flags |= SSLFlags.CentralSSL;
                }
            }
            foreach (var split in _targetPlugin.Split(_renewal.Binding))
            {
                _iisClient.AddOrUpdateBindings(split, flags, newCertificate, oldCertificate);
            }
        }
        private void AddToIIS(string host, byte[] certificateHash, X509Store store)
        {
            Site site;

            if (_tempSiteId == null)
            {
                site        = _iisClient.ServerManager.Sites.Add(host, "http", string.Format("*:80:{0}", host), "X:\\");
                _tempSiteId = site.Id;
            }
            else
            {
                site = _iisClient.ServerManager.Sites.Where(x => x.Id == _tempSiteId).FirstOrDefault();
            }

            SSLFlags flags = SSLFlags.SNI;

            if (Program.OptionsService.Options.CentralSsl)
            {
                flags |= SSLFlags.CentralSSL;
            }
            _iisClient.AddOrUpdateBindings(site, host, flags, certificateHash, store?.Name);
            _iisClient.Commit();
        }
예제 #10
0
 /// <summary>
 /// Turn on SNI for #915
 /// </summary>
 /// <param name="start"></param>
 /// <param name="match"></param>
 /// <param name="allBindings"></param>
 /// <returns></returns>
 private bool UpdateExistingBindingFlags(SSLFlags start, TBinding match, TBinding[] allBindings, out SSLFlags modified)
 {
     modified = start;
     if (_client.Version.Major < 8)
     {
         _log.Warning("Not updating binding on IIS version before 8");
     }
     else if (match.SSLFlags.HasFlag(SSLFlags.SNI))
     {
         _log.Information("Binding is already SNI, no update necessary");
     }
     else
     {
         if (allBindings
             .Except(new[] { match })
             .Where(x => x.Port == match.Port)
             .Where(x => StructuralComparisons.StructuralEqualityComparer.Equals(match.CertificateHash, x.CertificateHash))
             .Where(x => !x.SSLFlags.HasFlag(SSLFlags.SNI))
             .Any())
         {
             if (!string.IsNullOrEmpty(match.Host))
             {
                 _log.Warning("Turning on SNI for existing binding to avoid conflict");
                 modified = start | SSLFlags.SNI;
             }
             else
             {
                 _log.Warning("Our best match was the default binding and it seems there are other non-SNI enabled " +
                              "bindings listening to the same endpoint, which means we cannot update it without potentially " +
                              "causing problems. Instead, a new binding will be created. You may manually update the bindings " +
                              "if you want IIS to be configured in a different way.");
                 return(false);
             }
         }
     }
     return(true);
 }
예제 #11
0
        private void AddToIIS(CertificateInfo certificate)
        {
            var  host = certificate.HostNames.First();
            Site site;

            if (_tempSiteId == null)
            {
                site        = _iisClient.ServerManager.Sites.Add(host, "http", string.Format("*:80:{0}", host), "X:\\");
                _tempSiteId = site.Id;
            }
            else
            {
                site = _iisClient.ServerManager.Sites.Where(x => x.Id == _tempSiteId).FirstOrDefault();
            }

            SSLFlags flags = SSLFlags.SNI;

            if (certificate.Store == null)
            {
                flags |= SSLFlags.CentralSSL;
            }
            _iisClient.AddOrUpdateBindings(site, host, flags, certificate.Certificate.GetCertHash(), certificate.Store?.Name, 443);
            _iisClient.Commit();
        }
예제 #12
0
 public BindingOptions WithFlags(SSLFlags flags) => new BindingOptions(flags, Port, IP, Thumbprint, Store, Host, SiteId);
예제 #13
0
 public static bool HasSSLFlags(this Binding binding, SSLFlags flags) => (binding.SSLFlags() & flags) == flags;
예제 #14
0
 public static bool HasSSLFlags(this Binding binding, SSLFlags flags)
 {
     return((binding.SSLFlags() & flags) == flags);
 }
예제 #15
0
        public void AddMultipleWildcard2(string storeName, string bindingIp, int bindingPort, SSLFlags inputFlags, SSLFlags expectedFlags)
        {
            var originalBindings = new List <MockBinding> {
                new MockBinding()
                {
                    IP       = "*",
                    Port     = 80,
                    Host     = "a.example.com",
                    Protocol = "http"
                }
            };
            var site = new MockSite()
            {
                Id       = httpOnlyId,
                Bindings = originalBindings.ToList()
            };
            var iis = new MockIISClient(log)
            {
                MockSites = new[] { site }
            };
            var bindingOptions = new BindingOptions().
                                 WithSiteId(httpOnlyId).
                                 WithIP(bindingIp).
                                 WithPort(bindingPort).
                                 WithStore(storeName).
                                 WithFlags(inputFlags).
                                 WithThumbprint(newCert);

            iis.AddOrUpdateBindings(new[] { "*.example.com" }, bindingOptions, oldCert1);

            var expectedBindings = 2;

            Assert.AreEqual(expectedBindings, site.Bindings.Count);
            foreach (var newBinding in site.Bindings.Except(originalBindings))
            {
                Assert.AreEqual("https", newBinding.Protocol);
                Assert.AreEqual(storeName, newBinding.CertificateStoreName);
                Assert.AreEqual(newCert, newBinding.CertificateHash);
                Assert.AreEqual(bindingPort, newBinding.Port);
                Assert.AreEqual(bindingIp, newBinding.IP);
                Assert.AreEqual(expectedFlags, newBinding.SSLFlags);
            }
        }
예제 #16
0
        /// <summary>
        /// Update existing bindng
        /// </summary>
        /// <param name="site"></param>
        /// <param name="existingBinding"></param>
        /// <param name="flags"></param>
        /// <param name="thumbprint"></param>
        /// <param name="store"></param>
        private void UpdateBinding(Site site, Binding existingBinding, SSLFlags flags, byte[] thumbprint, string store)
        {
            flags = CheckFlags(existingBinding.Host, flags);

            // IIS 7.x is very picky about accessing the sslFlags attribute
            var currentFlags = (SSLFlags)existingBinding.Attributes.
                               Where(x => x.Name == "sslFlags").
                               Where(x => x.Value != null).
                               Select(x => int.Parse(x.Value.ToString())).
                               FirstOrDefault();

            if ((currentFlags & ~SSLFlags.SNI) == (flags & ~SSLFlags.SNI) && // Don't care about SNI status
                ((store == null && existingBinding.CertificateStoreName == null) ||
                 StructuralComparisons.StructuralEqualityComparer.Equals(existingBinding.CertificateHash, thumbprint) &&
                 string.Equals(existingBinding.CertificateStoreName, store, StringComparison.InvariantCultureIgnoreCase)))
            {
                _log.Verbose("No binding update needed");
            }
            else
            {
                _log.Information(true, "Updating existing https binding {host}:{port}", existingBinding.Host, existingBinding.EndPoint.Port);

                // Replace instead of change binding because of #371
                var     handled     = new[] { "protocol", "bindingInformation", "sslFlags", "certificateStoreName", "certificateHash" };
                Binding replacement = site.Bindings.CreateElement("binding");
                replacement.Protocol             = existingBinding.Protocol;
                replacement.BindingInformation   = existingBinding.BindingInformation;
                replacement.CertificateStoreName = store;
                replacement.CertificateHash      = thumbprint;
                foreach (ConfigurationAttribute attr in existingBinding.Attributes)
                {
                    try
                    {
                        if (!handled.Contains(attr.Name) && attr.Value != null)
                        {
                            replacement.SetAttributeValue(attr.Name, attr.Value);
                        }
                    }
                    catch (Exception ex)
                    {
                        _log.Warning("Unable to set attribute {name} on new binding: {ex}", attr.Name, ex.Message);
                    }
                }

                // If current binding has SNI, the updated version
                // will also have that flag set, regardless
                // of whether or not it was requested by the caller.
                // Callers should not generally request SNI unless
                // required for the binding, e.g. for TLS-SNI validation.
                // Otherwise let the admin be in control.
                if (currentFlags.HasFlag(SSLFlags.SNI))
                {
                    flags |= SSLFlags.SNI;
                }
                if (flags > 0)
                {
                    replacement.SetAttributeValue("sslFlags", flags);
                }
                site.Bindings.Remove(existingBinding);
                site.Bindings.Add(replacement);
            }
        }
예제 #17
0
        /// <summary>
        /// Create or update a single binding in a single site
        /// </summary>
        /// <param name="site"></param>
        /// <param name="host"></param>
        /// <param name="flags"></param>
        /// <param name="thumbprint"></param>
        /// <param name="store"></param>
        /// <param name="port"></param>
        public string AddOrUpdateBindings(Site site, string host, SSLFlags flags, byte[] thumbprint, string store, int?port, bool fuzzy)
        {
            // Get all bindings which could map to the host
            var matchingBindings = site.Bindings.
                                   Select(x => new { binding = x, fit = Fits(x.Host, host, flags) }).
                                   Where(x => x.fit > 0).
                                   OrderByDescending(x => x.fit).
                                   ToList();

            var httpsMatches = matchingBindings.Where(x => x.binding.Protocol == "https");
            var httpMatches  = matchingBindings.Where(x => x.binding.Protocol == "http");

            // Existing https binding for exactly the domain we are looking for, will be
            // updated to use the new ACME certificate
            var perfectHttpsMatches = httpsMatches.Where(x => x.fit == 100);

            if (perfectHttpsMatches.Any())
            {
                foreach (var perfectMatch in perfectHttpsMatches)
                {
                    UpdateBinding(site, perfectMatch.binding, flags, thumbprint, store);
                }
                return(host);
            }

            // If we find a http-binding for the domain, a corresponding https binding
            // is set up to match incoming secure traffic
            var perfectHttpMatches = httpMatches.Where(x => x.fit == 100);

            if (perfectHttpMatches.Any())
            {
                AddBinding(site, host, flags, thumbprint, store, port, "*");
                return(host);
            }

            if (fuzzy)
            {
                // There are no perfect matches for the domain, so at this point we start
                // to look at wildcard and/or default bindings binding. Since they are
                // order by 'best fit' we look at the first one.
                if (httpsMatches.Any())
                {
                    var bestMatch = httpsMatches.First();
                    UpdateBinding(site, bestMatch.binding, flags, thumbprint, store);
                    return(bestMatch.binding.Host);
                }

                // Nothing on https, then start to look at http
                if (httpMatches.Any())
                {
                    var bestMatch = httpMatches.First();
                    AddBinding(site, bestMatch.binding.Host, flags, thumbprint, store, port, "*");
                    return(bestMatch.binding.Host);
                }
            }


            // At this point we haven't even found a partial match for our hostname
            // so as the ultimate step we create new https binding
            AddBinding(site, host, flags, thumbprint, store, port, "*");
            return(host);
        }
예제 #18
0
        /// <summary>
        /// Update/create bindings for all host names in the certificate
        /// </summary>
        /// <param name="target"></param>
        /// <param name="flags"></param>
        /// <param name="thumbprint"></param>
        /// <param name="store"></param>
        public void AddOrUpdateBindings(Target target, SSLFlags flags, CertificateInfo newCertificate, CertificateInfo oldCertificate)
        {
            try
            {
                var allBindings = WebSites.
                                  SelectMany(site => site.Bindings, (site, binding) => new { site, binding }).
                                  ToList();

                var bindingsUpdated = 0;
                var found           = new List <string>();
                var oldThumbprint   = oldCertificate?.Certificate?.GetCertHash();
                if (oldThumbprint != null)
                {
                    var siteBindings = allBindings.
                                       Where(sb => StructuralComparisons.StructuralEqualityComparer.Equals(sb.binding.CertificateHash, oldThumbprint)).
                                       ToList();

                    // Update all bindings created using the previous certificate
                    foreach (var sb in siteBindings)
                    {
                        try
                        {
                            UpdateBinding(sb.site,
                                          sb.binding,
                                          flags,
                                          newCertificate.Certificate.GetCertHash(),
                                          newCertificate.Store?.Name);
                            found.Add(sb.binding.Host);
                            bindingsUpdated += 1;
                        }
                        catch (Exception ex)
                        {
                            _log.Error(ex, "Error updating binding {host}", sb.binding.BindingInformation);
                            throw;
                        }
                    }
                }

                // Find all hostnames which are not covered by any of the already updated
                // bindings yet, because we will want to make sure that those are accessable
                // in the target site
                var targetSite            = GetWebSite(target.InstallationSiteId ?? target.TargetSiteId ?? -1);
                IEnumerable <string> todo = target.GetHosts(true);
                while (todo.Count() > 0)
                {
                    // Filter by previously matched bindings
                    todo = todo.Where(host => !found.Any(binding => Fits(binding, host, flags) > 0));
                    if (todo.Count() > 0)
                    {
                        var current = todo.First();
                        try
                        {
                            var binding = AddOrUpdateBindings(
                                targetSite,
                                current,
                                flags,
                                newCertificate.Certificate.GetCertHash(),
                                newCertificate.Store?.Name,
                                target.SSLPort,
                                true);

                            // Allow a single newly created binding to match with
                            // multiple hostnames on the todo list, e.g. the *.example.com binding
                            // matches with both a.example.com and b.example.com
                            found.Add(binding);
                            bindingsUpdated += 1;
                        }
                        catch (Exception ex)
                        {
                            _log.Error(ex, "Error creating binding {host}: {ex}", current, ex.Message);

                            // Prevent infinite retry loop, we just skip the domain when
                            // an error happens creating a new binding for it. User can
                            // always change/add the bindings manually after all.
                            found.Add(current);
                        }
                    }
                }

                if (bindingsUpdated > 0)
                {
                    _log.Information("Committing {count} {type} binding changes to IIS", bindingsUpdated, "https");
                    Commit();
                    _log.Information("IIS will serve the new certificates after the Application Pool IdleTimeout has been reached.");
                }
                else
                {
                    _log.Warning("No bindings have been changed");
                }
            }
            catch (Exception ex)
            {
                _log.Error(ex, "Error installing");
                throw;
            }
        }
예제 #19
0
        public void UpdateSimple(string storeName, string bindingIp, int bindingPort, SSLFlags inputFlags, SSLFlags expectedFlags)
        {
            var iis = new MockIISClient(log)
            {
                MockSites = new[] {
                    new MockSite()
                    {
                        Id       = regularId,
                        Bindings = new List <MockBinding> {
                            new MockBinding()
                            {
                                IP       = "*",
                                Port     = 80,
                                Host     = regularHost,
                                Protocol = "http"
                            },
                            new MockBinding()
                            {
                                IP                   = AltIP,
                                Port                 = AltPort,
                                Host                 = regularHost,
                                Protocol             = "https",
                                CertificateHash      = oldCert1,
                                CertificateStoreName = AltStore,
                                SSLFlags             = SSLFlags.None
                            }
                        }
                    }
                }
            };

            var bindingOptions = new BindingOptions().
                                 WithSiteId(regularId).
                                 WithIP(bindingIp).
                                 WithPort(bindingPort).
                                 WithStore(storeName).
                                 WithFlags(inputFlags).
                                 WithThumbprint(newCert);

            var regularSite = iis.GetWebSite(regularId);

            iis.AddOrUpdateBindings(new[] { regularHost }, bindingOptions, oldCert1);
            Assert.AreEqual(2, regularSite.Bindings.Count);

            var updatedBinding = regularSite.Bindings[1];

            Assert.AreEqual(regularHost, updatedBinding.Host);
            Assert.AreEqual("https", updatedBinding.Protocol);
            Assert.AreEqual(storeName, updatedBinding.CertificateStoreName);
            Assert.AreEqual(newCert, updatedBinding.CertificateHash);
            Assert.AreEqual(AltPort, updatedBinding.Port);
            Assert.AreEqual(AltIP, updatedBinding.IP);
            Assert.AreEqual(expectedFlags, updatedBinding.SSLFlags);
        }
예제 #20
0
        public void UpdatePiramid(string certificateHost, string[] ignoreBindings, string expectedBinding, SSLFlags flags)
        {
            var iis = new MockIISClient(log)
            {
                MockSites = new[] {
                    new MockSite()
                    {
                        Id       = piramidId,
                        Bindings = new List <MockBinding> {
                            new MockBinding()
                            {
                                IP       = DefaultIP,
                                Port     = 80,
                                Host     = "a.b.c.com",
                                Protocol = "http"
                            },
                            new MockBinding()
                            {
                                IP       = DefaultIP,
                                Port     = 80,
                                Host     = "*.b.c.com",
                                Protocol = "http"
                            },
                            new MockBinding()
                            {
                                IP       = DefaultIP,
                                Port     = 80,
                                Host     = "*.x.y.z.com",
                                Protocol = "http"
                            },
                            new MockBinding()
                            {
                                IP       = DefaultIP,
                                Port     = 80,
                                Host     = "*.c.com",
                                Protocol = "http"
                            },
                            new MockBinding()
                            {
                                IP       = DefaultIP,
                                Port     = 80,
                                Host     = "*.com",
                                Protocol = "http"
                            },
                            new MockBinding()
                            {
                                IP       = DefaultIP,
                                Port     = 80,
                                Host     = "",
                                Protocol = "http"
                            }
                        }
                    }
                }
            };

            var bindingOptions = new BindingOptions().
                                 WithSiteId(piramidId).
                                 WithIP(DefaultIP).
                                 WithPort(DefaultPort).
                                 WithStore(DefaultStore).
                                 WithThumbprint(newCert).
                                 WithFlags(flags);

            var piramidSite = iis.GetWebSite(piramidId);
            var originalSet = piramidSite.Bindings.Where(x => !ignoreBindings.Contains(x.Host)).ToList();

            piramidSite.Bindings = originalSet.ToList().OrderBy(x => Guid.NewGuid()).ToList();
            iis.AddOrUpdateBindings(new[] { certificateHost }, bindingOptions, scopeCert);

            var newBindings = piramidSite.Bindings.Except(originalSet);

            Assert.AreEqual(1, newBindings.Count());

            var newBinding = newBindings.First();

            Assert.AreEqual(expectedBinding, newBinding.Host);
        }
예제 #21
0
        public void AddNewSingle(string storeName, string bindingIp, int bindingPort, SSLFlags inputFlags, SSLFlags expectedFlags, int iisVersion)
        {
            var iis = new MockIISClient(log, iisVersion)
            {
                MockSites = new[] {
                    new MockSite()
                    {
                        Id       = httpOnlyId,
                        Bindings = new List <MockBinding> {
                            new MockBinding()
                            {
                                IP       = "*",
                                Port     = 80,
                                Host     = httpOnlyHost,
                                Protocol = "http"
                            }
                        }
                    }
                }
            };
            var testHost       = httpOnlyHost;
            var bindingOptions = new BindingOptions().
                                 WithSiteId(httpOnlyId).
                                 WithIP(bindingIp).
                                 WithPort(bindingPort).
                                 WithStore(storeName).
                                 WithFlags(inputFlags).
                                 WithThumbprint(newCert);

            var httpOnlySite = iis.GetWebSite(httpOnlyId);

            iis.AddOrUpdateBindings(new[] { testHost }, bindingOptions, oldCert1);
            Assert.AreEqual(2, httpOnlySite.Bindings.Count);

            var newBinding = httpOnlySite.Bindings[1];

            Assert.AreEqual(testHost, newBinding.Host);
            Assert.AreEqual("https", newBinding.Protocol);
            Assert.AreEqual(storeName, newBinding.CertificateStoreName);
            Assert.AreEqual(newCert, newBinding.CertificateHash);
            Assert.AreEqual(bindingPort, newBinding.Port);
            Assert.AreEqual(bindingIp, newBinding.IP);
            Assert.AreEqual(expectedFlags, newBinding.SSLFlags);
        }