Exemplo n.º 1
0
        /// <summary>
        /// Validate File
        /// </summary>
        /// <param name="validationType">Is batch / Default / custom</param>
        /// <param name="applicationFiles">Application files</param>
        /// <param name="transferManager">File transfer manager</param>
        /// <returns></returns>
        public IValidationPlugin GetValidationAdptor(ValidationType validationType, ApplicationFile[] applicationFiles, FileTransferManager transferManager)
        {
            IValidationPlugin validationAdaptor = null;

            try
            {
                switch (validationType)
                {
                case ValidationType.Default:
                    validationAdaptor = new DefaultValidation(transferManager, applicationFiles.Select(T => T.Mask).ToList());
                    break;

                case ValidationType.Batch:
                    var validateFileInfos = (from appFile in applicationFiles
                                             select new ValidationFileInfo(appFile.IsRequired, appFile.Mask)).ToList();
                    ///
                    validationAdaptor = new BatchValidation(transferManager, validateFileInfos);
                    break;

                case ValidationType.Custom:
                    throw new NotSupportedException("Functionality for custom validation not supported.");

                default:
                    throw new InvalidOperationException("Invalid Validation type found.");
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
            return(validationAdaptor);
        }
Exemplo n.º 2
0
        /// <summary>
        /// Create a new plug in unattended mode, triggered by the --plugin command line switch
        /// </summary>
        private static void CreateNewCertificateUnattended()
        {
            _log.Information(true, "Running in unattended mode.", _options.Plugin);

            var targetPlugin = Plugins.GetByName(Plugins.Target, _options.Plugin);

            if (targetPlugin == null)
            {
                _log.Error("Target plugin {name} not found.", _options.Plugin);
                return;
            }

            var target = targetPlugin.Default(OptionsService);

            if (target == null)
            {
                _log.Error("Plugin {name} was unable to generate a target", _options.Plugin);
                return;
            }
            else
            {
                _log.Information("Plugin {name} generated target {target}", _options.Plugin, target);
            }

            IValidationPlugin validationPlugin = null;

            if (!string.IsNullOrWhiteSpace(_options.Validation))
            {
                validationPlugin = Plugins.GetValidationPlugin($"{_options.ValidationMode}.{_options.Validation}");
                if (validationPlugin == null)
                {
                    _log.Error("Validation plugin {name} not found.", _options.Validation);
                    return;
                }
            }
            else
            {
                validationPlugin = Plugins.GetByName(Plugins.Validation, nameof(FileSystem));
            }
            target.ValidationPluginName = $"{validationPlugin.ChallengeType}.{validationPlugin.Name}";
            try
            {
                validationPlugin.Default(OptionsService, target);
            }
            catch (Exception ex)
            {
                _log.Error(ex, "Invalid validation input");
                return;
            }
            var result = target.Plugin.Auto(target);

            if (!result.Success)
            {
                _log.Error("Create certificate failed", target);
            }
        }
Exemplo n.º 3
0
        /// <summary>
        /// Clean up after (succesful or unsuccesful) validation attempt
        /// </summary>
        /// <param name="validationContext"></param>
        /// <returns></returns>
        private async Task CleanValidation(IValidationPlugin validationPlugin)
        {
            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);
            }
        }
Exemplo n.º 4
0
        /// <summary>
        /// Clean up after (succesful or unsuccesful) validation attempt
        /// </summary>
        /// <param name="validationContext"></param>
        /// <returns></returns>
        private async Task <bool> CommitValidation(IValidationPlugin validationPlugin)
        {
            try
            {
                _log.Verbose("Starting commit stage");
                await validationPlugin.Commit();

                _log.Verbose("Commit was succesful");
                return(true);
            }
            catch (Exception ex)
            {
                _log.Error(ex, "An error occured while commiting validation configuration: {ex}", ex.Message);
                return(false);
            }
        }
Exemplo n.º 5
0
        /// <summary>
        /// Make sure we have authorization for every host in target
        /// </summary>
        /// <param name="target"></param>
        /// <returns></returns>
        private static AuthorizationState Authorize(ILifetimeScope renewalScope, Target target)
        {
            List <string>             identifiers = target.GetHosts(false);
            List <AuthorizationState> authStatus  = new List <AuthorizationState>();
            var client = renewalScope.Resolve <LetsEncryptClient>();

            foreach (var identifier in identifiers)
            {
                var authzState = client.Acme.AuthorizeIdentifier(identifier);
                if (authzState.Status == _authorizationValid && !_options.Test)
                {
                    _log.Information("Cached authorization result: {Status}", authzState.Status);
                    authStatus.Add(authzState);
                }
                else
                {
                    using (var identifierScope = AutofacBuilder.Identifier(renewalScope, target, identifier))
                    {
                        IValidationPluginFactory validationPluginFactory = null;
                        IValidationPlugin        validationPlugin        = null;
                        try
                        {
                            validationPluginFactory = identifierScope.Resolve <IValidationPluginFactory>();
                            validationPlugin        = identifierScope.Resolve <IValidationPlugin>();
                        }
                        catch { }
                        if (validationPluginFactory == null || validationPluginFactory is INull || validationPlugin == null)
                        {
                            return(new AuthorizationState {
                                Status = _authorizationInvalid
                            });
                        }
                        _log.Information("Authorizing {dnsIdentifier} using {challengeType} validation ({name})", identifier, validationPluginFactory.ChallengeType, validationPluginFactory.Name);
                        var challenge = client.Acme.DecodeChallenge(authzState, validationPluginFactory.ChallengeType);
                        validationPlugin.PrepareChallenge(challenge);
                        _log.Debug("Submitting answer");
                        authzState.Challenges = new AuthorizeChallenge[] { challenge };
                        client.Acme.SubmitChallengeAnswer(authzState, validationPluginFactory.ChallengeType, true);

                        // have to loop to wait for server to stop being pending.
                        // TODO: put timeout/retry limit in this loop
                        while (authzState.Status == _authorizationPending)
                        {
                            _log.Debug("Refreshing authorization");
                            Thread.Sleep(4000); // this has to be here to give ACME server a chance to think
                            var newAuthzState = client.Acme.RefreshIdentifierAuthorization(authzState);
                            if (newAuthzState.Status != _authorizationPending)
                            {
                                authzState = newAuthzState;
                            }
                        }

                        if (authzState.Status != _authorizationValid)
                        {
                            _log.Information("Authorization result: {Status}", authzState.Status);
                        }
                        else
                        {
                            _log.Error("Authorization result: {Status}", authzState.Status);
                        }
                        authStatus.Add(authzState);
                    }
                }
            }
            foreach (var authState in authStatus)
            {
                if (authState.Status != _authorizationValid)
                {
                    return(authState);
                }
            }
            return(new AuthorizationState {
                Status = _authorizationValid
            });
        }
Exemplo n.º 6
0
        /// <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);
            }
        }
Exemplo n.º 7
0
        /// <summary>
        /// Job Init processing
        /// </summary>
        /// <param name="sessionKey">Service generated GUID</param>
        /// <param name="appId">Application ID</param>
        /// <returns></returns>
        public List <RunNumberAndOutput> Processing(string sessionKey, int appId)
        {
            List <RunNumberAndOutput> objRunNumberAndOutputList = new List <RunNumberAndOutput>();

            emailList = new List <string>();
            try
            {
                String desLoc = String.Empty;
                SingletonLogger.Instance.Debug("Get application info");
                //Get application by id
                var appInfo = objApplicationRepository.Find(appId);
                if (appInfo == null)
                {
                    throw new NullReferenceException("Application details not found in database for Application Id : " + appId);
                }
                //Get applications Client information
                var clientInfo = objClientRepository.Find(appInfo.ClientId);
                if (clientInfo == null)
                {
                    throw new NullReferenceException("Client details not found in database for Client Id : " + appInfo.ClientId);
                }

                SingletonLogger.Instance.Debug("Client Id = " + clientInfo.ClientId + "\t Application Id : " + appId);
                SingletonLogger.Instance.Debug("Client Name = " + clientInfo.Name + "\t Application name : " + appInfo.Name);

                SingletonLogger.Instance.Debug("Adding Mapper...");
                mapper = new PatternMatchingMapper();
                mapper.SetCurrentDateFormat();
                mapper.SetClientAndAppDetails(clientInfo.Name, appInfo.Name);
                SingletonLogger.Instance.Debug("Mapper Added.");

                SingletonLogger.Instance.Debug("Get file transfer settings for application for File by Setting Id " + appInfo.FileTransferSettingId);
                var fileTransferSetting = objFileTransferSettingsRepository.Find(appInfo.FileTransferSettingId);
                if (fileTransferSetting == null)
                {
                    throw new Exception("No file transfer setting details found for File transfersettingId " + appInfo.FileTransferSettingId);
                }

                SingletonLogger.Instance.Debug("Get queue type for file transfer setting id " + fileTransferSetting.QueueTypeId);

                // Converting queue type from string, if not able to convert throw exception
                SingletonLogger.Instance.Debug("Checking for queue type.");
                QuequeType type = (QuequeType)Enum.ToObject(typeof(QuequeType), fileTransferSetting.QueueTypeId);
                SingletonLogger.Instance.Debug("Queue type is : " + type.ToString());

                var applicationFiles = objApplicationFileRepository.GetApplicationFileListByAppID(appInfo.ApplicationId);
                if (applicationFiles == null)
                {
                    throw new NullReferenceException("No app files (Input configuration) found in db for appId : " + appInfo.ApplicationId + "appName : " + appInfo.Name);
                }

                if (applicationFiles.Count() == 0)
                {
                    throw new InvalidDataException("No app files (Input configuration) found in db for appId : " + appInfo.ApplicationId + "appName : " + appInfo.Name);
                }

                SingletonLogger.Instance.Debug(string.Format("{0} files found for current application. ", applicationFiles.Count()));

                SingletonLogger.Instance.Debug("Processing files...");
                var validationType = ValidationType.Default;
                if (appInfo.IsBatch)
                {
                    validationType = ValidationType.Batch;
                }

                var adaptorSettings = SetLocationAdptorSettings(fileTransferSetting, appInfo, type);

                if (adaptorSettings == null)
                {
                    throw new NullReferenceException("Null validation adapter setting found when getting valid adapter.");
                }

                // Initializing transfer manager
                IFileTransferAdapter transferAdaptor = FileTransferAdapter.GetFileTransferAdapter(adaptorSettings);

                if (transferAdaptor == null)
                {
                    throw new NullReferenceException("Null transfer adapter found.");
                }

                FileTransferManager transferManager = new FileTransferManager(transferAdaptor);

                if (transferManager == null)
                {
                    throw new NullReferenceException("Null transfer manager found.");
                }

                SingletonLogger.Instance.Debug("validationType : " + validationType + "applicationFiles :" + applicationFiles.FirstOrDefault() + " transferManager :" + transferManager);

                IValidationPlugin validationAdaptor = GetValidationAdptor(validationType, applicationFiles.ToArray(), transferManager);

                if (validationAdaptor == null)
                {
                    throw new NullReferenceException("Null validation adapter found when getting valid adapter.");
                }

                // Validate
                if (validationAdaptor.Validate())
                {
                    SingletonLogger.Instance.Debug("file is  Validated by " + validationAdaptor + " now Ready to download");
                    int count = 1;
                    // If There are some valid files then insert run number information to DB.
                    if (validationAdaptor.ValidFiles.Count > 0 && validationAdaptor.Ready)
                    {
                        foreach (var file in validationAdaptor.ValidFiles)
                        {
                            RunNumberAndOutput objRunNumberAndOutput = new RunNumberAndOutput();

                            #region Create Job
                            switch (validationType)
                            {
                            case ValidationType.Default:
                                //Create run number and add entry in database
                                runNumber = GetRunNumber(clientInfo.Code, appInfo.Code, appId);
                                SingletonLogger.Instance.Debug("file is  Run in Single processing. RunNumber = " + runNumber);
                                runId = InsertRunDetails(appInfo.ApplicationId, runNumber);
                                SingletonLogger.Instance.Debug("Run details is saved in db successfully.");
                                break;

                            case ValidationType.Batch:
                                //Create run number and add entry in database
                                if (count == 1)
                                {
                                    runNumber = GetRunNumber(clientInfo.Code, appInfo.Code, appId);
                                    runId     = InsertRunDetails(appInfo.ApplicationId, runNumber);
                                }
                                SingletonLogger.Instance.Debug("Insert runDetails in db for RunNumber " + runNumber + " Client " + clientInfo.Name + " and Application " + appInfo.Name);
                                break;

                            case ValidationType.Custom:
                                throw new NotSupportedException("Functionality for custom validation not supported.");

                            default:
                                throw new InvalidOperationException("Invalid Validation type found.");
                            }
                            #endregion

                            #region Countinue Common Processing
                            mapper.SetClientAndAppDetails(runNumber);
                            if (String.IsNullOrEmpty(appInfo.HotFolder))
                            {
                                throw new Exception("Destination location is null or empty for " + appInfo.Name);
                            }

                            desLoc = mapper.EvaluateString(appInfo.HotFolder);
                            SingletonLogger.Instance.Debug("file is  downloading at " + desLoc);
                            transferAdaptor.Settings.DestinationLocation = desLoc;

                            // Add Run number and destination location
                            objRunNumberAndOutput.Output = desLoc;

                            #endregion

                            #region Download files
                            // download valid files
                            if (transferManager.DownloadFile(file))
                            {
                                SingletonLogger.Instance.Debug(file + " file is  downloaded successfully.");
                                //Inserting details to db
                                if (InsertRawFileDetails(runId, file, desLoc))
                                {
                                    SingletonLogger.Instance.Debug("file detail is saved in db in raw files");
                                    if (appInfo.IsArchive)
                                    {
                                        var arcvInpuFile = desLoc + "\\" + Path.GetFileName(file);
                                        mapper.SetFileFormat(arcvInpuFile);
                                        var outFile = mapper.EvaluateString(appInfo.ArchivePath + "\\" + appInfo.ArchiveFileName);
                                        Archieve(arcvInpuFile, outFile);
                                    }

                                    if (appInfo.IsFileMove)
                                    {
                                        try
                                        {
                                            SingletonLogger.Instance.Debug("Process start to delete file from " + file);
                                            transferManager.DeleteFile(file);
                                            SingletonLogger.Instance.Debug(file + " file is deleted from source location.");
                                        }
                                        catch (Exception ex)
                                        {
                                            throw ex;
                                        }
                                    }
                                }
                            }
                            #endregion

                            #region Create Run number and output List
                            switch (validationType)
                            {
                            case ValidationType.Default:        // Run each file as a single file
                                objRunNumberAndOutput.RunNumber = runNumber;
                                objRunNumberAndOutputList.Add(objRunNumberAndOutput);
                                break;

                            case ValidationType.Batch:
                                if (count == 1)       // If file downloading type is 'Batch' then no need to add directory in array, run file as a batch
                                {
                                    objRunNumberAndOutput.RunNumber = runNumber;
                                    objRunNumberAndOutputList.Add(objRunNumberAndOutput);
                                }
                                break;

                            case ValidationType.Custom:
                                throw new NotSupportedException("Functionality for custom validation not supported.");

                            default:
                                throw new InvalidOperationException("Invalid Validation type found.");
                            }
                            #endregion

                            #region Email

                            emailList.Add(Path.GetFileName(file));

                            #endregion

                            count++;
                        }
                    }
                    else
                    {
                        SingletonLogger.Instance.Debug("No valid files found or Files are not ready to download.");
                        objProcSessionsRepository.UpdateBySessionKey(sessionKey, Convert.ToByte(JobStatusType.Complete));
                    }
                    objProcSessionsRepository.UpdateBySessionKey(sessionKey, Convert.ToByte(JobStatusType.Complete));
                    SingletonLogger.Instance.Debug("Update values in ProcSession corresponding key" + sessionKey + " Value" + Convert.ToByte(JobStatusType.Complete));
                }

                SingletonLogger.Instance.Debug("No valid files found or Files are not ready to download.");
                objProcSessionsRepository.UpdateBySessionKey(sessionKey, Convert.ToByte(JobStatusType.Complete));

                //Prepare for email
                SendInputEmail inputEmail = new SendInputEmail();
                if (emailList != null)
                {
                    if (emailList.Count > 0)
                    {
                        inputEmail.SendInputFileEmail(appInfo, runId, emailList);
                    }
                }
                SingletonLogger.Instance.Debug("Email has been sent");
                return(objRunNumberAndOutputList);
            }
            catch (Exception ex)
            {
                objProcSessionsRepository.UpdateBySessionKey(sessionKey, Convert.ToByte(JobStatusType.Error));
                throw new Exception("Error in Job-init " + ex);
            }
        }
Exemplo n.º 8
0
        /// <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);
            }
        }
Exemplo n.º 9
0
        /// <summary>
        /// Make sure we have authorization for every host in target
        /// </summary>
        /// <param name="target"></param>
        /// <returns></returns>
        private static AuthorizationState Authorize(ILifetimeScope renewalScope, Target target)
        {
            var invalid = new AuthorizationState {
                Status = _authorizationInvalid
            };

            try
            {
                var identifiers = target.GetHosts(false);
                var authStatus  = new List <AuthorizationState>();
                var client      = renewalScope.Resolve <AcmeClientWrapper>();
                foreach (var identifier in identifiers)
                {
                    _log.Information("Authorize identifier: {identifier}", identifier);
                    var authzState = client.Acme.AuthorizeIdentifier(identifier);
                    if (authzState.Status == _authorizationValid && !_options.Test)
                    {
                        _log.Information("Cached authorization result: {Status}", authzState.Status);
                        authStatus.Add(authzState);
                    }
                    else
                    {
                        using (var identifierScope = AutofacBuilder.Identifier(renewalScope, target, identifier))
                        {
                            IValidationPluginFactory validationPluginFactory = null;
                            IValidationPlugin        validationPlugin        = null;
                            try
                            {
                                validationPluginFactory = identifierScope.Resolve <IValidationPluginFactory>();
                                validationPlugin        = identifierScope.Resolve <IValidationPlugin>();
                            }
                            catch (Exception ex)
                            {
                                _log.Error(ex, "Error resolving validation plugin");
                            }
                            if (validationPluginFactory == null || validationPluginFactory is INull || validationPlugin == null)
                            {
                                _log.Error("Validation plugin not found or not created.");
                                return(invalid);
                            }
                            if (!authzState.Challenges.Any(c => c.Type == validationPluginFactory.ChallengeType))
                            {
                                _log.Error("Expected challenge type {type} not available for {identifier}.", validationPluginFactory.ChallengeType, identifier);
                                return(invalid);
                            }
                            _log.Information("Authorizing {dnsIdentifier} using {challengeType} validation ({name})", identifier, validationPluginFactory.ChallengeType, validationPluginFactory.Name);
                            var challenge = client.Acme.DecodeChallenge(authzState, validationPluginFactory.ChallengeType);
                            try
                            {
                                validationPlugin.PrepareChallenge(challenge);
                            }
                            catch (Exception ex)
                            {
                                _log.Error(ex, "Error preparing for challenge answer");
                                return(invalid);
                            }
                            _log.Debug("Submitting answer");
                            authzState.Challenges = new AuthorizeChallenge[] { challenge };
                            client.Acme.SubmitChallengeAnswer(authzState, validationPluginFactory.ChallengeType, true);

                            // have to loop to wait for server to stop being pending.
                            // TODO: put timeout/retry limit in this loop
                            while (authzState.Status == _authorizationPending)
                            {
                                _log.Debug("Refreshing authorization");
                                Thread.Sleep(4000); // this has to be here to give ACME server a chance to think
                                var newAuthzState = client.Acme.RefreshIdentifierAuthorization(authzState);
                                if (newAuthzState.Status != _authorizationPending)
                                {
                                    authzState = newAuthzState;
                                }
                            }

                            if (authzState.Status != _authorizationValid)
                            {
                                _log.Error("Authorization result: {Status}", authzState.Status);
                            }
                            else
                            {
                                _log.Information("Authorization result: {Status}", authzState.Status);
                            }
                            authStatus.Add(authzState);
                        }
                    }
                }
                foreach (var authState in authStatus)
                {
                    if (authState.Status != _authorizationValid)
                    {
                        return(authState);
                    }
                }
                return(new AuthorizationState {
                    Status = _authorizationValid
                });
            }
            catch (Exception ex)
            {
                _log.Error("Error authorizing {target}", target);
                HandleException(ex);
                return(invalid);
            }
        }