Skip to content

Commit 2322f43

Browse files
authored
fix: NET462 requires TLS for GRPC to work (#72)
Signed-off-by: Eliot Eikenberry <[email protected]>
1 parent 33045cb commit 2322f43

File tree

2 files changed

+30
-9
lines changed

2 files changed

+30
-9
lines changed

Diff for: src/OpenFeature.Contrib.Providers.Flagd/FlagdProvider.cs

+29-9
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
using System.Linq;
55
using System.Threading.Tasks;
66
using System.Security.Cryptography.X509Certificates;
7+
using System.Net.Security;
78

89
using Google.Protobuf.WellKnownTypes;
910
using Grpc.Core;
@@ -539,30 +540,49 @@ private Service.ServiceClient BuildClientForPlatform(Uri url)
539540

540541
if (!useUnixSocket)
541542
{
542-
#if NET462
543+
#if NET462_OR_GREATER
543544
var handler = new WinHttpHandler();
544545
#else
545546
var handler = new HttpClientHandler();
546547
#endif
547548
if (_config.UseCertificate)
548549
{
549-
#if NET5_0_OR_GREATER
550-
if (File.Exists(_config.CertificatePath)) {
550+
if (File.Exists(_config.CertificatePath))
551+
{
551552
X509Certificate2 certificate = new X509Certificate2(_config.CertificatePath);
553+
#if NET5_0_OR_GREATER
552554
handler.ServerCertificateCustomValidationCallback = (message, cert, chain, _) => {
553555
// the the custom cert to the chain, Build returns a bool if valid.
554556
chain.ChainPolicy.TrustMode = X509ChainTrustMode.CustomRootTrust;
555557
chain.ChainPolicy.CustomTrustStore.Add(certificate);
556558
return chain.Build(cert);
557559
};
558-
} else {
559-
throw new ArgumentException("Specified certificate cannot be found.");
560-
}
560+
#elif NET462_OR_GREATER
561+
handler.ServerCertificateValidationCallback = (message, cert, chain, errors) => {
562+
if (errors == SslPolicyErrors.None) { return true; }
563+
564+
chain.ChainPolicy.VerificationFlags = X509VerificationFlags.AllowUnknownCertificateAuthority;
565+
566+
chain.ChainPolicy.ExtraStore.Add(certificate);
567+
568+
var isChainValid = chain.Build(cert);
569+
570+
if (!isChainValid) { return false; }
571+
572+
var isValid = chain.ChainElements
573+
.Cast<X509ChainElement>()
574+
.Any(x => x.Certificate.RawData.SequenceEqual(certificate.GetRawCertData()));
575+
576+
return isValid;
577+
};
561578
#else
562-
// Pre-NET5.0 APIs for custom CA validation are cumbersome.
563-
// Looking for additional contributions here.
564-
throw new ArgumentException("Custom certificate authorities not supported on this platform.");
579+
throw new ArgumentException("Custom Certificates are not supported on your platform");
565580
#endif
581+
}
582+
else
583+
{
584+
throw new ArgumentException("Specified certificate cannot be found.");
585+
}
566586
}
567587
return new Service.ServiceClient(GrpcChannel.ForAddress(url, new GrpcChannelOptions
568588
{

Diff for: src/OpenFeature.Contrib.Providers.Flagd/README.md

+1
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ The URI of the flagd server to which the `flagd Provider` connects to can either
8989

9090
Note that if `FLAGD_SOCKET_PATH` is set, this value takes precedence, and the other variables (`FLAGD_HOST`, `FLAGD_PORT`, `FLAGD_TLS`, `FLAGD_SERVER_CERT_PATH`) are disregarded.
9191

92+
Note that if you are on `NET462` through `NET48` as the target framework for your project, you are required to enable TLS and supply a certificate path as part of your configuration. This is a limitation Microsoft has [documented](https://learn.microsoft.com/en-us/aspnet/core/grpc/netstandard?view=aspnetcore-7.0#net-framework).
9293

9394
If you rely on the environment variables listed above, you can use the empty constructor which then configures the provider accordingly:
9495

0 commit comments

Comments
 (0)