summaryrefslogtreecommitdiffstats
path: root/src/main.lib/RenewalExecutor.cs
diff options
context:
space:
mode:
Diffstat (limited to 'src/main.lib/RenewalExecutor.cs')
-rw-r--r--src/main.lib/RenewalExecutor.cs225
1 files changed, 134 insertions, 91 deletions
diff --git a/src/main.lib/RenewalExecutor.cs b/src/main.lib/RenewalExecutor.cs
index 70a1e12..94665dc 100644
--- a/src/main.lib/RenewalExecutor.cs
+++ b/src/main.lib/RenewalExecutor.cs
@@ -46,9 +46,10 @@ namespace PKISharp.WACS
using var es = _scopeBuilder.Execution(ts, renewal, runLevel);
// Generate the target
var targetPlugin = es.Resolve<ITargetPlugin>();
- if (targetPlugin.Disabled.Item1)
+ var (disabled, disabledReason) = targetPlugin.Disabled;
+ if (disabled)
{
- throw new Exception($"Target plugin is not available. {targetPlugin.Disabled.Item2}");
+ throw new Exception($"Target plugin is not available. {disabledReason}");
}
var target = await targetPlugin.Generate();
if (target is INull)
@@ -77,7 +78,7 @@ namespace PKISharp.WACS
var cache = cs.CachedInfo(renewal, target);
if (cache != null)
{
- _log.Information(LogType.All, "Renewal for {renewal} is due after {date}", renewal.LastFriendlyName, renewal.GetDueDate());
+ _log.Information("Renewal for {renewal} is due after {date}", renewal.LastFriendlyName, renewal.GetDueDate());
return null;
}
else if (!renewal.New)
@@ -98,19 +99,30 @@ namespace PKISharp.WACS
// Create the order
var client = es.Resolve<AcmeClient>();
var identifiers = target.GetHosts(false);
+ _log.Verbose("Creating certificate order for hosts: {identifiers}", identifiers);
var order = await client.CreateOrder(identifiers);
// Check if the order is valid
- if (order.Payload.Status != AcmeClient.OrderReady &&
- order.Payload.Status != AcmeClient.OrderPending)
+ if ((order.Payload.Status != AcmeClient.OrderReady &&
+ order.Payload.Status != AcmeClient.OrderPending) ||
+ order.Payload.Error != null)
{
- return OnRenewFail(new Challenge() { Error = order.Payload.Error });
+ _log.Error("Failed to create order {url}: {detail}", order.OrderUrl, order.Payload.Error.Detail);
+ return OnRenewFail(new Challenge() { Error = "Unable to create order" });
+ }
+ else
+ {
+ _log.Verbose("Order {url} created", order.OrderUrl);
}
// Answer the challenges
foreach (var authUrl in order.Payload.Authorizations)
{
// Get authorization details
+ _log.Verbose("Handle authorization {n}/{m}",
+ order.Payload.Authorizations.ToList().IndexOf(authUrl) + 1,
+ order.Payload.Authorizations.Length + 1);
+
var authorization = await client.GetAuthorizationDetails(authUrl);
// Find a targetPart that matches the challenge
@@ -145,11 +157,12 @@ namespace PKISharp.WACS
var errors = challenge?.Error;
if (errors != null)
{
- _log.Error("ACME server reported:");
- _log.Error("{@value}", errors);
+ return new RenewResult($"Authorization failed: {errors.ToString()}");
+ }
+ else
+ {
+ return new RenewResult($"Authorization failed");
}
- return new RenewResult("Authorization failed");
-
}
/// <summary>
@@ -163,9 +176,13 @@ namespace PKISharp.WACS
{
var certificateService = renewalScope.Resolve<ICertificateService>();
var csrPlugin = target.CsrBytes == null ? renewalScope.Resolve<ICsrPlugin>() : null;
- if (csrPlugin != null && csrPlugin.Disabled.Item1)
+ if (csrPlugin != null)
{
- return new RenewResult($"CSR plugin is not available. {csrPlugin.Disabled.Item2}");
+ var (disabled, disabledReason) = csrPlugin.Disabled;
+ if (disabled)
+ {
+ return new RenewResult($"CSR plugin is not available. {disabledReason}");
+ }
}
var oldCertificate = certificateService.CachedInfo(renewal);
var newCertificate = await certificateService.RequestCertificate(csrPlugin, runLevel, renewal, target, order);
@@ -208,9 +225,10 @@ namespace PKISharp.WACS
{
_log.Information("Store with {name}...", storeOptions.Name);
}
- if (storePlugin.Disabled.Item1)
+ var (disabled, disabledReason) = storePlugin.Disabled;
+ if (disabled)
{
- return new RenewResult($"Store plugin is not available. {storePlugin.Disabled.Item2}");
+ return new RenewResult($"Store plugin is not available. {disabledReason}");
}
await storePlugin.Save(newCertificate);
storePlugins.Add(storePlugin);
@@ -247,9 +265,10 @@ namespace PKISharp.WACS
{
_log.Information("Installing with {name}...", installOptions.Name);
}
- if (installPlugin.Disabled.Item1)
+ var (disabled, disabledReason) = installPlugin.Disabled;
+ if (disabled)
{
- return new RenewResult($"Installation plugin is not available. {installPlugin.Disabled.Item2}");
+ return new RenewResult($"Installation plugin is not available. {disabledReason}");
}
await installPlugin.Install(storePlugins, newCertificate, oldCertificate);
}
@@ -338,76 +357,123 @@ namespace PKISharp.WACS
var valid = new Challenge { Status = AcmeClient.AuthorizationValid };
var client = execute.Resolve<AcmeClient>();
var identifier = authorization.Identifier.Value;
+ IValidationPlugin? validationPlugin = null;
try
{
- _log.Information("Authorize identifier: {identifier}", identifier);
- if (authorization.Status == AcmeClient.AuthorizationValid &&
- !runLevel.HasFlag(RunLevel.Test) &&
- !runLevel.HasFlag(RunLevel.IgnoreCache))
- {
- _log.Information("Cached authorization result: {Status}", authorization.Status);
- return valid;
- }
- else
+ if (authorization.Status == AcmeClient.AuthorizationValid)
{
- using var validation = _scopeBuilder.Validation(execute, options, targetPart, identifier);
- IValidationPlugin? validationPlugin = null;
- try
+ if (!runLevel.HasFlag(RunLevel.Test) &&
+ !runLevel.HasFlag(RunLevel.IgnoreCache))
{
- validationPlugin = validation.Resolve<IValidationPlugin>();
+ _log.Information("Cached authorization result: {Status}", authorization.Status);
+ return valid;
}
- catch (Exception ex)
+
+ if (runLevel.HasFlag(RunLevel.IgnoreCache))
{
- _log.Error(ex, "Error resolving validation plugin");
+ // Due to the IgnoreCache flag (--force switch)
+ // we are going to attempt to re-authorize the
+ // domain even though its already autorized.
+ // On failure, we can still use the cached result.
+ // This helps for migration scenarios.
+ invalid = valid;
}
- if (validationPlugin == null)
- {
- _log.Error("Validation plugin not found or not created.");
- return invalid;
- }
- if (validationPlugin.Disabled.Item1)
+ }
+
+ _log.Information("Authorize identifier: {identifier}", identifier);
+ _log.Verbose("Challenge types available: {challenges}", authorization.Challenges.Select(x => x.Type ?? "[Unknown]"));
+ var challenge = authorization.Challenges.FirstOrDefault(c => string.Equals(c.Type, options.ChallengeType, StringComparison.CurrentCultureIgnoreCase));
+ if (challenge == null)
+ {
+ if (authorization.Status == AcmeClient.AuthorizationValid)
{
- _log.Error($"Validation plugin is not available. {validationPlugin.Disabled.Item2}");
- return invalid;
- }
- var challenge = authorization.Challenges.FirstOrDefault(c => string.Equals(c.Type, options.ChallengeType, StringComparison.CurrentCultureIgnoreCase));
- if (challenge == null)
+ var usedType = authorization.Challenges.
+ Where(x => x.Status == AcmeClient.AuthorizationValid).
+ FirstOrDefault();
+ _log.Warning("Expected challenge type {type} not available for {identifier}, already validated using {valided}.",
+ options.ChallengeType,
+ authorization.Identifier.Value,
+ usedType?.Type ?? "[unknown]");
+ return valid;
+ }
+ else
{
_log.Error("Expected challenge type {type} not available for {identifier}.",
options.ChallengeType,
authorization.Identifier.Value);
+ invalid.Error = "Expected challenge type not available";
return invalid;
}
+ }
- if (challenge.Status == AcmeClient.AuthorizationValid &&
- !runLevel.HasFlag(RunLevel.Test) &&
- !runLevel.HasFlag(RunLevel.IgnoreCache))
- {
- _log.Information("{dnsIdentifier} already validated by {challengeType} validation ({name})",
- authorization.Identifier.Value,
- options.ChallengeType,
- options.Name);
- return valid;
- }
+ // We actually have to do validation now
+ using var validation = _scopeBuilder.Validation(execute, options, targetPart, identifier);
+ try
+ {
+ validationPlugin = validation.Resolve<IValidationPlugin>();
+ }
+ catch (Exception ex)
+ {
+ _log.Error(ex, "Error resolving validation plugin");
+ }
+ if (validationPlugin == null)
+ {
+ _log.Error("Validation plugin not found or not created.");
+ invalid.Error = "Validation plugin not found or not created.";
+ return invalid;
+ }
+ var (disabled, disabledReason) = validationPlugin.Disabled;
+ if (disabled)
+ {
+ _log.Error($"Validation plugin is not available. {disabledReason}");
+ invalid.Error = "Validation plugin is not available.";
+ return invalid;
+ }
+ _log.Information("Authorizing {dnsIdentifier} using {challengeType} validation ({name})",
+ identifier,
+ options.ChallengeType,
+ options.Name);
+ try
+ {
+ var details = await client.DecodeChallengeValidation(authorization, challenge);
+ await validationPlugin.PrepareChallenge(details);
+ }
+ catch (Exception ex)
+ {
+ _log.Error(ex, "Error preparing for challenge answer");
+ invalid.Error = "Error preparing for challenge answer";
+ return invalid;
+ }
- _log.Information("Authorizing {dnsIdentifier} using {challengeType} validation ({name})",
- identifier,
- options.ChallengeType,
- options.Name);
- try
- {
- var details = await client.DecodeChallengeValidation(authorization, challenge);
- await validationPlugin.PrepareChallenge(details);
- }
- catch (Exception ex)
+ _log.Debug("Submitting challenge answer");
+ challenge = await client.AnswerChallenge(challenge);
+ if (challenge.Status != AcmeClient.AuthorizationValid)
+ {
+ if (challenge.Error != null)
{
- _log.Error(ex, "Error preparing for challenge answer");
- return invalid;
+ _log.Error(challenge.Error.ToString());
}
-
- _log.Debug("Submitting challenge answer");
- challenge = await client.AnswerChallenge(challenge);
-
+ _log.Error("Authorization result: {Status}", challenge.Status);
+ invalid.Error = challenge.Error;
+ return invalid;
+ }
+ else
+ {
+ _log.Information("Authorization result: {Status}", challenge.Status);
+ return valid;
+ }
+ }
+ catch (Exception ex)
+ {
+ _log.Error("Error authorizing {renewal}", targetPart);
+ _exceptionHandler.HandleException(ex);
+ invalid.Error = ex.Message;
+ return invalid;
+ }
+ finally
+ {
+ if (validationPlugin != null)
+ {
try
{
_log.Verbose("Starting post-validation cleanup");
@@ -418,31 +484,8 @@ namespace PKISharp.WACS
{
_log.Warning("An error occured during post-validation cleanup: {ex}", ex.Message);
}
-
- if (challenge.Status != AcmeClient.AuthorizationValid)
- {
- if (challenge.Error != null)
- {
- _log.Error(challenge.Error.ToString());
- }
- _log.Error("Authorization result: {Status}", challenge.Status);
- return invalid;
- }
- else
- {
- _log.Information("Authorization result: {Status}", challenge.Status);
- return valid;
- }
-
-
}
}
- catch (Exception ex)
- {
- _log.Error("Error authorizing {renewal}", targetPart);
- _exceptionHandler.HandleException(ex);
- return invalid;
- }
}
}
}