/// <summary> /// Show certificate details /// </summary> private async Task ShowRenewal(Renewal renewal) { try { _input.Show("Id", renewal.Id, true); _input.Show("File", $"{renewal.Id}.renewal.json"); _input.Show("FriendlyName", string.IsNullOrEmpty(renewal.FriendlyName) ? $"[Auto] {renewal.LastFriendlyName}" : renewal.FriendlyName); _input.Show(".pfx password", renewal.PfxPassword?.Value); _input.Show("Renewal due", renewal.GetDueDate()?.ToString() ?? "now"); _input.Show("Renewed", $"{renewal.History.Where(x => x.Success).Count()} times"); renewal.TargetPluginOptions.Show(_input); renewal.ValidationPluginOptions.Show(_input); if (renewal.CsrPluginOptions != null) { renewal.CsrPluginOptions.Show(_input); } foreach (var ipo in renewal.StorePluginOptions) { ipo.Show(_input); } foreach (var ipo in renewal.InstallationPluginOptions) { ipo.Show(_input); } _input.Show("History"); await _input.WritePagedList(renewal.History.Select(x => Choice.Create(x))); } catch (Exception ex) { _log.Error(ex, "Unable to list details for target"); } }
/// <summary> /// Show certificate details /// </summary> private async Task ShowRenewal(Renewal renewal) { try { _input.CreateSpace(); _input.Show("Id", renewal.Id); _input.Show("File", $"{renewal.Id}.renewal.json"); _input.Show("FriendlyName", string.IsNullOrEmpty(renewal.FriendlyName) ? $"[Auto] {renewal.LastFriendlyName}" : renewal.FriendlyName); _input.Show(".pfx password", renewal.PfxPassword?.Value); _input.Show("Renewal due", renewal.GetDueDate()?.ToString() ?? "now"); _input.Show("Renewed", $"{renewal.History.Where(x => x.Success).Count()} times"); renewal.TargetPluginOptions.Show(_input); renewal.ValidationPluginOptions.Show(_input); if (renewal.OrderPluginOptions != null) { renewal.OrderPluginOptions.Show(_input); } if (renewal.CsrPluginOptions != null) { renewal.CsrPluginOptions.Show(_input); } foreach (var ipo in renewal.StorePluginOptions) { ipo.Show(_input); } foreach (var ipo in renewal.InstallationPluginOptions) { ipo.Show(_input); } var historyLimit = 10; if (renewal.History.Count <= historyLimit) { _input.Show("History"); } else { _input.Show($"History (most recent {historyLimit} of {renewal.History.Count} entries)"); } await _input.WritePagedList( renewal.History. AsEnumerable(). Reverse(). Take(historyLimit). Reverse(). Select(x => Choice.Create(x))); } catch (Exception ex) { _log.Error(ex, "Unable to list details for target"); } }
public void Save(Renewal renewal, RenewResult result) { var renewals = Renewals.ToList(); if (renewal.New) { renewal.History = new List <RenewResult>(); renewals.Add(renewal); _log.Information(LogType.All, "Adding renewal for {friendlyName}", renewal.LastFriendlyName); } // Set next date renewal.History.Add(result); if (result.Success) { _log.Information(LogType.All, "Next renewal scheduled at {date}", renewal.GetDueDate()); } renewal.Updated = true; Renewals = renewals; }
/// <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); }
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)); }
private bool ShouldRun(ILifetimeScope target, IEnumerable <Order> orders, Renewal renewal, RunLevel runLevel) { // Check if renewal is needed if (!runLevel.HasFlag(RunLevel.ForceRenew) && !renewal.Updated) { _log.Verbose("Checking {renewal}", renewal.LastFriendlyName); if (!renewal.IsDue()) { var cs = target.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 {renewal} running prematurely due to source change", renewal.LastFriendlyName); abort = false; break; } } if (abort) { _log.Information("Renewal {renewal} is due after {date}", renewal.LastFriendlyName, renewal.GetDueDate()); return(false); } } else if (!renewal.New) { _log.Information(LogType.All, "Renewing certificate {renewal}", renewal.LastFriendlyName); } } else if (runLevel.HasFlag(RunLevel.ForceRenew)) { _log.Information(LogType.All, "Force renewing certificate {renewal}", renewal.LastFriendlyName); } return(true); }