/// <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); }
/// <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); } }
/// <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); } }
/// <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); } }
/// <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 }); }
/// <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> /// 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); } }
/// <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); } }
/// <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); } }