diff options
21 files changed, 149 insertions, 161 deletions
diff --git a/src/main.lib/Clients/EmailClient.cs b/src/main.lib/Clients/EmailClient.cs index 5c98239..4f77115 100644 --- a/src/main.lib/Clients/EmailClient.cs +++ b/src/main.lib/Clients/EmailClient.cs @@ -122,6 +122,7 @@ namespace PKISharp.WACS.Clients bodyBuilder.HtmlBody = content + $"<p>Sent by win-acme version {_version} from {_computerName}</p>"; message.Body = bodyBuilder.ToMessageBody(); await client.SendAsync(message); + await client.DisconnectAsync(true); } } catch (Exception ex) @@ -130,7 +131,7 @@ namespace PKISharp.WACS.Clients } finally { - await client.DisconnectAsync(true); + } } } diff --git a/src/main.lib/Plugins/Interfaces/IValidationPlugin.cs b/src/main.lib/Plugins/Interfaces/IValidationPlugin.cs index ba899db..df5746e 100644 --- a/src/main.lib/Plugins/Interfaces/IValidationPlugin.cs +++ b/src/main.lib/Plugins/Interfaces/IValidationPlugin.cs @@ -1,5 +1,5 @@ using ACMESharp.Authorizations; -using System; +using PKISharp.WACS.DomainObjects; using System.Threading.Tasks; namespace PKISharp.WACS.Plugins.Interfaces @@ -16,11 +16,23 @@ namespace PKISharp.WACS.Plugins.Interfaces /// <param name="target"></param> /// <param name="challenge"></param> /// <returns></returns> - Task PrepareChallenge(IChallengeValidationDetails challengeDetails); + Task PrepareChallenge(ValidationContext context, IChallengeValidationDetails challenge); /// <summary> /// Clean up after validation attempt /// </summary> - Task CleanUp(); + Task CleanUp(ValidationContext context, IChallengeValidationDetails challenge); } + + public class ValidationContext + { + public ValidationContext(string identifier, TargetPart targetPart) + { + Identifier = identifier; + TargetPart = targetPart; + } + public string Identifier { get; set; } + public TargetPart TargetPart { get; set; } + } + } diff --git a/src/main.lib/Plugins/ValidationPlugins/Dns/Acme/Acme.cs b/src/main.lib/Plugins/ValidationPlugins/Dns/Acme/Acme.cs index ddcff59..b24cc38 100644 --- a/src/main.lib/Plugins/ValidationPlugins/Dns/Acme/Acme.cs +++ b/src/main.lib/Plugins/ValidationPlugins/Dns/Acme/Acme.cs @@ -1,5 +1,6 @@ using PKISharp.WACS.Clients; using PKISharp.WACS.Clients.DNS; +using PKISharp.WACS.Plugins.Interfaces; using PKISharp.WACS.Services; using System; using System.Threading.Tasks; @@ -11,7 +12,6 @@ namespace PKISharp.WACS.Plugins.ValidationPlugins.Dns private readonly IInputService _input; private readonly ProxyService _proxy; private readonly AcmeOptions _options; - private readonly string _identifier; public Acme( LookupClientProvider dnsClient, @@ -19,12 +19,10 @@ namespace PKISharp.WACS.Plugins.ValidationPlugins.Dns ISettingsService settings, IInputService input, ProxyService proxy, - AcmeOptions options, - string identifier) : + AcmeOptions options) : base(dnsClient, log, settings) { _options = options; - _identifier = identifier; _input = input; _proxy = proxy; } @@ -34,12 +32,12 @@ namespace PKISharp.WACS.Plugins.ValidationPlugins.Dns /// </summary> /// <param name="recordName"></param> /// <param name="token"></param> - public override async Task<bool> CreateRecord(string recordName, string token) + public override async Task<bool> CreateRecord(ValidationContext context, string recordName, string token) { var client = new AcmeDnsClient(_dnsClient, _proxy, _log, _settings, _input, new Uri(_options.BaseUri)); - return await client.Update(_identifier, token); + return await client.Update(context.Identifier, token); } - public override Task DeleteRecord(string recordName, string token) => Task.CompletedTask; + public override Task DeleteRecord(ValidationContext context, string recordName, string token) => Task.CompletedTask; } } diff --git a/src/main.lib/Plugins/ValidationPlugins/Dns/DnsValidation.cs b/src/main.lib/Plugins/ValidationPlugins/Dns/DnsValidation.cs index 87e5273..d88cc47 100644 --- a/src/main.lib/Plugins/ValidationPlugins/Dns/DnsValidation.cs +++ b/src/main.lib/Plugins/ValidationPlugins/Dns/DnsValidation.cs @@ -1,5 +1,7 @@ using ACMESharp.Authorizations;
using PKISharp.WACS.Clients.DNS;
+using PKISharp.WACS.DomainObjects;
+using PKISharp.WACS.Plugins.Interfaces;
using PKISharp.WACS.Services;
using System;
using System.Collections.Generic;
@@ -30,17 +32,17 @@ namespace PKISharp.WACS.Plugins.ValidationPlugins _settings = settings;
}
- public override async Task PrepareChallenge()
+ public override async Task PrepareChallenge(ValidationContext context, Dns01ChallengeValidationDetails challenge)
{
// Check for substitute domains
_authority = await _dnsClient.GetAuthority(
- Challenge.DnsRecordName,
+ challenge.DnsRecordName,
followCnames: _settings.Validation.AllowDnsSubstitution);
var success = false;
while (!success)
{
- success = await CreateRecord(_authority.Domain, Challenge.DnsRecordValue);
+ success = await CreateRecord(context, _authority.Domain, challenge.DnsRecordValue);
if (!success)
{
if (_authority.From == null)
@@ -61,7 +63,7 @@ namespace PKISharp.WACS.Plugins.ValidationPlugins var retrySeconds = _settings.Validation.PreValidateDnsRetryInterval;
while (_settings.Validation.PreValidateDns)
{
- if (await PreValidate())
+ if (await PreValidate(challenge.DnsRecordValue))
{
break;
}
@@ -82,7 +84,7 @@ namespace PKISharp.WACS.Plugins.ValidationPlugins }
}
- protected async Task<bool> PreValidate()
+ protected async Task<bool> PreValidate(string expectedValue)
{
try
{
@@ -100,7 +102,7 @@ namespace PKISharp.WACS.Plugins.ValidationPlugins _log.Warning("Preliminary validation failed: no TXT records found");
return false;
}
- if (!answers.Contains(Challenge.DnsRecordValue))
+ if (!answers.Contains(expectedValue))
{
_log.Debug("Preliminary validation found values: {answers}", answers);
_log.Warning("Preliminary validation failed: incorrect TXT record(s) found");
@@ -121,13 +123,13 @@ namespace PKISharp.WACS.Plugins.ValidationPlugins /// <summary>
/// Delete record when we're done
/// </summary>
- public override async Task CleanUp()
+ public override async Task CleanUp(ValidationContext context, Dns01ChallengeValidationDetails challenge)
{
- if (HasChallenge && _authority != null)
+ if (_authority != null)
{
try
{
- await DeleteRecord(_authority.Domain, Challenge.DnsRecordValue);
+ await DeleteRecord(context, _authority.Domain, challenge.DnsRecordValue);
}
catch (Exception ex)
{
@@ -140,14 +142,14 @@ namespace PKISharp.WACS.Plugins.ValidationPlugins /// Delete validation record
/// </summary>
/// <param name="recordName">Name of the record</param>
- public abstract Task DeleteRecord(string recordName, string token);
+ public abstract Task DeleteRecord(ValidationContext context, string recordName, string token);
/// <summary>
/// Create validation record
/// </summary>
/// <param name="recordName">Name of the record</param>
/// <param name="token">Contents of the record</param>
- public abstract Task<bool> CreateRecord(string recordName, string token);
+ public abstract Task<bool> CreateRecord(ValidationContext context, string recordName, string token);
/// <summary>
/// Match DNS zone to use from a list of all zones
diff --git a/src/main.lib/Plugins/ValidationPlugins/Dns/Manual/Manual.cs b/src/main.lib/Plugins/ValidationPlugins/Dns/Manual/Manual.cs index c584efb..b65ea07 100644 --- a/src/main.lib/Plugins/ValidationPlugins/Dns/Manual/Manual.cs +++ b/src/main.lib/Plugins/ValidationPlugins/Dns/Manual/Manual.cs @@ -1,4 +1,5 @@ using PKISharp.WACS.Clients.DNS; +using PKISharp.WACS.Plugins.Interfaces; using PKISharp.WACS.Services; using System.Threading.Tasks; @@ -7,28 +8,24 @@ namespace PKISharp.WACS.Plugins.ValidationPlugins.Dns internal class Manual : DnsValidation<Manual> { private readonly IInputService _input; - private readonly string _identifier; public Manual( LookupClientProvider dnsClient, ILogService log, IInputService input, - ISettingsService settings, - string identifier) - : base(dnsClient, log, settings) + ISettingsService settings) : base(dnsClient, log, settings) { // Usually it's a big no-no to rely on user input in validation plugin // because this should be able to run unattended. This plugin is for testing // only and therefor we will allow it. Future versions might be more advanced, // e.g. shoot an email to an admin and complete the order later. _input = input; - _identifier = identifier; } - public override async Task<bool> CreateRecord(string recordName, string token) + public override async Task<bool> CreateRecord(ValidationContext context, string recordName, string token) { _input.CreateSpace(); - _input.Show("Domain", _identifier); + _input.Show("Domain", context.Identifier); _input.Show("Record", recordName); _input.Show("Type", "TXT"); _input.Show("Content", $"\"{token}\""); @@ -42,7 +39,7 @@ namespace PKISharp.WACS.Plugins.ValidationPlugins.Dns // Pre-pre-validate, allowing the manual user to correct mistakes while (true) { - if (await PreValidate()) + if (await PreValidate(token)) { return true; } @@ -61,10 +58,10 @@ namespace PKISharp.WACS.Plugins.ValidationPlugins.Dns } } - public override Task DeleteRecord(string recordName, string token) + public override Task DeleteRecord(ValidationContext context, string recordName, string token) { _input.CreateSpace(); - _input.Show("Domain", _identifier); + _input.Show("Domain", context.Identifier); _input.Show("Record", recordName); _input.Show("Type", "TXT"); _input.Show("Content", $"\"{token}\""); diff --git a/src/main.lib/Plugins/ValidationPlugins/Dns/Script/Script.cs b/src/main.lib/Plugins/ValidationPlugins/Dns/Script/Script.cs index 80ece5e..0f2c6f4 100644 --- a/src/main.lib/Plugins/ValidationPlugins/Dns/Script/Script.cs +++ b/src/main.lib/Plugins/ValidationPlugins/Dns/Script/Script.cs @@ -1,5 +1,6 @@ using PKISharp.WACS.Clients; using PKISharp.WACS.Clients.DNS; +using PKISharp.WACS.Plugins.Interfaces; using PKISharp.WACS.Services; using System.Threading.Tasks; @@ -9,7 +10,6 @@ namespace PKISharp.WACS.Plugins.ValidationPlugins.Dns { private readonly ScriptClient _scriptClient; private readonly ScriptOptions _options; - private readonly string _identifier; internal const string DefaultCreateArguments = "create {Identifier} {RecordName} {Token}"; internal const string DefaultDeleteArguments = "delete {Identifier} {RecordName} {Token}"; @@ -19,16 +19,14 @@ namespace PKISharp.WACS.Plugins.ValidationPlugins.Dns LookupClientProvider dnsClient, ScriptClient client, ILogService log, - ISettingsService settings, - string identifier) : + ISettingsService settings) : base(dnsClient, log, settings) { - _identifier = identifier; _options = options; _scriptClient = client; } - public override async Task<bool> CreateRecord(string recordName, string token) + public override async Task<bool> CreateRecord(ValidationContext context, string recordName, string token) { var script = _options.Script ?? _options.CreateScript; if (!string.IsNullOrWhiteSpace(script)) @@ -38,7 +36,7 @@ namespace PKISharp.WACS.Plugins.ValidationPlugins.Dns { args = _options.CreateScriptArguments; } - await _scriptClient.RunScript(script, ProcessArguments(recordName, token, args, script.EndsWith(".ps1"))); + await _scriptClient.RunScript(script, ProcessArguments(context.Identifier, recordName, token, args, script.EndsWith(".ps1"))); return true; } else @@ -48,7 +46,7 @@ namespace PKISharp.WACS.Plugins.ValidationPlugins.Dns } } - public override async Task DeleteRecord(string recordName, string token) + public override async Task DeleteRecord(ValidationContext context, string recordName, string token) { var script = _options.Script ?? _options.DeleteScript; if (!string.IsNullOrWhiteSpace(script)) @@ -58,7 +56,7 @@ namespace PKISharp.WACS.Plugins.ValidationPlugins.Dns { args = _options.DeleteScriptArguments; } - await _scriptClient.RunScript(script, ProcessArguments(recordName, token, args, script.EndsWith(".ps1"))); + await _scriptClient.RunScript(script, ProcessArguments(context.Identifier, recordName, token, args, script.EndsWith(".ps1"))); } else { @@ -66,10 +64,10 @@ namespace PKISharp.WACS.Plugins.ValidationPlugins.Dns } } - private string ProcessArguments(string recordName, string token, string args, bool escapeToken) + private string ProcessArguments(string identifier, string recordName, string token, string args, bool escapeToken) { var ret = args; - ret = ret.Replace("{Identifier}", _identifier); + ret = ret.Replace("{Identifier}", identifier); ret = ret.Replace("{RecordName}", recordName); // Some tokens start with - which confuses Powershell. We did not want to // make a breaking change for .bat or .exe files, so instead escape the diff --git a/src/main.lib/Plugins/ValidationPlugins/Http/FileSystem/FileSystem.cs b/src/main.lib/Plugins/ValidationPlugins/Http/FileSystem/FileSystem.cs index f8d5b0b..ff23950 100644 --- a/src/main.lib/Plugins/ValidationPlugins/Http/FileSystem/FileSystem.cs +++ b/src/main.lib/Plugins/ValidationPlugins/Http/FileSystem/FileSystem.cs @@ -1,4 +1,5 @@ using PKISharp.WACS.Clients.IIS; +using PKISharp.WACS.DomainObjects; using System; using System.IO; using System.Linq; @@ -56,12 +57,12 @@ namespace PKISharp.WACS.Plugins.ValidationPlugins.Http /// Update webroot /// </summary> /// <param name="scheduled"></param> - protected override void Refresh() + protected override void Refresh(TargetPart targetPart) { if (string.IsNullOrEmpty(_options.Path)) { // Update web root path - var siteId = _options.SiteId ?? _targetPart.SiteId; + var siteId = _options.SiteId ?? targetPart.SiteId; if (siteId > 0) { _path = _iisClient.GetWebSite(siteId.Value).Path; diff --git a/src/main.lib/Plugins/ValidationPlugins/Http/HttpValidation.cs b/src/main.lib/Plugins/ValidationPlugins/Http/HttpValidation.cs index bc811fe..844b92e 100644 --- a/src/main.lib/Plugins/ValidationPlugins/Http/HttpValidation.cs +++ b/src/main.lib/Plugins/ValidationPlugins/Http/HttpValidation.cs @@ -42,13 +42,6 @@ namespace PKISharp.WACS.Plugins.ValidationPlugins private readonly ProxyService _proxy; /// <summary> - /// Current TargetPart that we are working on. A TargetPart is mainly used by - /// the IISSites TargetPlugin to indicate that we are working with different - /// IIS sites - /// </summary> - protected TargetPart _targetPart; - - /// <summary> /// Where to find the template for the web.config that's copied to the webroot /// </summary> protected string TemplateWebConfig => Path.Combine(Path.GetDirectoryName(_settings.ExePath), "web_config.xml"); @@ -79,25 +72,24 @@ namespace PKISharp.WACS.Plugins.ValidationPlugins _proxy = pars.ProxyService; _settings = pars.Settings; _renewal = pars.Renewal; - _targetPart = pars.TargetPart; } /// <summary> /// Handle http challenge /// </summary> - public async override Task PrepareChallenge() + public async override Task PrepareChallenge(ValidationContext context, Http01ChallengeValidationDetails challenge) { - Refresh(); - WriteAuthorizationFile(); - WriteWebConfig(); - _log.Information("Answer should now be browsable at {answerUri}", Challenge.HttpResourceUrl); + Refresh(context.TargetPart); + WriteAuthorizationFile(challenge); + WriteWebConfig(challenge); + _log.Information("Answer should now be browsable at {answerUri}", challenge.HttpResourceUrl); if (_runLevel.HasFlag(RunLevel.Test) && _renewal.New) { if (await _input.PromptYesNo("[--test] Try in default browser?", false)) { Process.Start(new ProcessStartInfo { - FileName = Challenge.HttpResourceUrl, + FileName = challenge.HttpResourceUrl, UseShellExecute = true }); await _input.Wait(); @@ -107,8 +99,8 @@ namespace PKISharp.WACS.Plugins.ValidationPlugins string? foundValue = null; try { - var value = await WarmupSite(); - if (Equals(value, Challenge.HttpResourceValue)) + var value = await WarmupSite(challenge); + if (Equals(value, challenge.HttpResourceValue)) { _log.Information("Preliminary validation looks good, but the ACME server will be more thorough"); } @@ -116,7 +108,7 @@ namespace PKISharp.WACS.Plugins.ValidationPlugins { _log.Warning("Preliminary validation failed, the server answered '{value}' instead of '{expected}'. The ACME server might have a different perspective", foundValue ?? "(null)", - Challenge.HttpResourceValue); + challenge.HttpResourceValue); } } catch (HttpRequestException hrex) @@ -135,10 +127,10 @@ namespace PKISharp.WACS.Plugins.ValidationPlugins /// Mostly relevant to classic FileSystem validation /// </summary> /// <param name="uri"></param> - private async Task<string> WarmupSite() + private async Task<string> WarmupSite(Http01ChallengeValidationDetails challenge) { using var client = _proxy.GetHttpClient(false); - var response = await client.GetAsync(Challenge.HttpResourceUrl); + var response = await client.GetAsync(challenge.HttpResourceUrl); return await response.Content.ReadAsStringAsync(); } @@ -147,13 +139,13 @@ namespace PKISharp.WACS.Plugins.ValidationPlugins /// </summary> /// <param name="answerPath">where the answerFile should be located</param> /// <param name="fileContents">the contents of the file to write</param> - private void WriteAuthorizationFile() + private void WriteAuthorizationFile(Http01ChallengeValidationDetails challenge) { if (_path == null) { throw new InvalidOperationException(); } - WriteFile(CombinePath(_path, Challenge.HttpResourcePath), Challenge.HttpResourceValue); + WriteFile(CombinePath(_path, challenge.HttpResourcePath), challenge.HttpResourceValue); _challengeWritten = true; } @@ -163,7 +155,7 @@ namespace PKISharp.WACS.Plugins.ValidationPlugins /// <param name="target"></param> /// <param name="answerPath"></param> /// <param name="token"></param> - private void WriteWebConfig() + private void WriteWebConfig(Http01ChallengeValidationDetails challenge) { if (_path == null) { @@ -174,8 +166,8 @@ namespace PKISharp.WACS.Plugins.ValidationPlugins try { _log.Debug("Writing web.config"); - var partialPath = Challenge.HttpResourcePath.Split('/').Last(); - var destination = CombinePath(_path, Challenge.HttpResourcePath.Replace(partialPath, "web.config")); + var partialPath = challenge.HttpResourcePath.Split('/').Last(); + var destination = CombinePath(_path, challenge.HttpResourcePath.Replace(partialPath, "web.config")); var content = GetWebConfig(); WriteFile(destination, content); _webConfigWritten = true; @@ -199,7 +191,7 @@ namespace PKISharp.WACS.Plugins.ValidationPlugins /// <param name="target"></param> /// <param name="answerPath"></param> /// <param name="token"></param> - private void DeleteWebConfig() + private void DeleteWebConfig(Http01ChallengeValidationDetails challenge) { if (_path == null) { @@ -208,8 +200,8 @@ namespace PKISharp.WACS.Plugins.ValidationPlugins if (_webConfigWritten) { _log.Debug("Deleting web.config"); - var partialPath = Challenge.HttpResourcePath.Split('/').Last(); - var destination = CombinePath(_path, Challenge.HttpResourcePath.Replace(partialPath, "web.config")); + var partialPath = challenge.HttpResourcePath.Split('/').Last(); + var destination = CombinePath(_path, challenge.HttpResourcePath.Replace(partialPath, "web.config")); DeleteFile(destination); } } @@ -221,15 +213,15 @@ namespace PKISharp.WACS.Plugins.ValidationPlugins /// <param name="token">the token</param> /// <param name="webRootPath">the website root path</param> /// <param name="filePath">the file path for the authorization file</param> - private void DeleteAuthorization() + private void DeleteAuthorization(Http01ChallengeValidationDetails challenge) { try { if (_path != null && _challengeWritten) { _log.Debug("Deleting answer"); - var path = CombinePath(_path, Challenge.HttpResourcePath); - var partialPath = Challenge.HttpResourcePath.Split('/').Last(); + var path = CombinePath(_path, challenge.HttpResourcePath); + var partialPath = challenge.HttpResourcePath.Split('/').Last(); DeleteFile(path); if (_settings.Validation.CleanupFolders) { @@ -319,15 +311,15 @@ namespace PKISharp.WACS.Plugins.ValidationPlugins /// </summary> /// <param name="scheduled"></param> /// <returns></returns> - protected virtual void Refresh() { } + protected virtual void Refresh(TargetPart targetPart) { } /// <summary> /// Dispose /// </summary> - public override Task CleanUp() + public override Task CleanUp(ValidationContext context, Http01ChallengeValidationDetails challenge) { - DeleteWebConfig(); - DeleteAuthorization(); + DeleteWebConfig(challenge); + DeleteAuthorization(challenge); return Task.CompletedTask; } } diff --git a/src/main.lib/Plugins/ValidationPlugins/Http/HttpValidationParameters.cs b/src/main.lib/Plugins/ValidationPlugins/Http/HttpValidationParameters.cs index b1958b4..7092cdd 100644 --- a/src/main.lib/Plugins/ValidationPlugins/Http/HttpValidationParameters.cs +++ b/src/main.lib/Plugins/ValidationPlugins/Http/HttpValidationParameters.cs @@ -7,9 +7,7 @@ namespace PKISharp.WACS.Plugins.ValidationPlugins { public ISettingsService Settings { get; private set; } public Renewal Renewal { get; private set; } - public TargetPart TargetPart { get; private set; } public RunLevel RunLevel { get; private set; } - public string Identifier { get; private set; } public ILogService LogService { get; private set; } public IInputService InputService { get; private set; } public ProxyService ProxyService { get; private set; } @@ -20,14 +18,10 @@ namespace PKISharp.WACS.Plugins.ValidationPlugins ISettingsService settings, ProxyService proxy, Renewal renewal, - TargetPart target, - RunLevel runLevel, - string identifier) + RunLevel runLevel) { Renewal = renewal; - TargetPart = target; RunLevel = runLevel; - Identifier = identifier; Settings = settings; ProxyService = proxy; LogService = log; diff --git a/src/main.lib/Plugins/ValidationPlugins/Http/SelfHosting/SelfHosting.cs b/src/main.lib/Plugins/ValidationPlugins/Http/SelfHosting/SelfHosting.cs index 6e165af..ad3d3be 100644 --- a/src/main.lib/Plugins/ValidationPlugins/Http/SelfHosting/SelfHosting.cs +++ b/src/main.lib/Plugins/ValidationPlugins/Http/SelfHosting/SelfHosting.cs @@ -1,4 +1,5 @@ using ACMESharp.Authorizations; +using PKISharp.WACS.Plugins.Interfaces; using PKISharp.WACS.Services; using System; using System.Collections.Generic; @@ -61,7 +62,7 @@ namespace PKISharp.WACS.Plugins.ValidationPlugins.Http } } - public override Task CleanUp() + public override Task CleanUp(ValidationContext context, Http01ChallengeValidationDetails challenge) { if (HasListener) { @@ -77,9 +78,9 @@ namespace PKISharp.WACS.Plugins.ValidationPlugins.Http return Task.CompletedTask; } - public override Task PrepareChallenge() + public override Task PrepareChallenge(ValidationContext context, Http01ChallengeValidationDetails challenge) { - _files.Add("/" + Challenge.HttpResourcePath, Challenge.HttpResourceValue); + _files.Add("/" + challenge.HttpResourcePath, challenge.HttpResourceValue); var protocol = _options.Https == true ? "https" : "http"; var port = _options.Port ?? (_options.Https == true ? DefaultHttpsValidationPort : diff --git a/src/main.lib/Plugins/ValidationPlugins/Http/WebDav/WebDav.cs b/src/main.lib/Plugins/ValidationPlugins/Http/WebDav/WebDav.cs index 990f338..9afd9d1 100644 --- a/src/main.lib/Plugins/ValidationPlugins/Http/WebDav/WebDav.cs +++ b/src/main.lib/Plugins/ValidationPlugins/Http/WebDav/WebDav.cs @@ -1,4 +1,6 @@ -using PKISharp.WACS.Client; +using ACMESharp.Authorizations; +using PKISharp.WACS.Client; +using PKISharp.WACS.Plugins.Interfaces; using PKISharp.WACS.Services; using System.Threading.Tasks; @@ -22,9 +24,9 @@ namespace PKISharp.WACS.Plugins.ValidationPlugins.Http protected override char PathSeparator => '/'; protected override void WriteFile(string path, string content) => _webdavClient.Upload(path, content); - public override Task CleanUp() + public override Task CleanUp(ValidationContext context, Http01ChallengeValidationDetails challenge) { - base.CleanUp(); + base.CleanUp(context, challenge); _webdavClient.Dispose(); return Task.CompletedTask; } diff --git a/src/main.lib/Plugins/ValidationPlugins/Tls/SelfHosting/SelfHosting.cs b/src/main.lib/Plugins/ValidationPlugins/Tls/SelfHosting/SelfHosting.cs index d43d58b..baefd16 100644 --- a/src/main.lib/Plugins/ValidationPlugins/Tls/SelfHosting/SelfHosting.cs +++ b/src/main.lib/Plugins/ValidationPlugins/Tls/SelfHosting/SelfHosting.cs @@ -1,5 +1,7 @@ using ACMESharp.Authorizations; using Org.BouncyCastle.Asn1; +using PKISharp.WACS.DomainObjects; +using PKISharp.WACS.Plugins.Interfaces; using PKISharp.WACS.Services; using System; using System.Collections.Generic; @@ -20,7 +22,6 @@ namespace PKISharp.WACS.Plugins.ValidationPlugins.Tls internal const int DefaultValidationPort = 443; private TcpListener? _listener; private X509Certificate2? _certificate; - private readonly string _identifier; private readonly SelfHostingOptions _options; private readonly ILogService _log; private readonly IUserRoleService _userRoleService; @@ -39,9 +40,8 @@ namespace PKISharp.WACS.Plugins.ValidationPlugins.Tls set => _listener = value; } - public SelfHosting(ILogService log, string identifier, SelfHostingOptions options, IUserRoleService userRoleService) + public SelfHosting(ILogService log, SelfHostingOptions options, IUserRoleService userRoleService) { - _identifier = identifier; _log = log; _options = options; _userRoleService = userRoleService; @@ -69,7 +69,7 @@ namespace PKISharp.WACS.Plugins.ValidationPlugins.Tls } } - public override Task CleanUp() + public override Task CleanUp(ValidationContext context, TlsAlpn01ChallengeValidationDetails challenge) { try { @@ -82,12 +82,12 @@ namespace PKISharp.WACS.Plugins.ValidationPlugins.Tls return Task.CompletedTask; } - public override Task PrepareChallenge() + public override Task PrepareChallenge(ValidationContext context, TlsAlpn01ChallengeValidationDetails challenge) { try { using var rsa = RSA.Create(2048); - var name = new X500DistinguishedName($"CN={_identifier}"); + var name = new X500DistinguishedName($"CN={context.Identifier}"); var request = new CertificateRequest( name, @@ -96,7 +96,7 @@ namespace PKISharp.WACS.Plugins.ValidationPlugins.Tls RSASignaturePadding.Pkcs1); using var sha = SHA256.Create(); - var hash = sha.ComputeHash(Encoding.UTF8.GetBytes(Challenge.TokenValue)); + var hash = sha.ComputeHash(Encoding.UTF8.GetBytes(challenge.TokenValue)); request.CertificateExtensions.Add( new X509Extension( new AsnEncodedData("1.3.6.1.5.5.7.1.31", @@ -104,7 +104,7 @@ namespace PKISharp.WACS.Plugins.ValidationPlugins.Tls true)); var sanBuilder = new SubjectAlternativeNameBuilder(); - sanBuilder.AddDnsName(_identifier); + sanBuilder.AddDnsName(context.Identifier); request.CertificateExtensions.Add(sanBuilder.Build()); _certificate = request.CreateSelfSigned( @@ -112,8 +112,8 @@ namespace PKISharp.WACS.Plugins.ValidationPlugins.Tls new DateTimeOffset(DateTime.UtcNow.AddDays(1))); _certificate = new X509Certificate2( - _certificate.Export(X509ContentType.Pfx, _identifier), - _identifier, + _certificate.Export(X509ContentType.Pfx, context.Identifier), + context.Identifier, X509KeyStorageFlags.MachineKeySet); _listener = new TcpListener(IPAddress.Any, _options.Port ?? DefaultValidationPort); diff --git a/src/main.lib/Plugins/ValidationPlugins/Validation.cs b/src/main.lib/Plugins/ValidationPlugins/Validation.cs index cb9da68..10906eb 100644 --- a/src/main.lib/Plugins/ValidationPlugins/Validation.cs +++ b/src/main.lib/Plugins/ValidationPlugins/Validation.cs @@ -10,31 +10,15 @@ namespace PKISharp.WACS.Plugins.ValidationPlugins /// </summary> public abstract class Validation<TChallenge> : IValidationPlugin where TChallenge : class, IChallengeValidationDetails { - public bool HasChallenge => _challenge != null; - public TChallenge Challenge - { - get - { - if (_challenge == null) - { - throw new InvalidOperationException(); - } - return _challenge; - } - } - private TChallenge? _challenge; - - /// <summary> /// Handle the challenge /// </summary> /// <param name="challenge"></param> - public async Task PrepareChallenge(IChallengeValidationDetails challenge) + public async Task PrepareChallenge(ValidationContext context, IChallengeValidationDetails challenge) { if (challenge is TChallenge typed) { - _challenge = typed; - await PrepareChallenge(); + await PrepareChallenge(context, typed); } else { @@ -46,12 +30,24 @@ namespace PKISharp.WACS.Plugins.ValidationPlugins /// Handle the challenge /// </summary> /// <param name="challenge"></param> - public abstract Task PrepareChallenge(); + public abstract Task PrepareChallenge(ValidationContext context, TChallenge typed); /// <summary> /// Clean up after validation /// </summary> - public abstract Task CleanUp(); + public async Task CleanUp(ValidationContext context, IChallengeValidationDetails challenge) + { + if (challenge is TChallenge typed) + { + await CleanUp(context, typed); + } + else + { + throw new InvalidOperationException("Unexpected challenge type"); + } + } + + public abstract Task CleanUp(ValidationContext context, TChallenge typed); /// <summary> /// Is the plugin currently disabled diff --git a/src/main.lib/RenewalExecutor.cs b/src/main.lib/RenewalExecutor.cs index aa38dca..68b4ff7 100644 --- a/src/main.lib/RenewalExecutor.cs +++ b/src/main.lib/RenewalExecutor.cs @@ -1,4 +1,5 @@ -using Autofac; +using ACMESharp.Authorizations; +using Autofac; using PKISharp.WACS.Clients.Acme; using PKISharp.WACS.Configuration; using PKISharp.WACS.DomainObjects; @@ -407,8 +408,10 @@ namespace PKISharp.WACS var client = context.Scope.Resolve<AcmeClient>(); var identifier = authorization.Identifier.Value; var options = context.Renewal.ValidationPluginOptions; + IChallengeValidationDetails? challengeDetails = null; IValidationPlugin? validationPlugin = null; - using var validation = _scopeBuilder.Validation(context.Scope, options, targetPart, identifier); + ValidationContext? validationContext = null; + using var validation = _scopeBuilder.Validation(context.Scope, options); try { if (authorization.Status == AcmeClient.AuthorizationValid) @@ -495,8 +498,9 @@ namespace PKISharp.WACS options.Name); try { - var details = await client.DecodeChallengeValidation(authorization, challenge); - await validationPlugin.PrepareChallenge(details); + var challengeValidationDetails = await client.DecodeChallengeValidation(authorization, challenge); + validationContext = new ValidationContext(identifier, targetPart); + await validationPlugin.PrepareChallenge(validationContext, challengeValidationDetails); } catch (Exception ex) { @@ -531,12 +535,14 @@ namespace PKISharp.WACS } finally { - if (validationPlugin != null) + if (validationPlugin != null && + challengeDetails != null && + validationContext != null) { try { _log.Verbose("Starting post-validation cleanup"); - await validationPlugin.CleanUp(); + await validationPlugin.CleanUp(validationContext, challengeDetails); _log.Verbose("Post-validation cleanup was succesful"); } catch (Exception ex) diff --git a/src/main.lib/Services/AutofacBuilder.cs b/src/main.lib/Services/AutofacBuilder.cs index 5a5e4f9..00080fd 100644 --- a/src/main.lib/Services/AutofacBuilder.cs +++ b/src/main.lib/Services/AutofacBuilder.cs @@ -202,19 +202,12 @@ namespace PKISharp.WACS.Services /// <param name="target"></param> /// <param name="identifier"></param> /// <returns></returns> - public ILifetimeScope Validation(ILifetimeScope execution, ValidationPluginOptions options, TargetPart target, string identifier) + public ILifetimeScope Validation(ILifetimeScope execution, ValidationPluginOptions options) { return execution.BeginLifetimeScope(builder => { - builder.RegisterType<HttpValidationParameters>(). - WithParameters(new[] { - new TypedParameter(typeof(string), identifier), - new TypedParameter(typeof(TargetPart), target) - }); + builder.RegisterType<HttpValidationParameters>(); builder.RegisterType(options.Instance). - WithParameters(new[] { - new TypedParameter(typeof(string), identifier), - }). As<IValidationPlugin>(). SingleInstance(); }); diff --git a/src/main.lib/Services/Interfaces/IAutofacBuilder.cs b/src/main.lib/Services/Interfaces/IAutofacBuilder.cs index c2a3893..eb11a39 100644 --- a/src/main.lib/Services/Interfaces/IAutofacBuilder.cs +++ b/src/main.lib/Services/Interfaces/IAutofacBuilder.cs @@ -50,6 +50,6 @@ namespace PKISharp.WACS.Services /// <param name="target"></param> /// <param name="identifier"></param> /// <returns></returns> - ILifetimeScope Validation(ILifetimeScope execution, ValidationPluginOptions options, TargetPart target, string identifier); + ILifetimeScope Validation(ILifetimeScope execution, ValidationPluginOptions options); } } diff --git a/src/plugin.validation.dns.azure/Azure.cs b/src/plugin.validation.dns.azure/Azure.cs index 2d8c1e0..f3bffd3 100755 --- a/src/plugin.validation.dns.azure/Azure.cs +++ b/src/plugin.validation.dns.azure/Azure.cs @@ -4,6 +4,7 @@ using Microsoft.Azure.Services.AppAuthentication; using Microsoft.Rest; using Microsoft.Rest.Azure.Authentication; using PKISharp.WACS.Clients.DNS; +using PKISharp.WACS.Plugins.Interfaces; using PKISharp.WACS.Services; using System; using System.Collections.Generic; @@ -16,24 +17,20 @@ namespace PKISharp.WACS.Plugins.ValidationPlugins.Dns internal class Azure : DnsValidation<Azure> { private DnsManagementClient _azureDnsClient; - private readonly DomainParseService _domainParser; private readonly ProxyService _proxyService; - private readonly AzureOptions _options; + public Azure(AzureOptions options, - DomainParseService domainParser, LookupClientProvider dnsClient, ProxyService proxyService, ILogService log, - ISettingsService settings) - : base(dnsClient, log, settings) + ISettingsService settings) : base(dnsClient, log, settings) { _options = options; - _domainParser = domainParser; _proxyService = proxyService; } - public override async Task<bool> CreateRecord(string recordName, string token) + public override async Task<bool> CreateRecord(ValidationContext context, string recordName, string token) { var client = await GetClient(); var zone = await GetHostedZone(recordName); @@ -128,7 +125,7 @@ namespace PKISharp.WACS.Plugins.ValidationPlugins.Dns return null; } - public override async Task DeleteRecord(string recordName, string token) + public override async Task DeleteRecord(ValidationContext context, string recordName, string token) { var client = await GetClient(); var zone = await GetHostedZone(recordName); diff --git a/src/plugin.validation.dns.cloudflare/Cloudflare.cs b/src/plugin.validation.dns.cloudflare/Cloudflare.cs index e770735..fb6a69a 100644 --- a/src/plugin.validation.dns.cloudflare/Cloudflare.cs +++ b/src/plugin.validation.dns.cloudflare/Cloudflare.cs @@ -3,6 +3,7 @@ using FluentCloudflare.Api; using FluentCloudflare.Api.Entities; using FluentCloudflare.Extensions; using PKISharp.WACS.Clients.DNS; +using PKISharp.WACS.Plugins.Interfaces; using PKISharp.WACS.Services; using System; using System.Linq; @@ -23,8 +24,7 @@ namespace PKISharp.WACS.Plugins.ValidationPlugins.Dns ProxyService proxyService, LookupClientProvider dnsClient, ILogService log, - ISettingsService settings) - : base(dnsClient, log, settings) + ISettingsService settings) : base(dnsClient, log, settings) { _options = options; _hc = proxyService.GetHttpClient(); @@ -54,7 +54,7 @@ namespace PKISharp.WACS.Plugins.ValidationPlugins.Dns return zonesResp.Unpack().First(); } - public override async Task<bool> CreateRecord(string recordName, string token) + public override async Task<bool> CreateRecord(ValidationContext context, string recordName, string token) { var ctx = GetContext(); var zone = await GetHostedZone(ctx, recordName).ConfigureAwait(false); @@ -105,7 +105,7 @@ namespace PKISharp.WACS.Plugins.ValidationPlugins.Dns } - public override async Task DeleteRecord(string recordName, string token) + public override async Task DeleteRecord(ValidationContext context, string recordName, string token) { var ctx = GetContext(); var zone = await GetHostedZone(ctx, recordName).ConfigureAwait(false); diff --git a/src/plugin.validation.dns.dreamhost/DreamhostDnsValidation.cs b/src/plugin.validation.dns.dreamhost/DreamhostDnsValidation.cs index 2e6e5db..4d5f0b2 100644 --- a/src/plugin.validation.dns.dreamhost/DreamhostDnsValidation.cs +++ b/src/plugin.validation.dns.dreamhost/DreamhostDnsValidation.cs @@ -1,4 +1,5 @@ using PKISharp.WACS.Clients.DNS; +using PKISharp.WACS.Plugins.Interfaces; using PKISharp.WACS.Plugins.ValidationPlugins.Dreamhost; using PKISharp.WACS.Services; using System; @@ -18,7 +19,7 @@ namespace PKISharp.WACS.Plugins.ValidationPlugins : base(dnsClient, logService, settings) => _client = new DnsManagementClient(options.ApiKey.Value, logService); - public override async Task<bool> CreateRecord(string recordName, string token) + public override async Task<bool> CreateRecord(ValidationContext context, string recordName, string token) { try { @@ -31,7 +32,7 @@ namespace PKISharp.WACS.Plugins.ValidationPlugins } } - public override async Task DeleteRecord(string recordName, string token) + public override async Task DeleteRecord(ValidationContext context, string recordName, string token) { try { diff --git a/src/plugin.validation.dns.luadns/luadns.cs b/src/plugin.validation.dns.luadns/luadns.cs index 4935681..c03fbd7 100644 --- a/src/plugin.validation.dns.luadns/luadns.cs +++ b/src/plugin.validation.dns.luadns/luadns.cs @@ -1,4 +1,5 @@ using PKISharp.WACS.Clients.DNS; +using PKISharp.WACS.Plugins.Interfaces; using PKISharp.WACS.Services; using System; using System.Collections.Generic; @@ -64,7 +65,7 @@ namespace PKISharp.WACS.Plugins.ValidationPlugins.Dns _apiKey = options.APIKey.Value; } - public override async Task<bool> CreateRecord(string recordName, string token) + public override async Task<bool> CreateRecord(ValidationContext context, string recordName, string token) { _log.Information("Creating LuaDNS verification record"); @@ -101,7 +102,7 @@ namespace PKISharp.WACS.Plugins.ValidationPlugins.Dns return true; } - public override async Task DeleteRecord(string recordName, string token) + public override async Task DeleteRecord(ValidationContext context, string recordName, string token) { if (!_recordsMap.ContainsKey(recordName)) { diff --git a/src/plugin.validation.dns.route53/Route53.cs b/src/plugin.validation.dns.route53/Route53.cs index b8bdeaf..ea0c2a2 100644 --- a/src/plugin.validation.dns.route53/Route53.cs +++ b/src/plugin.validation.dns.route53/Route53.cs @@ -8,23 +8,20 @@ using PKISharp.WACS.Services; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; -using System.Data.Common; +using PKISharp.WACS.Plugins.Interfaces; namespace PKISharp.WACS.Plugins.ValidationPlugins.Dns { internal sealed class Route53 : DnsValidation<Route53> { private readonly IAmazonRoute53 _route53Client; - private readonly DomainParseService _domainParser; public Route53( LookupClientProvider dnsClient, - DomainParseService domainParser, ILogService log, ProxyService proxy, ISettingsService settings, - Route53Options options) - : base(dnsClient, log, settings) + Route53Options options) : base(dnsClient, log, settings) { var region = RegionEndpoint.USEast1; var config = new AmazonRoute53Config() { RegionEndpoint = region }; @@ -34,7 +31,6 @@ namespace PKISharp.WACS.Plugins.ValidationPlugins.Dns : !string.IsNullOrWhiteSpace(options.AccessKeyId) && !string.IsNullOrWhiteSpace(options.SecretAccessKey.Value) ? new AmazonRoute53Client(options.AccessKeyId, options.SecretAccessKey.Value, config) : new AmazonRoute53Client(config); - _domainParser = domainParser; } private static ResourceRecordSet CreateResourceRecordSet(string name, string value) @@ -49,7 +45,7 @@ namespace PKISharp.WACS.Plugins.ValidationPlugins.Dns }; } - public override async Task<bool> CreateRecord(string recordName, string token) + public override async Task<bool> CreateRecord(ValidationContext context, string recordName, string token) { try { @@ -80,7 +76,7 @@ namespace PKISharp.WACS.Plugins.ValidationPlugins.Dns } } - public override async Task DeleteRecord(string recordName, string token) + public override async Task DeleteRecord(ValidationContext context, string recordName, string token) { var hostedZoneIds = await GetHostedZoneIds(recordName); _log.Information($"Deleting TXT record {recordName} with value {token}"); |