Exemple #1
0
        public async void CreateStepWithSecret()
        {
            Mock <IEntitiesRepository> entitiesRepository = new Mock <IEntitiesRepository>();

            entitiesRepository.Setup(sr => sr.GetFirstOrDefaultAsync <StepTemplate>(It.IsAny <Expression <Func <StepTemplate, bool> > >())).Returns(Task.FromResult(SecretSampleData.StepTemplate));
            var stepTemplate = await entitiesRepository.Object.GetFirstOrDefaultAsync <StepTemplate>(st => st.ReferenceId == SecretSampleData.StepTemplate.ReferenceId);

            var newStep = stepTemplate.GenerateStep(stepTemplate.ReferenceId, "", "", "", new Dictionary <string, object>()
            {
                { "secret", "This is a test" }
            }, null, null, ClusterStateService.GetEncryptionKey());

            _node.Setup(n => n.Handle(It.IsAny <AddShardWriteOperation>())).Returns(Task.FromResult(new AddShardWriteOperationResponse()
            {
                IsSuccessful = true
            }));

            var handler = new CreateStepCommandHandler(entitiesRepository.Object, clusterMoq.Object, _node.Object);

            var step = await handler.Handle(new CreateStepCommand()
            {
                StepTemplateId = stepTemplate.ReferenceId,
                Inputs         = new Dictionary <string, object>()
                {
                    { "secret", "This is a test" }
                }
            }, new System.Threading.CancellationToken());

            //Test encryption of step worked
            Assert.NotEqual("This is a test", (string)step.Result.Inputs["secret"]);
            //Test decryption of step
            Assert.Equal("This is a test", SecurityUtility.SymmetricallyDecrypt((string)step.Result.Inputs["secret"], ClusterStateService.GetEncryptionKey()));
        }
Exemple #2
0
        public async void AssignStepWithSecret()
        {
            var testPhrase = "This is a test";

            Mock <IEntitiesRepository> entitiesRepository = new Mock <IEntitiesRepository>();
            var newStep = SecretSampleData.StepTemplate.GenerateStep(SecretSampleData.StepTemplate.ReferenceId, "", "", "", new Dictionary <string, object>()
            {
                { "secret", testPhrase }
            }, null, null, ClusterStateService.GetEncryptionKey());

            entitiesRepository.Setup(sr => sr.GetFirstOrDefaultAsync(It.IsAny <Expression <Func <StepTemplate, bool> > >())).Returns(Task.FromResult(SecretSampleData.StepTemplate));

            entitiesRepository.Setup(st => st.GetAsync(It.IsAny <Expression <Func <Step, bool> > >(), null, It.IsAny <string>(), It.IsAny <int>(), It.IsAny <int>())).Returns(Task.FromResult((IEnumerable <Step>) new List <Step> {
                newStep
            }));

            var testKey = SecurityUtility.GenerateRSAKeyPair();

            entitiesRepository.Setup(kr => kr.GetFirstOrDefaultAsync(It.IsAny <Expression <Func <BotKey, bool> > >())).Returns(Task.FromResult(new BotKey()
            {
                PublicEncryptionKey = testKey.PublicKey
            }));



            var mockLogger = new Mock <ILogger <AssignStepCommandHandler> >();

            var node = Utility.GetMockConsensusCoreNode();

            node.Setup(s => s.Handle(It.IsAny <RequestDataShard>())).Returns(Task.FromResult(new RequestDataShardResponse()
            {
                AppliedLocked = true,
                IsSuccessful  = true
            }));

            var handler = new AssignStepCommandHandler(entitiesRepository.Object, clusterMoq.Object, mockLogger.Object, node.Object);

            var result = await handler.Handle(new AssignStepCommand()
            {
            }, new System.Threading.CancellationToken());

            var assignedStep = result.Result;

            Assert.NotEqual(testPhrase, (string)result.Result.Inputs["secret"]);

            var encryptionTestResult = SecurityUtility.RsaEncryptWithPublic(testPhrase, testKey.PublicKey);

            //Randomized padding is used
            Assert.NotEqual(encryptionTestResult, (string)result.Result.Inputs["secret"]);
            //Decryption using private key should work
            Assert.Equal(SecurityUtility.RsaDecryptWithPrivate(encryptionTestResult, testKey.PrivateKey), SecurityUtility.RsaDecryptWithPrivate((string)result.Result.Inputs["secret"], testKey.PrivateKey));
        }
Exemple #3
0
        public async void IgnoreEscapedReferenceSymbol()
        {
            entitiesRepository.Setup(sr => sr.GetFirstOrDefaultAsync <StepTemplate>(It.IsAny <Expression <Func <StepTemplate, bool> > >())).Returns(Task.FromResult(SecretSampleData.StepTemplate));
            var testPhrase   = "$secret";
            var stepTemplate = await entitiesRepository.Object.GetFirstOrDefaultAsync <StepTemplate>(st => st.ReferenceId == SecretSampleData.StepTemplate.ReferenceId);

            var newStep = stepTemplate.GenerateStep(stepTemplate.ReferenceId, "", "", "", new Dictionary <string, object>()
            {
                { "secret", "\\$secret" }
            }, null, null, ClusterStateService.GetEncryptionKey());



            entitiesRepository.Setup(st => st.GetAsync <Step>(It.IsAny <Expression <Func <Step, bool> > >(), null, It.IsAny <string>(), It.IsAny <int>(), It.IsAny <int>())).Returns(Task.FromResult((IEnumerable <Step>) new List <Step> {
                newStep
            }));

            var testKey = SecurityUtility.GenerateRSAKeyPair();


            entitiesRepository.Setup(kr => kr.GetFirstOrDefaultAsync(It.IsAny <Expression <Func <BotKey, bool> > >())).Returns(Task.FromResult(new BotKey()
            {
                PublicEncryptionKey = testKey.PublicKey
            }));

            var mockLogger = new Mock <ILogger <AssignStepCommandHandler> >();


            entitiesRepository.Setup(s => s.GetFirstOrDefaultAsync <GlobalValue>(It.IsAny <Expression <Func <GlobalValue, bool> > >())).Returns(
                Task.FromResult(new GlobalValue("secret", InputDataTypes.Secret, "", SecurityUtility.SymmetricallyEncrypt(testPhrase, ClusterStateService.GetEncryptionKey()), GlobalValueStatuses.Enabled, Guid.NewGuid(), "admin", DateTime.UtcNow))
                );

            var node = Utility.GetMockConsensusCoreNode();

            node.Setup(s => s.Handle(It.IsAny <RequestDataShard>())).Returns(Task.FromResult(new RequestDataShardResponse()
            {
                AppliedLocked = true, IsSuccessful = true
            }));

            var handler = new AssignStepCommandHandler(entitiesRepository.Object, clusterMoq.Object, mockLogger.Object, node.Object);

            var result = await handler.Handle(new AssignStepCommand()
            {
            }, new System.Threading.CancellationToken());

            Assert.NotEqual(testPhrase, (string)result.Result.Inputs["secret"]);
            var encryptionTestResult = SecurityUtility.RsaEncryptWithPublic(testPhrase, testKey.PublicKey);

            Assert.NotEqual(encryptionTestResult, (string)result.Result.Inputs["secret"]);
            Assert.Equal(SecurityUtility.RsaDecryptWithPrivate(encryptionTestResult, testKey.PrivateKey), SecurityUtility.RsaDecryptWithPrivate((string)result.Result.Inputs["secret"], testKey.PrivateKey));
        }
Exemple #4
0
        public async void EncryptOutputOnCompletion()
        {
            var stepTemplate = SecretSampleData.StepTemplate;
            var testPhrase   = "This is a test";
            var TestStep     = SecretSampleData.StepTemplate.GenerateStep(stepTemplate.ReferenceId, "", "", "", new Dictionary <string, object>()
            {
                { "secret", testPhrase }
            }, null, null, ClusterStateService.GetEncryptionKey());
            Mock <IEntitiesRepository> entitiesRepository = new Mock <IEntitiesRepository>();

            entitiesRepository.Setup(sr => sr.GetFirstOrDefaultAsync <StepTemplate>(It.IsAny <Expression <Func <StepTemplate, bool> > >())).Returns(Task.FromResult(stepTemplate));
            _node.Setup(n => n.Handle(It.IsAny <AddShardWriteOperation>())).Returns(Task.FromResult(new AddShardWriteOperationResponse()
            {
                IsSuccessful = true
            }));
            entitiesRepository.Setup(sr => sr.GetFirstOrDefaultAsync <Step>(It.IsAny <Expression <Func <Step, bool> > >())).Returns(Task.FromResult(TestStep));

            var mockLogger            = new Mock <ILogger <CompleteStepCommandHandler> >();
            Mock <IMediator> mediator = new Mock <IMediator>();

            var mockStateLogger = new Mock <ILogger <ClusterStateService> >();
            var testKey         = SecurityUtility.GenerateRSAKeyPair();


            entitiesRepository.Setup(kr => kr.GetFirstOrDefaultAsync(It.IsAny <Expression <Func <BotKey, bool> > >())).Returns(Task.FromResult(new BotKey()
            {
                PublicEncryptionKey = testKey.PublicKey
            }));

            var node = Utility.GetMockConsensusCoreNode();
            Mock <IClusterStateService> service = new Mock <IClusterStateService>();

            var handler = new CompleteStepCommandHandler(entitiesRepository.Object, service.Object, mockLogger.Object, _optionsMonitor.Object, mediator.Object, _node.Object);

            var completeResult = await handler.Handle(new CompleteStepCommand()
            {
                Id      = TestStep.Id,
                Outputs = new Dictionary <string, object>()
                {
                    { "secret", SecurityUtility.RsaEncryptWithPrivate(testPhrase, testKey.PrivateKey) }
                },
                Status     = StepStatuses.Successful,
                StatusCode = 0,
                Log        = "TEST"
            }, new System.Threading.CancellationToken());

            Assert.Equal(TestStep.Id.ToString(), completeResult.ObjectRefId);
        }
Exemple #5
0
        public async void EvaluateIntValueByValueReference()
        {
            entitiesRepository.Setup(sr => sr.GetFirstOrDefaultAsync <StepTemplate>(It.IsAny <Expression <Func <StepTemplate, bool> > >())).Returns(Task.FromResult(FibonacciSampleData.StepTemplate));
            var newStep = FibonacciSampleData.StepTemplate.GenerateStep(FibonacciSampleData.StepTemplate.ReferenceId, "", "", "", new Dictionary <string, object>()
            {
                { "n-1", "$1" },
                { "n-2", 2 }
            }, null, null, ClusterStateService.GetEncryptionKey());



            entitiesRepository.Setup(st => st.GetAsync <Step>(It.IsAny <Expression <Func <Step, bool> > >(), null, It.IsAny <string>(), It.IsAny <int>(), It.IsAny <int>())).Returns(Task.FromResult((IEnumerable <Step>) new List <Step> {
                newStep
            }));

            var testKey = SecurityUtility.GenerateRSAKeyPair();


            entitiesRepository.Setup(kr => kr.GetFirstOrDefaultAsync(It.IsAny <Expression <Func <BotKey, bool> > >())).Returns(Task.FromResult(new BotKey()
            {
                PublicEncryptionKey = testKey.PublicKey
            }));

            var mockLogger = new Mock <ILogger <AssignStepCommandHandler> >();


            entitiesRepository.Setup(s => s.GetFirstOrDefaultAsync <GlobalValue>(It.IsAny <Expression <Func <GlobalValue, bool> > >())).Returns(
                Task.FromResult(new GlobalValue("1", InputDataTypes.Int, "", 1, GlobalValueStatuses.Enabled, Guid.NewGuid(), "admin", DateTime.UtcNow))
                );

            var node = Utility.GetMockConsensusCoreNode();

            node.Setup(s => s.Handle(It.IsAny <RequestDataShard>())).Returns(Task.FromResult(new RequestDataShardResponse()
            {
                AppliedLocked = true,
                IsSuccessful  = true
            }));

            var handler = new AssignStepCommandHandler(entitiesRepository.Object, clusterMoq.Object, mockLogger.Object, node.Object);

            var result = await handler.Handle(new AssignStepCommand()
            {
            }, new System.Threading.CancellationToken());

            Assert.Equal(1, (int)result.Result.Inputs["n-1"]);
            Assert.Equal(2, (int)result.Result.Inputs["n-2"]);
        }
Exemple #6
0
        public async Task <CommandResult <Step> > Handle(CreateStepCommand request, CancellationToken cancellationToken)
        {
            var stopwatch = new Stopwatch();

            stopwatch.Start();

            var resolvedTemplate = await _entitiesRepository.GetFirstOrDefaultAsync <StepTemplate>(st => st.ReferenceId == request.StepTemplateId);

            if (resolvedTemplate == null)
            {
                throw new StepTemplateNotFoundException("Step template " + request.StepTemplateId + " not found.");
            }

            var newStep = resolvedTemplate.GenerateStep(request.StepTemplateId,
                                                        request.CreatedBy,
                                                        request.Name, request.Description,
                                                        request.Inputs,
                                                        request.Tests, request.WorkflowId,
                                                        ClusterStateService.GetEncryptionKey(),
                                                        request.ExecutionTemplateId,
                                                        request.ExecutionScheduleId);

            /* var createdStepId = await _entitiesRepository.InsertStepAsync(
             *   newStep
             *   );*/

            await _node.Handle(new AddShardWriteOperation()
            {
                Data             = newStep,
                WaitForSafeWrite = true,
                Operation        = ConsensusCore.Domain.Enums.ShardOperationOptions.Create
            });


            stopwatch.Stop();
            return(new CommandResult <Step>()
            {
                ObjectRefId = newStep.Id.ToString(),
                ElapsedMs = stopwatch.ElapsedMilliseconds,
                Type = CommandResultTypes.Create,
                Result = newStep
            });
        }
Exemple #7
0
        public async Task <CommandResult <Step> > Handle(AssignStepCommand request, CancellationToken cancellationToken)
        {
            var stopwatch = new Stopwatch();

            stopwatch.Start();
            List <Guid> ignoreUnassignedSteps = new List <Guid>();

            if (_clusterStateService.GetSettings.AssignmentEnabled)
            {
                var    assignedStepSuccessfully = false;
                Step   unassignedStep           = null;
                var    dateChecked = DateTime.UtcNow;
                BotKey botkey;

                if (!_cache.TryGetValue(request.BotId, out botkey))
                {
                    // Set cache options.
                    var cacheEntryOptions = new MemoryCacheEntryOptions()
                                            // Keep in cache for this time, reset time if accessed.
                                            .SetSlidingExpiration(TimeSpan.FromSeconds(10));
                    botkey = await _entitiesRepository.GetFirstOrDefaultAsync <BotKey>(bk => bk.Id == request.BotId);

                    // Save data in cache.
                    _cache.Set(request.BotId, botkey, cacheEntryOptions);
                }

                if (botkey.IsDisabled)
                {
                    return(new CommandResult <Step>(new BotKeyAssignmentException("Bot " + botkey.Id + " is disabled."))
                    {
                        Type = CommandResultTypes.Update,
                        ElapsedMs = stopwatch.ElapsedMilliseconds
                    });
                }

                ignoreUnassignedSteps.AddRange(_clusterStateService.GetState().Locks.Where(l => l.Key.Contains("_object")).Select(ol => new Guid(ol.Key.Split(':').Last())));

                do
                {
                    unassignedStep = (await _entitiesRepository.GetAsync <Step>(s => s.Status == StepStatuses.Unassigned && request.StepTemplateIds.Contains(s.StepTemplateId) && !ignoreUnassignedSteps.Contains(s.Id), null, "CreatedOn:1", 1, 0)).FirstOrDefault();
                    if (unassignedStep != null)
                    {
                        var assigned = await _node.Handle(new RequestDataShard()
                        {
                            Type          = unassignedStep.ShardType,
                            ObjectId      = unassignedStep.Id,
                            CreateLock    = true,
                            LockTimeoutMs = 10000
                        });

                        //Apply a lock on the item
                        if (assigned != null && assigned.IsSuccessful && assigned.AppliedLocked)
                        {
                            //Real values to pass to the Microservice
                            Dictionary <string, object> realAssignedValues = new Dictionary <string, object>();
                            //Inputs that have been converted to reference expression
                            Dictionary <string, object> convertedInputs = new Dictionary <string, object>();

                            var template = await _entitiesRepository.GetFirstOrDefaultAsync <StepTemplate>(st => st.ReferenceId == unassignedStep.StepTemplateId);

                            try
                            {
                                //This should not throw a error externally, the server should loop to the next one and log a error
                                if (unassignedStep.Status != StepStatuses.Unassigned)
                                {
                                    throw new InvalidStepQueueException("You cannot assign step " + unassignedStep.Id + " as it is not unassigned.");
                                }


                                bool inputsUpdated = false;

                                foreach (var input in unassignedStep.Inputs)
                                {
                                    string convertedValue     = "";
                                    bool   isReferenceByValue = false;
                                    var    isReference        = InputDataUtility.IsInputReference(input, out convertedValue, out isReferenceByValue);
                                    if (input.Value is string && ((string)input.Value).Length > 1)
                                    {
                                        if (isReference)
                                        {
                                            //Copy by reference
                                            if (isReferenceByValue)
                                            {
                                                var foundGlobalValue = await _entitiesRepository.GetFirstOrDefaultAsync <GlobalValue>(gv => gv.Name == convertedValue);

                                                if (foundGlobalValue == null)
                                                {
                                                    Logger.LogWarning("No global value was found for value " + input.Value);
                                                    realAssignedValues.Add(input.Key, null);
                                                    convertedInputs.Add(input.Key, input.Value + ":?");
                                                }
                                                else if (foundGlobalValue.Type != template.InputDefinitions[input.Key].Type)
                                                {
                                                    Logger.LogWarning("Global value was found for value " + input.Value + " however they are different types. " + template.InputDefinitions[input.Key].Type + " vs " + foundGlobalValue.Type);
                                                    realAssignedValues.Add(input.Key, null);
                                                    convertedInputs.Add(input.Key, input.Value + ":?");
                                                }
                                                else
                                                {
                                                    realAssignedValues.Add(input.Key, foundGlobalValue.Value);
                                                    convertedInputs.Add(input.Key, input.Value + ":" + foundGlobalValue.Journal.GetCurrentChainId());
                                                }
                                            }
                                            //copy by value
                                            else
                                            {
                                                var foundGlobalValue = await _entitiesRepository.GetFirstOrDefaultAsync <GlobalValue>(gv => gv.Name == convertedValue);

                                                if (foundGlobalValue == null)
                                                {
                                                    Logger.LogWarning("No global value was found for value " + input.Value);
                                                    realAssignedValues.Add(input.Key, null);
                                                    convertedInputs.Add(input.Key, null);
                                                }
                                                else if (foundGlobalValue.Type != template.InputDefinitions[input.Key].Type)
                                                {
                                                    Logger.LogWarning("Global value was found for value " + input.Value + " however they are different types. " + template.InputDefinitions[input.Key].Type + " vs " + foundGlobalValue.Type);
                                                    realAssignedValues.Add(input.Key, null);
                                                    convertedInputs.Add(input.Key, null);
                                                }
                                                else
                                                {
                                                    realAssignedValues.Add(input.Key, foundGlobalValue.Value);
                                                    convertedInputs.Add(input.Key, foundGlobalValue.Value);
                                                }
                                            }

                                            inputsUpdated = true;
                                        }
                                        else if (input.Value is string && ((string)input.Value).Length > 1 && ((string)input.Value).First() == '\\')
                                        {
                                            var escapedCommand = ((string)input.Value);
                                            //The $ is escaped
                                            realAssignedValues.Add(input.Key, ((string)input.Value).Substring(1, escapedCommand.Length - 1));
                                            convertedInputs.Add(input.Key, input.Value);
                                            inputsUpdated = true;
                                        }
                                        else
                                        {
                                            realAssignedValues.Add(input.Key, input.Value);
                                            convertedInputs.Add(input.Key, input.Value);
                                        }
                                    }
                                    else
                                    {
                                        realAssignedValues.Add(input.Key, input.Value);
                                        convertedInputs.Add(input.Key, input.Value);
                                    }
                                }

                                //If a update was detected then add it to the journal updates
                                if (inputsUpdated)
                                {
                                    unassignedStep.UpdateJournal(new Domain.Entities.JournalEntries.JournalEntry()
                                    {
                                        CreatedBy = SystemUsers.QUEUE_MANAGER,
                                        CreatedOn = DateTime.UtcNow,
                                        Updates   = new List <Update>()
                                        {
                                            new Update()
                                            {
                                                Type      = UpdateType.Override,
                                                FieldName = "status",
                                                Value     = StepStatuses.Assigned
                                            },
                                            new Update()
                                            {
                                                FieldName = "inputs",
                                                Type      = UpdateType.Override,
                                                Value     = convertedInputs
                                            },
                                            new Update()
                                            {
                                                FieldName = "assignedto",
                                                Type      = UpdateType.Override,
                                                Value     = request.BotId
                                            }
                                        }
                                    });
                                }
                                else
                                {
                                    unassignedStep.UpdateJournal(new Domain.Entities.JournalEntries.JournalEntry()
                                    {
                                        CreatedBy = SystemUsers.QUEUE_MANAGER,
                                        CreatedOn = DateTime.UtcNow,
                                        Updates   = new List <Update>()
                                        {
                                            new Update()
                                            {
                                                Type      = UpdateType.Override,
                                                FieldName = "status",
                                                Value     = StepStatuses.Assigned
                                            }
                                        }
                                    });
                                }

                                await _node.Handle(new AddShardWriteOperation()
                                {
                                    Data             = unassignedStep,
                                    WaitForSafeWrite = true,
                                    Operation        = ConsensusCore.Domain.Enums.ShardOperationOptions.Update,
                                    RemoveLock       = true,
                                    LockId           = assigned.LockId.Value
                                });

                                //await _entitiesRepository.UpdateStep(unassignedStep);
                                if (inputsUpdated)
                                {
                                    //Update the record with real values, this is not commited to DB
                                    unassignedStep.UpdateJournal(new Domain.Entities.JournalEntries.JournalEntry()
                                    {
                                        CreatedBy = SystemUsers.QUEUE_MANAGER,
                                        CreatedOn = DateTime.UtcNow,
                                        Updates   = new List <Update>()
                                        {
                                            new Update()
                                            {
                                                FieldName = "inputs",
                                                Type      = UpdateType.Override,
                                                Value     = realAssignedValues
                                            }
                                        }
                                    });
                                }
                            }
                            catch (Exception e)
                            {
                                Console.WriteLine(e.Message);
                                //throw e;
                            }
                            assignedStepSuccessfully = true;
                        }
                        else
                        {
                            ignoreUnassignedSteps.Add(unassignedStep.Id);
                            assignedStepSuccessfully = false;
                        }
                    }
                    //There were no unassigned steps to assign
                    else
                    {
                        assignedStepSuccessfully = true;
                    }
                }while (!assignedStepSuccessfully);


                if (unassignedStep != null)
                {
                    var template = await _entitiesRepository.GetFirstOrDefaultAsync <StepTemplate>(st => st.ReferenceId == unassignedStep.StepTemplateId);

                    //Decrypt the step
                    unassignedStep.Inputs = DynamicDataUtility.DecryptDynamicData(template.InputDefinitions, unassignedStep.Inputs, EncryptionProtocol.AES256, ClusterStateService.GetEncryptionKey());

                    unassignedStep.RemoveDelimiters();

                    //Encrypt the step
                    unassignedStep.Inputs = DynamicDataUtility.EncryptDynamicData(template.InputDefinitions, unassignedStep.Inputs, EncryptionProtocol.RSA, botkey.PublicEncryptionKey, true);
                }

                stopwatch.Stop();
                return(new CommandResult <Step>()
                {
                    ObjectRefId = unassignedStep != null?unassignedStep.Id.ToString() : "",
                                      ElapsedMs = stopwatch.ElapsedMilliseconds,
                                      Type = CommandResultTypes.Update,
                                      Result = unassignedStep != null ? unassignedStep : null
                });
            }
            else
            {
                return(new CommandResult <Step>()
                {
                    ObjectRefId = "",
                    ElapsedMs = stopwatch.ElapsedMilliseconds,
                    Type = CommandResultTypes.None
                });
            }
        }
Exemple #8
0
        public async Task <CommandResult <GlobalValue> > Handle(CreateGlobalValueCommand request, CancellationToken cancellationToken)
        {
            var stopwatch = new Stopwatch();

            stopwatch.Start();

            if (!InputDataTypes.IsValidDataType(request.Type))
            {
                throw new InvalidInputTypeException("Input " + request.Type + " is not valid.");
            }

            if (await _entitiesRepository.GetFirstOrDefaultAsync <GlobalValue>(
                    gv => gv.Name == request.Name) != null)
            {
                throw new InvalidGlobalValuesException("The global value name " + request.Name + " is already in-use.");
            }

            var createdGV = new GlobalValue(
                request.Name,
                request.Type,
                request.Description,
                request.Type == InputDataTypes.Secret ? SecurityUtility.SymmetricallyEncrypt((string)request.Value, ClusterStateService.GetEncryptionKey()) : request.Value,
                GlobalValueStatuses.Enabled,
                Guid.NewGuid(),
                request.CreatedBy,
                DateTime.UtcNow
                );

            var result = _node.Handle(new AddShardWriteOperation()
            {
                Operation        = ConsensusCore.Domain.Enums.ShardOperationOptions.Create,
                WaitForSafeWrite = true,
                Data             = createdGV
            });

            stopwatch.Stop();

            return(new CommandResult <GlobalValue>()
            {
                ObjectRefId = createdGV.Id.ToString(),
                ElapsedMs = stopwatch.ElapsedMilliseconds,
                Type = CommandResultTypes.Create,
                Result = createdGV
            });
        }
Exemple #9
0
        public async Task <CommandResult <Workflow> > Handle(CreateWorkflowCommand request, CancellationToken cancellationToken)
        {
            var stopwatch = new Stopwatch();

            stopwatch.Start();

            WorkflowTemplate template = await _entitiesRepository.GetFirstOrDefaultAsync <WorkflowTemplate>(wft => wft.ReferenceId == request.WorkflowTemplateId);

            if (template == null)
            {
                throw new WorkflowTemplateNotFoundException("Workflow Template " + request.WorkflowTemplateId + " not found.");
            }

            if (template.InputDefinitions.Count() < request.Inputs.Count())
            {
                throw new InvalidInputsException("Invalid number of inputs, number passed was " + request.Inputs.Count() + " which is less then defined " + template.InputDefinitions.Count());
            }

            var verifiedWorkflowInputs = new Dictionary <string, object>();

            if (template.InputDefinitions != null)
            {
                foreach (var input in template.InputDefinitions)
                {
                    if (!request.Inputs.ContainsKey(input.Key))
                    {
                        throw new MissingInputException("Workflow input data is missing " + input.Key);
                    }
                }

                foreach (var input in request.Inputs)
                {
                    if (template.InputDefinitions.ContainsKey(input.Key) && template.InputDefinitions[input.Key].Type == InputDataTypes.Secret && !InputDataUtility.IsInputReference(input, out _, out _))
                    {
                        verifiedWorkflowInputs.Add(input.Key.ToLower(), SecurityUtility.SymmetricallyEncrypt((string)input.Value, ClusterStateService.GetEncryptionKey()));
                    }
                    else
                    {
                        verifiedWorkflowInputs.Add(input.Key.ToLower(), input.Value);
                    }
                }
            }

            var createdWorkflowId  = Guid.NewGuid();
            var startingLogicBlock = template.LogicBlocks.Where(lb => lb.Value.Dependencies.Evaluate(new List <Step>())).ToList();

            var createdWorkflowTemplateId = await _node.Handle(new AddShardWriteOperation()
            {
                Data = new Domain.Entities.Workflows.Workflow(
                    createdWorkflowId,
                    request.WorkflowTemplateId,
                    verifiedWorkflowInputs, //Encrypted inputs
                    request.Name,
                    request.CreatedBy,
                    DateTime.UtcNow,
                    request.ExecutionTemplateId,
                    request.ExecutionScheduleId
                    ),
                WaitForSafeWrite = true,
                Operation        = ConsensusCore.Domain.Enums.ShardOperationOptions.Create
            });

            var workflow = await _entitiesRepository.GetFirstOrDefaultAsync <Workflow>(w => w.Id == createdWorkflowId);

            //When there are no conditions to be met

            // Needs to happen before first step is added
            DateTimeOffset WorkflowStartTime = DateTime.Now;

            foreach (var block in startingLogicBlock)
            {
                try
                {
                    foreach (var subBlock in block.Value.SubsequentSteps)
                    {
                        var newStepTemplate = await _entitiesRepository.GetFirstOrDefaultAsync <StepTemplate>(st => st.ReferenceId == subBlock.Value.StepTemplateId);

                        if (newStepTemplate == null)
                        {
                            throw new StepTemplateNotFoundException("Template " + subBlock.Value.StepTemplateId + " not found.");
                        }

                        var verifiedInputs = new Dictionary <string, object>();

                        foreach (var mapping in subBlock.Value.Mappings)
                        {
                            string mappedValue = "";
                            if ((mapping.Value.DefaultValue != null && (mapping.Value.OutputReferences == null || mapping.Value.OutputReferences.Count() == 0)) || (mapping.Value.DefaultValue != null && mapping.Value.OutputReferences.First() != null && mapping.Value.DefaultValue.Priority > mapping.Value.OutputReferences.First().Priority))
                            {
                                // Change the ID to match the output
                                verifiedInputs.Add(mapping.Key, mapping.Value.DefaultValue.Value);
                            }
                            else if (mapping.Value.OutputReferences != null)
                            {
                                verifiedInputs.Add(mapping.Key, DynamicDataUtility.GetData(request.Inputs, mapping.Value.OutputReferences.First().OutputId).Value);
                            }
                        }

                        await _mediator.Send(new CreateStepCommand()
                        {
                            StepTemplateId = subBlock.Value.StepTemplateId,
                            CreatedBy      = SystemUsers.QUEUE_MANAGER,
                            Description    = null,
                            Inputs         = verifiedInputs,
                            WorkflowId     = createdWorkflowId,
                            Name           = subBlock.Key
                        });
                    }


                    workflow.UpdateJournal(
                        new JournalEntry()
                    {
                        CreatedBy = request.CreatedBy,
                        CreatedOn = DateTime.UtcNow,
                        Updates   = new List <Update>()
                        {
                            new Update()
                            {
                                FieldName = "completedlogicblocks",
                                Type      = UpdateType.Append,
                                Value     = block.Key //Add the logic block
                            }
                        }
                    });

                    await _node.Handle(new AddShardWriteOperation()
                    {
                        Data             = workflow,
                        WaitForSafeWrite = true,
                        Operation        = ConsensusCore.Domain.Enums.ShardOperationOptions.Update
                    });
                }
                catch (Exception e)
                {
                    _logger.LogCritical("Failed to action logic block " + block.Key + " with error " + e.Message + Environment.NewLine + e.StackTrace);
                }
            }

            stopwatch.Stop();

            return(new CommandResult <Workflow>()
            {
                Result = workflow,
                ObjectRefId = createdWorkflowId.ToString(),
                ElapsedMs = stopwatch.ElapsedMilliseconds,
                Type = CommandResultTypes.Create
            });
        }
Exemple #10
0
        public async Task <CommandResult> Handle(ScanWorkflowCommand request, CancellationToken cancellationToken)
        {
            var stopwatch = new Stopwatch();

            stopwatch.Start();
            List <string> messages             = new List <string>();
            bool          workflowStillRunning = false;

            var workflow = await _entitiesRepository.GetFirstOrDefaultAsync <Workflow>(w => w.Id == request.WorkflowId);

            if (workflow == null)
            {
                throw new MissingWorkflowException("Failed to find workflow " + request.WorkflowId + " as workflow does not exist.");
            }

            //Get the workflow template
            var workflowTemplate = await _entitiesRepository.GetFirstOrDefaultAsync <WorkflowTemplate>(wt => wt.ReferenceId == workflow.WorkflowTemplateId);

            if (workflowTemplate == null)
            {
                throw new WorkflowTemplateNotFoundException("Failed to scan workflow " + request.WorkflowId + " workflow template " + workflow.WorkflowTemplateId + ".");
            }

            //Get all the steps related to this task
            var workflowSteps = (await _entitiesRepository.GetAsync <Step>(s => s.WorkflowId == request.WorkflowId)).ToList();

            foreach (var workflowStep in workflowSteps)
            {
                workflowStep.Outputs = DynamicDataUtility.DecryptDynamicData((await _entitiesRepository.GetFirstOrDefaultAsync <StepTemplate>(st => st.ReferenceId == workflowStep.StepTemplateId)).OutputDefinitions, workflowStep.Outputs, EncryptionProtocol.AES256, ClusterStateService.GetEncryptionKey());
                if (!workflowStep.IsComplete())
                {
                    messages.Add("Workflow step " + workflowStep.Id + " (" + workflowStep.Name + ")" + " is running.");
                    workflowStillRunning = true;
                }
            }

            bool stepCreated = false;

            if (!workflowStillRunning)
            {
                if (workflow.CompletedLogicBlocks == null)
                {
                    workflow.CompletedLogicBlocks = new List <string>();
                }

                //Evaluate all logic blocks that have not been completed
                var logicBlocks = workflowTemplate.LogicBlocks.Where(lb => !workflow.CompletedLogicBlocks.Contains(lb.Key)).ToList();

                foreach (var logicBlock in logicBlocks)
                {
                    var  lockId       = Guid.NewGuid();
                    bool lockObtained = false;
                    while (!lockObtained)
                    {
                        while (_clusterStateService.IsLogicBlockLocked(request.WorkflowId, logicBlock.Key))
                        {
                            Console.WriteLine("Found " + ("workflow:" + request.WorkflowId + ">logicBlock:" + logicBlock) + " Lock");
                            await Task.Delay(1000);
                        }

                        int entryNumber = await _clusterStateService.LockLogicBlock(lockId, request.WorkflowId, logicBlock.Key);

                        //Check whether you got the lock
                        lockObtained = _clusterStateService.WasLockObtained(lockId, request.WorkflowId, logicBlock.Key);
                    }

                    //When the logic block is released, recheck whether this logic block has been evaluated
                    workflow = await _entitiesRepository.GetFirstOrDefaultAsync <Workflow>(w => w.Id == request.WorkflowId);

                    workflow.Inputs = DynamicDataUtility.DecryptDynamicData(workflowTemplate.InputDefinitions, workflow.Inputs, EncryptionProtocol.AES256, ClusterStateService.GetEncryptionKey());


                    if (workflow.CompletedLogicBlocks == null)
                    {
                        workflow.CompletedLogicBlocks = new List <string>();
                    }

                    //If the logic block is ready to be processed, submit the steps
                    if (logicBlock.Value.Dependencies.Evaluate(workflowSteps) && !workflow.CompletedLogicBlocks.Contains(logicBlock.Key))
                    {
                        foreach (var substep in logicBlock.Value.SubsequentSteps)
                        {
                            if (workflowSteps.Where(s => s.Name == substep.Key).Count() == 0)
                            {
                                var verifiedInputs = new Dictionary <string, object>();

                                foreach (var mapping in substep.Value.Mappings)
                                {
                                    //find the mapping with the highest priority
                                    var highestPriorityReference = WorkflowTemplateUtility.GetHighestPriorityReference(mapping.Value.OutputReferences, workflowSteps.ToArray());
                                    //if the highest priority reference is null, there are no mappings
                                    if (highestPriorityReference == null && mapping.Value.DefaultValue == null)
                                    {
                                    }
                                    // If default value is higher priority
                                    else if (mapping.Value.DefaultValue != null && (highestPriorityReference == null || highestPriorityReference.Priority < mapping.Value.DefaultValue.Priority))
                                    {
                                        verifiedInputs.Add(mapping.Key, mapping.Value.DefaultValue.Value);
                                    }
                                    // If the step ref is not -1 it is a step in the array but the workflow
                                    else if (highestPriorityReference.StepName != ReservedValues.WorkflowStartStepName)
                                    {
                                        var parentStep = workflowSteps.Where(ss => ss.Name == highestPriorityReference.StepName).FirstOrDefault();

                                        //If there is a AND and there is no parent step, throw a error
                                        if (parentStep == null)
                                        {
                                            throw new InvalidWorkflowProcessingException("Missing source for mapping " + mapping.Key + " from step " + highestPriorityReference.StepName);
                                        }
                                        else
                                        {
                                            if (parentStep != null)
                                            {
                                                try
                                                {
                                                    // Get the output value based on the pre-requisite id
                                                    var outPutValue = DynamicDataUtility.GetData(parentStep.Outputs, highestPriorityReference.OutputId);
                                                    // Validate it is in the definition
                                                    verifiedInputs.Add(mapping.Key, outPutValue.Value);
                                                }
                                                catch (Exception e)
                                                {
                                                    //TO DO Move this to logger
                                                    Console.WriteLine("Found error at mapping " + mapping.Key + " for step " + substep.Key);
                                                    throw e;
                                                }
                                            }
                                        }
                                    }
                                    //Get the value from the workflow ref
                                    else
                                    {
                                        // Validate it is in the definition
                                        verifiedInputs.Add(mapping.Key, DynamicDataUtility.GetData(workflow.Inputs, highestPriorityReference.OutputId).Value);
                                    }
                                }
                                stepCreated = true;
                                //Add the step TODO, add step priority
                                await _mediator.Send(new CreateStepCommand()
                                {
                                    StepTemplateId = substep.Value.StepTemplateId,
                                    CreatedBy      = SystemUsers.QUEUE_MANAGER,
                                    Inputs         = verifiedInputs,
                                    WorkflowId     = workflow.Id,
                                    Name           = substep.Key //create the step with the right subsequent step
                                });

                                messages.Add("Started workflow step " + substep.Key);
                            }
                        }

                        //Mark it as evaluated
                        workflow.UpdateJournal(
                            new JournalEntry()
                        {
                            CreatedBy = request.CreatedBy,
                            CreatedOn = DateTime.UtcNow,
                            Updates   = new List <Update>()
                            {
                                new Update()
                                {
                                    FieldName = "completedlogicblocks",
                                    Type      = UpdateType.Append,
                                    Value     = logicBlock.Key
                                }
                            }
                        });

                        //await _workflowsRepository.UpdateWorkflow(workflow);
                        await _node.Handle(new AddShardWriteOperation()
                        {
                            Data             = workflow,
                            WaitForSafeWrite = true,
                            Operation        = ConsensusCore.Domain.Enums.ShardOperationOptions.Update
                        });
                    }
                    await _clusterStateService.UnlockLogicBlock(lockId, request.WorkflowId, logicBlock.Key);
                }

                //Check if there are no longer any steps that are unassigned or assigned

                var workflowStatus = workflow.Status;
                workflowSteps = (await _entitiesRepository.GetAsync <Step>(s => s.WorkflowId == request.WorkflowId)).ToList();
                var highestStatus     = StepStatuses.GetHighestPriority(workflowSteps.Select(s => s.Status).ToArray());
                var newWorkflowStatus = stepCreated ? WorkflowStatuses.ConvertStepStatusToWorkflowStatus(StepStatuses.Unassigned) : WorkflowStatuses.ConvertStepStatusToWorkflowStatus(highestStatus);

                if (newWorkflowStatus != workflow.Status)
                {
                    workflow.UpdateJournal(
                        new JournalEntry()
                    {
                        CreatedBy = request.CreatedBy,
                        CreatedOn = DateTime.UtcNow,
                        Updates   = new List <Update>()
                        {
                            new Update()
                            {
                                FieldName = "status",
                                Type      = UpdateType.Override,
                                Value     = newWorkflowStatus
                            }
                        }
                    });

                    //await _workflowsRepository.UpdateWorkflow(workflow);
                    await _node.Handle(new AddShardWriteOperation()
                    {
                        Data             = workflow,
                        WaitForSafeWrite = true,
                        Operation        = ConsensusCore.Domain.Enums.ShardOperationOptions.Update
                    });


                    messages.Add("Updated workflow status " + newWorkflowStatus + ".");
                }
            }

            return(new CommandResult()
            {
                ObjectRefId = request.WorkflowId.ToString(),
                ElapsedMs = stopwatch.ElapsedMilliseconds,
                Type = CommandResultTypes.Update,
                IsSuccessful = true,
                Messages = messages.ToArray()
            });
        }
Exemple #11
0
        public async Task <QueryResult <string> > Handle(UnencryptStepFieldQuery request, CancellationToken cancellationToken)
        {
            var stopwatch = new Stopwatch();

            stopwatch.Start();

            if (request.Type != StepEncryptionTypes.Inputs && request.Type != StepEncryptionTypes.Outputs)
            {
                throw new InvalidUnencryptionRequestException("No such encryption type " + request.Type);
            }
            var step = await _entitiesRepository.GetFirstOrDefaultAsync <Step>(s => s.Id == request.StepId);


            if (step.CreatedBy != request.UserId)
            {
                throw new InvalidStepPermissionException("Only the creating user can decrypt the step secret.");
            }

            var stepTemplate = await _entitiesRepository.GetFirstOrDefaultAsync <StepTemplate>(st => st.ReferenceId == step.StepTemplateId);

            //Compare the to lower of inputs, TODO - this is inefficient
            if (!stepTemplate.InputDefinitions.ContainsKey(request.FieldName.ToLower()))
            {
                throw new InvalidUnencryptionRequestException("Field " + request.FieldName + " does not exist on step template " + stepTemplate.Id);
            }

            DynamicDataDescription kv = request.Type == StepEncryptionTypes.Inputs ? stepTemplate.InputDefinitions[request.FieldName.ToLower()] : stepTemplate.OutputDefinitions[request.FieldName.ToLower()];

            if (kv.Type != InputDataTypes.Secret)
            {
                throw new InvalidUnencryptionRequestException("Field " + request.FieldName + " is not a secret type.");
            }

            var decryptedInput = DynamicDataUtility.DecryptDynamicData(stepTemplate.InputDefinitions, request.Type == StepEncryptionTypes.Inputs ? step.Inputs : step.Outputs, EncryptionProtocol.AES256, ClusterStateService.GetEncryptionKey(), false);

            stopwatch.Stop();

            return(new QueryResult <string>()
            {
                ElapsedMs = stopwatch.ElapsedMilliseconds,
                Count = 1,
                Result = (string)decryptedInput[request.FieldName.ToLower()]
            });
        }