runtime: ExtendedProtectionPolicy constructor throws unnecessarily on WASM
Description
This was an issue discovered by a WCF customer. WCF tracking issue is dotnet/wcf#4942.
It’s not possible to construct an instance of ExtendedProtectionPolicy
on WASM. This makes it impossible to have a public API expose this type unless you return null when running in a browser. ExtendedProtectionPolicy
has the ability to have a policy enforcement that it is never used, which is appropriate for platforms where extended protection isn’t supported.
In addition to this problem, the property ExtendedProtectionPolicy.OSSupportsExtendedProtection
always returns true with no regard to platform.
WCF exposes a property of type ExtendedProtectionPolicy
to enable clients to optionally turn on the use of Extended Protection. The default value for this property is a policy where enforcement is disabled. This is constructed using this line of code:
private static readonly ExtendedProtectionPolicy s_disabledPolicy = new ExtendedProtectionPolicy(PolicyEnforcement.Never);
In our property, when a new value is being set, we check if the new value has an enforcement policy set to Always
, and if it is we check the value of ExtendedProtectionPolicy.OSSupportsExtendedProtection
and throw if trying to set a policy which can’t be supported.
if (value.PolicyEnforcement == PolicyEnforcement.Always &&
!System.Security.Authentication.ExtendedProtection.ExtendedProtectionPolicy.OSSupportsExtendedProtection)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
new PlatformNotSupportedException(SR.ExtendedProtectionNotSupported));
}
If OSSupportsExtendedProtection
were implemented to reflect whether extended protection, then this should be sufficient for apps to guard against trying to use extended protection where it’s not supported.
Throwing an exception on construction of a policy instance regardless of enforcement policy means all public properties need to return null where previously they didn’t. This changes a not null value to a sometimes null value. This also requires adding logic to interpret null to mean the same as PolicyEnforcement.Never
and duplicating that logic change everywhere the instance propagates through the code base.
Reproduction Steps
In a Blazor app, create a new instance of BasicHttpBinding
using the default constructor. It throws with a PlatformNotSupportedException
stating “System.Net.Security is not supported on this platform.”
This was customer reported, but based on my understanding of how the throwing of an exception is generated, I suspect getting ExtendedProtectionPolicy.OSSupportsExtendedProtection
will throw a PlatformNotSupportedException
too instead of returning false.
Expected behavior
When constructing an instance with a PolicyEnforcement
value of Never
or WhenSupported
will not throw. These classes are just OM around describing extended protection so I would expect an exception to only be thrown when a class which accepts an ExtendedProtectionPolicy
is passed one with PolicyEnforcement.Always
, as WCF does. In this case, the class would never throw.
This isn’t a new expectation; this is what happened on OS’s earlier than Win7 where extended protection isn’t supported.
Actual behavior
Constructing an ExtendedProtectionPolicy
with any enforcement policy throws a PlatformNotSupportedException.
Regression?
Regression from .NET Framework and .NET Core outside of a browser. On .NET Framework, OS’s prior to Windows 7 didn’t support extended protection, and ExtendedProtectionPolicy.OSSupportsExtendedProtection
would return false so that libraries and applications can avoid an exception being thrown by trying to use extended protection when it’s not supported. The same model should work for .NET too.
Known Workarounds
Add lots of ugly logic through the WCF code base treating null as PolicyEnforcement.Never
. This could also cause consuming code to throw a NullReferenceException
if expecting the property to return a non-null value as it does on every other platform.
Configuration
No response
Other information
No response
About this issue
- Original URL
- State: closed
- Created 2 years ago
- Comments: 19 (18 by maintainers)
Yes that’s possible. See https://github.com/dotnet/runtime/blob/f44e2e6d4af37adca6469022105bf8ac049b8305/src/libraries/System.Net.Primitives/src/System.Net.Primitives.csproj#L14 for an example.
@ericstj @ViktorHofer - is there a way to generate PNSE stubs for all the code in an assembly, but still allow a “partial” implementation for one of the APIs? As above - if we want to return
false
for this static bool property, and have all the other code thrown PNSE.It looks like
ExtendedProtectionPolicy
is part of System.Net.Security instead of System.Security.I’m guessing it’s using an auto-generated PNSE on wasm. @mconnew 's suggestion of making the static supported property return false and the ctor not fail for Never/WhenSupported sounds reasonable to me.