예제 #1
0
        /// <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);
        }
예제 #2
0
        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);
        }
예제 #3
0
        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));
        }
예제 #4
0
 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);
 }
예제 #5
0
        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();
            }));
        }
예제 #7
0
        /// <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));
                }
            }
        }
예제 #8
0
        /// <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);
        }
예제 #9
0
        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);
        }
예제 #10
0
        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);
            }
        }
예제 #11
0
        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);
            }
        }
예제 #12
0
        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);
        }
예제 #13
0
        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);
        }
예제 #14
0
        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);
            }
        }
예제 #15
0
 /// <summary>
 /// Refresh the scheduled renewal (e.g. for a changed web root path)
 /// </summary>
 /// <param name="renewal"></param>
 public virtual void Refresh(ScheduledRenewal renewal)
 {
 }
예제 #16
0
        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}");
        }
예제 #17
0
        /// <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);
        }
예제 #18
0
 /// <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);
 }