diff --git a/sdk/mgmtcommon/ClientRuntime/ClientRuntime/HttpRequestMessageWrapper.cs b/sdk/mgmtcommon/ClientRuntime/ClientRuntime/HttpRequestMessageWrapper.cs
index 8252d364a67d3..3cee7645c2f3a 100644
--- a/sdk/mgmtcommon/ClientRuntime/ClientRuntime/HttpRequestMessageWrapper.cs
+++ b/sdk/mgmtcommon/ClientRuntime/ClientRuntime/HttpRequestMessageWrapper.cs
@@ -1,6 +1,7 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.
+using Microsoft.Rest.Utilities;
using System;
using System.Collections.Generic;
using System.Net.Http;
@@ -26,6 +27,7 @@ public HttpRequestMessageWrapper(HttpRequestMessage httpRequest, string content)
this.CopyHeaders(httpRequest.Headers);
this.CopyHeaders(httpRequest.GetContentHeaders());
+ HttpRequestSanitizer.SanitizerHeaders(Headers);
this.Content = content;
this.Method = httpRequest.Method;
diff --git a/sdk/mgmtcommon/ClientRuntime/ClientRuntime/Microsoft.Rest.ClientRuntime.csproj b/sdk/mgmtcommon/ClientRuntime/ClientRuntime/Microsoft.Rest.ClientRuntime.csproj
index 724c69b38be58..3c97e78233fb1 100644
--- a/sdk/mgmtcommon/ClientRuntime/ClientRuntime/Microsoft.Rest.ClientRuntime.csproj
+++ b/sdk/mgmtcommon/ClientRuntime/ClientRuntime/Microsoft.Rest.ClientRuntime.csproj
@@ -3,12 +3,13 @@
Infrastructure for error handling, tracing, and HttpClient pipeline configuration. Required by client libraries generated using AutoRest.
Microsoft.Rest.ClientRuntime
Client Runtime Library for Microsoft AutoRest Generated Clients
- 2.3.23
+ 2.3.24
Microsoft.Rest.ClientRuntime
Microsoft AutoRest ClientRuntime $(NugetCommonTags) $(NugetCommonProfileTags)
diff --git a/sdk/mgmtcommon/ClientRuntime/ClientRuntime/Utilities/HttpRequestSanitizer.cs b/sdk/mgmtcommon/ClientRuntime/ClientRuntime/Utilities/HttpRequestSanitizer.cs
new file mode 100644
index 0000000000000..2e4b4ba5fd963
--- /dev/null
+++ b/sdk/mgmtcommon/ClientRuntime/ClientRuntime/Utilities/HttpRequestSanitizer.cs
@@ -0,0 +1,65 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace Microsoft.Rest.Utilities
+{
+ ///
+ /// Sanitizer used internall by .
+ ///
+ internal class HttpRequestSanitizer
+ {
+ private readonly static string _redactedPlaceholder = "REDACTED";
+ private readonly static HashSet _allowedHeaders = new HashSet(new string[]
+ {
+ "x-ms-request-id",
+ "x-ms-client-request-id",
+ "x-ms-return-client-request-id",
+ "traceparent",
+ "MS-CV",
+
+ "Accept",
+ "Cache-Control",
+ "Connection",
+ "Content-Length",
+ "Content-Type",
+ "Date",
+ "ETag",
+ "Expires",
+ "If-Match",
+ "If-Modified-Since",
+ "If-None-Match",
+ "If-Unmodified-Since",
+ "Last-Modified",
+ "Pragma",
+ "Request-Id",
+ "Retry-After",
+ "Server",
+ "Transfer-Encoding",
+ "User-Agent",
+ "WWW-Authenticate" // OAuth Challenge header.
+ }, StringComparer.OrdinalIgnoreCase);
+
+ ///
+ /// Sanitize value of sensitive headers in the given .
+ ///
+ /// A collection of headers to sanitize.
+ public static void SanitizerHeaders(IDictionary> headers)
+ {
+ if (headers == null)
+ {
+ return;
+ }
+
+ var namesOfHeaderToSanitize = headers.Keys.Except(_allowedHeaders, StringComparer.OrdinalIgnoreCase).ToList();
+
+ foreach (string name in namesOfHeaderToSanitize)
+ {
+ headers[name] = new string[] { _redactedPlaceholder };
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/sdk/mgmtcommon/ClientRuntime/Tests/ClientRuntime.NetCore.Tests/HttpRequestSanitizerTest.cs b/sdk/mgmtcommon/ClientRuntime/Tests/ClientRuntime.NetCore.Tests/HttpRequestSanitizerTest.cs
new file mode 100644
index 0000000000000..af7c7ea947a77
--- /dev/null
+++ b/sdk/mgmtcommon/ClientRuntime/Tests/ClientRuntime.NetCore.Tests/HttpRequestSanitizerTest.cs
@@ -0,0 +1,96 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+namespace Microsoft.Rest.ClientRuntime.Tests
+{
+ using System.Net;
+ using System.Net.Http;
+ using System.Collections.Generic;
+ using Xunit;
+ using System.Linq;
+
+ public class HttpRequestSanitizerTest
+ {
+ [Theory]
+ [InlineData("authorization")]
+ [InlineData("Authorization")]
+ [InlineData("AUTHORIZATION")]
+ public void SanitizeAuthorizationHeader(string headerName)
+ {
+ var request = CreateRequestWrapper(headerName, "test");
+
+ Assert.True(request.Headers.TryGetValue(HttpRequestHeader.Authorization.ToString(), out IEnumerable sanitizedValues));
+ Assert.Single(sanitizedValues);
+ Assert.NotEqual("test", sanitizedValues.First());
+ Assert.Equal("REDACTED", sanitizedValues.First());
+ }
+
+ [Theory]
+ [InlineData("custom")]
+ [InlineData("foo")]
+ [InlineData("x-ms-secret")]
+ public void SanitizeCustomHeader(string headerName)
+ {
+ var request = CreateRequestWrapper(headerName, "test");
+
+ Assert.True(request.Headers.TryGetValue(headerName, out IEnumerable sanitizedValues));
+ Assert.Single(sanitizedValues);
+ Assert.NotEqual("test", sanitizedValues.First());
+ Assert.Equal("REDACTED", sanitizedValues.First());
+ }
+
+ [Theory]
+ [InlineData("Accept", "application/json")]
+ [InlineData("User-Agent", "azure-sdk")]
+ [InlineData("Pragma", "foo")]
+ public void KeepAllowedHeaders(string headerName, string headerValue)
+ {
+ var request = CreateRequestWrapper(headerName, headerValue);
+
+ Assert.True(request.Headers.TryGetValue(headerName, out IEnumerable sanitizedValues));
+ Assert.Single(sanitizedValues);
+ Assert.Equal(headerValue, sanitizedValues.First());
+ }
+
+ [Theory]
+ [InlineData("accept", "Accept", "application/json")]
+ [InlineData("user-agent", "User-Agent", "azure-sdk")]
+ [InlineData("pragma", "Pragma", "foo")]
+ public void AllowedHeaderNamesAreCaseInsensitive(string headerName, string standardName, string headerValue)
+ {
+ var request = CreateRequestWrapper(headerName, headerValue);
+
+ Assert.True(request.Headers.TryGetValue(standardName, out IEnumerable sanitizedValues));
+ Assert.Single(sanitizedValues);
+ Assert.Equal(headerValue, sanitizedValues.First());
+ }
+
+ [Fact]
+ public void OnlySanitizeNotAllowedHeader()
+ {
+ var request = CreateRequestWrapper("Authorization", "test");
+ request.Headers.Add("Pragma", new string[] { "foo" });
+ request.Headers.Add("User-Agent", new string[] { "azure-sdk" });
+
+ Assert.True(request.Headers.TryGetValue(HttpRequestHeader.Authorization.ToString(), out IEnumerable sanitizedValues));
+ Assert.Single(sanitizedValues);
+ Assert.NotEqual("test", sanitizedValues.First());
+ Assert.Equal("REDACTED", sanitizedValues.First());
+
+ Assert.True(request.Headers.TryGetValue("Pragma", out sanitizedValues));
+ Assert.Single(sanitizedValues);
+ Assert.Equal("foo", sanitizedValues.First());
+
+ Assert.True(request.Headers.TryGetValue("User-Agent", out sanitizedValues));
+ Assert.Single(sanitizedValues);
+ Assert.Equal("azure-sdk", sanitizedValues.First());
+ }
+
+ private HttpRequestMessageWrapper CreateRequestWrapper(string headerName, string headerValue)
+ {
+ var request = new HttpRequestMessage();
+ request.Headers.Add(headerName, headerValue);
+ return new HttpRequestMessageWrapper(request, "");
+ }
+ }
+}
\ No newline at end of file
diff --git a/sdk/mgmtcommon/ClientRuntime/Tests/ClientRuntime.NetCore.Tests/ServiceClientTests.cs b/sdk/mgmtcommon/ClientRuntime/Tests/ClientRuntime.NetCore.Tests/ServiceClientTests.cs
index 2a0c26466ba86..3f2964aa03a0d 100644
--- a/sdk/mgmtcommon/ClientRuntime/Tests/ClientRuntime.NetCore.Tests/ServiceClientTests.cs
+++ b/sdk/mgmtcommon/ClientRuntime/Tests/ClientRuntime.NetCore.Tests/ServiceClientTests.cs
@@ -206,7 +206,7 @@ public void HeadersAndPayloadAreNotDisposed()
GC.Collect();
Assert.NotNull(ex.Request);
Assert.NotNull(ex.Response);
- Assert.Equal("2013-11-01", ex.Request.Headers["x-ms-version"].First());
+ Assert.Equal("REDACTED", ex.Request.Headers["x-ms-version"].First());
Assert.Equal("Text", ex.Response.Content);
}
}