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 e265feae33b..3dcf289761a 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 @@ -957,20 +957,13 @@ internal virtual HttpClient GetHttpClient(bool handleRedirect) } // This indicates GetResponse will handle redirects. - if (handleRedirect || AllowInsecureRedirect) + if (handleRedirect || WebSession.MaximumRedirection == 0) { handler.AllowAutoRedirect = false; } - else if (WebSession.MaximumRedirection > -1) + else if (WebSession.MaximumRedirection > 0) { - if (WebSession.MaximumRedirection == 0) - { - handler.AllowAutoRedirect = false; - } - else - { - handler.MaxAutomaticRedirections = WebSession.MaximumRedirection; - } + handler.MaxAutomaticRedirections = WebSession.MaximumRedirection; } handler.SslProtocols = (SslProtocols)SslProtocol; @@ -1263,7 +1256,7 @@ private bool ShouldRetry(HttpStatusCode code) ); } - internal virtual HttpResponseMessage GetResponse(HttpClient client, HttpRequestMessage request, bool keepAuthorization) + internal virtual HttpResponseMessage GetResponse(HttpClient client, HttpRequestMessage request, bool handleRedirect) { ArgumentNullException.ThrowIfNull(client); @@ -1282,7 +1275,10 @@ internal virtual HttpResponseMessage GetResponse(HttpClient client, HttpRequestM _cancelToken = new CancellationTokenSource(); response = client.SendAsync(req, HttpCompletionOption.ResponseHeadersRead, _cancelToken.Token).GetAwaiter().GetResult(); - if ((keepAuthorization || (AllowInsecureRedirect && (WebSession.MaximumRedirection > 0 || WebSession.MaximumRedirection == -1))) && IsRedirectCode(response.StatusCode) && response.Headers.Location != null) + if (handleRedirect + && WebSession.MaximumRedirection is not 0 + && IsRedirectCode(response.StatusCode) + && response.Headers.Location is not null) { _cancelToken.Cancel(); _cancelToken = null; @@ -1303,10 +1299,10 @@ internal virtual HttpResponseMessage GetResponse(HttpClient client, HttpRequestM currentUri = new Uri(request.RequestUri, response.Headers.Location); // Continue to handle redirection - using (client = GetHttpClient(handleRedirect: true)) + using (client = GetHttpClient(handleRedirect)) using (HttpRequestMessage redirectRequest = GetRequest(currentUri)) { - response = GetResponse(client, redirectRequest, keepAuthorization); + response = GetResponse(client, redirectRequest, handleRedirect); } } @@ -1344,7 +1340,7 @@ internal virtual HttpResponseMessage GetResponse(HttpClient client, HttpRequestM WriteVerbose(reqVerboseMsg); - return GetResponse(client, requestWithoutRange, keepAuthorization); + return GetResponse(client, requestWithoutRange, handleRedirect); } } @@ -1418,14 +1414,14 @@ protected override void ProcessRecord() ValidateParameters(); PrepareSession(); - // if the request contains an authorization header and PreserveAuthorizationOnRedirect is not set, + // If the request contains an authorization header and PreserveAuthorizationOnRedirect is not set, // it needs to be stripped on the first redirect. - bool keepAuthorization = WebSession is not null - && WebSession.Headers is not null - && PreserveAuthorizationOnRedirect.IsPresent - && WebSession.Headers.ContainsKey(HttpKnownHeaderNames.Authorization); + bool keepAuthorizationOnRedirect = PreserveAuthorizationOnRedirect.IsPresent + && WebSession.Headers.ContainsKey(HttpKnownHeaderNames.Authorization); + + bool handleRedirect = keepAuthorizationOnRedirect || AllowInsecureRedirect; - using (HttpClient client = GetHttpClient(keepAuthorization)) + using (HttpClient client = GetHttpClient(handleRedirect)) { int followedRelLink = 0; Uri uri = Uri; @@ -1459,7 +1455,7 @@ protected override void ProcessRecord() WriteVerbose(reqVerboseMsg); - HttpResponseMessage response = GetResponse(client, request, keepAuthorization); + HttpResponseMessage response = GetResponse(client, request, handleRedirect); string contentType = ContentHelper.GetContentType(response); string respVerboseMsg = string.Format( diff --git a/test/powershell/Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1 index b930c27d7d9..285be044eb4 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1 @@ -133,14 +133,22 @@ function ExecuteRedirectRequest { $Method = 'GET', [switch] - $PreserveAuthorizationOnRedirect + $PreserveAuthorizationOnRedirect, + + [ValidateRange(0, [int]::MaxValue)] + [int] + $MaximumRedirection ) $result = [PSObject]@{Output = $null; Error = $null; Content = $null} try { $headers = @{"Authorization" = "test"} if ($Cmdlet -eq 'Invoke-WebRequest') { - $result.Output = Invoke-WebRequest -Uri $uri -Headers $headers -PreserveAuthorizationOnRedirect:$PreserveAuthorizationOnRedirect.IsPresent -Method $Method + if ($MaximumRedirection -gt 0) { + $result.Output = Invoke-WebRequest -Uri $uri -Headers $headers -PreserveAuthorizationOnRedirect:$PreserveAuthorizationOnRedirect.IsPresent -Method $Method -MaximumRedirection:$MaximumRedirection + } else { + $result.Output = Invoke-WebRequest -Uri $uri -Headers $headers -PreserveAuthorizationOnRedirect:$PreserveAuthorizationOnRedirect.IsPresent -Method $Method + } $result.Content = $result.Output.Content | ConvertFrom-Json } else { $result.Output = Invoke-RestMethod -Uri $uri -Headers $headers -PreserveAuthorizationOnRedirect:$PreserveAuthorizationOnRedirect.IsPresent -Method $Method @@ -885,6 +893,14 @@ Describe "Invoke-WebRequest tests" -Tags "Feature", "RequireAdminOnWindows" { $response.Error | Should -BeNullOrEmpty $response.Content.Headers."Authorization" | Should -BeExactly "test" } + + It "Validates Invoke-WebRequest with -PreserveAuthorizationOnRedirect respects -MaximumRedirection on redirect: " -TestCases $redirectTests { + param($redirectType, $redirectedMethod) + $uri = Get-WebListenerUrl -Test 'Redirect' -TestValue '3' -Query @{type = $redirectType} + $response = ExecuteRedirectRequest -Uri $uri -PreserveAuthorizationOnRedirect -MaximumRedirection 2 + + $response.Error.FullyQualifiedErrorId | Should -Be "WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeWebRequestCommand" + } It "Validates Invoke-WebRequest preserves the authorization header on multiple redirects: " -TestCases $redirectTests { param($redirectType)