diff --git a/.gitignore b/.gitignore
index 900d44ccd..6f3f97632 100644
--- a/.gitignore
+++ b/.gitignore
@@ -32,6 +32,7 @@ lhctl/lhctl
# Others
local-dev/certs/
build/
+.config
# Python
__pycache__
diff --git a/sdk-dotnet/Examples/BasicExample/BasicExample.csproj b/sdk-dotnet/Examples/BasicExample/BasicExample.csproj
index 654bb87e7..1c58361d1 100644
--- a/sdk-dotnet/Examples/BasicExample/BasicExample.csproj
+++ b/sdk-dotnet/Examples/BasicExample/BasicExample.csproj
@@ -2,7 +2,7 @@
Exe
- net6.0
+ net8.0
enable
enable
diff --git a/sdk-dotnet/LittleHorse.Sdk.Tests/LHInputVariablesTest.cs b/sdk-dotnet/LittleHorse.Sdk.Tests/LHInputVariablesTest.cs
index 84355d525..b24d57dfc 100644
--- a/sdk-dotnet/LittleHorse.Sdk.Tests/LHInputVariablesTest.cs
+++ b/sdk-dotnet/LittleHorse.Sdk.Tests/LHInputVariablesTest.cs
@@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
-using System.IO;
using Xunit;
namespace LittleHorse.Sdk.Tests.Internal
@@ -169,7 +168,7 @@ public void LHConfigVariables_WithSomeLHOptionsCommentedInFile_ShouldReturnSetOp
Assert.Equal(int.Parse(keyValueLHConfigs["LHC_API_PORT"]), inputVariables.LHC_API_PORT);
Assert.Equal(DefaultLHConfigVariables.LHC_API_PROTOCOL, inputVariables.LHC_API_PROTOCOL);
Assert.Null(inputVariables.LHC_CA_CERT);
- Assert.Equal(string.Empty, inputVariables.LHW_TASK_WORKER_VERSION);
+ Assert.Equal(DefaultLHConfigVariables.LHW_TASK_WORKER_VERSION, inputVariables.LHW_TASK_WORKER_VERSION);
}
[Fact]
diff --git a/sdk-dotnet/LittleHorse.Sdk.Tests/Utils/CertificatesHandlerTest.cs b/sdk-dotnet/LittleHorse.Sdk.Tests/Utils/CertificatesHandlerTest.cs
deleted file mode 100644
index 40668e140..000000000
--- a/sdk-dotnet/LittleHorse.Sdk.Tests/Utils/CertificatesHandlerTest.cs
+++ /dev/null
@@ -1,40 +0,0 @@
-using System;
-using System.IO;
-using LittleHorse.Sdk.Utils;
-using Xunit;
-
-namespace LittleHorse.Sdk.Tests.Utils;
-
-public class CertificatesHandlerTest
-{
- [Fact]
- public void CertManager_WithCaCertificateTrusted_ShouldReturnHttpHandler()
- {
- const string caFilename = "trusted_ca.crt";
- string caCertPath = Path.Combine(Directory.GetCurrentDirectory(), "Resources", caFilename);
-
- var currentHttpHandler = CertificatesHandler.GetHttpHandlerFrom(caCertPath);
-
- Assert.NotNull(currentHttpHandler);
- }
-
- [Fact]
- public void CertManager_WithoutCaCertificate_ShouldThrowFileNotFoundException()
- {
- const string caCertPath = "file_not_found.crt";
- var exception = Assert.Throws(() => CertificatesHandler.GetHttpHandlerFrom(caCertPath));
-
- Assert.Contains($"Certificate file {caCertPath} does not exist.", exception.Message);
- }
-
- [Fact]
- public void CertManager_WithEmptyCaCertificate_ShouldThrowException()
- {
- const string caFilename = "empty_ca.crt";
- string caCertPath = Path.Combine(Directory.GetCurrentDirectory(), "Resources", caFilename);
-
- var exception = Assert.Throws(() => CertificatesHandler.GetHttpHandlerFrom(caCertPath));
-
- Assert.Contains($"Certificate file {caCertPath} has corrupted data.", exception.Message);
- }
-}
\ No newline at end of file
diff --git a/sdk-dotnet/LittleHorse.Sdk/LHConfig.cs b/sdk-dotnet/LittleHorse.Sdk/LHConfig.cs
index 819ecd965..ba01fdf5a 100644
--- a/sdk-dotnet/LittleHorse.Sdk/LHConfig.cs
+++ b/sdk-dotnet/LittleHorse.Sdk/LHConfig.cs
@@ -5,6 +5,9 @@
using LittleHorse.Sdk.Internal;
using LittleHorse.Sdk.Utils;
using Microsoft.Extensions.Logging;
+using System.Net.Http;
+using System.Security.Cryptography.X509Certificates;
+using System.Net.Security;
using static LittleHorse.Common.Proto.LittleHorse;
namespace LittleHorse.Sdk {
@@ -136,11 +139,7 @@ private GrpcChannel CreateChannel(string host, int port)
{
var httpHandler = new HttpClientHandler();
var address = $"{BootstrapProtocol}://{host}:{port}";
-
- if (_inputVariables.LHC_CA_CERT != null)
- {
- httpHandler = CertificatesHandler.GetHttpHandlerFrom(_inputVariables.LHC_CA_CERT);
- }
+ httpHandler.ServerCertificateCustomValidationCallback = ServerCertificateCustomValidation;
if (_inputVariables.LHC_CLIENT_CERT != null && _inputVariables.LHC_CLIENT_KEY != null)
{
@@ -150,7 +149,7 @@ private GrpcChannel CreateChannel(string host, int port)
httpHandler.ClientCertificates.Add(cert);
}
-
+
if (IsOAuth)
{
return CreateGrpcChannelWithOauthCredentials(address, httpHandler);
@@ -162,6 +161,21 @@ private GrpcChannel CreateChannel(string host, int port)
});
}
+ private bool ServerCertificateCustomValidation(HttpRequestMessage requestMessage, X509Certificate2? certificate, X509Chain? certChain, SslPolicyErrors sslErrors)
+ {
+ var pathCaCert = _inputVariables.LHC_CA_CERT;
+ if (pathCaCert != null)
+ {
+ var caCert = new X509Certificate2(File.ReadAllBytes(pathCaCert));
+
+ certChain!.ChainPolicy.TrustMode = X509ChainTrustMode.CustomRootTrust;
+ certChain.ChainPolicy.CustomTrustStore.Add(caCert);
+ }
+
+ var certChainBuilder = certificate != null && certChain != null && certChain.Build(certificate);
+ return certChainBuilder;
+ }
+
private GrpcChannel CreateGrpcChannelWithOauthCredentials(string address, HttpClientHandler httpHandler)
{
InitializeOAuth();
diff --git a/sdk-dotnet/LittleHorse.Sdk/Utils/CertificatesHandler.cs b/sdk-dotnet/LittleHorse.Sdk/Utils/CertificatesHandler.cs
index 0e4f673f1..18a328e39 100644
--- a/sdk-dotnet/LittleHorse.Sdk/Utils/CertificatesHandler.cs
+++ b/sdk-dotnet/LittleHorse.Sdk/Utils/CertificatesHandler.cs
@@ -1,39 +1,16 @@
+using System.Net.Security;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
+using System.Security.Authentication;
using System.Security.Cryptography.X509Certificates;
+using LittleHorse.Sdk.Internal;
+using Microsoft.Extensions.Logging;
[assembly: InternalsVisibleTo("LittleHorse.Sdk.Tests")]
namespace LittleHorse.Sdk.Utils {
internal class CertificatesHandler
{
- internal static HttpClientHandler GetHttpHandlerFrom(string pathCaCert)
- {
- try
- {
- var caCert = new X509Certificate2(File.ReadAllBytes(pathCaCert));
- var handler = new HttpClientHandler();
-
- handler.ServerCertificateCustomValidationCallback =
- (httpRequestMessage, cert, certChain, sslPolicyErrors) =>
- {
- return certChain!.ChainElements.Any(element =>
- element.Certificate.Thumbprint == caCert.Thumbprint);
- };
-
- return handler;
- }
- catch (System.Security.Cryptography.CryptographicException)
- {
- throw new Exception($"Certificate file {pathCaCert} has corrupted data.");
- }
- catch (Exception ex)
- {
- throw new FileNotFoundException($"Certificate file {pathCaCert} does not exist.",
- ex.Message);
- }
- }
-
internal static X509Certificate2 GetX509CertificateFrom(string pathPrivateCert, string pathRequestedCert)
{
string certificatePem = File.ReadAllText(pathRequestedCert);