Skip to content

Commit

Permalink
feat: support TLS connection in flagD provider
Browse files Browse the repository at this point in the history
Signed-off-by: odubajDT <[email protected]>
  • Loading branch information
odubajDT committed Apr 4, 2023
1 parent f4d2142 commit dca5d09
Show file tree
Hide file tree
Showing 3 changed files with 72 additions and 6 deletions.
33 changes: 29 additions & 4 deletions src/OpenFeature.Contrib.Providers.Flagd/FlagdProvider.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
using System;
using System.IO;
using System.Text;
using System.Linq;
using System.Threading.Tasks;
using System.Security.Cryptography.X509Certificates;

using Google.Protobuf.WellKnownTypes;
using Grpc.Core;
Expand Down Expand Up @@ -505,14 +508,36 @@ private static Service.ServiceClient buildClientForPlatform(Uri url)

if (!useUnixSocket)
{
var flagdCertPath = Environment.GetEnvironmentVariable("FLAGD_SERVER_CERT_PATH") ?? "";
#if NET462
return new Service.ServiceClient(GrpcChannel.ForAddress(url, new GrpcChannelOptions
var handler = new WinHttpHandler();
#else
var handler = new HttpClientHandler();
#endif
if (flagdCertPath != "")
{
HttpHandler = new WinHttpHandler(),
}));
#if NET5_0_OR_GREATER
if (File.Exists(flagdCertPath)) {
X509Certificate2 certificate = new X509Certificate2(flagdCertPath);
handler.ServerCertificateCustomValidationCallback = (message, cert, chain, _) => {
// the the custom cert to the chain, Build returns a bool if valid.
chain.ChainPolicy.TrustMode = X509ChainTrustMode.CustomRootTrust;
chain.ChainPolicy.CustomTrustStore.Add(certificate);
return chain.Build(cert);
};
} else {
throw new ArgumentException("Specified certificate cannot be found.");
}
#else
return new Service.ServiceClient(GrpcChannel.ForAddress(url));
// Pre-NET5.0 APIs for custom CA validation are cumbersome.
// Looking for additional contributions here.
throw new ArgumentException("Custom certificate authorities not supported on this platform.");
#endif
}
return new Service.ServiceClient(GrpcChannel.ForAddress(url, new GrpcChannelOptions
{
HttpHandler = handler
}));
}

#if NET5_0_OR_GREATER
Expand Down
3 changes: 2 additions & 1 deletion src/OpenFeature.Contrib.Providers.Flagd/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,12 +81,13 @@ The URI of the flagd server to which the `flagd Provider` connects to can either
| host | FLAGD_HOST | string | localhost | |
| port | FLAGD_PORT | number | 8013 | |
| tls | FLAGD_TLS | boolean | false | |
| tls certPath | FLAGD_SERVER_CERT_PATH | string | | |
| unix socket path | FLAGD_SOCKET_PATH | string | | |
| Caching | FLAGD_CACHE | string | | LRU |
| Maximum cache size | FLAGD_MAX_CACHE_SIZE | number | 10 | |
| Maximum event stream retries | FLAGD_MAX_EVENT_STREAM_RETRIES | number | 3 | |

Note that if `FLAGD_SOCKET_PATH` is set, this value takes precedence, and the other variables (`FLAGD_HOST`, `FLAGD_PORT`, `FLAGD_TLS`) are disregarded.
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.


If you rely on the environment variables listed above, you can use the empty constructor which then configures the provider accordingly:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,54 @@
using OpenFeature.Error;
using ProtoValue = Google.Protobuf.WellKnownTypes.Value;
using System.Collections.Generic;
using System.Linq;
using OpenFeature.Model;
using System.Threading;
using System;

namespace OpenFeature.Contrib.Providers.Flagd.Test
{
public class UnitTestFlagdProvider
{
[Fact]
public void BuildClientForPlatform_Should_Throw_Exception_When_FlagdCertPath_Not_Exists()
{
// Arrange
var url = new Uri("https://localhost:5001");
System.Environment.SetEnvironmentVariable("FLAGD_SERVER_CERT_PATH", "non-existing-path");

// Act & Assert
Assert.Throws<ArgumentException>(() => new FlagdProvider(url));

// Cleanup
System.Environment.SetEnvironmentVariable("FLAGD_SERVER_CERT_PATH", "");
}

[Fact]
public void BuildClientForPlatform_Should_Return_Client_For_Non_Unix_Socket_Without_Certificate()
{
// Arrange
var url = new Uri("https://localhost:5001");

// Act
var flagdProvider = new FlagdProvider(url);
var client = flagdProvider.GetClient();

// Assert
Assert.NotNull(client);
Assert.IsType<Service.ServiceClient>(client);
}

#if NET462
[Fact]
public void BuildClientForPlatform_Should_Throw_Exception_For_Unsupported_DotNet_Version()
{
// Arrange
var url = new Uri("unix:///var/run/flagd.sock");

// Act & Assert
Assert.Throws<Exception>(() => new FlagdProvider(url));
}
#endif
[Fact]
public void TestGetProviderName()
{
Expand Down

0 comments on commit dca5d09

Please sign in to comment.