From b479395bb8220f4176452802539b113f7dbc2365 Mon Sep 17 00:00:00 2001
From: JoshLove-msft <54595583+JoshLove-msft@users.noreply.github.com>
Date: Tue, 1 Aug 2023 15:03:07 -0700
Subject: [PATCH 1/7] Sanitize requests when logging
---
.../Azure.Sdk.Tools.TestProxy.Tests.csproj | 7 ++
.../LoggingTests.cs | 115 ++++++++++++++++++
.../TestLogger.cs | 28 +++++
.../Azure.Sdk.Tools.TestProxy/Admin.cs | 18 +--
.../Common/DebugLogger.cs | 64 ++++++----
.../Azure.Sdk.Tools.TestProxy/Playback.cs | 4 +-
.../Properties/AssemblyInfo.cs | 7 ++
.../Azure.Sdk.Tools.TestProxy/Record.cs | 2 +-
.../RecordingHandler.cs | 27 ++--
tools/test-proxy/Directory.Build.targets | 8 ++
10 files changed, 234 insertions(+), 46 deletions(-)
create mode 100644 tools/test-proxy/Azure.Sdk.Tools.TestProxy.Tests/LoggingTests.cs
create mode 100644 tools/test-proxy/Azure.Sdk.Tools.TestProxy.Tests/TestLogger.cs
create mode 100644 tools/test-proxy/Azure.Sdk.Tools.TestProxy/Properties/AssemblyInfo.cs
create mode 100644 tools/test-proxy/Directory.Build.targets
diff --git a/tools/test-proxy/Azure.Sdk.Tools.TestProxy.Tests/Azure.Sdk.Tools.TestProxy.Tests.csproj b/tools/test-proxy/Azure.Sdk.Tools.TestProxy.Tests/Azure.Sdk.Tools.TestProxy.Tests.csproj
index 9ab73a30465..9af34f989a4 100644
--- a/tools/test-proxy/Azure.Sdk.Tools.TestProxy.Tests/Azure.Sdk.Tools.TestProxy.Tests.csproj
+++ b/tools/test-proxy/Azure.Sdk.Tools.TestProxy.Tests/Azure.Sdk.Tools.TestProxy.Tests.csproj
@@ -25,6 +25,9 @@
PreserveNewest
+
+ AzureSDKToolsKey.snk
+
@@ -33,4 +36,8 @@
+
+
+
+
diff --git a/tools/test-proxy/Azure.Sdk.Tools.TestProxy.Tests/LoggingTests.cs b/tools/test-proxy/Azure.Sdk.Tools.TestProxy.Tests/LoggingTests.cs
new file mode 100644
index 00000000000..b06106317d8
--- /dev/null
+++ b/tools/test-proxy/Azure.Sdk.Tools.TestProxy.Tests/LoggingTests.cs
@@ -0,0 +1,115 @@
+using System.IO;
+using System.Net.Http;
+using System.Text;
+using System.Threading.Tasks;
+using Azure.Sdk.Tools.TestProxy.Common;
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.Extensions.Logging.Abstractions;
+using Xunit;
+
+namespace Azure.Sdk.Tools.TestProxy.Tests
+{
+ ///
+ /// Logging tests cannot be run in parallel with other tests because they share a static logger.
+ ///
+ [Collection(nameof(LoggingCollection))]
+ public class LoggingTests
+ {
+ [Fact]
+ public async Task PlaybackLogsSanitizedRequest()
+ {
+ var logger = new TestLogger();
+ DebugLogger.Logger = logger;
+
+ try
+ {
+ RecordingHandler testRecordingHandler = new RecordingHandler(Directory.GetCurrentDirectory());
+ var httpContext = new DefaultHttpContext();
+ var body = "{\"x-recording-file\":\"Test.RecordEntries/request_with_binary_content.json\"}";
+ httpContext.Request.Body = TestHelpers.GenerateStreamRequestBody(body);
+ httpContext.Request.ContentLength = body.Length;
+
+ var controller = new Playback(testRecordingHandler, new NullLoggerFactory())
+ {
+ ControllerContext = new ControllerContext()
+ {
+ HttpContext = httpContext
+ }
+ };
+ await controller.Start();
+
+ var recordingId = httpContext.Response.Headers["x-recording-id"].ToString();
+ Assert.NotNull(recordingId);
+ Assert.True(testRecordingHandler.PlaybackSessions.ContainsKey(recordingId));
+ var entry = testRecordingHandler.PlaybackSessions[recordingId].Session.Entries[0];
+ HttpRequest request = TestHelpers.CreateRequestFromEntry(entry);
+ request.Headers["Authorization"] = "fake-auth-header";
+
+ HttpResponse response = new DefaultHttpContext().Response;
+ await testRecordingHandler.HandlePlaybackRequest(recordingId, request, response);
+
+ Assert.Single(logger.Logs);
+ var logEntry = logger.Logs[0].ToString();
+ Assert.DoesNotContain(@"""Authorization"":[""fake-auth-header""]", logEntry);
+ Assert.Contains(@"""Authorization"":[""Sanitized""]", logEntry);
+ }
+ finally
+ {
+ DebugLogger.Logger = null;
+ }
+ }
+
+ [Fact]
+ public async Task RecordingHandlerLogsSanitizedRequests()
+ {
+ var logger = new TestLogger();
+ DebugLogger.Logger = logger;
+ var httpContext = new DefaultHttpContext();
+ var bodyBytes = Encoding.UTF8.GetBytes("{\"hello\":\"world\"}");
+ var mockClient = new HttpClient(new MockHttpHandler(bodyBytes, "application/json"));
+ var path = Directory.GetCurrentDirectory();
+ var recordingHandler = new RecordingHandler(path)
+ {
+ RedirectableClient = mockClient,
+ RedirectlessClient = mockClient
+ };
+
+ var relativePath = "recordings/logs";
+ var fullPathToRecording = Path.Combine(path, relativePath) + ".json";
+
+ await recordingHandler.StartRecordingAsync(relativePath, httpContext.Response);
+
+ var recordingId = httpContext.Response.Headers["x-recording-id"].ToString();
+
+ httpContext.Request.ContentType = "application/json";
+ httpContext.Request.Headers["Authorization"] = "fake-auth-header";
+ httpContext.Request.ContentLength = 0;
+ httpContext.Request.Headers["x-recording-id"] = recordingId;
+ httpContext.Request.Headers["x-recording-upstream-base-uri"] = "http://example.org";
+ httpContext.Request.Method = "GET";
+ httpContext.Request.Body = new MemoryStream(CompressionUtilities.CompressBody(bodyBytes, httpContext.Request.Headers));
+
+ await recordingHandler.HandleRecordRequestAsync(recordingId, httpContext.Request, httpContext.Response);
+ recordingHandler.StopRecording(recordingId);
+
+ try
+ {
+ Assert.Single(logger.Logs);
+ var logEntry = logger.Logs[0].ToString();
+ Assert.DoesNotContain(@"""Authorization"":[""fake-auth-header""]", logEntry);
+ Assert.Contains(@"""Authorization"":[""Sanitized""]", logEntry);
+ }
+ finally
+ {
+ File.Delete(fullPathToRecording);
+ DebugLogger.Logger = null;
+ }
+ }
+ }
+
+ [CollectionDefinition(nameof(LoggingCollection), DisableParallelization = true)]
+ public class LoggingCollection
+ {
+ }
+}
\ No newline at end of file
diff --git a/tools/test-proxy/Azure.Sdk.Tools.TestProxy.Tests/TestLogger.cs b/tools/test-proxy/Azure.Sdk.Tools.TestProxy.Tests/TestLogger.cs
new file mode 100644
index 00000000000..f09029ec9a5
--- /dev/null
+++ b/tools/test-proxy/Azure.Sdk.Tools.TestProxy.Tests/TestLogger.cs
@@ -0,0 +1,28 @@
+using System;
+using System.Collections.Generic;
+using Microsoft.Extensions.Logging;
+using ILogger = Microsoft.Extensions.Logging.ILogger;
+
+namespace Azure.Sdk.Tools.TestProxy.Tests
+{
+ public class TestLogger : ILogger
+ {
+ internal readonly List