protected async Task SendDscAsync(DscPullConfig.ServerConfig server, HttpMethod verb, string route, DscRequest dscRequ) { await SendDscAsync(server, verb, route, dscRequ, null); }
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)); } }
protected void AssertServerConfig(DscPullConfig.ServerConfig config) { AssertState(config?.ServerUrl != null, /*SR*/ "missing server URL configuration"); }