Exemple #1
0
        protected HttpContent ExtractBodyFromRequestModel(DscRequest dscRequ)
        {
            HttpContent  content          = null;
            PropertyInfo fromBodyProperty = null;

            foreach (var pi in dscRequ.GetType().GetProperties())
            {
                var attr = pi.GetCustomAttribute(typeof(FromBodyAttribute))
                           as FromBodyAttribute;
                if (attr != null)
                {
                    fromBodyProperty = pi;
                    break;
                }
            }

            if (fromBodyProperty != null)
            {
                // We test for a few principal property types that we can send directly as body,
                // content and otherwise we assume a custom model object that we serialize via JSON

                var required = fromBodyProperty.GetCustomAttribute(typeof(RequiredAttribute))
                               as RequiredAttribute;

                if (typeof(string).IsAssignableFrom(fromBodyProperty.PropertyType))
                {
                    var body = (string)fromBodyProperty.GetValue(dscRequ);
                    if (body != null)
                    {
                        content = new StringContent(body);
                    }
                }
                else if (typeof(byte[]).IsAssignableFrom(fromBodyProperty.PropertyType))
                {
                    var body = (byte[])fromBodyProperty.GetValue(dscRequ);
                    if (body != null)
                    {
                        content = new ByteArrayContent(body);
                    }
                }
                else if (typeof(Stream).IsAssignableFrom(fromBodyProperty.PropertyType))
                {
                    var body = (Stream)fromBodyProperty.GetValue(dscRequ);
                    if (body != null)
                    {
                        content = new StreamContent(body);
                    }
                }
                else
                {
                    var body = fromBodyProperty.GetValue(dscRequ);
                    if (body != null)
                    {
                        var bodySer = JsonConvert.SerializeObject(body, _jsonSerSettings);
                        content = new StringContent(bodySer);
                    }
                    else if ((bool)required?.AllowEmptyStrings)
                    {
                        content = new StringContent(string.Empty);
                    }
                }
            }

            return(content);
        }
Exemple #2
0
        protected async Task <IDisposable> SendDscAsync(DscPullConfig.ServerConfig server, HttpMethod verb, string route,
                                                        DscRequest dscRequ, DscResponse dscResp)
        {
            if (LOG.IsEnabled(LogLevel.Trace))
            {
                LOG.LogTrace(nameof(SendDscAsync));
            }

            AssertInit();

            dscRequ.ProtocolVersionHeader = "2.0";

            var routeExpanded = route;

            if (dscRequ is DscAgentRequest)
            {
                var dscAgentRequ = (DscAgentRequest)dscRequ;
                routeExpanded = route.Replace("{AgentId}", dscAgentRequ.AgentId.ToString());
            }

            var requUrl = new Uri(server.ServerUrl, routeExpanded);

            if (LOG.IsEnabled(LogLevel.Debug))
            {
                LOG.LogDebug("Computed request URL:  [{url}]", requUrl);
            }

            var httpHandler = new HttpClientHandler();

            if (server.Proxy != null)
            {
                if (LOG.IsEnabled(LogLevel.Debug))
                {
                    LOG.LogDebug("Enabling Proxy:  [{proxy}] supported=[{supported}]",
                                 server.Proxy, httpHandler.SupportsProxy);
                }
                httpHandler.UseProxy = true;
                httpHandler.Proxy    = server.Proxy;
            }

            var requMessage = new HttpRequestMessage
            {
                Method     = verb,
                RequestUri = requUrl,
            };

            // By default, we only send JSON unless something else was specified
            var contentType = dscRequ.ContentTypeHeader;

            if (string.IsNullOrEmpty(contentType))
            {
                contentType = DscContentTypes.JSON;
            }
            requMessage.Headers.Accept.Clear();
            requMessage.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue(contentType));

            ExtractFromRequestModel(dscRequ, requMessage);

            // See if we need to add RegKey authorization data
            if (!string.IsNullOrEmpty(server.RegistrationKey) &&
                dscRequ.MsDateHeader == COMPUTE_MS_DATE_HEADER &&
                requMessage.Content != null)
            {
                LOG.LogInformation("Computing RegKey Authorization");

                // Shhh!  This is the super-secret formula for computing an
                // Authorization challenge when using Reg Key Authentication
                // Details can be found at /references/regkey-authorization.md
                var msDate = DateTime.UtcNow.ToString(DscRequest.X_MS_DATE_FORMAT);
                requMessage.Headers.Remove(DscRequest.X_MS_DATE_HEADER);
                requMessage.Headers.Add(DscRequest.X_MS_DATE_HEADER, msDate);
                dscRequ.MsDateHeader = null;

                var macKey = Encoding.UTF8.GetBytes(server.RegistrationKey);

                using (var sha = SHA256.Create())
                    using (var mac = new HMACSHA256(macKey))
                        using (var ms = new MemoryStream())
                        {
                            await requMessage.Content.CopyToAsync(ms);

                            var body = ms.ToArray();
                            LOG.LogDebug("Computing hash over body content");
                            LOG.LogDebug("BODY:-----------------------------");
                            LOG.LogDebug($"<{Encoding.UTF8.GetString(body)}>");
                            LOG.LogDebug("-----------------------------:BODY");

                            var digest = sha.ComputeHash(body);
                            var digB64 = Convert.ToBase64String(digest);
                            LOG.LogDebug("  * digB64=" + digB64);
                            var concat = $"{digB64}\n{msDate}";
                            LOG.LogDebug("  * concat=" + concat);
                            var macSig = mac.ComputeHash(Encoding.UTF8.GetBytes(concat));
                            var sigB64 = Convert.ToBase64String(macSig);

                            requMessage.Headers.Authorization = new AuthenticationHeaderValue("Shared", sigB64);
                        }
            }

            // TODO:  Eventually we'll address this improper usage pattern as described here:
            //    https://aspnetmonsters.com/2016/08/2016-08-27-httpclientwrong/
            HttpResponseMessage respMessage = null;

            using (var http = _clientFactory(httpHandler))
            {
                respMessage = await http.SendAsync(requMessage);
            }

            respMessage.EnsureSuccessStatusCode();

            if (dscResp == null)
            {
                return(null);
            }
            else
            {
                return(await ExtractToResponseModel(respMessage, dscResp));
            }
        }
Exemple #3
0
        protected void ExtractFromRequestModel(DscRequest dscRequ, HttpRequestMessage requMessage)
        {
            // For POST or PUT requests, we search to see if any
            // property is supposed to be sent as the request body
            if (requMessage.Method == HttpMethod.Post || requMessage.Method == HttpMethod.Put)
            {
                requMessage.Content = ExtractBodyFromRequestModel(dscRequ);
            }

            // This will be resolved and populated on-demand
            // if there are any "FromRoute" model properties
            StringBuilder route = null;

            foreach (var pi in dscRequ.GetType().GetProperties())
            {
                var fromHeader = pi.GetCustomAttribute(typeof(FromHeaderAttribute))
                                 as FromHeaderAttribute;
                if (fromHeader != null)
                {
                    var name = fromHeader.Name;
                    if (string.IsNullOrEmpty(name))
                    {
                        name = pi.Name;
                    }

                    var value = pi.GetValue(dscRequ);
                    if (value == null)
                    {
                        continue;
                    }

                    if (!typeof(string).IsAssignableFrom(value.GetType()))
                    {
                        value = ConvertTo <string>(value);
                    }

                    if (LOG.IsEnabled(LogLevel.Debug))
                    {
                        LOG.LogDebug("Extracting request header [{name}] from property [{property}]",
                                     name, pi.Name);
                    }

                    if (!(TryAddHeader(requMessage.Headers, name, (string)value, replace: true)))
                    {
                        if (!(TryAddHeader(requMessage.Content?.Headers, name, (string)value,
                                           replace: true)))
                        {
                            throw new Exception(
                                      /*SR*/ "unable to add header anywhere to request message")
                                  .WithData(nameof(name), name)
                                  .WithData(nameof(value), value);
                        }
                        else if (LOG.IsEnabled(LogLevel.Debug))
                        {
                            LOG.LogDebug("    added as CONTENT header");
                        }
                        else if (LOG.IsEnabled(LogLevel.Debug))
                        {
                            LOG.LogDebug("    added as REQUEST header");
                        }
                    }

                    continue;
                }

                var fromRoute = pi.GetCustomAttribute(typeof(FromRouteAttribute))
                                as FromRouteAttribute;
                if (fromRoute != null)
                {
                    if (route == null)
                    {
                        // This must be the first property that updates the route
                        route = new StringBuilder(requMessage.RequestUri.ToString());
                    }

                    var name = fromRoute.Name;
                    if (string.IsNullOrEmpty(name))
                    {
                        name = pi.Name;
                    }

                    var value = pi.GetValue(dscRequ);
                    if (value == null)
                    {
                        // TODO: is this the right assumption???
                        value = string.Empty;
                    }

                    if (!typeof(string).IsAssignableFrom(value.GetType()))
                    {
                        value = ConvertTo <string>(value);
                    }

                    if (LOG.IsEnabled(LogLevel.Debug))
                    {
                        LOG.LogDebug("Extracting route element [{name}] from property [{property}]", name, pi.Name);
                    }

                    // Replace all occurrences of the route element
                    // name wrapped in curlies with this value
                    route.Replace($"{{{name}}}", (string)value);
                }

                // TODO:  Also need to do FromQuery
            }

            // If the route was modified, update the request's URL
            if (route != null)
            {
                requMessage.RequestUri = new Uri(route.ToString());
            }
        }
Exemple #4
0
 protected async Task SendDscAsync(DscPullConfig.ServerConfig server, HttpMethod verb, string route,
                                   DscRequest dscRequ)
 {
     await SendDscAsync(server, verb, route, dscRequ, null);
 }