From 594abae9a1c65eb23a6816a716971f377be88f23 Mon Sep 17 00:00:00 2001 From: Aditya Patwardhan Date: Thu, 9 Nov 2023 03:08:28 +0000 Subject: [PATCH] Merged PR 28409: Remove Auth header content from ErrorRecord Remove Auth header content from ErrorRecord --- .../Common/WebRequestPSCmdlet.Common.cs | 27 ++++++++++++++++--- .../WebCmdlets.Tests.ps1 | 26 ++++++++++++++++++ 2 files changed, 50 insertions(+), 3 deletions(-) diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/Common/WebRequestPSCmdlet.Common.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/Common/WebRequestPSCmdlet.Common.cs index 95b25e4e4d..981bdd08fd 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/Common/WebRequestPSCmdlet.Common.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/Common/WebRequestPSCmdlet.Common.cs @@ -634,7 +634,7 @@ namespace Microsoft.PowerShell.Commands response.ReasonPhrase); HttpResponseException httpEx = new(message, response); - ErrorRecord er = new(httpEx, "WebCmdletWebResponseException", ErrorCategory.InvalidOperation, request); + ErrorRecord er = new(httpEx, "WebCmdletWebResponseException", ErrorCategory.InvalidOperation, RedactAuthorizationHeader(request)); string detailMsg = string.Empty; try { @@ -675,7 +675,7 @@ namespace Microsoft.PowerShell.Commands // (and still writing out the result), users can debug actual HTTP redirect problems. if (_maximumRedirection == 0 && IsRedirectCode(response.StatusCode)) { - ErrorRecord er = new(new InvalidOperationException(), "MaximumRedirectExceeded", ErrorCategory.InvalidOperation, request); + ErrorRecord er = new(new InvalidOperationException(), "MaximumRedirectExceeded", ErrorCategory.InvalidOperation, RedactAuthorizationHeader(request)); er.ErrorDetails = new ErrorDetails(WebCmdletStrings.MaximumRedirectionCountExceeded); WriteError(er); } @@ -687,7 +687,7 @@ namespace Microsoft.PowerShell.Commands } catch (HttpRequestException ex) { - ErrorRecord er = new(ex, "WebCmdletWebResponseException", ErrorCategory.InvalidOperation, request); + ErrorRecord er = new(ex, "WebCmdletWebResponseException", ErrorCategory.InvalidOperation, RedactAuthorizationHeader(request)); if (ex.InnerException is not null) { er.ErrorDetails = new ErrorDetails(ex.InnerException.Message); @@ -1525,6 +1525,27 @@ namespace Microsoft.PowerShell.Commands return string.Create(CultureInfo.InvariantCulture, $"Bearer {new NetworkCredential(string.Empty, Token).Password}"); } + private static HttpRequestMessage RedactAuthorizationHeader(HttpRequestMessage request) + { + if (request.Headers is not null && request.Headers.Authorization is not null && request.Headers.Authorization.Parameter is not null) + { + // redact the auth parameter, but leave the last 4 characters for developers to validate + // the right token was sent + var authParameter = request.Headers.Authorization.Parameter; + var redactLength = authParameter.Length - 4; + if (redactLength < 0) + { + redactLength = authParameter.Length; + } + + request.Headers.Authorization = new AuthenticationHeaderValue( + request.Headers.Authorization.Scheme, + string.Concat("****", authParameter.Substring(redactLength).AsSpan())); + } + + return request; + } + private void ProcessAuthentication() { if (Authentication == WebAuthenticationType.Basic) diff --git a/test/powershell/Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1 index bb283b5795..cd356071b4 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1 @@ -1966,6 +1966,19 @@ Describe "Invoke-WebRequest tests" -Tags "Feature", "RequireAdminOnWindows" { $result.Headers.Authorization | Should -Match "^$AuthType " } + + It 'Invoke-WebRequest redacts Authorization header in ErrorRecord' { + $token = ConvertTo-SecureString -AsPlainText 'secret' + try { + Invoke-WebRequest -Authentication Bearer -Token $token -Uri https://localhost:443 + } + catch { + $errorText = Get-Error $_ | Out-String + } + + ($errorText | Select-String 'secret').Matches | Should -BeNullOrEmpty + ($errorText | Select-String '\*cret').Matches | Should -Not -BeNullOrEmpty + } } Context "Invoke-WebRequest -SslProtocol Test" { @@ -3922,6 +3935,19 @@ Describe "Invoke-RestMethod tests" -Tags "Feature", "RequireAdminOnWindows" { $result.Headers.Authorization | Should -Match "^$AuthType " } + + It 'Invoke-RestMethod redacts Authorization header in ErrorRecord' { + $token = ConvertTo-SecureString -AsPlainText 'secret' + try { + Invoke-RestMethod -Authentication Bearer -Token $token -Uri https://localhost:443 + } + catch { + $errorText = Get-Error $_ | Out-String + } + + ($errorText | Select-String 'secret').Matches | Should -BeNullOrEmpty + ($errorText | Select-String '\*cret').Matches | Should -Not -BeNullOrEmpty + } } Context "Invoke-RestMethod -SslProtocol Test" {