Closed Minty123 closed 2 years ago
Thank you for the report and your in-depth analysis.
When Request-FalconToken
is first run, it creates a hashtable containing a [System.Net.Http.HttpClientHandler]
object, stored under $Falcon.Api.Handler
. This handler is used to make requests with an accompanying [System.Net.Http.HttpClient]
object stored under $Falcon.Api.Client
.
The SslProtocols
property in the [System.Net.Http.HttpClientHandler]
class is used to enforce TLS 1.2 (required by the Falcon APIs) for all request by PSFalcon, without setting it for the entire PowerShell session (which is what is happening when you set [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls12
).
Given that you can set this for the session, but not for the particular class, I suspect that this is a .NET bug. Unfortunately, I don't know where to begin to even attempt to get that fixed.
If you run the steps in this order, does it allow you to request the token without any errors?
[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls12
Import-Module -Name PSFalcon
Request-FalconToken
Thank you for the fast response and the great explanation! I tried your steps, though I get the same error. The article you've referenced doesn'lt list .NET Framework 4.6.2, which is why I assume the property just doesn't exist there (as stated by that StackOverflow response too).
Out of spite, I installed .NET Framework 4.8 on the server, and it worked right out of the box, which would also confirm the assumption the property is just not available in .NET 4.6.2. I wonder what would be the best way to go about it. Finding a workaround that works for all or just make it a requirement for PSFalcon and call it a day...
In earlier versions of PSFalcon, I used the [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls12
command to set TLS. This worked as long as the device had TLS 1.2 available (pretty much any device with PowerShell 5.1 or above), but I would like to avoid making a change that impacts the entire PowerShell session. Using the [System.Net.Http.HttpClientHandler]
method seemed like a good alternative.
I should be able to run a check before changing the setting to verify that the property is available, and if not, change it for the PowerShell session. I'll test and update if I think I can create a workaround.
Sounds great! Thanks so much for your help. If there's anything I can test to help, just let me know. :-)
Can you replace your local copy of Public\oauth2.ps1
with the contents of this file? https://raw.githubusercontent.com/CrowdStrike/psfalcon/master/Public/oauth2.ps1
I added a check for the SslProtocols
property before attempting to set it, and if not present, it uses [System.Net.ServicePointManager]
instead. I expect that it should eliminate the error message for you, without impacting other .NET versions that have the property available.
Interesting! The property "SslProtocols" exists, so it still tries to set a value, but fails while doing so. I'm getting the same error.
I can confirm the System.Net.Http.HttpClientHandler
object which gets created by [ApiClient]::New()
shows the property:
PS C:\Users\redacted> ([ApiClient]::New()).Handler
CheckCertificateRevocationList :
ClientCertificates : {}
DefaultProxyCredentials :
MaxConnectionsPerServer : 2
MaxResponseHeadersLength : 64
Properties : {}
ServerCertificateCustomValidationCallback :
SslProtocols :
...
Edit: What works is replacing your check with:
try {
$Script:Falcon.Api.Handler.SslProtocols = 'Tls12'
} catch {
# Set TLS 1.2 for PowerShell session
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
}
Though that's pretty broad. Unfortunately the exception thrown is not very specific, so I don't think I could narrow down the catch.
I'd appreciate it if .NET bugs were a little more logically consistent. 😆
I like your try/catch method--that's not a way that I ever really use try/catch but it makes sense and I think it's a more elegant solution.
Would you like to commit the change, with appropriate comments? You've got a great idea and I'd love to properly record your contribution.
Maybe something like:
try {
# Initiate ApiClient, set SslProtocol and UserAgent
$Script:Falcon = Get-ApiCredential $PSBoundParameters
$Script:Falcon.Add('Api', [ApiClient]::New())
if ($Script:Falcon.Api) {
try {
# Set TLS 1.2 for [System.Net.Http.HttpClientHandler]
$Script:Falcon.Api.Handler.SslProtocols = 'Tls12'
} catch {
if ([Net.ServicePointManager]::SecurityProtocol -notmatch 'Tls12') {
# Set TLS 1.2 for PowerShell session
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
}
}
$Script:Falcon.Api.Handler.AutomaticDecompression = [System.Net.DecompressionMethods]::Gzip,
[System.Net.DecompressionMethods]::Deflate
$Script:Falcon.Api.Client.DefaultRequestHeaders.UserAgent.ParseAdd(
"$((Show-FalconModule).UserAgent)")
} else {
Write-Error "Unable to initialize [ApiClient] object."
}
} catch {
throw $_
}
EDIT: Added an if
to the catch
, since the session setting isn't required unless it's not present.
I can confirm the
System.Net.Http.HttpClientHandler
object which gets created by[ApiClient]::New()
shows the property
Thinking more about this, I wonder if it's a case of the property being present, but Tls12
not existing as an accepted value within that particular .NET version. I've seen weirdness like this before between .NET versions.
Your try/catch mentioned above should resolve it either way.
I'll test it on one or two other OS first, then I'll gladly make the commit. :-) Regarding your if-addition, couldn't an if-clause also be added to $Script:Falcon.Api.Handler.SslProtocols = 'Tls12'
or will that one always be initialized without a value?
Edit: Just some small tests with combinations I could find: | OS | .NET | Result |
---|---|---|---|
Server 2016 | .NET Framework 4.6.2 | Works. Uses [Net.ServicePointManager] | |
Server 2012 R2 | .NET Framework 4.7.2 | Works. Uses [System.Net.Http.HttpClientHandler] | |
Server 2016 | .NET Framework 4.8 | Works. Uses [System.Net.Http.HttpClientHandler] |
I'll test it on one or two other OS first, then I'll gladly make the commit. :-)
Awesome!
Regarding your if-addition, couldn't an if-clause also be added to
$Script:Falcon.Api.Handler.SslProtocols = 'Tls12'
or will that one always be initialized without a value?
Yes, this is always initialized without a value.
OS .NET Result Server 2016 .NET Framework 4.6.2 Works. Uses [Net.ServicePointManager] Server 2012 R2 .NET Framework 4.7.2 Works. Uses [System.Net.Http.HttpClientHandler] Server 2016 .NET Framework 4.8 Works. Uses [System.Net.Http.HttpClientHandler]
My guess is that 4.6.2 is the only one you'll find that requires [System.Net.ServicePointManager]
. Nothing brings me more joy than finding these weird differences between .NET and PowerShell. I hope that came across appropriately dripping with sarcasm.
Alright, so I made a PR. Hopefully everything was correct. I've also added two Write-Verbose lines to the code to indicate the method used. Might be relevant in the future, though if you want, feel free to remove it again. Thanks for your help and the effort you put in this project! :-)
Merged, but I'm going to re-open this issue in case anyone else runs into this problem before the v2.1.7 release.
For those following along, if you're experiencing this issue, you can replace Public\oauth2.ps1
with the contents of this file to fix the problem before v2.1.7 is released: https://raw.githubusercontent.com/CrowdStrike/psfalcon/master/Public/oauth2.ps1
Closing due to v2.1.7 release. Thank you for your contribution!
Describe the bug When using PSFalcon 2.1.6 (same happens with 2.1.5), I get the exception:
To Reproduce
Line 85 in oauth2.ps1 runs
$Script:Falcon.Api.Handler.SslProtocols = 'Tls12'
, however according to https://stackoverflow.com/a/48832145 the property doesn't exist in .NET 4.6.2, which is the default for Server 2016 apparently. [Source]Workaround
[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls12
before running PSFalcon commandsEven when doing step 1 first, requesting the token will fail once.
Expected behavior Error doesn't appear.
Environment (please complete the following information):
Additional context I'm afraid I'm not sure if the problem is related to the server config, PSFalcon or .NET. Still thought it might be a good idea to bring it up here, in case others experience the same.
Thanks for any help or feedback! Your work on the module is highly appreciated as always!