/// <summary> /// If renewal is already Scheduled, replace it with the new options /// </summary> /// <param name="target"></param> /// <returns></returns> private static ScheduledRenewal CreateRenewal(ScheduledRenewal temp) { var renewal = _renewalService.Find(temp.Binding); if (renewal == null) { renewal = temp; } renewal.New = true; renewal.Test = temp.Test; renewal.Binding = temp.Binding; renewal.CentralSslStore = temp.CentralSslStore; renewal.KeepExisting = temp.KeepExisting; renewal.Script = temp.Script; renewal.ScriptParameters = temp.ScriptParameters; renewal.Warmup = temp.Warmup; return(renewal); }
public List <ScheduledRenewal> LoadRenewals() { var result = new List <ScheduledRenewal>(); var values = Registry.GetValue(registryKey, renewalsValueName, null) as string[]; if (values != null) { foreach (var value in values) { var renewal = ScheduledRenewal.Load(value); if (renewal != null) { result.Add(renewal); } } } return(result); }
private static RenewResult Renew(ILifetimeScope renewalScope, ScheduledRenewal renewal) { var targetPlugin = renewalScope.Resolve <ITargetPlugin>(); renewal.Binding = targetPlugin.Refresh(renewal.Binding); if (renewal.Binding == null) { _log.Error("Renewal target not found"); return(new RenewResult(new Exception("Renewal target not found"))); } foreach (var target in targetPlugin.Split(renewal.Binding)) { var auth = Authorize(renewalScope, target); if (auth.Status != _authorizationValid) { return(OnRenewFail(auth)); } } return(OnRenewSuccess(renewalScope, renewal)); }
private static RenewResult Renew(ILifetimeScope renewalScope, ScheduledRenewal renewal) { var targetPlugin = renewalScope.Resolve<ITargetPlugin>(); renewal.Binding = targetPlugin.Refresh(renewal.Binding); if (renewal.Binding == null) { _log.Error("Renewal target not found"); return new RenewResult(new Exception("Renewal target not found")); } var split = targetPlugin.Split(renewal.Binding); renewal.Binding.AlternativeNames = split.SelectMany(s => s.AlternativeNames).ToList(); foreach (var target in split) { var auth = Authorize(renewalScope, target); if (auth.Status != _authorizationValid) { return OnRenewFail(auth); } } return OnRenewSuccess(renewalScope, renewal); }
const float renewalPeriod = 60; // can't easily make this a command line option since it would have to be saved public static void ScheduleRenewal(Target target) { EnsureTaskScheduler(); var renewals = settings.LoadRenewals(); foreach (var existing in from r in renewals.ToArray() where r.Binding.Host == target.Host select r) { Console.WriteLine($" Removing existing scheduled renewal {existing}"); renewals.Remove(existing); } var result = new ScheduledRenewal() { Binding = target, CentralSSL = Options.CentralSSLStore, Date = DateTime.UtcNow.AddDays(renewalPeriod) }; renewals.Add(result); settings.SaveRenewals(renewals); Console.WriteLine($" Renewal Scheduled {result}"); }
internal static ILifetimeScope Renewal(IContainer main, ScheduledRenewal renewal, RunLevel runLevel) { IResolver resolver = null; if (runLevel > RunLevel.Unattended) { resolver = main.Resolve <InteractiveResolver>( new TypedParameter(typeof(ScheduledRenewal), renewal), new TypedParameter(typeof(RunLevel), runLevel)); } else { resolver = main.Resolve <UnattendedResolver>(new TypedParameter(typeof(ScheduledRenewal), renewal)); } return(main.BeginLifetimeScope(builder => { builder.RegisterType <LetsEncryptClient>().SingleInstance(); builder.RegisterType <CertificateService>().SingleInstance(); builder.RegisterInstance(resolver); builder.RegisterInstance(renewal); builder.Register(c => runLevel).As <RunLevel>(); builder.RegisterType <TaskSchedulerService>(). WithParameter(new TypedParameter(typeof(RunLevel), runLevel)). WithParameter(new TypedParameter(typeof(string), main.ResolveNamed <string>("clientName"))). SingleInstance(); builder.Register(c => resolver.GetTargetPlugin(main)).As <ITargetPluginFactory>().SingleInstance(); builder.Register(c => resolver.GetInstallationPlugins(main)).As <List <IInstallationPluginFactory> >().SingleInstance(); builder.Register(c => resolver.GetValidationPlugin(main)).As <IValidationPluginFactory>().SingleInstance(); builder.Register(c => resolver.GetStorePlugin(main)).As <IStorePluginFactory>().SingleInstance(); builder.Register(c => c.Resolve(c.Resolve <ITargetPluginFactory>().Instance)).As <ITargetPlugin>().SingleInstance(); builder.Register(c => c.Resolve(c.Resolve <IStorePluginFactory>().Instance)).As <IStorePlugin>().SingleInstance(); })); }
/// <summary> /// Find the most recently issued certificate for a specific target /// </summary> /// <param name="target"></param> /// <returns></returns> public static X509Certificate2 FindCertificate(ScheduledRenewal scheduled) { if (scheduled == null) { return(null); } var thumbprint = scheduled.History. OrderByDescending(x => x.Date). Where(x => x.Success). Select(x => x.Thumbprint). FirstOrDefault(); var friendlyName = scheduled.Binding.Host; var useThumbprint = !string.IsNullOrEmpty(thumbprint); if (!_options.CentralSsl) { if (useThumbprint) { return(_certificateStoreService.GetCertificateByThumbprint(thumbprint)); } else { return(_certificateStoreService.GetCertificateByFriendlyName(friendlyName)); } } else { if (useThumbprint) { return(_centralSslService.GetCertificateByThumbprint(thumbprint)); } else { return(_centralSslService.GetCertificateByFriendlyName(friendlyName)); } } }
/// <summary> /// Steps to take on succesful (re)authorization /// </summary> /// <param name="target"></param> private static RenewResult OnRenewSuccess(ILifetimeScope renewalScope, ScheduledRenewal renewal) { RenewResult result = null; try { var certificateService = renewalScope.Resolve <CertificateService>(); var storePlugin = renewalScope.Resolve <IStorePlugin>(); var oldCertificate = renewal.Certificate(storePlugin); var newCertificate = certificateService.RequestCertificate(renewal.Binding); // Test if a new certificate has been generated if (newCertificate == null) { return(new RenewResult(new Exception("No certificate generated"))); } else { result = new RenewResult(newCertificate); } // Early escape for testing validation only if (_options.Test && renewal.New && !_input.PromptYesNo($"[--test] Do you want to install the certificate?")) { return(result); } try { // Check if the newly requested certificate is already in the store, // which might be the case due to the cache mechanism built into the // RequestCertificate function var storedCertificate = storePlugin.FindByThumbprint(newCertificate.Certificate.Thumbprint); if (storedCertificate != null) { // Copy relevant properties _log.Warning("Certificate with thumbprint {thumbprint} is already in the store", newCertificate.Certificate.Thumbprint); newCertificate.Store = storedCertificate.Store; } else { // Save to store storePlugin.Save(newCertificate); } } catch (Exception ex) { _log.Error(ex, "Unable to store certificate"); result.Success = false; result.ErrorMessage = $"Store failed: {ex.Message}"; return(result); } // Run installation plugin(s) try { var installFactories = renewalScope.Resolve <List <IInstallationPluginFactory> >(); var steps = installFactories.Count(); for (var i = 0; i < steps; i++) { var installFactory = installFactories[i]; if (!(installFactory is INull)) { var installInstance = (IInstallationPlugin)renewalScope.Resolve(installFactory.Instance); if (steps > 1) { _log.Information("Installation step {n}/{m}: {name}...", i + 1, steps, installFactory.Description); } else { _log.Information("Installing with {name}...", installFactory.Description); } installInstance.Install(newCertificate, oldCertificate); } } } catch (Exception ex) { _log.Error(ex, "Unable to install certificate"); result.Success = false; result.ErrorMessage = $"Install failed: {ex.Message}"; } // Delete the old certificate if not forbidden, found and not re-used if ((!renewal.KeepExisting ?? false) && oldCertificate != null && newCertificate.Certificate.Thumbprint != oldCertificate.Certificate.Thumbprint) { try { storePlugin.Delete(oldCertificate); } catch (Exception ex) { _log.Error(ex, "Unable to delete previous certificate"); //result.Success = false; // not a show-stopper, consider the renewal a success result.ErrorMessage = $"Delete failed: {ex.Message}"; } } // Add or update renewal if (renewal.New && !_options.NoTaskScheduler && (!_options.Test || _input.PromptYesNo($"Do you want to automatically renew this certificate in {_renewalService.RenewalPeriod} days?"))) { var taskScheduler = _container.Resolve <TaskSchedulerService>(); taskScheduler.EnsureTaskScheduler(); _renewalService.Save(renewal, result); } return(result); } catch (Exception ex) { // Result might still contain the Thumbprint of the certificate // that was requested and (partially? installed, which might help // with debugging HandleException(ex); if (result == null) { result = new RenewResult(ex); } else { result.Success = false; result.ErrorMessage = ex.Message; } } return(result); }
const float renewalPeriod = 60; // can't easily make this a command line option since it would have to be saved public static void ScheduleRenewal(Target target) { EnsureTaskScheduler(); var renewals = settings.LoadRenewals(); foreach (var existing in from r in renewals.ToArray() where r.Binding.Host == target.Host select r) { Console.WriteLine($" Removing existing scheduled renewal {existing}"); Log.Information("Removing existing scheduled renewal {existing}", existing); renewals.Remove(existing); } var result = new ScheduledRenewal() { Binding = target, CentralSSL = Options.CentralSSLStore, SAN = Options.SAN.ToString(), Date = DateTime.UtcNow.AddDays(renewalPeriod) }; renewals.Add(result); settings.SaveRenewals(renewals); Console.WriteLine($" Renewal Scheduled {result}"); Log.Information("Renewal Scheduled {result}", result); }
private static void ProcessRenewal(List <ScheduledRenewal> renewals, DateTime now, ScheduledRenewal renewal) { if (!_options.ForceRenewal) { _log.Verbose("Checking {renewal}", renewal.Binding.Host); if (renewal.Date >= now) { _log.Information("Renewal for certificate {renewal} not scheduled, due after {date}", renewal.Binding.Host, renewal.Date.ToUserString()); return; } } _log.Information(true, "Renewing certificate for {renewal}", renewal.Binding.Host); _options.CentralSslStore = renewal.CentralSsl; _options.KeepExisting = string.Equals(renewal.KeepExisting, "true", StringComparison.InvariantCultureIgnoreCase); _options.Script = renewal.Script; _options.ScriptParameters = renewal.ScriptParameters; _options.Warmup = renewal.Warmup; try { // Let the plugin run var result = renewal.Binding.Plugin.Auto(renewal.Binding); // Process result if (result.Success) { renewal.Date = DateTime.UtcNow.AddDays(_renewalService.RenewalPeriod); _log.Information(true, "Renewal for {host} succeeded, next one scheduled for {date}", renewal.Binding.Host, renewal.Date.ToUserString()); } else { _log.Error("Renewal for {host} failed, will retry on next run", renewal.Binding.Host); } // Store historical information if (renewal.History == null) { renewal.History = new List <RenewResult>(); } renewal.History.Add(result); // Persist to registry _renewalService.Renewals = renewals; } catch (Exception ex) { HandleException(ex); _log.Error("Renewal for {host} failed, will retry on next run", renewal.Binding.Host); } }
private static void ProcessRenewal(List <ScheduledRenewal> renewals, DateTime now, ScheduledRenewal renewal) { if (!Options.ForceRenewal) { Log.Information("Checking {renewal}", renewal); if (renewal.Date >= now) { Log.Information("Renewal for certificate {renewal} not scheduled", renewal); return; } } Log.Information("Renewing certificate for {renewal}", renewal); Options.CentralSslStore = renewal.CentralSsl; Options.San = string.Equals(renewal.San, "true", StringComparison.InvariantCultureIgnoreCase); Options.KeepExisting = string.Equals(renewal.KeepExisting, "true", StringComparison.InvariantCultureIgnoreCase); Options.Script = renewal.Script; Options.ScriptParameters = renewal.ScriptParameters; Options.Warmup = renewal.Warmup; Options.WebRoot = renewal.Binding?.WebRootPath ?? Options.WebRootDefault; if (renewal.AzureOptions != null) { renewal.AzureOptions.ApplyOn(Options); } else { new AzureOptions().ApplyOn(Options); } try { renewal.Binding.Plugin.Renew(renewal.Binding); renewal.Date = DateTime.UtcNow.AddDays(RenewalPeriod); _settings.SaveRenewals(renewals); Log.Information("Renewal scheduled {renewal}", renewal); } catch { Log.Error("Renewal failed {renewal}, will retry on next run", renewal); } }
public static void ScheduleRenewal(Target target) { EnsureTaskScheduler(); var renewals = _settings.LoadRenewals(); foreach (var existing in from r in renewals.ToArray() where r.Binding.Host == target.Host select r) { Console.WriteLine($" Removing existing scheduled renewal {existing}"); Log.Information("Removing existing scheduled renewal {existing}", existing); renewals.Remove(existing); } var result = new ScheduledRenewal() { Binding = target, CentralSsl = Options.CentralSslStore, San = Options.San.ToString(), Date = DateTime.UtcNow.AddDays(RenewalPeriod), KeepExisting = Options.KeepExisting.ToString(), Script = Options.Script, ScriptParameters = Options.ScriptParameters, Warmup = Options.Warmup }; renewals.Add(result); _settings.SaveRenewals(renewals); Console.WriteLine($" Renewal Scheduled {result}"); Log.Information("Renewal Scheduled {result}", result); }
private static void ProcessRenewal(List<ScheduledRenewal> renewals, DateTime now, ScheduledRenewal renewal) { Console.WriteLine($" Checking {renewal}"); Log.Information("Checking {renewal}", renewal); if (renewal.Date >= now) return; Console.WriteLine($" Renewing certificate for {renewal}"); Log.Information("Renewing certificate for {renewal}", renewal); if (string.IsNullOrWhiteSpace(renewal.CentralSsl)) { //Not using Central SSL CentralSsl = false; Options.CentralSslStore = null; } else { //Using Central SSL CentralSsl = true; Options.CentralSslStore = renewal.CentralSsl; } if (string.IsNullOrWhiteSpace(renewal.San)) { //Not using San Options.San = false; } else if (renewal.San.ToLower() == "true") { //Using San Options.San = true; } else { //Not using San Options.San = false; } if (string.IsNullOrWhiteSpace(renewal.KeepExisting)) { //Not using KeepExisting Options.KeepExisting = false; } else if (renewal.KeepExisting.ToLower() == "true") { //Using KeepExisting Options.KeepExisting = true; } else { //Not using KeepExisting Options.KeepExisting = false; } if (!string.IsNullOrWhiteSpace(renewal.Script)) { Options.Script = renewal.Script; } if (!string.IsNullOrWhiteSpace(renewal.ScriptParameters)) { Options.ScriptParameters = renewal.ScriptParameters; } if (renewal.Warmup) { Options.Warmup = true; } renewal.Binding.Plugin.Renew(renewal.Binding); renewal.Date = DateTime.UtcNow.AddDays(RenewalPeriod); _settings.SaveRenewals(renewals); Console.WriteLine($" Renewal Scheduled {renewal}"); Log.Information("Renewal Scheduled {renewal}", renewal); }
private static void ProcessRenewal(List <ScheduledRenewal> renewals, DateTime now, ScheduledRenewal renewal) { if (!Options.ForceRenewal) { Log.Verbose("Checking {renewal}", renewal.Binding.Host); if (renewal.Date >= now) { Log.Information("Renewal for certificate {renewal} not scheduled", renewal.Binding.Host); return; } } Log.Information(true, "Renewing certificate for {renewal}", renewal.Binding.Host); Options.CentralSslStore = renewal.CentralSsl; Options.KeepExisting = string.Equals(renewal.KeepExisting, "true", StringComparison.InvariantCultureIgnoreCase); Options.Script = renewal.Script; Options.ScriptParameters = renewal.ScriptParameters; Options.Warmup = renewal.Warmup; Options.WebRoot = renewal.Binding?.WebRootPath ?? Options.WebRootDefault; try { renewal.Binding.Plugin.Renew(renewal.Binding); renewal.Date = DateTime.UtcNow.AddDays(RenewalPeriod); Settings.Renewals = renewals; Log.Information(true, "Renewal for {host} succeeded, rescheduled for {date}", renewal.Binding.Host, renewal.Date.ToString(Properties.Settings.Default.FileDateFormat)); } catch { Log.Error("Renewal for {host} failed, will retry on next run", renewal.Binding.Host); } }
/// <summary> /// Refresh the scheduled renewal (e.g. for a changed web root path) /// </summary> /// <param name="renewal"></param> public virtual void Refresh(ScheduledRenewal renewal) { }
const float renewalPeriod = 60; // can't easily make this a command line option since it would have to be saved static void ScheduleRenewal(TargetBinding binding) { EnsureTaskScheduler(); var renewals = settings.LoadRenewals(); foreach (var existing in from r in renewals.ToArray() where r.Binding.Host == binding.Host select r) { Console.WriteLine($" Removing existing scheduled renewal {existing}"); renewals.Remove(existing); } var result = new ScheduledRenewal() { Binding = binding, Date = DateTime.UtcNow.AddDays(renewalPeriod) }; renewals.Add(result); settings.SaveRenewals(renewals); Console.WriteLine($" Renewal Scheduled {result}"); }
/// <summary> /// Steps to take on succesful (re)authorization /// </summary> /// <param name="target"></param> private static RenewResult OnRenewSuccess(ILifetimeScope renewalScope, ScheduledRenewal renewal) { RenewResult result = null; try { var certificateService = renewalScope.Resolve <CertificateService>(); var storePlugin = renewalScope.Resolve <IStorePlugin>(); var oldCertificate = renewal.Certificate(storePlugin); var newCertificate = certificateService.RequestCertificate(renewal.Binding); if (newCertificate == null) { return(new RenewResult(new Exception("No certificate generated"))); } else { result = new RenewResult(newCertificate); } // Early escape for testing validation only if (_options.Test && renewal.New && !_input.PromptYesNo($"Do you want to save the certificate?")) { return(result); } // Save to store storePlugin.Save(newCertificate); // Run installation plugin(s) try { var installFactories = renewalScope.Resolve <List <IInstallationPluginFactory> >(); var steps = installFactories.Count(); for (var i = 0; i < steps; i++) { var installFactory = installFactories[i]; if (!(installFactory is INull)) { var installInstance = (IInstallationPlugin)renewalScope.Resolve(installFactory.Instance); if (steps > 1) { _log.Information("Installation step {n}/{m}: {name}...", i + 1, steps, installFactory.Description); } else { _log.Information("Installing with {name}...", installFactory.Description); } installInstance.Install(newCertificate, oldCertificate); } } } catch (Exception ex) { _log.Error(ex, "Unable to install certificate"); result.Success = false; result.ErrorMessage = $"Install failed: {ex.Message}"; } // Delete the old certificate if specified and found if (!renewal.KeepExisting && oldCertificate != null) { try { storePlugin.Delete(oldCertificate); } catch (Exception ex) { _log.Error(ex, "Unable to delete previous certificate"); //result.Success = false; // not a show-stopper, consider the renewal a success result.ErrorMessage = $"Delete failed: {ex.Message}"; } } // Add or update renewal if (renewal.New && !_options.NoTaskScheduler && (!_options.Test || _input.PromptYesNo($"Do you want to automatically renew this certificate in {_renewalService.RenewalPeriod} days? This will add a task scheduler task."))) { var taskScheduler = _container.Resolve <TaskSchedulerService>(); taskScheduler.EnsureTaskScheduler(); _renewalService.Save(renewal, result); } return(result); } catch (Exception ex) { // Result might still contain the Thumbprint of the certificate // that was requested and (partially? installed, which might help // with debugging HandleException(ex); if (result == null) { result = new RenewResult(ex); } else { result.Success = false; result.ErrorMessage = ex.Message; } } return(result); }
/// <summary> /// Refresh the scheduled renewal (e.g. for a changed web root path) /// </summary> /// <param name="renewal"></param> public virtual ScheduledRenewal Refresh(ScheduledRenewal renewal) { return(renewal); }