diff options
Diffstat (limited to 'src/main.lib/Clients/IIS')
-rw-r--r-- | src/main.lib/Clients/IIS/IISClient.cs | 117 | ||||
-rw-r--r-- | src/main.lib/Clients/IIS/IISHelper.cs | 17 | ||||
-rw-r--r-- | src/main.lib/Clients/IIS/IISHttpBindingUpdater.cs | 42 | ||||
-rw-r--r-- | src/main.lib/Clients/IIS/IISSiteWrapper.cs | 2 |
4 files changed, 108 insertions, 70 deletions
diff --git a/src/main.lib/Clients/IIS/IISClient.cs b/src/main.lib/Clients/IIS/IISClient.cs index 3ee4386..3171531 100644 --- a/src/main.lib/Clients/IIS/IISClient.cs +++ b/src/main.lib/Clients/IIS/IISClient.cs @@ -18,8 +18,10 @@ namespace PKISharp.WACS.Clients.IIS public Version Version { get; set; } [SuppressMessage("Code Quality", "IDE0069:Disposable fields should be disposed", Justification = "Actually is disposed")] - private ServerManager? _ServerManager; private readonly ILogService _log; + private ServerManager? _serverManager; + private List<IISSiteWrapper>? _webSites = null; + private List<IISSiteWrapper>? _ftpSites = null; public IISClient(ILogService log) { @@ -34,14 +36,16 @@ namespace PKISharp.WACS.Clients.IIS { get { - if (_ServerManager == null) + if (_serverManager == null) { if (Version.Major > 0) { - _ServerManager = new ServerManager(); + _serverManager = new ServerManager(); + _webSites = null; + _ftpSites = null; } } - return _ServerManager; + return _serverManager; } } @@ -53,11 +57,11 @@ namespace PKISharp.WACS.Clients.IIS /// </summary> private void Commit() { - if (_ServerManager != null) + if (_serverManager != null) { try { - _ServerManager.CommitChanges(); + _serverManager.CommitChanges(); } catch { @@ -73,18 +77,29 @@ namespace PKISharp.WACS.Clients.IIS public void Refresh() { - if (_ServerManager != null) + _webSites = null; + _ftpSites = null; + if (_serverManager != null) { - _ServerManager.Dispose(); - _ServerManager = null; + _serverManager.Dispose(); + _serverManager = null; } } #region _ Basic retrieval _ + IEnumerable<IIISSite> IIISClient.WebSites => WebSites; + + IEnumerable<IIISSite> IIISClient.FtpSites => FtpSites; + + IIISSite IIISClient.GetWebSite(long id) => GetWebSite(id); + + IIISSite IIISClient.GetFtpSite(long id) => GetFtpSite(id); + public bool HasWebSites => Version.Major > 0 && WebSites.Any(); - IEnumerable<IIISSite> IIISClient.WebSites => WebSites; + public bool HasFtpSites => Version >= new Version(7, 5) && FtpSites.Any(); + public IEnumerable<IISSiteWrapper> WebSites { get @@ -93,59 +108,65 @@ namespace PKISharp.WACS.Clients.IIS { return new List<IISSiteWrapper>(); } - return ServerManager.Sites.AsEnumerable(). - Where(s => s.Bindings.Any(sb => sb.Protocol == "http" || sb.Protocol == "https")). - Where(s => - { - try - { - return s.State == ObjectState.Started; - } - catch - { - // Prevent COMExceptions such as misconfigured - // application pools from crashing the whole - _log.Warning("Unable to determine state for Site {id}", s.Id); - return false; - } - }). - OrderBy(s => s.Name). - Select(x => new IISSiteWrapper(x)); + if (_webSites == null) + { + _webSites = ServerManager.Sites.AsEnumerable(). + Where(s => s.Bindings.Any(sb => sb.Protocol == "http" || sb.Protocol == "https")). + Where(s => + { + + try + { + return s.State == ObjectState.Started; + } + catch + { + // Prevent COMExceptions such as misconfigured + // application pools from crashing the whole + _log.Warning("Unable to determine state for Site {id}", s.Id); + return false; + } + }). + OrderBy(s => s.Name). + Select(x => new IISSiteWrapper(x)). + ToList(); + } + return _webSites; } } - IIISSite IIISClient.GetWebSite(long id) => GetWebSite(id); - public IISSiteWrapper GetWebSite(long id) + public IEnumerable<IISSiteWrapper> FtpSites { - foreach (var site in WebSites) + get { - if (site.Site.Id == id) + if (ServerManager == null) { - return site; + return new List<IISSiteWrapper>(); + } + if (_ftpSites == null) + { + _ftpSites = ServerManager.Sites.AsEnumerable(). + Where(s => s.Bindings.Any(sb => sb.Protocol == "ftp")). + OrderBy(s => s.Name). + Select(x => new IISSiteWrapper(x)). + ToList(); } + return _ftpSites; } - throw new Exception($"Unable to find IIS SiteId #{id}"); } - public bool HasFtpSites => Version >= new Version(7, 5) && FtpSites.Any(); - - IEnumerable<IIISSite> IIISClient.FtpSites => FtpSites; - public IEnumerable<IISSiteWrapper> FtpSites + public IISSiteWrapper GetWebSite(long id) { - get + foreach (var site in WebSites) { - if (ServerManager == null) + if (site.Site.Id == id) { - return new List<IISSiteWrapper>(); + return site; } - return ServerManager.Sites.AsEnumerable(). - Where(s => s.Bindings.Any(sb => sb.Protocol == "ftp")). - OrderBy(s => s.Name). - Select(x => new IISSiteWrapper(x)); } + throw new Exception($"Unable to find IIS SiteId #{id}"); } - IIISSite IIISClient.GetFtpSite(long id) => GetFtpSite(id); public IISSiteWrapper GetFtpSite(long id) { foreach (var site in FtpSites) @@ -316,9 +337,9 @@ namespace PKISharp.WACS.Clients.IIS { if (disposing) { - if (_ServerManager != null) + if (_serverManager != null) { - _ServerManager.Dispose(); + _serverManager.Dispose(); } } disposedValue = true; diff --git a/src/main.lib/Clients/IIS/IISHelper.cs b/src/main.lib/Clients/IIS/IISHelper.cs index 63a8649..7f28176 100644 --- a/src/main.lib/Clients/IIS/IISHelper.cs +++ b/src/main.lib/Clients/IIS/IISHelper.cs @@ -79,12 +79,17 @@ namespace PKISharp.WACS.Clients.IIS Where(sb => !string.IsNullOrWhiteSpace(sb.binding.Host)). ToList(); + static string lookupKey(IIISSite site, IIISBinding binding) => + site.Id + "#" + binding.BindingInformation.ToLower(); + // Option: hide http bindings when there are already https equivalents - var https = siteBindings.Where(sb => - sb.binding.Protocol == "https" || - sb.site.Bindings.Any(other => - other.Protocol == "https" && - string.Equals(sb.binding.Host, other.Host, StringComparison.InvariantCultureIgnoreCase))).ToList(); + var https = siteBindings + .Where(sb => + sb.binding.Protocol == "https" || + sb.site.Bindings.Any(other => + other.Protocol == "https" && + string.Equals(sb.binding.Host, other.Host, StringComparison.InvariantCultureIgnoreCase))) + .ToDictionary(sb => lookupKey(sb.site, sb.binding)); var targets = siteBindings. Select(sb => new @@ -92,7 +97,7 @@ namespace PKISharp.WACS.Clients.IIS host = sb.binding.Host.ToLower(), sb.site, sb.binding, - https = https.Contains(sb) + https = https.ContainsKey(lookupKey(sb.site, sb.binding)) }). Select(sbi => new IISBindingOption(sbi.host, _idnMapping.GetAscii(sbi.host)) { diff --git a/src/main.lib/Clients/IIS/IISHttpBindingUpdater.cs b/src/main.lib/Clients/IIS/IISHttpBindingUpdater.cs index 9e8f3bf..43945c3 100644 --- a/src/main.lib/Clients/IIS/IISHttpBindingUpdater.cs +++ b/src/main.lib/Clients/IIS/IISHttpBindingUpdater.cs @@ -61,9 +61,11 @@ namespace PKISharp.WACS.Clients.IIS { try { - UpdateBinding(site, binding, bindingOptions); found.Add(binding.Host); - bindingsUpdated += 1; + if (UpdateBinding(site, binding, bindingOptions)) + { + bindingsUpdated += 1; + } } catch (Exception ex) { @@ -91,7 +93,7 @@ namespace PKISharp.WACS.Clients.IIS var current = todo.First(); try { - var binding = AddOrUpdateBindings( + var (hostFound, commitRequired) = AddOrUpdateBindings( allBindings.Select(x => x.binding).ToArray(), targetSite, bindingOptions.WithHost(current)); @@ -99,7 +101,7 @@ namespace PKISharp.WACS.Clients.IIS // 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 - if (binding == null) + if (hostFound == null) { // We were unable to create the binding because it would // lead to a duplicate. Pretend that we did add it to @@ -108,8 +110,11 @@ namespace PKISharp.WACS.Clients.IIS } else { - found.Add(binding); - bindingsUpdated += 1; + found.Add(hostFound); + if (commitRequired) + { + bindingsUpdated += 1; + } } } catch (Exception ex) @@ -143,13 +148,16 @@ namespace PKISharp.WACS.Clients.IIS /// <param name="port"></param> /// <param name="ipAddress"></param> /// <param name="fuzzy"></param> - private string? AddOrUpdateBindings(TBinding[] allBindings, TSite site, BindingOptions bindingOptions) + private (string?, bool) AddOrUpdateBindings(TBinding[] allBindings, TSite site, BindingOptions bindingOptions) { if (bindingOptions.Host == null) { throw new InvalidOperationException("bindingOptions.Host is null"); } + // Require IIS manager to commit + var commitRequired = false; + // Get all bindings which could map to the host var matchingBindings = site.Bindings. Select(x => new { binding = x, fit = Fits(x.Host, bindingOptions.Host, bindingOptions.Flags) }). @@ -167,7 +175,7 @@ namespace PKISharp.WACS.Clients.IIS // All existing https bindings var existing = bestMatches. Where(x => x.binding.Protocol == "https"). - Select(x => x.binding.BindingInformation). + Select(x => x.binding.BindingInformation.ToLower()). ToList(); foreach (var match in bestMatches) @@ -178,7 +186,7 @@ namespace PKISharp.WACS.Clients.IIS if (UpdateExistingBindingFlags(bindingOptions.Flags, match.binding, allBindings, out var updateFlags)) { var updateOptions = bindingOptions.WithFlags(updateFlags); - UpdateBinding(site, match.binding, updateOptions); + commitRequired = UpdateBinding(site, match.binding, updateOptions); } } else @@ -194,14 +202,15 @@ namespace PKISharp.WACS.Clients.IIS } var binding = addOptions.Binding; - if (!existing.Contains(binding) && AllowAdd(addOptions, allBindings)) + if (!existing.Contains(binding.ToLower()) && AllowAdd(addOptions, allBindings)) { AddBinding(site, addOptions); existing.Add(binding); + commitRequired = true; } } } - return bestMatch.binding.Host; + return (bestMatch.binding.Host, commitRequired); } } @@ -210,11 +219,12 @@ namespace PKISharp.WACS.Clients.IIS if (AllowAdd(bindingOptions, allBindings)) { AddBinding(site, bindingOptions); - return bindingOptions.Host; + commitRequired = true; + return (bindingOptions.Host, commitRequired); } // We haven't been able to do anything - return null; + return (null, commitRequired); } /// <summary> @@ -243,7 +253,7 @@ namespace PKISharp.WACS.Clients.IIS // In general we shouldn't create duplicate bindings // because then only one of them will be usable at the // same time. - if (allBindings.Any(x => x.BindingInformation == bindingInfoFull)) + if (allBindings.Any(x => string.Equals(x.BindingInformation, bindingInfoFull, StringComparison.InvariantCultureIgnoreCase))) { _log.Warning($"Prevent adding duplicate binding for {bindingInfoFull}"); return false; @@ -365,7 +375,7 @@ namespace PKISharp.WACS.Clients.IIS _client.AddBinding(site, options); } - private void UpdateBinding(TSite site, TBinding existingBinding, BindingOptions options) + private bool UpdateBinding(TSite site, TBinding existingBinding, BindingOptions options) { // Check flags options = options.WithFlags(CheckFlags(false, existingBinding.Host, options.Flags)); @@ -377,6 +387,7 @@ namespace PKISharp.WACS.Clients.IIS string.Equals(existingBinding.CertificateStoreName, options.Store, StringComparison.InvariantCultureIgnoreCase)))) { _log.Verbose("No binding update needed"); + return false; } else { @@ -401,6 +412,7 @@ namespace PKISharp.WACS.Clients.IIS existingBinding.Port, (int)options.Flags); _client.UpdateBinding(site, existingBinding, options); + return true; } } diff --git a/src/main.lib/Clients/IIS/IISSiteWrapper.cs b/src/main.lib/Clients/IIS/IISSiteWrapper.cs index cb1ecd2..9bc204b 100644 --- a/src/main.lib/Clients/IIS/IISSiteWrapper.cs +++ b/src/main.lib/Clients/IIS/IISSiteWrapper.cs @@ -24,7 +24,7 @@ namespace PKISharp.WACS.Clients.IIS { Site = site; - Bindings = site.Bindings.Select(x => new IISBindingWrapper(x)); + Bindings = site.Bindings.Select(x => new IISBindingWrapper(x)).ToList(); } } |