public IJsonHttpClient Create(HttpAuthentication auth)
 {
     return(new JsonHttpClient(
                _httpClientFactory.Create(auth),
                _serializers,
                _jmesPathQuery,
                _secretTracker));
 }
Beispiel #2
0
        public MyAuthenticationHandler(AuthenticationConfiguration configuration, HttpConfiguration httpConfiguration = null)
        {
            _authN = new HttpAuthentication(configuration);

            if (httpConfiguration != null)
            {
                InnerHandler = new HttpControllerDispatcher(httpConfiguration);
            }
        }
Beispiel #3
0
        public static string CreateSessionToken(HttpRequestMessage request)
        {
            ILog _log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);

            _log.Info("AutoLogin.CreateSessionToken");
            HttpAuthentication _httpAuthentication     = new HttpAuthentication(WebApiConfig.CreateAuthenticationConfiguration(_log));
            string             _resultadoAutenticacion = _httpAuthentication.CreateSessionTokenResponse(_httpAuthentication.Authenticate(request));

            _log.Info("Resultado autenticación: " + _resultadoAutenticacion);
            return(_resultadoAutenticacion);
        }
        /// <summary>
        /// Constructor for basic authentication with checking
        /// </summary>
        /// <param name="uri">Remote access</param>
        /// <param name="certFile">Certification file path</param>
        /// <param name="keyFile">Key file path</param>

        public HttpRemoteEngineControl(Uri uri, string certFile, string keyFile)
        {
            if (uri.Scheme == Uri.UriSchemeHttps && certFile != null && keyFile != null)
            {
                HttpAuthentication auth = new HttpAuthentication(certFile, keyFile);
                this.Init(uri, auth);
            }
            else
            {
                throw new ArgumentException("Use HTTPS remote address for certificate autentication!");
            }
        }
        private static bool AuthorizeRequest(HttpRequestMessage request)
        {
            var authN = new HttpAuthentication(WebApiConfig.Configuration);

            // Code to minimize time after token expiration when token is still successfully validated. Just for test purposes!
            authN.Configuration.Mappings.First().TokenHandler.Configuration.MaxClockSkew = TimeSpan.FromSeconds(3);

            ClaimsPrincipal principal;

            try
            {
                principal = authN.Authenticate(request);
            }
            catch (SecurityTokenValidationException)
            {
                return(false);
            }
            return(principal.Identity.IsAuthenticated);
        }
Beispiel #6
0
        public IHttpActionResult Get(HttpRequestMessage request)
        {
            var authN = new HttpAuthentication(WebApiConfig.Configuration);

            // Code to minimize time after token expiration when token is still successfully validated. Just for test purposes!
            authN.Configuration.Mappings.First().TokenHandler.Configuration.MaxClockSkew = TimeSpan.FromSeconds(3);
            try
            {
                ClaimsPrincipal principal = authN.Authenticate(request);
                if (principal.Identity.IsAuthenticated == false)
                {
                    return(StatusCode(HttpStatusCode.Forbidden));
                }
            } catch (SecurityTokenValidationException)
            {
                return(StatusCode(HttpStatusCode.Forbidden));
            }

            return(Ok());
        }
        /// <summary>
        /// Gets http authentication.
        /// </summary>
        /// <param name="updateJobAuthenticationParams">Http authentication properties specified via PowerShell.</param>
        /// <param name="authentication">Existing job http authentication.</param>
        /// <returns>HttpAuthentication object.</returns>
        private HttpAuthentication GetExistingAuthentication(PSHttpJobAuthenticationParams updateJobAuthenticationParams, HttpAuthentication authentication)
        {
            if (updateJobAuthenticationParams == null)
            {
                return null;
            }

            if(updateJobAuthenticationParams.HttpAuthType != null &&
               (authentication == null || 
                authentication.Type == null ||
                !updateJobAuthenticationParams.HttpAuthType.Equals(authentication.Type.ToString(), StringComparison.InvariantCultureIgnoreCase)))
            {
                return this.PopulateHttpAuthentication(updateJobAuthenticationParams);
            }

            switch (authentication.Type)
            {
                case HttpAuthenticationType.ClientCertificate:
                    var clientCertificate = authentication as ClientCertAuthentication;
                    clientCertificate.Pfx = updateJobAuthenticationParams.ClientCertPfx.GetValueOrDefault(defaultValue: clientCertificate.Pfx);
                    clientCertificate.Password = updateJobAuthenticationParams.ClientCertPassword.GetValueOrDefault(defaultValue: clientCertificate.Password);
                    return clientCertificate;

                case HttpAuthenticationType.Basic:
                    var basic = authentication as BasicAuthentication;
                    basic.Username = updateJobAuthenticationParams.Username.GetValueOrDefault(defaultValue: basic.Username);
                    basic.Password = updateJobAuthenticationParams.Password.GetValueOrDefault(defaultValue: basic.Password);
                    return basic;

                case HttpAuthenticationType.ActiveDirectoryOAuth:
                    var adOAuth = authentication as OAuthAuthentication;
                    adOAuth.Audience = updateJobAuthenticationParams.Audience.GetValueOrDefault(defaultValue: adOAuth.Audience);
                    adOAuth.ClientId = updateJobAuthenticationParams.ClientId.GetValueOrDefault(defaultValue: adOAuth.ClientId);
                    adOAuth.Secret = updateJobAuthenticationParams.Secret.GetValueOrDefault(defaultValue: adOAuth.Secret);
                    adOAuth.Tenant = updateJobAuthenticationParams.Tenant.GetValueOrDefault(defaultValue: adOAuth.Tenant);
                    return adOAuth;

                default:
                    return authentication;
            }
        }
Beispiel #8
0
        private HttpAuthentication SetHttpAuthentication(PSCreateJobParams jobRequest, JobCreateOrUpdateParameters jobUpdateParams)
        {
            HttpAuthentication httpAuthentication = null;

            if (!string.IsNullOrEmpty(jobRequest.HttpAuthType))
            {
                switch (jobRequest.HttpAuthType.ToLower())
                {
                case "clientcertificate":
                    if (jobRequest.ClientCertPfx != null && jobRequest.ClientCertPassword != null)
                    {
                        httpAuthentication = new ClientCertAuthentication
                        {
                            Type     = HttpAuthenticationType.ClientCertificate,
                            Password = jobRequest.ClientCertPassword,
                            Pfx      = jobRequest.ClientCertPfx
                        };
                    }
                    else
                    {
                        throw new InvalidOperationException(Resources.SchedulerInvalidClientCertAuthRequest);
                    }
                    break;

                case "activedirectoryoauth":
                    if (jobRequest.Tenant != null && jobRequest.Audience != null && jobRequest.ClientId != null && jobRequest.Secret != null)
                    {
                        httpAuthentication = new AADOAuthAuthentication
                        {
                            Type     = HttpAuthenticationType.ActiveDirectoryOAuth,
                            Tenant   = jobRequest.Tenant,
                            Audience = jobRequest.Audience,
                            ClientId = jobRequest.ClientId,
                            Secret   = jobRequest.Secret
                        };
                    }
                    else
                    {
                        throw new InvalidOperationException(Resources.SchedulerInvalidAADOAuthRequest);
                    }
                    break;

                case "basic":
                    if (jobRequest.Username != null && jobRequest.Password != null)
                    {
                        httpAuthentication = new BasicAuthentication
                        {
                            Type     = HttpAuthenticationType.Basic,
                            Username = jobRequest.Username,
                            Password = jobRequest.Password
                        };
                    }
                    else
                    {
                        throw new InvalidOperationException(Resources.SchedulerInvalidBasicAuthRequest);
                    }
                    break;

                case "none":
                    if (!string.IsNullOrEmpty(jobRequest.ClientCertPfx) || !string.IsNullOrEmpty(jobRequest.ClientCertPassword) ||
                        !string.IsNullOrEmpty(jobRequest.Tenant) || !string.IsNullOrEmpty(jobRequest.Secret) || !string.IsNullOrEmpty(jobRequest.ClientId) || !string.IsNullOrEmpty(jobRequest.Audience) ||
                        !string.IsNullOrEmpty(jobRequest.Username) || !string.IsNullOrEmpty(jobRequest.Password))
                    {
                        throw new InvalidOperationException(Resources.SchedulerInvalidNoneAuthRequest);
                    }
                    break;
                }
            }
            return(httpAuthentication);
        }
        /// <summary>
        /// Gets http authentication.
        /// </summary>
        /// <param name="updateJobAuthenticationParams">Http authentication properties specified via PowerShell.</param>
        /// <param name="authentication">Existing job http authentication.</param>
        /// <returns>HttpAuthentication object.</returns>
        private HttpAuthentication GetExistingAuthentication(PSHttpJobAuthenticationParams updateJobAuthenticationParams, HttpAuthentication authentication)
        {
            if (updateJobAuthenticationParams == null)
            {
                return(null);
            }

            if (updateJobAuthenticationParams.HttpAuthType != null &&
                (authentication == null ||
                 authentication.Type == null ||
                 !updateJobAuthenticationParams.HttpAuthType.Equals(authentication.Type.ToString(), StringComparison.InvariantCultureIgnoreCase)))
            {
                return(this.PopulateHttpAuthentication(updateJobAuthenticationParams));
            }

            switch (authentication.Type)
            {
            case HttpAuthenticationType.ClientCertificate:
                var clientCertificate = authentication as ClientCertAuthentication;
                clientCertificate.Pfx      = updateJobAuthenticationParams.ClientCertPfx.GetValueOrDefault(defaultValue: clientCertificate.Pfx);
                clientCertificate.Password = updateJobAuthenticationParams.ClientCertPassword.GetValueOrDefault(defaultValue: clientCertificate.Password);
                return(clientCertificate);

            case HttpAuthenticationType.Basic:
                var basic = authentication as BasicAuthentication;
                basic.Username = updateJobAuthenticationParams.Username.GetValueOrDefault(defaultValue: basic.Username);
                basic.Password = updateJobAuthenticationParams.Password.GetValueOrDefault(defaultValue: basic.Password);
                return(basic);

            case HttpAuthenticationType.ActiveDirectoryOAuth:
                var adOAuth = authentication as OAuthAuthentication;
                adOAuth.Audience = updateJobAuthenticationParams.Audience.GetValueOrDefault(defaultValue: adOAuth.Audience);
                adOAuth.ClientId = updateJobAuthenticationParams.ClientId.GetValueOrDefault(defaultValue: adOAuth.ClientId);
                adOAuth.Secret   = updateJobAuthenticationParams.Secret.GetValueOrDefault(defaultValue: adOAuth.Secret);
                adOAuth.Tenant   = updateJobAuthenticationParams.Tenant.GetValueOrDefault(defaultValue: adOAuth.Tenant);
                return(adOAuth);

            default:
                return(authentication);
            }
        }
Beispiel #10
0
        /// <summary>
        /// Get http job authentication details.
        /// </summary>
        /// <param name="authentication">Http authentication.</param>
        /// <returns>PSHttpJobAuthenticationDetails</returns>
        internal static PSHttpJobAuthenticationDetails GetSchedulerHttpJobAuthenticationDetails(HttpAuthentication authentication)
        {
            if (authentication == null)
            {
                return null;
            }

            switch (authentication.Type)
            {
                case HttpAuthenticationType.ClientCertificate:
                    var clientCertAuthentication = authentication as ClientCertAuthentication;

                    var psClientCertAuthentication = new PSHttpJobClientCertAuthenticationDetails()
                    {
                        HttpAuthType = Constants.HttpAuthenticationClientCertificate,
                    };

                    if (clientCertAuthentication != null)
                    {
                        psClientCertAuthentication.ClientCertExpiryDate = clientCertAuthentication.CertificateExpirationDate.ToString();
                        psClientCertAuthentication.ClientCertSubjectName = clientCertAuthentication.CertificateSubjectName;
                        psClientCertAuthentication.ClientCertThumbprint = clientCertAuthentication.CertificateThumbprint;
                    }

                    return psClientCertAuthentication;

                case HttpAuthenticationType.Basic:
                    var basicAuthentication = authentication as BasicAuthentication;

                    var psBasicAuthentication = new PSHttpJobBasicAuthenticationDetails()
                    {
                        HttpAuthType = Constants.HttpAuthenticationBasic,
                        Username = basicAuthentication == null ? null : basicAuthentication.Username,
                    };

                    return psBasicAuthentication;

                case HttpAuthenticationType.ActiveDirectoryOAuth:
                    var oAuthAuthentication = authentication as OAuthAuthentication;

                    var psOAuthAuthentication = new PSHttpJobOAuthAuthenticationDetails()
                    {
                        HttpAuthType = Constants.HttpAuthenticationActiveDirectoryOAuth,
                    };

                    if (oAuthAuthentication != null)
                    {
                        psOAuthAuthentication.Audience = oAuthAuthentication.Audience;
                        psOAuthAuthentication.ClientId = oAuthAuthentication.ClientId;
                        psOAuthAuthentication.Tenant = oAuthAuthentication.Tenant;
                    }

                    return psOAuthAuthentication;

                default:
                    return new PSHttpJobAuthenticationDetails()
                    {
                        HttpAuthType = Constants.HttpAuthenticationNone
                    };
            }
        }
 private void Init(Uri uri, HttpAuthentication auth)
 {
     this.communicator = new HttpCommunicator(uri, auth);
     datastore         = new HttpRemoteDataStore(this.communicator);
 }
 /// <summary>
 ///
 /// </summary>
 /// <param name="remote">remote datastore Uri</param>
 /// <param name="auth">authentication object</param>
 public HttpRemoteEngineControl(Uri uri, HttpAuthentication auth)
 {
     this.Init(uri, auth);
 }
Beispiel #13
0
 public AuthenticationHandler(AuthenticationConfiguration configuration, IHttpRequestMessageFactory httpRequestMessageFactory)
 {
     this.authenticationHandler     = new HttpAuthentication(configuration);
     this.httpRequestMessageFactory = httpRequestMessageFactory;
 }
Beispiel #14
0
        /// <summary>
        /// Get http job authentication details.
        /// </summary>
        /// <param name="authentication">Http authentication.</param>
        /// <returns>PSHttpJobAuthenticationDetails</returns>
        internal static PSHttpJobAuthenticationDetails GetSchedulerHttpJobAuthenticationDetails(HttpAuthentication authentication)
        {
            if (authentication == null)
            {
                return(null);
            }

            switch (authentication.Type)
            {
            case HttpAuthenticationType.ClientCertificate:
                var clientCertAuthentication = authentication as ClientCertAuthentication;

                var psClientCertAuthentication = new PSHttpJobClientCertAuthenticationDetails()
                {
                    HttpAuthType = Constants.HttpAuthenticationClientCertificate,
                };

                if (clientCertAuthentication != null)
                {
                    psClientCertAuthentication.ClientCertExpiryDate  = clientCertAuthentication.CertificateExpirationDate.ToString();
                    psClientCertAuthentication.ClientCertSubjectName = clientCertAuthentication.CertificateSubjectName;
                    psClientCertAuthentication.ClientCertThumbprint  = clientCertAuthentication.CertificateThumbprint;
                }

                return(psClientCertAuthentication);

            case HttpAuthenticationType.Basic:
                var basicAuthentication = authentication as BasicAuthentication;

                var psBasicAuthentication = new PSHttpJobBasicAuthenticationDetails()
                {
                    HttpAuthType = Constants.HttpAuthenticationBasic,
                    Username     = basicAuthentication == null ? null : basicAuthentication.Username,
                };

                return(psBasicAuthentication);

            case HttpAuthenticationType.ActiveDirectoryOAuth:
                var oAuthAuthentication = authentication as OAuthAuthentication;

                var psOAuthAuthentication = new PSHttpJobOAuthAuthenticationDetails()
                {
                    HttpAuthType = Constants.HttpAuthenticationActiveDirectoryOAuth,
                };

                if (oAuthAuthentication != null)
                {
                    psOAuthAuthentication.Audience = oAuthAuthentication.Audience;
                    psOAuthAuthentication.ClientId = oAuthAuthentication.ClientId;
                    psOAuthAuthentication.Tenant   = oAuthAuthentication.Tenant;
                }

                return(psOAuthAuthentication);

            default:
                return(new PSHttpJobAuthenticationDetails()
                {
                    HttpAuthType = Constants.HttpAuthenticationNone
                });
            }
        }
Beispiel #15
0
        private async Task ExecuteOperation(ExecutionContext context)
        {
            var operation = context.Operation;

            if (operation.values != null)
            {
                context.AddValuesIn(ProcessValues(operation.values, context.Values));
            }

            var patternOkay = context.PatternMatcher.IsMatch(context.Path);

            var message = ConvertToString(ProcessValues(operation.message, context.Values));

            var conditionOkay = true;

            if (!string.IsNullOrEmpty(operation.condition))
            {
                var conditionResult = _jmesPathQuery.Search(operation.condition, context.Values);
                conditionOkay = ConditionBoolean(conditionResult);
            }

            for (var shouldExecute = patternOkay && conditionOkay; shouldExecute; shouldExecute = await EvaluateRepeat(context))
            {
                if (!string.IsNullOrEmpty(message))
                {
                    _console.WriteLine();
                    _console.WriteLine($"{new string(' ', context.Indent * 2)}- {message.Color(ConsoleColor.Cyan)}");
                }

                var debugPath = Path.Combine(OutputDirectory.Required(), "logs", $"{++_operationCount:000}-{new string('-', context.Indent * 2)}{new string((message ?? operation.write ?? operation.request ?? operation.template ?? string.Empty).Select(ch => char.IsLetterOrDigit(ch) ? ch : '-').ToArray())}.yaml");
                Directory.CreateDirectory(Path.GetDirectoryName(debugPath));
                using (var writer = _secretTracker.FilterTextWriter(File.CreateText(debugPath)))
                {
                    var logentry = new Dictionary <object, object>
                    {
                        {
                            "operation",
                            new Dictionary <object, object>
                            {
                                { "message", message },
                                { "target", operation.target },
                                { "condition", operation.condition },
                                { "repeat", operation.repeat },
                                { "request", operation.request },
                                { "template", operation.template },
                                { "write", operation.write },
                            }
                        },
                        { "valuesIn", context.ValuesIn },
                        { "valuesOut", context.ValuesOut },
                        { "request", null },
                        { "response", null },
                        { "cumulativeValues", context.Values },
                    };
                    try
                    {
                        object result = null;

                        // First special type of operation - executing a request
                        if (!string.IsNullOrWhiteSpace(operation.request))
                        {
                            WorkflowModel.Request request = context.TemplateEngine.Render <WorkflowModel.Request>(
                                operation.request,
                                context.Values);

                            logentry["request"] = request;

                            HttpAuthentication auth = null;
                            if (request.auth != null)
                            {
                                // TODO: remove these defaults
                                auth = new HttpAuthentication
                                {
                                    tenant      = request?.auth?.tenant ?? "common",
                                    resourceId  = request?.auth?.resource ?? "499b84ac-1321-427f-aa17-267ca6975798",
                                    clientId    = request?.auth?.client ?? "e8f3cc86-b3b2-4ebb-867c-9c314925b384",
                                    interactive = IsInteractive
                                };
                            }

                            var client = _clientFactory.Create(auth);

                            var method = new HttpMethod(request.method ?? "GET");
                            if (IsDryRun && method.Method != "GET")
                            {
                                _console.WriteLine($"Skipping {method.Method.ToString().Color(ConsoleColor.DarkYellow)} {request.url}");
                            }
                            else
                            {
                                try
                                {
                                    var jsonRequest = new JsonRequest
                                    {
                                        method  = method,
                                        url     = request.url,
                                        headers = request.headers,
                                        body    = request.body,
                                        secret  = request.secret,
                                    };

                                    var jsonResponse = await client.SendAsync(jsonRequest);

                                    if ((int)jsonResponse.status >= 400)
                                    {
                                        throw new ApplicationException($"Request failed with status code {jsonResponse.status}");
                                    }

                                    result = new WorkflowModel.Response
                                    {
                                        status  = (int)jsonResponse.status,
                                        headers = jsonResponse.headers,
                                        body    = jsonResponse.body,
                                    };

                                    logentry["response"] = result;
                                }
                                catch
                                {
                                    // TODO - retry logic here?
                                    throw;
                                }
                            }
                        }

                        // Second special type of operation - rendering a template
                        if (!string.IsNullOrWhiteSpace(operation.template))
                        {
                            if (!string.IsNullOrEmpty(operation.write))
                            {
                                var targetPath = Path.Combine(OutputDirectory.Required(), operation.write);

                                Directory.CreateDirectory(Path.GetDirectoryName(targetPath));

                                using (var targetWriter = File.CreateText(targetPath))
                                {
                                    if (!string.IsNullOrWhiteSpace(operation.template))
                                    {
                                        context.TemplateEngine.Render(operation.template, context.Values, targetWriter);
                                    }
                                }
                            }
                            else
                            {
                                result = context.TemplateEngine.Render <object>(operation.template, context.Values);
                            }
                        }

                        // Third special type of operation - nested operations
                        if (operation.operations != null)
                        {
                            result = await ExecuteOperations(context, operation.operations);
                        }

                        // If output is specifically stated - use it to query
                        if (operation.output != null)
                        {
                            if (operation.operations != null)
                            {
                                // for nested operations, output expressions can pull in the current operation's cumulative values as well
                                context.AddValuesOut(ProcessValues(operation.output, MergeUtils.Merge(result, context.Values) ?? context.Values));
                            }
                            else if (result != null)
                            {
                                // for request and template operations, the current operation result is a well-known property to avoid collisions
                                var merged = MergeUtils.Merge(new Dictionary <object, object> {
                                    { "result", result }
                                }, context.Values);

                                context.AddValuesOut(ProcessValues(operation.output, merged));
                            }
                            else
                            {
                                // there are no values coming out of this operation - output queries are based only on cumulative values
                                context.AddValuesOut(ProcessValues(operation.output, context.Values));
                            }
                        }

                        if (operation.@throw != null)
                        {
                            var throwMessage = ConvertToString(ProcessValues([email protected], context.Values));
                            throwMessage = string.IsNullOrEmpty(throwMessage) ? message : throwMessage;

                            var throwDetails = ProcessValues([email protected], context.Values);

                            _console.WriteLine(throwMessage.Color(ConsoleColor.DarkRed));
                            if (throwDetails != null)
                            {
                                _console.WriteLine(_serializers.YamlSerializer.Serialize(throwDetails).Color(ConsoleColor.DarkRed));
                            }

                            throw new OperationException(string.IsNullOrEmpty(throwMessage) ? message : throwMessage)
                                  {
                                      Details = throwDetails
                                  };
                        }

                        // otherwise if output is unstated, and there are nested operations with output - those flows back as effective output
                        if (operation.output == null && operation.operations != null && result != null)
                        {
                            context.AddValuesOut(result);
                        }
                    }
                    catch (Exception ex)
                    {
                        logentry["error"] = new Dictionary <object, object>
                        {
                            { "type", ex.GetType().FullName },
                            { "message", ex.Message },
                            { "stack", ex.StackTrace },
                        };

                        throw;
                    }
                    finally
                    {
                        logentry["valuesIn"]         = context?.ValuesIn;
                        logentry["valuesOut"]        = context?.ValuesOut;
                        logentry["cumulativeValues"] = context?.Values;
                        _serializers.YamlSerializer.Serialize(writer, logentry);
                    }
                }
            }
        }
Beispiel #16
0
        public static async Task <HttpResponseMessage> ApiRequest(ApiRequest request, HttpAuthentication authentication = null)
        {
            if (request == null)
            {
                throw new ArgumentNullException(nameof(request));
            }
            using (var client = new HttpClient {
                BaseAddress = request.BaseAddress
            })
            {
                if (authentication != null)
                {
                    client.DefaultRequestHeaders.Authorization = authentication.Header;
                }

                return(await client.SendAsync(request.Message));
            }
        }
Beispiel #17
0
        /// <summary>
        /// Gets http authentication.
        /// </summary>
        /// <param name="updateJobAuthenticationParams">Http authentication properties specified via PowerShell.</param>
        /// <param name="authentication">Existing job http authentication.</param>
        /// <returns>HttpAuthentication object.</returns>
        private HttpAuthentication GetExistingAuthentication(PSHttpJobAuthenticationParams updateJobAuthenticationParams, HttpAuthentication authentication)
        {
            // With current SDK design (limits within Swagger for inheritance), we won't be able to update Authentication params.
            // In order for user to update Authentication params, the user must enter the credentials again.
            if (updateJobAuthenticationParams != null && updateJobAuthenticationParams.HttpAuthType != null)
            {
                return(this.PopulateHttpAuthentication(updateJobAuthenticationParams));
            }

            return(null);
        }
Beispiel #18
0
        private async Task ExecuteOperationInner(OperationContext context)
        {
            var operation = context.Operation;

            if (operation.values != null)
            {
                context.AddValuesIn(_valuesEngine.ProcessValues(operation.values, context.Values));
            }

            var patternOkay = context.PatternMatcher.IsMatch(context.Path);

            var conditionOkay = operation.condition == null ? true : _valuesEngine.EvaluateToBoolean(operation.condition, context.Values);

            for (var shouldExecute = patternOkay && conditionOkay; shouldExecute; shouldExecute = await EvaluateRepeat(context))
            {
                var message  = _valuesEngine.EvaluateToString(operation.message, context.Values);
                var write    = _valuesEngine.EvaluateToString(operation.write, context.Values);
                var workflow = _valuesEngine.EvaluateToString(operation.workflow, context.Values);

                if (!string.IsNullOrEmpty(message))
                {
                    _console.WriteLine();
                    _console.WriteLine($"{new string(' ', context.Indent * 2)}- {message.Color(ConsoleColor.Cyan)}");
                }

                var debugPath = Path.Combine(context.ExecutionContext.OutputDirectory, "logs", $"{++_operationCount:000}-{new string('-', context.Indent * 2)}{new string((message ?? write ?? operation.request ?? operation.template ?? workflow ?? string.Empty).Select(ch => char.IsLetterOrDigit(ch) ? ch : '-').ToArray())}.yaml");
                Directory.CreateDirectory(Path.GetDirectoryName(debugPath));
                using (var writer = _secretTracker.FilterTextWriter(File.CreateText(debugPath)))
                {
                    var logentry = new Dictionary <object, object>
                    {
                        {
                            "operation",
                            new Dictionary <object, object>
                            {
                                { "message", message },
                                { "target", operation.target },
                                { "condition", operation.condition },
                                { "repeat", operation.repeat },
                                { "request", operation.request },
                                { "template", operation.template },
                                { "workflow", workflow },
                                { "write", write },
                            }
                        },
                        { "valuesIn", context.ValuesIn },
                        { "valuesOut", context.ValuesOut },
                        { "request", null },
                        { "response", null },
                        { "cumulativeValues", context.Values },
                    };

                    try
                    {
                        // object result = null;
                        object outputContext = context.Values;

                        try
                        {
                            // First special type of operation - executing a request
                            if (!string.IsNullOrWhiteSpace(operation.request))
                            {
                                var request = context.TemplateEngine.Render <WorkflowModel.Request>(
                                    operation.request,
                                    context.Values);

                                logentry["request"] = request;

                                HttpAuthentication auth = null;
                                if (request.auth != null)
                                {
                                    // TODO: remove these defaults
                                    auth = new HttpAuthentication
                                    {
                                        tenant      = request?.auth?.tenant ?? "common",
                                        resourceId  = request?.auth?.resource ?? "499b84ac-1321-427f-aa17-267ca6975798",
                                        clientId    = request?.auth?.client ?? "e8f3cc86-b3b2-4ebb-867c-9c314925b384",
                                        interactive = context.ExecutionContext.IsInteractive
                                    };
                                }

                                var client = _clientFactory.Create(auth);

                                var method = new HttpMethod(request.method ?? "GET");

                                var parts = UriParts.Parse(request.url);
                                foreach (var query in request.query ?? Enumerable.Empty <KeyValuePair <string, object> >())
                                {
                                    parts.Query = parts.Query.Add(query.Key, Convert.ToString(query.Value));
                                }

                                var url = parts.ToString();

                                if (context.ExecutionContext.IsDryRun && method.Method != "GET")
                                {
                                    _console.WriteLine($"Skipping {method.Method.ToString().Color(ConsoleColor.DarkYellow)} {request.url}");
                                }
                                else
                                {
                                    var jsonRequest = new JsonRequest
                                    {
                                        method  = method,
                                        url     = url,
                                        headers = request.headers,
                                        body    = request.body,
                                        secret  = request.secret,
                                    };

                                    var jsonResponse = await client.SendAsync(jsonRequest);

                                    var response = new WorkflowModel.Response
                                    {
                                        status  = (int)jsonResponse.status,
                                        headers = jsonResponse.headers,
                                        body    = jsonResponse.body,
                                    };

                                    logentry["response"] = response;

                                    outputContext = MergeUtils.Merge(new Dictionary <object, object> {
                                        { "result", response }
                                    }, outputContext);

                                    if (response.status >= 400)
                                    {
                                        var error = new RequestException($"Request failed with status code {jsonResponse.status}")
                                        {
                                            Request  = request,
                                            Response = response,
                                        };
                                        throw error;
                                    }
                                }
                            }

                            // Second special type of operation - rendering a template
                            if (!string.IsNullOrWhiteSpace(operation.template))
                            {
                                if (!string.IsNullOrEmpty(write))
                                {
                                    if (string.Equals(write, "stdout"))
                                    {
                                        context.TemplateEngine.Render(operation.template, context.Values, Console.Out);
                                    }
                                    else if (string.Equals(write, "stderr"))
                                    {
                                        context.TemplateEngine.Render(operation.template, context.Values, Console.Error);
                                    }
                                    else
                                    {
                                        var targetPath = Path.Combine(context.ExecutionContext.OutputDirectory, write);

                                        Directory.CreateDirectory(Path.GetDirectoryName(targetPath));

                                        using (var targetWriter = File.CreateText(targetPath))
                                        {
                                            context.TemplateEngine.Render(operation.template, context.Values, targetWriter);
                                        }
                                    }
                                }

                                if (operation.output != null)
                                {
                                    var templateResult = context.TemplateEngine.Render <object>(operation.template, context.Values);

                                    outputContext = MergeUtils.Merge(new Dictionary <object, object> {
                                        { "result", templateResult }
                                    }, outputContext);
                                }
                            }

                            if (!string.IsNullOrEmpty(workflow))
                            {
                                var subBlueprint = await _blueprintManager.GetBlueprintPackageDependency(context.ExecutionContext.BlueprintPackage, workflow);

                                if (subBlueprint == null)
                                {
                                    throw new OperationException($"Unable to load sub-workflow {workflow}");
                                }

                                var(subTemplateEngine, subWorkflow, subValues) = _workflowLoader.Load(subBlueprint, context.ValuesIn, GenerateOutput);

                                var subContext = new ExecutionContext.Builder()
                                                 .CopyFrom(context)
                                                 .UseBlueprintPackage(subBlueprint)
                                                 .UseTemplateEngine(subTemplateEngine)
                                                 .SetValues(subValues)
                                                 .Build();

                                if (subWorkflow.values != null)
                                {
                                    subContext.AddValuesIn(_valuesEngine.ProcessValues(subWorkflow.values, subContext.Values));
                                }

                                var nestedResult = await ExecuteOperations(subContext, subWorkflow.operations);

                                if (subWorkflow.output != null)
                                {
                                    nestedResult = _valuesEngine.ProcessValues(subWorkflow.output, nestedResult);
                                }

                                outputContext = MergeUtils.Merge(new Dictionary <object, object> {
                                    { "result", nestedResult }
                                }, outputContext);
                            }

                            // Third special type of operation - nested operations
                            if (operation.operations != null)
                            {
                                var nestedResult = await ExecuteOperations(context, operation.operations);

                                if (operation.output == null)
                                {
                                    // if output is unstated, and there are nested operations with output - those flows back as effective output
                                    context.AddValuesOut(nestedResult);
                                }
                                else
                                {
                                    // if output is stated, nested operations with output are visible to output queries
                                    outputContext = MergeUtils.Merge(nestedResult, context.Values) ?? context.Values;
                                }
                            }

                            // If output is specifically stated - use it to query
                            if (operation.output != null)
                            {
                                context.AddValuesOut(ProcessValues(operation.output, outputContext));
                            }

                            if (operation.@throw != null)
                            {
                                var throwMessage = _valuesEngine.EvaluateToString([email protected], context.Values);
                                throwMessage = string.IsNullOrEmpty(throwMessage) ? message : throwMessage;

                                var throwDetails = ProcessValues([email protected], context.Values);

                                _console.WriteLine(throwMessage.Color(ConsoleColor.DarkRed));
                                if (throwDetails != null)
                                {
                                    _console.WriteLine(_serializers.YamlSerializer.Serialize(throwDetails).Color(ConsoleColor.DarkRed));
                                }

                                throw new OperationException(string.IsNullOrEmpty(throwMessage) ? message : throwMessage)
                                      {
                                          Details = throwDetails
                                      };
                            }
                        }
                        catch (Exception ex) when(CatchCondition(ex, operation.@catch, outputContext))
                        {
                            if ([email protected] != null)
                            {
                                var mergedContext = MergeError(ex, outputContext);
                                var catchDetails  = ProcessValues([email protected], mergedContext);
                                context.AddValuesOut(catchDetails);
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        logentry["error"] = new Dictionary <object, object>
                        {
                            { "type", ex.GetType().FullName },
                            { "message", ex.Message },
                            { "stack", ex.StackTrace },
                        };

                        throw;
                    }
                    finally
                    {
                        logentry["valuesIn"]         = context?.ValuesIn;
                        logentry["valuesOut"]        = context?.ValuesOut;
                        logentry["cumulativeValues"] = context?.Values;
                        _serializers.YamlSerializer.Serialize(writer, logentry);
                    }
                }
            }
        }
 public IJsonHttpClient Create(HttpAuthentication auth) => new StubJsonHttpClient(this);