Merge branch 'release/v7.0.0-preview.2' into master
# Conflicts: # test/nanoserver/nanoserver.tests.ps1
This commit is contained in:
commit
6f0dacddc1
|
@ -699,6 +699,7 @@ timcurwick
|
|||
timestamp
|
||||
timothywlewis
|
||||
-title
|
||||
tokenizing
|
||||
tomconte
|
||||
toolchain
|
||||
toolset
|
||||
|
@ -716,6 +717,7 @@ unregister-event
|
|||
unregister-packagesource
|
||||
unregister-psrepository
|
||||
unregister-pssessionconfiguration
|
||||
untracked
|
||||
un-versioned
|
||||
update-formatdata
|
||||
update-modulemanifest
|
||||
|
@ -831,6 +833,7 @@ SytzeAndr
|
|||
yashrajbharti
|
||||
- CHANGELOG.md
|
||||
aavdberg
|
||||
asrosent
|
||||
azkarmoulana
|
||||
chucklu
|
||||
Claustn
|
||||
|
@ -843,8 +846,11 @@ jeis2497052
|
|||
Jocapear
|
||||
lassehastrup
|
||||
markwragg
|
||||
nbkalex
|
||||
NeoBeum
|
||||
nycjan
|
||||
paalbra
|
||||
robdy
|
||||
SeeminglyScience
|
||||
StingyJack
|
||||
ThreeFive-O
|
||||
|
|
124
CHANGELOG.md
124
CHANGELOG.md
|
@ -1,5 +1,129 @@
|
|||
# Changelog
|
||||
|
||||
## v7.0.0-preview.2 - 07/15/2019
|
||||
|
||||
### Breaking Changes
|
||||
|
||||
- Cleanup workflow - remove `PSProxyJob` (#10083) (Thanks @iSazonov!)
|
||||
- Disable `Enter-PSHostProcess` cmdlet when system in lock down mode (Internal 9168)
|
||||
|
||||
### Engine Updates and Fixes
|
||||
|
||||
- Consider `DBNull.Value` and `NullString.Value` the same as `$null` when comparing with `$null` and casting to bool (#9794) (Thanks @vexx32!)
|
||||
- Allow methods to be named after keywords (#9812) (Thanks @vexx32!)
|
||||
- Create `JumpList` in `STA` thread as some `COM` `APIs` are strictly `STA` only to avoid sporadic `CLR` crashes (#9928) (#10057) (Thanks @bergmeister!)
|
||||
- Skip `JumpList` on `NanoServer` and `IoT` (#10164)
|
||||
- Display `COM` method signature with argument names (#9858) (Thanks @nbkalex!)
|
||||
- Use the original precision (prior-dotnet-core-3) for double/float-to-string conversion (#9893)
|
||||
- `Import-DscResource` should allow to overwrite DSC built-in resources. (#9879)
|
||||
- Add ability to pass `InitialSessionState` to the `ConsoleShell.Start` (#9802) (Thanks @asrosent!)
|
||||
- Have console host not enter command prompt mode when using `Read-Host -Prompt` (#9743)
|
||||
- Fix use of `Start-Process http://bing.com` (#9793)
|
||||
- Support negative numbers in `-split` operator (#8960) (Thanks @ece-jacob-scott!)
|
||||
|
||||
### General Cmdlet Updates and Fixes
|
||||
|
||||
- Support DSC compilation on Linux. (#9834)
|
||||
- Add alias for Service `StartType` (#9940) (Thanks @NeoBeum!)
|
||||
- Add `-SecurityDescriptorSddl` parameter to `Set-Service` (#8626) (Thanks @kvprasoon!)
|
||||
- Fix auto-download of files when enumerating files from a `OneDrive` folder (#9895)
|
||||
- Set request headers when request body is empty in Web Cmdlets (#10034) (Thanks @markekraus!)
|
||||
- Fix wrong comparison in `CertificateProvider` (#9987) (Thanks @iSazonov!)
|
||||
- Sync docs changes into the embedded help for `pwsh` (#9952)
|
||||
- Display Duration when displaying `HistoryInfo` (#9751) (Thanks @rkeithhill!)
|
||||
- Update console startup and help `url` for PowerShell docs (#9775)
|
||||
- Make `UseAbbreviationExpansion` and `TempDrive` official features (#9872)
|
||||
- Fix `Get-ChildItem -Path` with wildcard `char` (#9257) (Thanks @kwkam!)
|
||||
|
||||
### Performance
|
||||
|
||||
- Add another fast path to `WildcardPattern.IsMatch` for patterns that only have an asterisk in the end (#10054) (Thanks @iSazonov!)
|
||||
- Move some of the creations of `WildcardPattern` in outer loop to avoid unnecessary allocation (#10053) (Thanks @iSazonov!)
|
||||
- Make `Foreach-Object` 2 times faster by reducing unnecessary allocations and boxing (#10047)
|
||||
- Use a static cache for `PSVersionInfo.PSVersion` to avoid casting `SemanticVersion` to `Version` every time accessing that property (#10028)
|
||||
- Reduce allocations in `NavigationCmdletProvider.NormalizePath()` (#10038) (Thanks @iSazonov!)
|
||||
- Add fast path for wildcard patterns that contains no wildcard characters (#10020)
|
||||
- Avoid `Assembly.GetName()` in `ClrFacade.GetAssemblies(string)` to reduce allocations of `CultureInfo` objects (#10024) (Thanks @iSazonov!)
|
||||
- Avoid the `int[]` and `int[,]` allocation when tokenizing line comments and matching wildcard pattern (#10009)
|
||||
|
||||
### Tools
|
||||
|
||||
- Update change log generation tool to deal with private commits (#10096)
|
||||
- Update `Start-PSBuild -Clean` logic of `git clean` to ignore locked files from `VS2019` (#10071) (Thanks @bergmeister!)
|
||||
- Indent fix in `markdown-link.tests.ps1` (#10049) (Thanks @RDIL!)
|
||||
- `Start-PSBuild -Clean` does not remove all untracked files (#10022) (Thanks @vexx32!)
|
||||
- Add module to support Pester tests for automating debugger commands (`stepInto`, `stepOut`, etc.), along with basic tests (#9825) (Thanks @KirkMunro!)
|
||||
- Remove `markdownlint` tests due to security issues (#10163)
|
||||
|
||||
### Code Cleanup
|
||||
|
||||
- Cleanup `CompiledScriptBlock.cs` (#9735) (Thanks @vexx32!)
|
||||
- Cleanup workflow code (#9638) (Thanks @iSazonov!)
|
||||
- Use `AddOrUpdate()` instead of `Remove` then `Add` to register runspace (#10007) (Thanks @iSazonov!)
|
||||
- Suppress `PossibleIncorrectUsageOfAssignmentOperator` rule violation by adding extra parenthesis (#9460) (Thanks @xtqqczze!)
|
||||
- Use `AddRange` in `GetModules()` (#9975) (Thanks @iSazonov!)
|
||||
- Code cleanup: use `IndexOf(char)` overload (#9722) (Thanks @iSazonov!)
|
||||
- Move `consts` and methods to single `CharExtensions` class (#9992) (Thanks @iSazonov!)
|
||||
- Cleanup: Use `EndsWith(char)` and `StartsWith(char)` (#9994) (Thanks @iSazonov!)
|
||||
- Remove `LCIDToLocaleName` `P/Invoke` from `GetComputerInfoCommand` (#9716) (Thanks @iSazonov!)
|
||||
- Cleanup Parser tests (#9792) (Thanks @vexx32!)
|
||||
- Remove `EtwActivity` empty constructor and make minor style fixes (#9958) (Thanks @RDIL!)
|
||||
- Fix style issues from last commits (#9937) (Thanks @iSazonov!)
|
||||
- Remove dead code about `IsTransparentProxy` (#9966)
|
||||
- Fix minor typos in code comments (#9917) (Thanks @RDIL!)
|
||||
- Style fixes for `CimAsyncOperations` (#9945) (Thanks @RDIL!)
|
||||
- Fix minor `CodeFactor` style issues in `ModuleCmdletBase` (#9915) (Thanks @RDIL!)
|
||||
- Clean up the use of `SetProfileRoot` and `StartProfile` in ConsoleHost (#9931)
|
||||
- Fix minor style issues come from last commits (#9640) (Thanks @iSazonov!)
|
||||
- Improve whitespace for Parser tests (#9806) (Thanks @vexx32!)
|
||||
- Use new `string.ConCat()` in `Process.cs` (#9720) (Thanks @iSazonov!)
|
||||
- Code Cleanup: Tidy up `scriptblock.cs` (#9732) (Thanks @vexx32!)
|
||||
|
||||
### Tests
|
||||
|
||||
- Mark `Set-Service` tests with password as `Pending` (#10146)
|
||||
- Fix test password generation rule to meet Windows complexity requirements (#10143)
|
||||
- Add test for `New-Item -Force` (#9971) (Thanks @robdy!)
|
||||
- Fix gulp versions (#9916) (Thanks @RDIL!)
|
||||
- Indentation fixes in `ci.psm1` (#9947) (Thanks @RDIL!)
|
||||
- Remove some `Travis-CI` references (#9919) (Thanks @RDIL!)
|
||||
- Improve release testing Docker images (#9942) (Thanks @RDIL!)
|
||||
- Use `yarn` to install global tools (#9904) (Thanks @RDIL!)
|
||||
- Attempt to work around the zip download issue in Azure DevOps Windows CI (#9911)
|
||||
- Update PowerShell SDK version for hosting tests (Internal 9185)
|
||||
|
||||
### Build and Packaging Improvements
|
||||
|
||||
- Update the target framework for reference assemblies to `netcoreapp3.0` (#9747)
|
||||
- Pin version of `netDumbster` to `2.0.0.4` (#9748)
|
||||
- Fix daily `CodeCoverageAndTest` build by explicitly calling `Start-PSBootStrap` (#9724)
|
||||
- Split the `fxdependent` package on Windows into two packages (#10134)
|
||||
- Bump `System.Data.SqlClient` (#10109)
|
||||
- Bump `System.Security.AccessControl` (#10100)
|
||||
- Add performance tag to change log command (Internal)
|
||||
- Upgrade .Net Core 3 SDK from `preview5` to `preview6` and related out of band `Nuget` packages from `2.1` to `3.0-preview6` (#9888) (Thanks @bergmeister!)
|
||||
- Add to `/etc/shells` on macOS (#10066)
|
||||
- Bump `Markdig.Signed` from `0.17.0` to `0.17.1` (#10062)
|
||||
- Update copyright symbol for `NuGet` packages (#9936)
|
||||
- Download latest version `(6.2.0)` of `PSDesiredStateConfiguration` `nuget` package. (#9932)
|
||||
- Add automated `RPM` signing to release build (#10013)
|
||||
- Bump `ThreadJob` from `1.1.2` to `2.0.1` in `/src/Modules` (#10003)
|
||||
- Bump `PowerShellGet` from `2.1.4` to `2.2` in /src/Modules (#9933) (#10085)
|
||||
- Bump `PackageManagement` from `1.4` to `1.4.3` in `/src/Modules` (#9820) (#9918) (#10084)
|
||||
- Update to use `TSAv2` (#9914)
|
||||
- Bump `NJsonSchema` from `9.14.1` to `10.0.21` (#9805) (#9843) (#9854) (#9862) (#9875) (#9885) (#9954) (#10017)
|
||||
- Bump `System.Net.Http.WinHttpHandler` from `4.5.3` to `4.5.4` (#9786)
|
||||
- Bump `Microsoft.ApplicationInsights` from `2.9.1` to `2.10.0` (#9757)
|
||||
- Increase timeout of NuGet job to workaround build timeout (#9772)
|
||||
|
||||
### Documentation and Help Content
|
||||
|
||||
- Change log `6.1.4` (#9759)
|
||||
- Change log for release `6.2.1` (#9760)
|
||||
- Add quick steps for adding docs to cmdlets (#9978)
|
||||
- Update readme `gitter` badge (#9920) (Thanks @RDIL!)
|
||||
- Update `README` and `metadata.json` for `7.0.0-preview.1` release (#9767)
|
||||
|
||||
## v7.0.0-preview.1 - 05/30/2019
|
||||
|
||||
### Breaking Changes
|
||||
|
|
|
@ -226,7 +226,7 @@ namespace Microsoft.PowerShell.Commands
|
|||
|
||||
if (s_imageRegex == null)
|
||||
{
|
||||
s_imageRegex = new Regex(@"<img\s+[^>]*>",
|
||||
s_imageRegex = new Regex(@"<img\s+[^\s>]*>",
|
||||
RegexOptions.Singleline | RegexOptions.IgnoreCase | RegexOptions.Compiled);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -417,7 +417,10 @@ namespace Microsoft.PowerShell.Commands
|
|||
return result;
|
||||
}
|
||||
|
||||
private static readonly Regex s_metaexp = new Regex(@"<meta\s[.\n]*[^><]*charset\s*=\s*[""'\n]?(?<charset>[A-Za-z].[^\s""'\n<>]*)[\s""'\n>]");
|
||||
private static readonly Regex s_metaexp = new Regex(
|
||||
@"<meta\s.*[^.><]*charset\s*=\s*[""'\n]?(?<charset>[A-Za-z].[^\s""'\n<>]*)[\s""'\n>]",
|
||||
RegexOptions.Compiled | RegexOptions.Singleline | RegexOptions.ExplicitCapture | RegexOptions.CultureInvariant | RegexOptions.IgnoreCase
|
||||
);
|
||||
|
||||
internal static string DecodeStream(Stream stream, ref Encoding encoding)
|
||||
{
|
||||
|
|
|
@ -13,6 +13,7 @@ using System.Management.Automation.Host;
|
|||
using System.Management.Automation.Internal;
|
||||
using System.Management.Automation.Remoting;
|
||||
using System.Management.Automation.Runspaces;
|
||||
using System.Management.Automation.Security;
|
||||
using System.Text;
|
||||
|
||||
namespace Microsoft.PowerShell.Commands
|
||||
|
@ -126,6 +127,19 @@ namespace Microsoft.PowerShell.Commands
|
|||
/// </summary>
|
||||
protected override void EndProcessing()
|
||||
{
|
||||
// Check if system is in locked down mode, in which case this cmdlet is disabled.
|
||||
if (SystemPolicy.GetSystemLockdownPolicy() == SystemEnforcementMode.Enforce)
|
||||
{
|
||||
WriteError(
|
||||
new ErrorRecord(
|
||||
new PSSecurityException(RemotingErrorIdStrings.EnterPSHostProcessCmdletDisabled),
|
||||
"EnterPSHostProcessCmdletDisabled",
|
||||
ErrorCategory.SecurityError,
|
||||
null));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Check for host that supports interactive remote sessions.
|
||||
_interactiveHost = this.Host as IHostSupportsInteractiveSession;
|
||||
if (_interactiveHost == null)
|
||||
|
|
|
@ -1684,4 +1684,7 @@ All WinRM sessions connected to PowerShell session configurations, such as Micro
|
|||
<data name="PSCoreRemotingEnableWarning" xml:space="preserve">
|
||||
<value>PowerShell remoting has been enabled only for PowerShell 6+ configurations and does not affect Windows PowerShell remoting configurations. Run this cmdlet in Windows PowerShell to affect all PowerShell remoting configurations.</value>
|
||||
</data>
|
||||
<data name="EnterPSHostProcessCmdletDisabled" xml:space="preserve">
|
||||
<value>Enter-PSHostProcess cmdlet is disabled because an application control policy such as 'AppLocker' or 'Windows Defender Application Control' is in enforcement.</value>
|
||||
</data>
|
||||
</root>
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
<PackageReference Include="xunit" Version="2.4.0" />
|
||||
<PackageReference Include="XunitXml.TestLogger" Version="2.0.0" />
|
||||
<!-- The version of Microsoft.PowerShell.SDK should be the version we are releasing, so the tests use the correct SDK before publishing to NuGet.org -->
|
||||
<PackageReference Include="Microsoft.PowerShell.SDK" Version="7.0.0-preview.1" />
|
||||
<PackageReference Include="Microsoft.PowerShell.SDK" Version="7.0.0-preview.2" />
|
||||
<PackageReference Include="Xunit.SkippableFact" Version="1.3.6" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.0" />
|
||||
</ItemGroup>
|
||||
|
|
|
@ -1164,6 +1164,31 @@ try
|
|||
}
|
||||
}
|
||||
|
||||
Describe "Enter-PSHostProcess cmdlet should be disabled on locked down systems" -Tags 'Feature','RequireAdminOnWindows' {
|
||||
|
||||
It "Verifies that Enter-PSHostProcess is disabled with lock down policy" {
|
||||
|
||||
$expectedError = $null
|
||||
try
|
||||
{
|
||||
Invoke-LanguageModeTestingSupportCmdlet -SetLockdownMode
|
||||
$ExecutionContext.SessionState.LanguageMode = "ConstrainedLanguage"
|
||||
|
||||
Enter-PSHostProcess -Id 5555 -ErrorAction Stop
|
||||
}
|
||||
catch
|
||||
{
|
||||
$expectedError = $_
|
||||
}
|
||||
finally
|
||||
{
|
||||
Invoke-LanguageModeTestingSupportCmdlet -RevertLockdownMode -EnableFullLanguageMode
|
||||
}
|
||||
|
||||
$expectedError.FullyQualifiedErrorId | Should -BeExactly 'EnterPSHostProcessCmdletDisabled,Microsoft.PowerShell.Commands.EnterPSHostProcessCommand'
|
||||
}
|
||||
}
|
||||
|
||||
# End Describe blocks
|
||||
}
|
||||
finally
|
||||
|
|
|
@ -780,90 +780,89 @@ Describe "Invoke-WebRequest tests" -Tags "Feature", "RequireAdminOnWindows" {
|
|||
$result.Output.RelationLink["next"] | Should -BeExactly "${baseUri}?maxlinks=3&linknumber=2&type=${type}"
|
||||
}
|
||||
|
||||
#region Redirect tests
|
||||
Context "Redirect" {
|
||||
It "Validates Invoke-WebRequest with -PreserveAuthorizationOnRedirect preserves the authorization header on redirect: <redirectType> <redirectedMethod>" -TestCases $redirectTests {
|
||||
param($redirectType, $redirectedMethod)
|
||||
$uri = Get-WebListenerUrl -Test 'Redirect' -Query @{type = $redirectType}
|
||||
$response = ExecuteRedirectRequest -Uri $uri -PreserveAuthorizationOnRedirect
|
||||
|
||||
It "Validates Invoke-WebRequest with -PreserveAuthorizationOnRedirect preserves the authorization header on redirect: <redirectType> <redirectedMethod>" -TestCases $redirectTests {
|
||||
param($redirectType, $redirectedMethod)
|
||||
$uri = Get-WebListenerUrl -Test 'Redirect' -Query @{type = $redirectType}
|
||||
$response = ExecuteRedirectRequest -Uri $uri -PreserveAuthorizationOnRedirect
|
||||
$response.Error | Should -BeNullOrEmpty
|
||||
$response.Content.Headers."Authorization" | Should -BeExactly "test"
|
||||
}
|
||||
|
||||
$response.Error | Should -BeNullOrEmpty
|
||||
$response.Content.Headers."Authorization" | Should -BeExactly "test"
|
||||
It "Validates Invoke-WebRequest preserves the authorization header on multiple redirects: <redirectType>" -TestCases $redirectTests {
|
||||
param($redirectType)
|
||||
$uri = Get-WebListenerUrl -Test 'Redirect' -TestValue 3 -Query @{type = $redirectType}
|
||||
$response = ExecuteRedirectRequest -Uri $uri -PreserveAuthorizationOnRedirect
|
||||
|
||||
$response.Error | Should -BeNullOrEmpty
|
||||
$response.Content.Headers."Authorization" | Should -BeExactly "test"
|
||||
}
|
||||
|
||||
It "Validates Invoke-WebRequest strips the authorization header on various redirects: <redirectType>" -TestCases $redirectTests {
|
||||
param($redirectType)
|
||||
$uri = Get-WebListenerUrl -Test 'Redirect' -Query @{type = $redirectType}
|
||||
$response = ExecuteRedirectRequest -Uri $uri
|
||||
|
||||
$response.Error | Should -BeNullOrEmpty
|
||||
# ensure user-agent is present (i.e., no false positives )
|
||||
$response.Content.Headers."User-Agent" | Should -Not -BeNullOrEmpty
|
||||
# ensure Authorization header has been removed.
|
||||
$response.Content.Headers."Authorization" | Should -BeNullOrEmpty
|
||||
}
|
||||
|
||||
# NOTE: Only testing redirection of POST -> GET for unique underlying values of HttpStatusCode.
|
||||
# Some names overlap in underlying value.
|
||||
It "Validates Invoke-WebRequest strips the authorization header redirects and switches from POST to GET when it handles the redirect: <redirectType> <redirectedMethod>" -TestCases $redirectTests {
|
||||
param($redirectType, $redirectedMethod)
|
||||
$uri = Get-WebListenerUrl -Test 'Redirect' -Query @{type = $redirectType}
|
||||
$response = ExecuteRedirectRequest -Uri $uri -Method 'POST'
|
||||
|
||||
$response.Error | Should -BeNullOrEmpty
|
||||
# ensure user-agent is present (i.e., no false positives )
|
||||
$response.Content.Headers."User-Agent" | Should -Not -BeNullOrEmpty
|
||||
# ensure Authorization header has been removed.
|
||||
$response.Content.Headers."Authorization" | Should -BeNullOrEmpty
|
||||
# ensure POST was changed to GET for selected redirections and remains as POST for others.
|
||||
$response.Content.Method | Should -Be $redirectedMethod
|
||||
}
|
||||
|
||||
It "Validates Invoke-WebRequest -PreserveAuthorizationOnRedirect keeps the authorization header redirects and switches from POST to GET when it handles the redirect: <redirectType> <redirectedMethod>" -TestCases $redirectTests {
|
||||
param($redirectType, $redirectedMethod)
|
||||
$uri = Get-WebListenerUrl -Test 'Redirect' -Query @{type = $redirectType}
|
||||
$response = ExecuteRedirectRequest -PreserveAuthorizationOnRedirect -Uri $uri -Method 'POST'
|
||||
|
||||
$response.Error | Should -BeNullOrEmpty
|
||||
# ensure user-agent is present (i.e., no false positives )
|
||||
$response.Content.Headers."User-Agent" | Should -Not -BeNullOrEmpty
|
||||
# ensure Authorization header has been removed.
|
||||
$response.Content.Headers."Authorization" | Should -BeExactly 'test'
|
||||
# ensure POST was changed to GET for selected redirections and remains as POST for others.
|
||||
$response.Content.Method | Should -Be $redirectedMethod
|
||||
}
|
||||
|
||||
It "Validates Invoke-WebRequest handles responses without Location header for requests with Authorization header and redirect: <redirectType>" -TestCases $redirectTests {
|
||||
param($redirectType, $redirectedMethod)
|
||||
# Skip relative test as it is not a valid response type.
|
||||
if ($redirectType -eq 'relative') { return }
|
||||
|
||||
# When an Authorization request header is present,
|
||||
# and -PreserveAuthorizationOnRedirect is not present,
|
||||
# PowerShell should throw an HTTP Response Exception
|
||||
# for a redirect response which does not contain a Location response header.
|
||||
# The correct redirect status code should be included in the exception.
|
||||
|
||||
$StatusCode = [int][System.Net.HttpStatusCode]$redirectType
|
||||
$uri = Get-WebListenerUrl -Test Response -Query @{statuscode = $StatusCode}
|
||||
$command = "Invoke-WebRequest -Uri '$uri' -Headers @{Authorization = 'foo'}"
|
||||
$response = ExecuteWebCommand -command $command
|
||||
|
||||
$response.Error.Exception | Should -BeOfType 'Microsoft.PowerShell.Commands.HttpResponseException'
|
||||
$response.Error.Exception.Response.StatusCode | Should -Be $StatusCode
|
||||
$response.Error.Exception.Response.Headers.Location | Should -BeNullOrEmpty
|
||||
}
|
||||
}
|
||||
|
||||
It "Validates Invoke-WebRequest preserves the authorization header on multiple redirects: <redirectType>" -TestCases $redirectTests {
|
||||
param($redirectType)
|
||||
$uri = Get-WebListenerUrl -Test 'Redirect' -TestValue 3 -Query @{type = $redirectType}
|
||||
$response = ExecuteRedirectRequest -Uri $uri -PreserveAuthorizationOnRedirect
|
||||
|
||||
$response.Error | Should -BeNullOrEmpty
|
||||
$response.Content.Headers."Authorization" | Should -BeExactly "test"
|
||||
}
|
||||
|
||||
It "Validates Invoke-WebRequest strips the authorization header on various redirects: <redirectType>" -TestCases $redirectTests {
|
||||
param($redirectType)
|
||||
$uri = Get-WebListenerUrl -Test 'Redirect' -Query @{type = $redirectType}
|
||||
$response = ExecuteRedirectRequest -Uri $uri
|
||||
|
||||
$response.Error | Should -BeNullOrEmpty
|
||||
# ensure user-agent is present (i.e., no false positives )
|
||||
$response.Content.Headers."User-Agent" | Should -Not -BeNullOrEmpty
|
||||
# ensure Authorization header has been removed.
|
||||
$response.Content.Headers."Authorization" | Should -BeNullOrEmpty
|
||||
}
|
||||
|
||||
# NOTE: Only testing redirection of POST -> GET for unique underlying values of HttpStatusCode.
|
||||
# Some names overlap in underlying value.
|
||||
It "Validates Invoke-WebRequest strips the authorization header redirects and switches from POST to GET when it handles the redirect: <redirectType> <redirectedMethod>" -TestCases $redirectTests {
|
||||
param($redirectType, $redirectedMethod)
|
||||
$uri = Get-WebListenerUrl -Test 'Redirect' -Query @{type = $redirectType}
|
||||
$response = ExecuteRedirectRequest -Uri $uri -Method 'POST'
|
||||
|
||||
$response.Error | Should -BeNullOrEmpty
|
||||
# ensure user-agent is present (i.e., no false positives )
|
||||
$response.Content.Headers."User-Agent" | Should -Not -BeNullOrEmpty
|
||||
# ensure Authorization header has been removed.
|
||||
$response.Content.Headers."Authorization" | Should -BeNullOrEmpty
|
||||
# ensure POST was changed to GET for selected redirections and remains as POST for others.
|
||||
$response.Content.Method | Should -Be $redirectedMethod
|
||||
}
|
||||
|
||||
It "Validates Invoke-WebRequest -PreserveAuthorizationOnRedirect keeps the authorization header redirects and switches from POST to GET when it handles the redirect: <redirectType> <redirectedMethod>" -TestCases $redirectTests {
|
||||
param($redirectType, $redirectedMethod)
|
||||
$uri = Get-WebListenerUrl -Test 'Redirect' -Query @{type = $redirectType}
|
||||
$response = ExecuteRedirectRequest -PreserveAuthorizationOnRedirect -Uri $uri -Method 'POST'
|
||||
|
||||
$response.Error | Should -BeNullOrEmpty
|
||||
# ensure user-agent is present (i.e., no false positives )
|
||||
$response.Content.Headers."User-Agent" | Should -Not -BeNullOrEmpty
|
||||
# ensure Authorization header has been removed.
|
||||
$response.Content.Headers."Authorization" | Should -BeExactly 'test'
|
||||
# ensure POST was changed to GET for selected redirections and remains as POST for others.
|
||||
$response.Content.Method | Should -Be $redirectedMethod
|
||||
}
|
||||
|
||||
It "Validates Invoke-WebRequest handles responses without Location header for requests with Authorization header and redirect: <redirectType>" -TestCases $redirectTests {
|
||||
param($redirectType, $redirectedMethod)
|
||||
# Skip relative test as it is not a valid response type.
|
||||
if ($redirectType -eq 'relative') { return }
|
||||
|
||||
# When an Authorization request header is present,
|
||||
# and -PreserveAuthorizationOnRedirect is not present,
|
||||
# PowerShell should throw an HTTP Response Exception
|
||||
# for a redirect response which does not contain a Location response header.
|
||||
# The correct redirect status code should be included in the exception.
|
||||
|
||||
$StatusCode = [int][System.Net.HttpStatusCode]$redirectType
|
||||
$uri = Get-WebListenerUrl -Test Response -Query @{statuscode = $StatusCode}
|
||||
$command = "Invoke-WebRequest -Uri '$uri' -Headers @{Authorization = 'foo'}"
|
||||
$response = ExecuteWebCommand -command $command
|
||||
|
||||
$response.Error.Exception | Should -BeOfType 'Microsoft.PowerShell.Commands.HttpResponseException'
|
||||
$response.Error.Exception.Response.StatusCode | Should -Be $StatusCode
|
||||
$response.Error.Exception.Response.Headers.Location | Should -BeNullOrEmpty
|
||||
}
|
||||
|
||||
#endregion Redirect tests
|
||||
|
||||
Context "Invoke-WebRequest SkipHeaderVerification Tests" {
|
||||
BeforeAll {
|
||||
|
@ -1168,75 +1167,76 @@ Describe "Invoke-WebRequest tests" -Tags "Feature", "RequireAdminOnWindows" {
|
|||
#endregion charset encoding tests
|
||||
|
||||
#region Content Header Inclusion
|
||||
Context "Content Header" {
|
||||
It "Verifies Invoke-WebRequest includes Content headers in Headers property" {
|
||||
$query = @{
|
||||
contenttype = 'text/plain'
|
||||
body = 'OK'
|
||||
}
|
||||
$uri = Get-WebListenerUrl -Test 'Response' -Query $query
|
||||
$command = "Invoke-WebRequest -Uri '$uri'"
|
||||
$result = ExecuteWebCommand -command $command
|
||||
ValidateResponse $result
|
||||
|
||||
It "Verifies Invoke-WebRequest includes Content headers in Headers property" {
|
||||
$query = @{
|
||||
contenttype = 'text/plain'
|
||||
body = 'OK'
|
||||
$result.Output.Headers.'Content-Type' | Should -Be 'text/plain'
|
||||
$result.Output.Headers.'Content-Length' | Should -Be 2
|
||||
}
|
||||
$uri = Get-WebListenerUrl -Test 'Response' -Query $query
|
||||
$command = "Invoke-WebRequest -Uri '$uri'"
|
||||
$result = ExecuteWebCommand -command $command
|
||||
ValidateResponse $result
|
||||
|
||||
$result.Output.Headers.'Content-Type' | Should -Be 'text/plain'
|
||||
$result.Output.Headers.'Content-Length' | Should -Be 2
|
||||
}
|
||||
It "Verifies Invoke-WebRequest includes Content headers in RawContent property" {
|
||||
$query = @{
|
||||
contenttype = 'text/plain'
|
||||
body = 'OK'
|
||||
}
|
||||
$uri = Get-WebListenerUrl -Test 'Response' -Query $query
|
||||
$command = "Invoke-WebRequest -Uri '$uri'"
|
||||
$result = ExecuteWebCommand -command $command
|
||||
ValidateResponse $result
|
||||
|
||||
It "Verifies Invoke-WebRequest includes Content headers in RawContent property" {
|
||||
$query = @{
|
||||
contenttype = 'text/plain'
|
||||
body = 'OK'
|
||||
$result.Output.RawContent | Should -Match ([regex]::Escape('Content-Type: text/plain'))
|
||||
$result.Output.RawContent | Should -Match ([regex]::Escape('Content-Length: 2'))
|
||||
}
|
||||
$uri = Get-WebListenerUrl -Test 'Response' -Query $query
|
||||
$command = "Invoke-WebRequest -Uri '$uri'"
|
||||
$result = ExecuteWebCommand -command $command
|
||||
ValidateResponse $result
|
||||
|
||||
$result.Output.RawContent | Should -Match ([regex]::Escape('Content-Type: text/plain'))
|
||||
$result.Output.RawContent | Should -Match ([regex]::Escape('Content-Length: 2'))
|
||||
}
|
||||
It "Verifies Invoke-WebRequest Supports Multiple response headers with same name" {
|
||||
$query = @{
|
||||
contenttype = 'text/plain'
|
||||
body = 'OK'
|
||||
headers = @{
|
||||
'X-Fake-Header' = @('testvalue01', 'testvalue02')
|
||||
} | ConvertTo-Json -Compress
|
||||
}
|
||||
$uri = Get-WebListenerUrl -Test 'Response' -Query $query
|
||||
$command = "Invoke-WebRequest -Uri '$uri'"
|
||||
$result = ExecuteWebCommand -command $command
|
||||
ValidateResponse $result
|
||||
|
||||
It "Verifies Invoke-WebRequest Supports Multiple response headers with same name" {
|
||||
$query = @{
|
||||
contenttype = 'text/plain'
|
||||
body = 'OK'
|
||||
headers = @{
|
||||
'X-Fake-Header' = @('testvalue01', 'testvalue02')
|
||||
} | ConvertTo-Json -Compress
|
||||
$result.Output.Headers.'X-Fake-Header'.Count | Should -Be 2
|
||||
$result.Output.Headers.'X-Fake-Header'.Contains('testvalue01') | Should -BeTrue
|
||||
$result.Output.Headers.'X-Fake-Header'.Contains('testvalue02') | Should -BeTrue
|
||||
$result.Output.RawContent | Should -Match ([regex]::Escape('X-Fake-Header: testvalue01'))
|
||||
$result.Output.RawContent | Should -Match ([regex]::Escape('X-Fake-Header: testvalue02'))
|
||||
}
|
||||
$uri = Get-WebListenerUrl -Test 'Response' -Query $query
|
||||
$command = "Invoke-WebRequest -Uri '$uri'"
|
||||
$result = ExecuteWebCommand -command $command
|
||||
ValidateResponse $result
|
||||
|
||||
$result.Output.Headers.'X-Fake-Header'.Count | Should -Be 2
|
||||
$result.Output.Headers.'X-Fake-Header'.Contains('testvalue01') | Should -BeTrue
|
||||
$result.Output.Headers.'X-Fake-Header'.Contains('testvalue02') | Should -BeTrue
|
||||
$result.Output.RawContent | Should -Match ([regex]::Escape('X-Fake-Header: testvalue01'))
|
||||
$result.Output.RawContent | Should -Match ([regex]::Escape('X-Fake-Header: testvalue02'))
|
||||
}
|
||||
It "Verifies Invoke-WebRequest does not sent expect 100-continue headers by default" {
|
||||
$uri = Get-WebListenerUrl -Test 'Get'
|
||||
|
||||
It "Verifies Invoke-WebRequest does not sent expect 100-continue headers by default" {
|
||||
$uri = Get-WebListenerUrl -Test 'Get'
|
||||
$response = Invoke-WebRequest -Uri $uri
|
||||
$result = $response.Content | ConvertFrom-Json
|
||||
|
||||
$response = Invoke-WebRequest -Uri $uri
|
||||
$result = $response.Content | ConvertFrom-Json
|
||||
$result.headers.Expect | Should -BeNullOrEmpty
|
||||
$result.method | Should -BeExactly "GET"
|
||||
$result.url | Should -BeExactly $uri.ToString()
|
||||
}
|
||||
|
||||
$result.headers.Expect | Should -BeNullOrEmpty
|
||||
$result.method | Should -BeExactly "GET"
|
||||
$result.url | Should -BeExactly $uri.ToString()
|
||||
}
|
||||
It "Verifies Invoke-WebRequest sends expect 100-continue header when defined in -Headers" {
|
||||
$uri = Get-WebListenerUrl -Test 'Get'
|
||||
|
||||
It "Verifies Invoke-WebRequest sends expect 100-continue header when defined in -Headers" {
|
||||
$uri = Get-WebListenerUrl -Test 'Get'
|
||||
$response = Invoke-WebRequest -Uri $uri -Headers @{Expect = '100-continue'}
|
||||
$result = $response.Content | ConvertFrom-Json
|
||||
|
||||
$response = Invoke-WebRequest -Uri $uri -Headers @{Expect = '100-continue'}
|
||||
$result = $response.Content | ConvertFrom-Json
|
||||
|
||||
$result.headers.Expect | Should -BeExactly '100-continue'
|
||||
$result.method | Should -BeExactly "GET"
|
||||
$result.url | Should -BeExactly $uri.ToString()
|
||||
$result.headers.Expect | Should -BeExactly '100-continue'
|
||||
$result.method | Should -BeExactly "GET"
|
||||
$result.url | Should -BeExactly $uri.ToString()
|
||||
}
|
||||
}
|
||||
|
||||
#endregion Content Header Inclusion
|
||||
|
@ -1865,6 +1865,66 @@ Describe "Invoke-WebRequest tests" -Tags "Feature", "RequireAdminOnWindows" {
|
|||
$jsonResult.SessionId | Should -BeExactly $sessionId
|
||||
}
|
||||
}
|
||||
|
||||
Context "Denial of service" -Tag 'DOS' {
|
||||
It "Image Parsing" {
|
||||
$dosUri = Get-WebListenerUrl -Test 'Dos' -query @{
|
||||
dosType='img'
|
||||
dosLength='5000'
|
||||
}
|
||||
$script:content = ''
|
||||
[TimeSpan] $timeSpan = Measure-Command {
|
||||
$response = Invoke-WebRequest -Uri $dosUri
|
||||
$script:content = $response.content
|
||||
$response.Images | out-null
|
||||
}
|
||||
|
||||
$script:content | should -Not -BeNullOrEmpty
|
||||
|
||||
# pathological regex
|
||||
$regex = [RegEx]::new('<img\s+[^>]*>')
|
||||
|
||||
[TimeSpan] $pathologicalTimeSpan = Measure-Command {
|
||||
$regex.Match($content)
|
||||
}
|
||||
|
||||
$pathologicalRatio = $pathologicalTimeSpan.TotalMilliseconds/$timeSpan.TotalMilliseconds
|
||||
Write-Verbose "Pathological ratio: $pathologicalRatio" -Verbose
|
||||
|
||||
# dosLength 4,000 on my 3.5 GHz 6-Core Intel Xeon E5 macpro produced a ratio of 12
|
||||
# dosLength 5,000 on my 3.5 GHz 6-Core Intel Xeon E5 macpro produced a ratio of 21
|
||||
# dosLength 10,000 on my 3.5 GHz 6-Core Intel Xeon E5 macpro produced a ratio of 75
|
||||
$pathologicalRatio | Should -BeGreaterThan 10
|
||||
}
|
||||
It "Charset Parsing" {
|
||||
$dosUri = Get-WebListenerUrl -Test 'Dos' -query @{
|
||||
dosType='charset'
|
||||
dosLength='2850'
|
||||
}
|
||||
$script:content = ''
|
||||
[TimeSpan] $timeSpan = Measure-Command {
|
||||
$response = Invoke-WebRequest -Uri $dosUri
|
||||
$script:content = $response.content
|
||||
}
|
||||
|
||||
# Pathological regex
|
||||
$regex = [RegEx]::new('<meta\s[.\n]*[^><]*charset\s*=\s*["''\n]?(?<charset>[A-Za-z].[^\s"''\n<>]*)[\s"''\n>]')
|
||||
|
||||
$script:content | should -Not -BeNullOrEmpty
|
||||
|
||||
[TimeSpan] $pathologicalTimeSpan = Measure-Command {
|
||||
$regex.Match($content)
|
||||
}
|
||||
|
||||
$pathologicalRatio = $pathologicalTimeSpan.TotalMilliseconds/$timeSpan.TotalMilliseconds
|
||||
Write-Verbose "Pathological ratio: $pathologicalRatio" -Verbose
|
||||
|
||||
# dosLength 2,750 on my 3.5 GHz 6-Core Intel Xeon E5 macpro produced a ratio of 13
|
||||
# dosLength 2,850 on my 3.5 GHz 6-Core Intel Xeon E5 macpro produced a ratio of 22
|
||||
# dosLength 3,000 on my 3.5 GHz 6-Core Intel Xeon E5 macpro produced a ratio of 31
|
||||
$pathologicalRatio | Should -BeGreaterThan 10
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Describe "Invoke-RestMethod tests" -Tags "Feature", "RequireAdminOnWindows" {
|
||||
|
|
|
@ -217,6 +217,7 @@ function Get-WebListenerUrl {
|
|||
'Compression',
|
||||
'Delay',
|
||||
'Delete',
|
||||
'Dos',
|
||||
'Encoding',
|
||||
'Get',
|
||||
'Home',
|
||||
|
|
71
test/tools/WebListener/Controllers/DosController.cs
Normal file
71
test/tools/WebListener/Controllers/DosController.cs
Normal file
|
@ -0,0 +1,71 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.Extensions.Primitives;
|
||||
using mvc.Models;
|
||||
|
||||
namespace mvc.Controllers
|
||||
{
|
||||
public class DosController : Controller
|
||||
{
|
||||
public string Index()
|
||||
{
|
||||
string output = string.Empty;
|
||||
string contentType = Constants.ApplicationJson;
|
||||
|
||||
Response.StatusCode = 200;
|
||||
|
||||
|
||||
StringValues dosType;
|
||||
if (Request.Query.TryGetValue("dosType", out dosType))
|
||||
{
|
||||
output = dosType.FirstOrDefault();
|
||||
}
|
||||
|
||||
StringValues dosLengths;
|
||||
Int32 dosLength =1;
|
||||
if (Request.Query.TryGetValue("dosLength", out dosLengths))
|
||||
{
|
||||
Int32.TryParse(dosLengths.FirstOrDefault(), out dosLength);
|
||||
}
|
||||
|
||||
string body = string.Empty;
|
||||
switch(dosType)
|
||||
{
|
||||
case "img":
|
||||
contentType = "text/html; charset=utf8";
|
||||
body = "<img" + (new String(' ', dosLength));
|
||||
break;
|
||||
case "charset":
|
||||
contentType = "text/html; charset=melon";
|
||||
body = "<meta " + (new String('.', dosLength));
|
||||
break;
|
||||
default:
|
||||
throw new InvalidOperationException("Invalid dosType: "+dosType);
|
||||
}
|
||||
|
||||
// Content-Type must be applied right before it is sent to the client or MVC will overwrite.
|
||||
Response.OnStarting(state =>
|
||||
{
|
||||
var httpContext = (HttpContext) state;
|
||||
httpContext.Response.ContentType = contentType;
|
||||
return Task.FromResult(0);
|
||||
}, HttpContext);
|
||||
|
||||
Response.ContentLength = Encoding.UTF8.GetBytes(body).Length;
|
||||
|
||||
return body;
|
||||
}
|
||||
|
||||
public IActionResult Error()
|
||||
{
|
||||
return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });
|
||||
}
|
||||
}
|
||||
}
|
|
@ -235,6 +235,42 @@ Invoke-RestMethod -Uri $uri -Body $body -Method 'Delete'
|
|||
}
|
||||
```
|
||||
|
||||
### /Dos/
|
||||
|
||||
Returns HTML designed to create denial of service against specific RegEx Expressions
|
||||
|
||||
#### Image Parsing RegEx
|
||||
|
||||
```powershell
|
||||
$uri = Get-WebListenerUrl -Test 'Dos' -query @{
|
||||
dosType='img'
|
||||
dosLength='5000'
|
||||
}
|
||||
Invoke-RestMethod -Uri $uri -Body $body -Method 'Delete'
|
||||
```
|
||||
|
||||
Return the following followed by 5,000 spaces.
|
||||
|
||||
```html
|
||||
<img
|
||||
```
|
||||
|
||||
#### Charset Parsing RegEx
|
||||
|
||||
```powershell
|
||||
$uri = Get-WebListenerUrl -Test 'Dos' -query @{
|
||||
dosType='charset'
|
||||
dosLength='5000'
|
||||
}
|
||||
Invoke-RestMethod -Uri $uri -Body $body -Method 'Delete'
|
||||
```
|
||||
|
||||
Return the following followed by 5,000 spaces.
|
||||
|
||||
```html
|
||||
<meta
|
||||
```
|
||||
|
||||
### /Encoding/Utf8/
|
||||
|
||||
Returns page containing UTF-8 data.
|
||||
|
|
Loading…
Reference in a new issue