Beispiel #1
0
        /// <summary>
        /// Check if there are multiple renewals installing to the same site
        /// or requesting certificates for the same domains
        /// </summary>
        /// <param name="selectedRenewals"></param>
        /// <returns></returns>
        private async Task <IEnumerable <Renewal> > Analyze(IEnumerable <Renewal> selectedRenewals)
        {
            var foundHosts = new Dictionary <Identifier, List <Renewal> >();
            var foundSites = new Dictionary <long, List <Renewal> >();

            foreach (var renewal in selectedRenewals)
            {
                using var targetScope = _scopeBuilder.Target(_container, renewal, RunLevel.Unattended);
                var target = targetScope.Resolve <Target>();
                foreach (var targetPart in target.Parts)
                {
                    if (targetPart.SiteId != null)
                    {
                        var siteId = targetPart.SiteId.Value;
                        if (!foundSites.ContainsKey(siteId))
                        {
                            foundSites.Add(siteId, new List <Renewal>());
                        }
                        foundSites[siteId].Add(renewal);
                    }
                    foreach (var host in targetPart.GetIdentifiers(true))
                    {
                        if (!foundHosts.ContainsKey(host))
                        {
                            foundHosts.Add(host, new List <Renewal>());
                        }
                        foundHosts[host].Add(renewal);
                    }
                }
            }

            // List results
            var options = new List <Choice <List <Renewal> > >();

            foreach (var site in foundSites)
            {
                if (site.Value.Count > 1)
                {
                    options.Add(
                        Choice.Create(
                            site.Value,
                            $"Select {site.Value.Count} renewals covering IIS site {site.Key}"));
                }
            }
            foreach (var host in foundHosts)
            {
                if (host.Value.Count > 1)
                {
                    options.Add(
                        Choice.Create(
                            host.Value,
                            $"Select {host.Value.Count} renewals covering host {host.Key}"));
                }
            }
            _input.CreateSpace();
            if (options.Count == 0)
            {
                _input.Show(null, "Analysis didn't find any overlap between renewals.");
                return(selectedRenewals);
            }
            else
            {
                options.Add(
                    Choice.Create(
                        selectedRenewals.ToList(),
                        $"Back"));
                _input.Show(null, "Analysis found some overlap between renewals. You can select the overlapping renewals from the menu.");
                return(await _input.ChooseFromMenu("Please choose from the menu", options));
            }
        }
        /// <summary>
        /// Setup a new scheduled renewal
        /// </summary>
        /// <param name="runLevel"></param>
        internal async Task SetupRenewal(RunLevel runLevel, Renewal?tempRenewal = null)
        {
            if (_args.Test)
            {
                runLevel |= RunLevel.Test;
            }
            if (_args.Force)
            {
                runLevel |= RunLevel.IgnoreCache;
            }
            _log.Information(LogType.All, "Running in mode: {runLevel}", runLevel);
            if (tempRenewal == null)
            {
                tempRenewal = Renewal.Create(_args.Id, _settings.ScheduledTask.RenewalDays, _passwordGenerator);
            }
            using var configScope = _scopeBuilder.Configuration(_container, tempRenewal, runLevel);
            // Choose target plugin
            var targetPluginOptionsFactory = configScope.Resolve <ITargetPluginOptionsFactory>();

            if (targetPluginOptionsFactory is INull)
            {
                _exceptionHandler.HandleException(message: $"No source plugin could be selected");
                return;
            }
            var(targetPluginDisabled, targetPluginDisabledReason) = targetPluginOptionsFactory.Disabled;
            if (targetPluginDisabled)
            {
                _exceptionHandler.HandleException(message: $"Source plugin {targetPluginOptionsFactory.Name} is not available. {targetPluginDisabledReason}");
                return;
            }
            var targetPluginOptions = runLevel.HasFlag(RunLevel.Unattended) ?
                                      await targetPluginOptionsFactory.Default() :
                                      await targetPluginOptionsFactory.Aquire(_input, runLevel);

            if (targetPluginOptions == null)
            {
                _exceptionHandler.HandleException(message: $"Source plugin {targetPluginOptionsFactory.Name} aborted or failed");
                return;
            }
            tempRenewal.TargetPluginOptions = targetPluginOptions;

            // Generate Target and validation plugin choice
            using var targetScope = _scopeBuilder.Target(_container, tempRenewal, runLevel);
            var initialTarget = targetScope.Resolve <Target>();

            if (initialTarget is INull)
            {
                _exceptionHandler.HandleException(message: $"Source plugin {targetPluginOptionsFactory.Name} was unable to generate a target");
                return;
            }
            if (!initialTarget.IsValid(_log))
            {
                _exceptionHandler.HandleException(message: $"Source plugin {targetPluginOptionsFactory.Name} generated an invalid target");
                return;
            }
            _log.Information("Source generated using plugin {name}: {target}", targetPluginOptions.Name, initialTarget);

            // Choose FriendlyName
            if (!string.IsNullOrEmpty(_args.FriendlyName))
            {
                tempRenewal.FriendlyName = _args.FriendlyName;
            }
            else if (runLevel.HasFlag(RunLevel.Advanced | RunLevel.Interactive))
            {
                var alt = await _input.RequestString($"Suggested friendly name '{initialTarget.FriendlyName}', press <Enter> to accept or type an alternative");

                if (!string.IsNullOrEmpty(alt))
                {
                    tempRenewal.FriendlyName = alt;
                }
            }
            tempRenewal.LastFriendlyName = tempRenewal.FriendlyName ?? initialTarget.FriendlyName;

            // Choose validation plugin
            var validationPluginOptionsFactory = targetScope.Resolve <IValidationPluginOptionsFactory>();

            if (validationPluginOptionsFactory is INull)
            {
                _exceptionHandler.HandleException(message: $"No validation plugin could be selected");
                return;
            }

            // Configure validation
            try
            {
                var validationOptions = runLevel.HasFlag(RunLevel.Unattended)
                    ? await validationPluginOptionsFactory.Default(initialTarget)
                    : await validationPluginOptionsFactory.Aquire(initialTarget, _input, runLevel);

                if (validationOptions == null)
                {
                    _exceptionHandler.HandleException(message: $"Validation plugin {validationPluginOptionsFactory.Name} was unable to generate options");
                    return;
                }
                tempRenewal.ValidationPluginOptions = validationOptions;
            }
            catch (Exception ex)
            {
                _exceptionHandler.HandleException(ex, $"Validation plugin {validationPluginOptionsFactory.Name} aborted or failed");
                return;
            }

            // Choose order plugin
            var orderPluginOptionsFactory = targetScope.Resolve <IOrderPluginOptionsFactory>();

            if (orderPluginOptionsFactory is INull)
            {
                _exceptionHandler.HandleException(message: $"No order plugin could be selected");
                return;
            }

            // Configure order
            try
            {
                var orderOptions = runLevel.HasFlag(RunLevel.Unattended) ?
                                   await orderPluginOptionsFactory.Default() :
                                   await orderPluginOptionsFactory.Aquire(_input, runLevel);

                if (orderOptions == null)
                {
                    _exceptionHandler.HandleException(message: $"Order plugin {orderPluginOptionsFactory.Name} was unable to generate options");
                    return;
                }
                tempRenewal.OrderPluginOptions = orderOptions;
            }
            catch (Exception ex)
            {
                _exceptionHandler.HandleException(ex, $"Order plugin {orderPluginOptionsFactory.Name} aborted or failed");
                return;
            }

            // Choose CSR plugin
            if (initialTarget.CsrBytes == null)
            {
                var csrPluginOptionsFactory = configScope.Resolve <ICsrPluginOptionsFactory>();
                if (csrPluginOptionsFactory is INull)
                {
                    _exceptionHandler.HandleException(message: $"No CSR plugin could be selected");
                    return;
                }

                // Configure CSR
                try
                {
                    var csrOptions = runLevel.HasFlag(RunLevel.Unattended) ?
                                     await csrPluginOptionsFactory.Default() :
                                     await csrPluginOptionsFactory.Aquire(_input, runLevel);

                    if (csrOptions == null)
                    {
                        _exceptionHandler.HandleException(message: $"CSR plugin {csrPluginOptionsFactory.Name} was unable to generate options");
                        return;
                    }
                    tempRenewal.CsrPluginOptions = csrOptions;
                }
                catch (Exception ex)
                {
                    _exceptionHandler.HandleException(ex, $"CSR plugin {csrPluginOptionsFactory.Name} aborted or failed");
                    return;
                }
            }

            // Choose and configure store plugins
            var resolver = configScope.Resolve <IResolver>();
            var storePluginOptionsFactories = new List <IStorePluginOptionsFactory>();

            try
            {
                while (true)
                {
                    var storePluginOptionsFactory = await resolver.GetStorePlugin(configScope, storePluginOptionsFactories);

                    if (storePluginOptionsFactory == null)
                    {
                        _exceptionHandler.HandleException(message: $"Store could not be selected");
                        return;
                    }
                    StorePluginOptions?storeOptions;
                    try
                    {
                        storeOptions = runLevel.HasFlag(RunLevel.Unattended)
                            ? await storePluginOptionsFactory.Default()
                            : await storePluginOptionsFactory.Aquire(_input, runLevel);
                    }
                    catch (Exception ex)
                    {
                        _exceptionHandler.HandleException(ex, $"Store plugin {storePluginOptionsFactory.Name} aborted or failed");
                        return;
                    }
                    if (storeOptions == null)
                    {
                        _exceptionHandler.HandleException(message: $"Store plugin {storePluginOptionsFactory.Name} was unable to generate options");
                        return;
                    }
                    var isNull = storePluginOptionsFactory is NullStoreOptionsFactory;
                    if (!isNull || storePluginOptionsFactories.Count == 0)
                    {
                        tempRenewal.StorePluginOptions.Add(storeOptions);
                        storePluginOptionsFactories.Add(storePluginOptionsFactory);
                    }
                    if (isNull)
                    {
                        break;
                    }
                }
            }
            catch (Exception ex)
            {
                _exceptionHandler.HandleException(ex, "Invalid selection of store plugins");
                return;
            }

            // Choose and configure installation plugins
            var installationPluginFactories = new List <IInstallationPluginOptionsFactory>();

            try
            {
                while (true)
                {
                    var installationPluginOptionsFactory = await resolver.GetInstallationPlugin(configScope,
                                                                                                tempRenewal.StorePluginOptions.Select(x => x.Instance),
                                                                                                installationPluginFactories);

                    if (installationPluginOptionsFactory == null)
                    {
                        _exceptionHandler.HandleException(message: $"Installation plugin could not be selected");
                        return;
                    }
                    InstallationPluginOptions installOptions;
                    try
                    {
                        installOptions = runLevel.HasFlag(RunLevel.Unattended)
                            ? await installationPluginOptionsFactory.Default(initialTarget)
                            : await installationPluginOptionsFactory.Aquire(initialTarget, _input, runLevel);
                    }
                    catch (Exception ex)
                    {
                        _exceptionHandler.HandleException(ex, $"Installation plugin {installationPluginOptionsFactory.Name} aborted or failed");
                        return;
                    }
                    if (installOptions == null)
                    {
                        _exceptionHandler.HandleException(message: $"Installation plugin {installationPluginOptionsFactory.Name} was unable to generate options");
                        return;
                    }
                    var isNull = installationPluginOptionsFactory is NullInstallationOptionsFactory;
                    if (!isNull || installationPluginFactories.Count == 0)
                    {
                        tempRenewal.InstallationPluginOptions.Add(installOptions);
                        installationPluginFactories.Add(installationPluginOptionsFactory);
                    }
                    if (isNull)
                    {
                        break;
                    }
                }
            }
            catch (Exception ex)
            {
                _exceptionHandler.HandleException(ex, "Invalid selection of installation plugins");
                return;
            }

            // Try to run for the first time
            var renewal = await CreateRenewal(tempRenewal, runLevel);

retry:
            var result = await _renewalExecution.HandleRenewal(renewal, runLevel);

            if (result.Abort)
            {
                _exceptionHandler.HandleException(message: $"Create certificate cancelled");
            }
            else if (!result.Success)
            {
                if (runLevel.HasFlag(RunLevel.Interactive) &&
                    await _input.PromptYesNo("Create certificate failed, retry?", false))
                {
                    goto retry;
                }
                if (!renewal.New &&
                    await _input.PromptYesNo("Save these new settings anyway?", false))
                {
                    _renewalStore.Save(renewal, result);
                }
                _exceptionHandler.HandleException(message: $"Create certificate failed: {string.Join("\n\t- ", result.ErrorMessages)}");
            }
            else
            {
                try
                {
                    _renewalStore.Save(renewal, result);
                    await _notification.NotifyCreated(renewal, _log.Lines);
                }
                catch (Exception ex)
                {
                    _exceptionHandler.HandleException(ex);
                }
            }
        }
Beispiel #3
0
        /// <summary>
        /// Determine if the renewal should be executes
        /// </summary>
        /// <param name="renewal"></param>
        /// <param name="runLevel"></param>
        /// <returns></returns>
        public async Task <RenewResult> HandleRenewal(Renewal renewal, RunLevel runLevel)
        {
            _input.CreateSpace();
            _log.Reset();
            using var ts = _scopeBuilder.Target(_container, renewal, runLevel);
            using var es = _scopeBuilder.Execution(ts, renewal, runLevel);
            // Generate the target
            var targetPlugin = es.Resolve <ITargetPlugin>();

            var(disabled, disabledReason) = targetPlugin.Disabled;
            if (disabled)
            {
                return(new RenewResult($"Target plugin is not available. {disabledReason}"));
            }
            var target = await targetPlugin.Generate();

            if (target is INull)
            {
                return(new RenewResult($"Target plugin did not generate a target"));
            }
            if (!target.IsValid(_log))
            {
                return(new RenewResult($"Target plugin generated an invalid target"));
            }

            // Check if our validation plugin is (still) up to the task
            var validationPlugin = es.Resolve <IValidationPluginOptionsFactory>();

            if (!validationPlugin.CanValidate(target))
            {
                return(new RenewResult($"Validation plugin is unable to validate the target. A wildcard host was introduced into a HTTP validated renewal."));
            }

            // Create one or more orders based on the target
            var orderPlugin = es.Resolve <IOrderPlugin>();
            var orders      = orderPlugin.Split(renewal, target);

            if (orders == null || orders.Count() == 0)
            {
                return(new RenewResult("Order plugin failed to create order(s)"));
            }
            _log.Verbose("Targeted convert into {n} order(s)", orders.Count());

            // Check if renewal is needed
            if (!runLevel.HasFlag(RunLevel.ForceRenew) && !renewal.Updated)
            {
                _log.Verbose("Checking {renewal}", renewal.LastFriendlyName);
                if (!renewal.IsDue())
                {
                    var cs    = es.Resolve <ICertificateService>();
                    var abort = true;
                    foreach (var order in orders)
                    {
                        var cache = cs.CachedInfo(order);
                        if (cache == null && !renewal.New)
                        {
                            _log.Information(LogType.All, "Renewal for {renewal} running prematurely due to detected target change", renewal.LastFriendlyName);
                            abort = false;
                            break;
                        }
                    }
                    if (abort)
                    {
                        _log.Information("Renewal for {renewal} is due after {date}", renewal.LastFriendlyName, renewal.GetDueDate());
                        return(new RenewResult()
                        {
                            Abort = true
                        });
                    }
                }
                else if (!renewal.New)
                {
                    _log.Information(LogType.All, "Renewing certificate for {renewal}", renewal.LastFriendlyName);
                }
            }
            else if (runLevel.HasFlag(RunLevel.ForceRenew))
            {
                _log.Information(LogType.All, "Force renewing certificate for {renewal}", renewal.LastFriendlyName);
            }

            // If at this point we haven't retured already with an error/abort
            // actually execute the renewal
            var result = await ExecuteRenewal(es, orders.ToList(), runLevel);

            // Configure task scheduler
            if (result.Success && !result.Abort)
            {
                if ((renewal.New || renewal.Updated) && !_args.NoTaskScheduler)
                {
                    if (runLevel.HasFlag(RunLevel.Test) && !await _input.PromptYesNo($"[--test] Do you want to automatically renew with these settings?", true))
                    {
                        // Early out for test runs
                        result.Abort = true;
                        return(result);
                    }
                    else
                    {
                        // Make sure the Task Scheduler is configured
                        await es.Resolve <TaskSchedulerService>().EnsureTaskScheduler(runLevel, false);
                    }
                }
            }
            return(result);
        }
Beispiel #4
0
        /// <summary>
        /// Setup a new scheduled renewal
        /// </summary>
        /// </summary>
        /// <param name="runLevel"></param>
        /// <param name="steps"></param>
        /// <param name="tempRenewal"></param>
        /// <returns></returns>
        internal async Task SetupRenewal(RunLevel runLevel, Steps steps = Steps.All, Renewal?tempRenewal = null)
        {
            if (_args.Test)
            {
                runLevel |= RunLevel.Test;
            }
            if (_args.Force)
            {
                runLevel |= RunLevel.IgnoreCache;
            }
            _log.Information(LogType.All, "Running in mode: {runLevel}", runLevel);
            if (tempRenewal == null)
            {
                tempRenewal = Renewal.Create(_args.Id, _passwordGenerator);
            }
            using var configScope = _scopeBuilder.Configuration(_container, tempRenewal, runLevel);

            // Choose the target plugin
            if (steps.HasFlag(Steps.Target))
            {
                var targetOptions = await SetupTarget(configScope, runLevel);

                if (targetOptions == null)
                {
                    return;
                }
                tempRenewal.TargetPluginOptions = targetOptions;
            }

            // Generate initial target
            using var targetScope = _scopeBuilder.Target(_container, tempRenewal, runLevel);
            var initialTarget = targetScope.Resolve <Target>();

            if (initialTarget is INull)
            {
                _exceptionHandler.HandleException(message: $"Source plugin {tempRenewal.TargetPluginOptions.Name} was unable to generate the certificate parameters.");
                return;
            }
            if (!initialTarget.IsValid(_log))
            {
                _exceptionHandler.HandleException(message: $"Source plugin {tempRenewal.TargetPluginOptions.Name} generated invalid certificate parameters");
                return;
            }
            _log.Information("Source generated using plugin {name}: {target}", tempRenewal.TargetPluginOptions.Name, initialTarget);

            // Setup the friendly name
            var ask = runLevel.HasFlag(RunLevel.Advanced | RunLevel.Interactive) && steps.HasFlag(Steps.Target);

            await SetupFriendlyName(tempRenewal, initialTarget, ask);

            // Choose the validation plugin
            if (steps.HasFlag(Steps.Validation))
            {
                var validationOptions = await SetupValidation(targetScope, initialTarget, runLevel);

                if (validationOptions == null)
                {
                    return;
                }
                tempRenewal.ValidationPluginOptions = validationOptions;
            }

            // Choose the order plugin
            if (steps.HasFlag(Steps.Order))
            {
                tempRenewal.OrderPluginOptions = await SetupOrder(targetScope, runLevel);

                if (tempRenewal.OrderPluginOptions == null)
                {
                    return;
                }
            }

            // Choose the CSR plugin
            if (initialTarget.UserCsrBytes != null)
            {
                tempRenewal.CsrPluginOptions = null;
            }
            else if (steps.HasFlag(Steps.Csr))
            {
                tempRenewal.CsrPluginOptions = await SetupCsr(configScope, runLevel);

                if (tempRenewal.CsrPluginOptions == null)
                {
                    return;
                }
            }

            // Choose store plugin(s)
            if (steps.HasFlag(Steps.Store))
            {
                var store = await SetupStore(configScope, runLevel);

                if (store != null)
                {
                    tempRenewal.StorePluginOptions = store;
                }
                else
                {
                    return;
                }
            }

            // Choose installation plugin(s)
            if (steps.HasFlag(Steps.Installation))
            {
                var install = await SetupInstallation(configScope, runLevel, tempRenewal, initialTarget);

                if (install != null)
                {
                    tempRenewal.InstallationPluginOptions = install;
                }
                else
                {
                    return;
                }
            }

            // Try to run for the first time
            var renewal = await CreateRenewal(tempRenewal, runLevel);

retry:
            var result = await _renewalExecution.HandleRenewal(renewal, runLevel);

            if (result.Abort)
            {
                _log.Information($"Create certificate cancelled");
            }
            else if (result.Success != true)
            {
                if (runLevel.HasFlag(RunLevel.Interactive) &&
                    await _input.PromptYesNo("Create certificate failed, retry?", false))
                {
                    goto retry;
                }
                if (!renewal.New &&
                    runLevel.HasFlag(RunLevel.Interactive) &&
                    await _input.PromptYesNo("Save these new settings anyway?", false))
                {
                    _renewalStore.Save(renewal, result);
                }
                _exceptionHandler.HandleException(message: $"Create certificate failed: {string.Join("\n\t- ", result.ErrorMessages)}");
            }
            else
            {
                try
                {
                    _renewalStore.Save(renewal, result);
                    await _notification.NotifyCreated(renewal, _log.Lines);
                }
                catch (Exception ex)
                {
                    _exceptionHandler.HandleException(ex);
                }
            }
        }
Beispiel #5
0
        public async Task <RenewResult> Renew(Renewal renewal, RunLevel runLevel)
        {
            using var ts = _scopeBuilder.Target(_container, renewal, runLevel);
            using var es = _scopeBuilder.Execution(ts, renewal, runLevel);
            // Generate the target
            var targetPlugin = es.Resolve <ITargetPlugin>();

            if (targetPlugin.Disabled)
            {
                throw new Exception($"Target plugin is not available to the current user, try running as administrator");
            }
            var target = await targetPlugin.Generate();

            if (target == null)
            {
                throw new Exception($"Target plugin did not generate a target");
            }
            if (!target.IsValid(_log))
            {
                throw new Exception($"Target plugin generated an invalid target");
            }

            // Check if our validation plugin is (still) up to the task
            var validationPlugin = es.Resolve <IValidationPluginOptionsFactory>();

            if (!validationPlugin.CanValidate(target))
            {
                throw new Exception($"Validation plugin is unable to validate the target. A wildcard host was introduced into a HTTP validated renewal.");
            }

            // Check if renewal is needed
            if (!runLevel.HasFlag(RunLevel.ForceRenew) && !renewal.Updated)
            {
                _log.Verbose("Checking {renewal}", renewal.LastFriendlyName);
                if (!renewal.IsDue())
                {
                    var cs    = es.Resolve <ICertificateService>();
                    var cache = cs.CachedInfo(renewal);
                    if (cache != null && cache.Match(target))
                    {
                        _log.Information(LogType.All, "Renewal for {renewal} is due after {date}", renewal.LastFriendlyName, renewal.GetDueDate());
                        return(null);
                    }
                    else if (!renewal.New)
                    {
                        _log.Information(LogType.All, "Renewal for {renewal} running prematurely due to detected target change", renewal.LastFriendlyName);
                    }
                }
                else if (!renewal.New)
                {
                    _log.Information(LogType.All, "Renewing certificate for {renewal}", renewal.LastFriendlyName);
                }
            }
            else if (runLevel.HasFlag(RunLevel.ForceRenew))
            {
                _log.Information(LogType.All, "Force renewing certificate for {renewal}", renewal.LastFriendlyName);
            }

            // Create the order
            var client      = es.Resolve <AcmeClient>();
            var identifiers = target.GetHosts(false);
            var order       = await client.CreateOrder(identifiers);

            // Check if the order is valid
            if (order.Payload.Status != AcmeClient.OrderReady &&
                order.Payload.Status != AcmeClient.OrderPending)
            {
                return(OnRenewFail(new Challenge()
                {
                    Error = order.Payload.Error
                }));
            }

            // Answer the challenges
            foreach (var authUrl in order.Payload.Authorizations)
            {
                // Get authorization details
                var authorization = await client.GetAuthorizationDetails(authUrl);

                // Find a targetPart that matches the challenge
                var targetPart = target.Parts.
                                 FirstOrDefault(tp => tp.GetHosts(false).
                                                Any(h => authorization.Identifier.Value == h.Replace("*.", "")));
                if (targetPart == null)
                {
                    return(OnRenewFail(new Challenge()
                    {
                        Error = "Unable to match challenge to target"
                    }));
                }

                // Run the validation plugin
                var challenge = await Authorize(es, runLevel, renewal.ValidationPluginOptions, targetPart, authorization);

                if (challenge.Status != AcmeClient.AuthorizationValid)
                {
                    return(OnRenewFail(challenge));
                }
            }
            return(await OnValidationSuccess(es, renewal, target, order, runLevel));
        }
Beispiel #6
0
        /// <summary>
        /// Determine if the renewal should be executes
        /// </summary>
        /// <param name="renewal"></param>
        /// <param name="runLevel"></param>
        /// <returns></returns>
        public async Task <RenewResult> HandleRenewal(Renewal renewal, RunLevel runLevel)
        {
            _input.CreateSpace();
            _log.Reset();
            using var ts = _scopeBuilder.Target(_container, renewal, runLevel);
            using var es = _scopeBuilder.Execution(ts, renewal, runLevel);

            // Generate the target
            var targetPlugin = es.Resolve <ITargetPlugin>();

            var(disabled, disabledReason) = targetPlugin.Disabled;
            if (disabled)
            {
                return(new RenewResult($"Source plugin is not available. {disabledReason}"));
            }
            var target = await targetPlugin.Generate();

            if (target is INull)
            {
                return(new RenewResult($"Source plugin did not generate source"));
            }

            // Create one or more orders based on the target
            var orderPlugin = es.Resolve <IOrderPlugin>();
            var orders      = orderPlugin.Split(renewal, target);

            if (orders == null || !orders.Any())
            {
                return(new RenewResult("Order plugin failed to create order(s)"));
            }
            _log.Verbose("Source converted into {n} order(s)", orders.Count());
            foreach (var order in orders)
            {
                if (!order.Target.IsValid(_log))
                {
                    return(new RenewResult($"Source plugin generated invalid source"));
                }
            }

            /// Start to check the renewal
            var result = await HandleOrders(es, renewal, orders.ToList(), runLevel);

            // Configure task scheduler
            var setupTaskScheduler = _args.SetupTaskScheduler;

            if (!setupTaskScheduler && !_args.NoTaskScheduler)
            {
                setupTaskScheduler = result.Success == true && !result.Abort && (renewal.New || renewal.Updated);
            }
            if (setupTaskScheduler && runLevel.HasFlag(RunLevel.Test))
            {
                setupTaskScheduler = await _input.PromptYesNo($"[--test] Do you want to automatically renew with these settings?", true);

                if (!setupTaskScheduler)
                {
                    result.Abort = true;
                }
            }
            if (setupTaskScheduler)
            {
                var taskLevel = runLevel;
                if (_args.SetupTaskScheduler)
                {
                    taskLevel |= RunLevel.ForceRenew;
                }
                await es.Resolve <TaskSchedulerService>().EnsureTaskScheduler(runLevel);
            }
            return(result);
        }
Beispiel #7
0
        /// <summary>
        /// Determine if the renewal should be executes
        /// </summary>
        /// <param name="renewal"></param>
        /// <param name="runLevel"></param>
        /// <returns></returns>
        public async Task <RenewResult> HandleRenewal(Renewal renewal, RunLevel runLevel)
        {
            _input.CreateSpace();
            _log.Reset();
            using var ts = _scopeBuilder.Target(_container, renewal, runLevel);
            using var es = _scopeBuilder.Execution(ts, renewal, runLevel);
            // Generate the target
            var targetPlugin = es.Resolve <ITargetPlugin>();

            var(disabled, disabledReason) = targetPlugin.Disabled;
            if (disabled)
            {
                return(new RenewResult($"Source plugin is not available. {disabledReason}"));
            }
            var target = await targetPlugin.Generate();

            if (target is INull)
            {
                return(new RenewResult($"Source plugin did not generate source"));
            }
            if (!target.IsValid(_log))
            {
                return(new RenewResult($"Source plugin generated invalid source"));
            }

            // Check if our validation plugin is (still) up to the task
            var validationPlugin = es.Resolve <IValidationPluginOptionsFactory>();

            if (!validationPlugin.CanValidate(target))
            {
                return(new RenewResult($"Validation plugin is unable to validate the source. A wildcard host was introduced into a HTTP validated renewal."));
            }

            // Create one or more orders based on the target
            var orderPlugin = es.Resolve <IOrderPlugin>();
            var orders      = orderPlugin.Split(renewal, target);

            if (orders == null || !orders.Any())
            {
                return(new RenewResult("Order plugin failed to create order(s)"));
            }
            _log.Verbose("Targeted convert into {n} order(s)", orders.Count());

            // Test if this renewal should run right now
            if (!ShouldRun(es, orders, renewal, runLevel))
            {
                return(new RenewResult()
                {
                    Abort = true
                });
            }

            // If at this point we haven't retured already with an error/abort
            // actually execute the renewal
            var preScript    = _settings.Execution?.DefaultPreExecutionScript;
            var scriptClient = es.Resolve <ScriptClient>();

            if (!string.IsNullOrWhiteSpace(preScript))
            {
                await scriptClient.RunScript(preScript, $"{renewal.Id}");
            }
            var result = await ExecuteRenewal(es, orders.ToList(), runLevel);

            var postScript = _settings.Execution?.DefaultPostExecutionScript;

            if (!string.IsNullOrWhiteSpace(postScript))
            {
                await scriptClient.RunScript(postScript, $"{renewal.Id}");
            }

            // Configure task scheduler
            var setupTaskScheduler = _args.SetupTaskScheduler;

            if (!setupTaskScheduler && !_args.NoTaskScheduler)
            {
                setupTaskScheduler = result.Success && !result.Abort && (renewal.New || renewal.Updated);
            }
            if (setupTaskScheduler && runLevel.HasFlag(RunLevel.Test))
            {
                setupTaskScheduler = await _input.PromptYesNo($"[--test] Do you want to automatically renew with these settings?", true);

                if (!setupTaskScheduler)
                {
                    result.Abort = true;
                }
            }
            if (setupTaskScheduler)
            {
                var taskLevel = runLevel;
                if (_args.SetupTaskScheduler)
                {
                    taskLevel |= RunLevel.ForceRenew;
                }
                await es.Resolve <TaskSchedulerService>().EnsureTaskScheduler(runLevel);
            }
            return(result);
        }
Beispiel #8
0
        /// <summary>
        /// Setup a new scheduled renewal
        /// </summary>
        /// <param name="runLevel"></param>
        internal async Task SetupRenewal(RunLevel runLevel)
        {
            if (_args.Test)
            {
                runLevel |= RunLevel.Test;
            }
            if (_args.Force)
            {
                runLevel |= RunLevel.IgnoreCache;
            }
            _log.Information(LogType.All, "Running in mode: {runLevel}", runLevel);
            var tempRenewal = Renewal.Create(_args.Id, _settings.ScheduledTask.RenewalDays, _passwordGenerator);

            using var configScope = _scopeBuilder.Configuration(_container, tempRenewal, runLevel);
            // Choose target plugin
            var targetPluginOptionsFactory = configScope.Resolve <ITargetPluginOptionsFactory>();

            if (targetPluginOptionsFactory is INull)
            {
                _exceptionHandler.HandleException(message: $"No target plugin could be selected");
                return;
            }
            if (targetPluginOptionsFactory.Disabled)
            {
                _exceptionHandler.HandleException(message: $"Target plugin {targetPluginOptionsFactory.Name} is not available to the current user, try running as administrator");
                return;
            }
            var targetPluginOptions = runLevel.HasFlag(RunLevel.Unattended) ?
                                      await targetPluginOptionsFactory.Default() :
                                      await targetPluginOptionsFactory.Aquire(_input, runLevel);

            if (targetPluginOptions == null)
            {
                _exceptionHandler.HandleException(message: $"Target plugin {targetPluginOptionsFactory.Name} aborted or failed");
                return;
            }
            tempRenewal.TargetPluginOptions = targetPluginOptions;

            // Generate Target and validation plugin choice
            Target initialTarget = null;
            IValidationPluginOptionsFactory validationPluginOptionsFactory = null;

            using (var targetScope = _scopeBuilder.Target(_container, tempRenewal, runLevel))
            {
                initialTarget = targetScope.Resolve <Target>();
                if (initialTarget == null)
                {
                    _exceptionHandler.HandleException(message: $"Target plugin {targetPluginOptionsFactory.Name} was unable to generate a target");
                    return;
                }
                if (!initialTarget.IsValid(_log))
                {
                    _exceptionHandler.HandleException(message: $"Target plugin {targetPluginOptionsFactory.Name} generated an invalid target");
                    return;
                }
                _log.Information("Target generated using plugin {name}: {target}", targetPluginOptions.Name, initialTarget);

                // Choose FriendlyName
                if (runLevel.HasFlag(RunLevel.Advanced) &&
                    runLevel.HasFlag(RunLevel.Interactive) &&
                    string.IsNullOrEmpty(_args.FriendlyName))
                {
                    var alt = await _input.RequestString($"Suggested FriendlyName is '{initialTarget.FriendlyName}', press enter to accept or type an alternative");

                    if (!string.IsNullOrEmpty(alt))
                    {
                        tempRenewal.FriendlyName = alt;
                    }
                }
                tempRenewal.LastFriendlyName = initialTarget.FriendlyName;

                // Choose validation plugin
                validationPluginOptionsFactory = targetScope.Resolve <IValidationPluginOptionsFactory>();
                if (validationPluginOptionsFactory is INull)
                {
                    _exceptionHandler.HandleException(message: $"No validation plugin could be selected");
                    return;
                }
            }

            // Configure validation
            try
            {
                var validationOptions = runLevel.HasFlag(RunLevel.Unattended)
                    ? await validationPluginOptionsFactory.Default(initialTarget)
                    : await validationPluginOptionsFactory.Aquire(initialTarget, _input, runLevel);

                if (validationOptions == null)
                {
                    _exceptionHandler.HandleException(message: $"Validation plugin {validationPluginOptionsFactory.Name} was unable to generate options");
                    return;
                }
                tempRenewal.ValidationPluginOptions = validationOptions;
            }
            catch (Exception ex)
            {
                _exceptionHandler.HandleException(ex, $"Validation plugin {validationPluginOptionsFactory.Name} aborted or failed");
                return;
            }

            // Choose CSR plugin
            if (initialTarget.CsrBytes == null)
            {
                var csrPluginOptionsFactory = configScope.Resolve <ICsrPluginOptionsFactory>();
                if (csrPluginOptionsFactory is INull)
                {
                    _exceptionHandler.HandleException(message: $"No CSR plugin could be selected");
                    return;
                }

                // Configure CSR
                try
                {
                    var csrOptions = runLevel.HasFlag(RunLevel.Unattended) ?
                                     await csrPluginOptionsFactory.Default() :
                                     await csrPluginOptionsFactory.Aquire(_input, runLevel);

                    if (csrOptions == null)
                    {
                        _exceptionHandler.HandleException(message: $"CSR plugin {csrPluginOptionsFactory.Name} was unable to generate options");
                        return;
                    }
                    tempRenewal.CsrPluginOptions = csrOptions;
                }
                catch (Exception ex)
                {
                    _exceptionHandler.HandleException(ex, $"CSR plugin {csrPluginOptionsFactory.Name} aborted or failed");
                    return;
                }
            }

            // Choose and configure store plugins
            var resolver = configScope.Resolve <IResolver>();
            var storePluginOptionsFactories = new List <IStorePluginOptionsFactory>();

            try
            {
                while (true)
                {
                    var storePluginOptionsFactory = await resolver.GetStorePlugin(configScope, storePluginOptionsFactories);

                    if (storePluginOptionsFactory == null)
                    {
                        _exceptionHandler.HandleException(message: $"Store could not be selected");
                    }
                    if (storePluginOptionsFactory is NullStoreOptionsFactory)
                    {
                        if (storePluginOptionsFactories.Count == 0)
                        {
                            throw new Exception();
                        }
                        break;
                    }
                    StorePluginOptions storeOptions;
                    try
                    {
                        storeOptions = runLevel.HasFlag(RunLevel.Unattended)
                            ? await storePluginOptionsFactory.Default()
                            : await storePluginOptionsFactory.Aquire(_input, runLevel);
                    }
                    catch (Exception ex)
                    {
                        _exceptionHandler.HandleException(ex, $"Store plugin {storePluginOptionsFactory.Name} aborted or failed");
                        return;
                    }
                    if (storeOptions == null)
                    {
                        _exceptionHandler.HandleException(message: $"Store plugin {storePluginOptionsFactory.Name} was unable to generate options");
                        return;
                    }
                    tempRenewal.StorePluginOptions.Add(storeOptions);
                    storePluginOptionsFactories.Add(storePluginOptionsFactory);
                }
            }
            catch (Exception ex)
            {
                _exceptionHandler.HandleException(ex, "Invalid selection of store plugins");
                return;
            }

            // Choose and configure installation plugins
            var installationPluginFactories = new List <IInstallationPluginOptionsFactory>();

            try
            {
                while (true)
                {
                    var installationPluginFactory = await resolver.GetInstallationPlugin(configScope,
                                                                                         tempRenewal.StorePluginOptions.Select(x => x.Instance),
                                                                                         installationPluginFactories);

                    if (installationPluginFactory == null)
                    {
                        _exceptionHandler.HandleException(message: $"Installation plugin could not be selected");
                    }
                    InstallationPluginOptions installOptions;
                    try
                    {
                        installOptions = runLevel.HasFlag(RunLevel.Unattended)
                            ? await installationPluginFactory.Default(initialTarget)
                            : await installationPluginFactory.Aquire(initialTarget, _input, runLevel);
                    }
                    catch (Exception ex)
                    {
                        _exceptionHandler.HandleException(ex, $"Installation plugin {installationPluginFactory.Name} aborted or failed");
                        return;
                    }
                    if (installOptions == null)
                    {
                        _exceptionHandler.HandleException(message: $"Installation plugin {installationPluginFactory.Name} was unable to generate options");
                        return;
                    }
                    if (installationPluginFactory is NullInstallationOptionsFactory)
                    {
                        if (installationPluginFactories.Count == 0)
                        {
                            tempRenewal.InstallationPluginOptions.Add(installOptions);
                            installationPluginFactories.Add(installationPluginFactory);
                        }
                        break;
                    }
                    tempRenewal.InstallationPluginOptions.Add(installOptions);
                    installationPluginFactories.Add(installationPluginFactory);
                }
            }
            catch (Exception ex)
            {
                _exceptionHandler.HandleException(ex, "Invalid selection of installation plugins");
                return;
            }

            // Try to run for the first time
            var renewal = await CreateRenewal(tempRenewal, runLevel);

            var result = await _renewalExecution.Renew(renewal, runLevel);

            if (!result.Success)
            {
                _exceptionHandler.HandleException(message: $"Create certificate failed: {result.ErrorMessage}");
            }
            else
            {
                _renewalStore.Save(renewal, result);
            }
        }