public ArticleTarget(TargetHead codeHead, TargetPart codePart, ConfigCode codeBody, TargetSeed seedBody) { this.InternalHead = codeHead; this.InternalPart = codePart; this.InternalCode = codeBody; this.InternalSeed = seedBody; }
public TargetItem AddMainPart(TargetHead codeHead, ISourceValues tagsBody) { TargetPart PART_CODE = ArticleTarget.PART_CODE_NULL; ConfigCode BODY_CODE = GetPartConfigCode(); return(AddGeneralItem(codeHead, PART_CODE, BODY_CODE, ArticleTarget.BODY_SEED_NULL, tagsBody)); }
public TargetItem AddMainHead(ISourceValues tagsBody) { TargetHead HEAD_CODE = ArticleTarget.HEAD_CODE_NULL; TargetPart PART_CODE = ArticleTarget.PART_CODE_NULL; ConfigCode BODY_CODE = GetHeadConfigCode(); return(AddGeneralItem(HEAD_CODE, PART_CODE, BODY_CODE, ArticleTarget.BODY_SEED_NULL, tagsBody)); }
private IEnumerable <TargetItem> CreateTargetsQueue(ConfigCode code, TargetItem target, IEnumerable <TargetHead> heads, IEnumerable <Tuple <TargetHead, TargetPart> > parts) { IEnumerable <ArticleTarget> targetList = new List <ArticleTarget>(); ConfigType targetType = ModelSourceProfile.GetConfigType(code); ConfigBind targetBind = ModelSourceProfile.GetConfigBind(code); TargetHead codeHead = 0; TargetPart codePart = 0; ConfigCode codeBody = code; TargetSeed seedBody = 0; if (targetBind == (ConfigBind)ArticleBind.ARTICLE_OPT) { return(targetList); } if (targetType == (ConfigType)ArticleType.NO_HEAD_PART_TYPE) { targetList = new List <ArticleTarget>() { new ArticleTarget(codeHead, codePart, codeBody, seedBody) }; } if (targetType == (ConfigType)ArticleType.HEAD_CODE_ARTICLE) { if (target.Head() != 0) { codeHead = target.Head(); targetList = new List <ArticleTarget>() { new ArticleTarget(codeHead, codePart, codeBody, seedBody) }; } else { targetList = heads.Select((ch) => (new ArticleTarget(ch, codePart, codeBody, seedBody))).ToList(); } } else if (targetType == (ConfigType)ArticleType.PART_CODE_ARTICLE) { if (target.Head() != 0 && target.Part() != 0) { codeHead = target.Head(); codePart = target.Part(); targetList = new List <ArticleTarget>() { new ArticleTarget(codeHead, codePart, codeBody, seedBody) }; } else { targetList = parts.Select((pp) => (new ArticleTarget(pp.Item1, pp.Item2, codeBody, seedBody))).ToList(); } } return(targetList); }
/// <summary> /// Constructor /// </summary> /// <param name="log"></param> /// <param name="input"></param> /// <param name="options"></param> /// <param name="proxy"></param> /// <param name="renewal"></param> /// <param name="target"></param> /// <param name="runLevel"></param> /// <param name="identifier"></param> public HttpValidation(TOptions options, HttpValidationParameters pars) : base(pars.LogService, options, pars.Identifier) { _input = pars.InputService; _proxy = pars.ProxyService; _renewal = pars.Renewal; _targetPart = pars.TargetPart; _path = options.Path; }
public TargetItem StoreGeneralItem(TargetHead codeHead, TargetPart codePart, ConfigCode codeBody, TargetSeed seedBody, ISourceValues tagsBody) { ArticleTarget newTarget = new ArticleTarget(codeHead, codePart, codeBody, seedBody); SourcePack newSource = GetTemplateSourceForArticle(codeBody, tagsBody); model.Add(newTarget, newSource); return(newTarget); }
public ValidationContextParameters( AuthorizationContext authorization, TargetPart targetPart, ValidationPluginOptions options) { TargetPart = targetPart; OrderContext = authorization.Order; Authorization = authorization.Authorization; Options = options; }
public void DomainSplit() { var parts = new TargetPart[] { new TargetPart(new[] { new DnsIdentifier("x.com") }) }; var target = new Target("x.com", "x.com", parts); var renewal = new Renewal(); var container = new MockContainer().TestScope(); var domain = container.Resolve <Domain>(); var split = domain.Split(renewal, target); Assert.IsNotNull(split); }
/// <summary> /// Constructor /// </summary> /// <param name="log"></param> /// <param name="input"></param> /// <param name="options"></param> /// <param name="proxy"></param> /// <param name="renewal"></param> /// <param name="target"></param> /// <param name="runLevel"></param> /// <param name="identifier"></param> public HttpValidation(TOptions options, RunLevel runLevel, HttpValidationParameters pars) { _options = options; _runLevel = runLevel; _path = options.Path; _log = pars.LogService; _input = pars.InputService; _proxy = pars.ProxyService; _settings = pars.Settings; _renewal = pars.Renewal; _targetPart = pars.TargetPart; }
public ValidationContextParameters( Authorization authorization, TargetPart targetPart, string challengeType, string pluginName, bool orderValid) { TargetPart = targetPart; Authorization = authorization; ChallengeType = challengeType; PluginName = pluginName; OrderValid = orderValid; }
/// <summary> /// Parse unique DNS identifiers that the certificate should be created for /// </summary> /// <param name="unicode"></param> /// <returns></returns> public static List <string> GetHosts(this TargetPart target, bool unicode) { var idn = new IdnMapping(); var hosts = target.Identifiers.Distinct(); if (unicode) { return(hosts.Select(x => x.ConvertPunycode()).ToList()); } else { return(hosts.Select(x => idn.GetAscii(x)).ToList()); } }
public HttpValidationParameters( ILogService log, IInputService input, ProxyService proxy, Renewal renewal, TargetPart target, RunLevel runLevel, string identifier) { Renewal = renewal; TargetPart = target; RunLevel = runLevel; Identifier = identifier; ProxyService = proxy; LogService = log; InputService = input; }
/// <summary> /// Make sure we have authorization for every host in target /// </summary> /// <param name="target"></param> /// <returns></returns> private Challenge Authorize(ILifetimeScope execute, RunLevel runLevel, OrderDetails order, ValidationPluginOptions options, TargetPart targetPart, Authorization authorization) { var invalid = new Challenge { Status = _authorizationInvalid }; var valid = new Challenge { Status = _authorizationValid }; var client = execute.Resolve <AcmeClient>(); var identifier = authorization.Identifier.Value; try { _log.Information("Authorize identifier: {identifier}", identifier); if (authorization.Status == _authorizationValid && !runLevel.HasFlag(RunLevel.Test)) { _log.Information("Cached authorization result: {Status}", authorization.Status); return(valid); } else { using (var validation = _scopeBuilder.Validation(execute, options, targetPart, identifier)) { IValidationPlugin validationPlugin = null; 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."); return(invalid); } var challenge = authorization.Challenges.FirstOrDefault(c => c.Type == options.ChallengeType); if (challenge == null) { _log.Error("Expected challenge type {type} not available for {identifier}.", options.ChallengeType, authorization.Identifier.Value); return(invalid); } if (challenge.Status == _authorizationValid && !runLevel.HasFlag(RunLevel.Test)) { _log.Information("{dnsIdentifier} already validated by {challengeType} validation ({name})", authorization.Identifier.Value, options.ChallengeType, options.Name); return(valid); } _log.Information("Authorizing {dnsIdentifier} using {challengeType} validation ({name})", identifier, options.ChallengeType, options.Name); try { var details = client.DecodeChallengeValidation(authorization, challenge); validationPlugin.PrepareChallenge(details); } catch (Exception ex) { _log.Error(ex, "Error preparing for challenge answer"); return(invalid); } _log.Debug("Submitting challenge answer"); challenge = client.AnswerChallenge(challenge); // Have to loop to wait for server to stop being pending var tries = 0; var maxTries = 4; while (challenge.Status == _authorizationPending) { _log.Debug("Refreshing authorization"); Thread.Sleep(2000); // this has to be here to give ACME server a chance to think challenge = client.GetChallengeDetails(challenge.Url); tries += 1; if (tries > maxTries) { _log.Error("Authorization timed out"); return(invalid); } } if (challenge.Status != _authorizationValid) { _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); HandleException(ex); return(invalid); } }
/// <summary> /// Parse unique DNS identifiers that the certificate should be created for /// </summary> /// <param name="unicode"></param> /// <returns></returns> public static List <Identifier> GetIdentifiers(this TargetPart part, bool unicode) => part.Identifiers.Distinct().Select(x => x.Unicode(unicode)).ToList();
public static Func <TargetItem, bool> TargetCodePlusPartFunc(TargetCode targetCode, TargetHead targetHead, TargetPart targetPart) { return((x) => (x.IsEqualByCodePlusHeadAndPart(targetCode, targetHead, targetPart))); }
public static Func <TargetItem, bool> TargetCodePlusHeadAndNullPartFunc(TargetCode targetCode, TargetHead targetHead) { TargetPart targetPart = ArticleTarget.PART_CODE_NULL; return((x) => (x.IsEqualByCodePlusHeadAndPart(targetCode, targetHead, targetPart))); }
/// <summary> /// Refresh /// </summary> /// <param name="scheduled"></param> /// <returns></returns> protected virtual void Refresh(TargetPart targetPart) { }
/// <summary> /// Make sure we have authorization for every host in target /// </summary> /// <param name="target"></param> /// <returns></returns> private async Task <Challenge> Authorize( ILifetimeScope execute, RunLevel runLevel, ValidationPluginOptions options, TargetPart targetPart, Authorization authorization) { var invalid = new Challenge { Status = AcmeClient.AuthorizationInvalid }; var valid = new Challenge { Status = AcmeClient.AuthorizationValid }; var client = execute.Resolve <AcmeClient>(); var identifier = authorization.Identifier.Value; 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 { using var validation = _scopeBuilder.Validation(execute, options, targetPart, identifier); IValidationPlugin validationPlugin = null; 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."); return(invalid); } if (validationPlugin.Disabled) { _log.Error("Validation plugin is not available to the current user, try running as administrator."); return(invalid); } var challenge = authorization.Challenges.FirstOrDefault(c => c.Type == options.ChallengeType); if (challenge == null) { _log.Error("Expected challenge type {type} not available for {identifier}.", options.ChallengeType, authorization.Identifier.Value); 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); } _log.Information("Authorizing {dnsIdentifier} using {challengeType} validation ({name})", identifier, options.ChallengeType, options.Name); try { var details = client.DecodeChallengeValidation(authorization, challenge); await validationPlugin.PrepareChallenge(details); } catch (Exception ex) { _log.Error(ex, "Error preparing for challenge answer"); return(invalid); } _log.Debug("Submitting challenge answer"); challenge = await client.AnswerChallenge(challenge); 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); } }
public IEnumerable <Order> Split(Renewal renewal, Target target) { var ret = new Dictionary <string, Order>(); var parts = new Dictionary <string, List <TargetPart> >(); foreach (var part in target.Parts) { foreach (var host in part.GetIdentifiers(true)) { var domain = host.Value; switch (host) { case DnsIdentifier dns: domain = _domainParseService.GetRegisterableDomain(host.Value.TrimStart('.', '*')); break; default: _log.Warning("Unsupported identifier type {type}", host.Type); break; } var sourceParts = target.Parts.Where(p => p.GetIdentifiers(true).Contains(host)); if (!ret.ContainsKey(domain)) { var filteredParts = sourceParts.Select(p => new TargetPart(new List <Identifier> { host }) { SiteId = p.SiteId, SiteType = p.SiteType }).ToList(); var newTarget = new Target( target.FriendlyName ?? "", host, filteredParts); var newOrder = new Order( renewal, newTarget, friendlyNamePart: domain, cacheKeyPart: domain); ret.Add(domain, newOrder); parts.Add(domain, filteredParts); } else { var existingParts = parts[domain]; foreach (var sourcePart in sourceParts) { var existingPart = existingParts.Where(x => sourcePart.SiteId == x.SiteId).FirstOrDefault(); if (existingPart == null) { existingPart = new TargetPart(new[] { host }) { SiteId = sourcePart.SiteId, SiteType = sourcePart.SiteType }; existingParts.Add(existingPart); } else if (!existingPart.Identifiers.Contains(host)) { existingPart.Identifiers.Add(host); } } } } } return(ret.Values); }
static private IEnumerable <IArticleTarget> SelectEquals(IEnumerable <IArticleTarget> targetList, TargetHead codeHead, TargetPart codePart, ConfigCode codeBody) { return(targetList.Where(x => (EqualitySelector(x, codeHead, codePart, codeBody))).ToList()); }
public bool IsEqualByHeadAndPart(TargetHead otherHead, TargetPart otherPart) { return(this.InternalHead == otherHead && this.InternalPart == otherPart); }
/// <summary> /// Make sure we have authorization for every host in target /// </summary> /// <param name="target"></param> /// <returns></returns> private async Task HandleChallenge(ExecutionContext context, TargetPart targetPart, acme.Authorization authorization) { var valid = false; var client = context.Scope.Resolve <AcmeClient>(); var identifier = authorization.Identifier.Value; var options = context.Renewal.ValidationPluginOptions; IValidationPlugin?validationPlugin = null; using var validation = _scopeBuilder.Validation(context.Scope, options, targetPart, identifier); try { if (authorization.Status == AcmeClient.AuthorizationValid) { _log.Information("Cached authorization result for {identifier}: {Status}", identifier, authorization.Status); if (!context.RunLevel.HasFlag(RunLevel.Test) && !context.RunLevel.HasFlag(RunLevel.IgnoreCache)) { return; } // Used to make --force or --test re-validation errors non-fatal _log.Information("Handling challenge anyway because --test and/or --force is active"); valid = true; } _log.Information("Authorize identifier {identifier}", identifier); _log.Verbose("Initial authorization status: {status}", authorization.Status); _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 (valid) { var usedType = authorization.Challenges. Where(x => x.Status == AcmeClient.ChallengeValid). FirstOrDefault(); _log.Warning("Expected challenge type {type} not available for {identifier}, already validated using {valided}.", options.ChallengeType, authorization.Identifier.Value, usedType?.Type ?? "[unknown]"); return; } else { _log.Error("Expected challenge type {type} not available for {identifier}.", options.ChallengeType, authorization.Identifier.Value); context.Result.AddErrorMessage("Expected challenge type not available", !valid); return; } } else { _log.Verbose("Initial challenge status: {status}", challenge.Status); if (challenge.Status == AcmeClient.ChallengeValid) { // We actually should not get here because if one of the // challenges is valid, the authorization itself should also // be valid. if (!context.RunLevel.HasFlag(RunLevel.Test) && !context.RunLevel.HasFlag(RunLevel.IgnoreCache)) { _log.Information("Cached challenge result: {Status}", authorization.Status); return; } } } // We actually have to do validation now 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"); context.Result.AddErrorMessage("Validation plugin not found or not created", !valid); return; } var(disabled, disabledReason) = validationPlugin.Disabled; if (disabled) { _log.Error($"Validation plugin is not available. {disabledReason}"); context.Result.AddErrorMessage("Validation plugin is not available", !valid); return; } _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"); context.Result.AddErrorMessage("Error preparing for challenge answer", !valid); return; } _log.Debug("Submitting challenge answer"); challenge = await client.AnswerChallenge(challenge); if (challenge.Status != AcmeClient.ChallengeValid) { if (challenge.Error != null) { _log.Error(challenge.Error.ToString()); } _log.Error("Authorization result: {Status}", challenge.Status); context.Result.AddErrorMessage(challenge.Error?.ToString() ?? "Unspecified error", !valid); return; } else { _log.Information("Authorization result: {Status}", challenge.Status); return; } } catch (Exception ex) { _log.Error("Error authorizing {renewal}", targetPart); var message = _exceptionHandler.HandleException(ex); context.Result.AddErrorMessage(message, !valid); } finally { if (validationPlugin != null) { try { _log.Verbose("Starting post-validation cleanup"); await validationPlugin.CleanUp(); _log.Verbose("Post-validation cleanup was succesful"); } catch (Exception ex) { _log.Warning("An error occured during post-validation cleanup: {ex}", ex.Message); } } } }
public bool IsEqualByCodePlusHeadAndSeed(ConfigCode otherCode, TargetHead otherHead, TargetPart otherSeed) { return(this.InternalCode == otherCode && this.InternalHead == otherHead && this.InternalSeed == otherSeed); }
public bool IsEqualByCodePlusHeadAndPart(ConfigCode otherCode, TargetHead otherHead, TargetPart otherPart) { return(this.InternalCode == otherCode && this.InternalHead == otherHead && this.InternalPart == otherPart); }
/// <summary> /// Validation /// </summary> /// <param name="execution"></param> /// <param name="options"></param> /// <param name="target"></param> /// <param name="identifier"></param> /// <returns></returns> public ILifetimeScope Validation(ILifetimeScope execution, ValidationPluginOptions options, TargetPart target, string identifier) { return(execution.BeginLifetimeScope(builder => { builder.RegisterType <HttpValidationParameters>(). WithParameters(new[] { new TypedParameter(typeof(string), identifier), new TypedParameter(typeof(TargetPart), target) }); builder.RegisterType(options.Instance). WithParameters(new[] { new TypedParameter(typeof(string), identifier), }). As <IValidationPlugin>(). SingleInstance(); })); }
public TargetItem AddHeadItem(TargetHead codeHead, ConfigCode codeBody, ISourceValues tagsBody) { TargetPart PART_CODE = ArticleTarget.PART_CODE_NULL; return(AddGeneralItem(codeHead, PART_CODE, codeBody, ArticleTarget.BODY_SEED_NULL, tagsBody)); }
static public TargetSeed GetSeedToNewTarget(IEnumerable <IArticleTarget> targetList, TargetHead codeHead, TargetPart codePart, ConfigCode codeBody) { IEnumerable <IArticleTarget> selectedTargets = SelectEquals(targetList, codeHead, codePart, codeBody); IEnumerable <TargetSeed> oneCodeSeeds = ExtractCodeSeed(selectedTargets); return(NewSeqSeedFromList(oneCodeSeeds.OrderBy(x => x).ToArray())); }
public TargetItem AddPartItem(TargetHead codeHead, TargetPart codePart, ConfigCode codeBody, ISourceValues tagsBody) { return(AddGeneralItem(codeHead, codePart, codeBody, ArticleTarget.BODY_SEED_NULL, tagsBody)); }
public static bool EqualitySelector(IArticleTarget target, TargetHead codeHead, TargetPart codePart, ConfigCode codeBody) { return(target.Head() == codeHead && target.Part() == codePart && target.Code() == codeBody); }
public TargetItem AddGeneralItem(TargetHead codeHead, TargetPart codePart, ConfigCode codeBody, TargetSeed seedBody, ISourceValues tagsBody) { TargetSeed newTargetSeed = TargetSelector.GetSeedToNewTarget(model.Keys, codeHead, codePart, codeBody); return(StoreGeneralItem(codeHead, codePart, codeBody, newTargetSeed, tagsBody)); }