diff --git a/src/Testcontainers/Builders/MTlsEndpointAuthenticationProvider.cs b/src/Testcontainers/Builders/MTlsEndpointAuthenticationProvider.cs index 31d3e73cd..3f203c01d 100644 --- a/src/Testcontainers/Builders/MTlsEndpointAuthenticationProvider.cs +++ b/src/Testcontainers/Builders/MTlsEndpointAuthenticationProvider.cs @@ -8,6 +8,7 @@ namespace DotNet.Testcontainers.Builders using DotNet.Testcontainers.Configurations; using JetBrains.Annotations; using Org.BouncyCastle.Crypto; + using Org.BouncyCastle.Crypto.Parameters; using Org.BouncyCastle.OpenSsl; using Org.BouncyCastle.Pkcs; using Org.BouncyCastle.Security; @@ -79,11 +80,13 @@ private static X509Certificate2 CreateFromPemFile(string certPemFilePath, string var password = Guid.NewGuid().ToString("D"); - var keyPair = (AsymmetricCipherKeyPair)new PemReader(keyPairStream).ReadObject(); + var keyObject = new PemReader(keyPairStream).ReadObject(); var certificateEntry = new X509CertificateEntry(certificate); - var keyEntry = new AsymmetricKeyEntry(keyPair.Private); + var keyParameter = ResolveKeyParameter(keyObject); + + var keyEntry = new AsymmetricKeyEntry(keyParameter); store.SetKeyEntry(certificate.SubjectDN + "_key", keyEntry, new[] { certificateEntry }); using (var certificateStream = new MemoryStream()) @@ -93,5 +96,18 @@ private static X509Certificate2 CreateFromPemFile(string certPemFilePath, string } } } + + private static AsymmetricKeyParameter ResolveKeyParameter(object keyObject) + { + switch (keyObject) + { + case AsymmetricCipherKeyPair ackp: + return ackp.Private; + case RsaPrivateCrtKeyParameters rpckp: + return rpckp; + default: + throw new ArgumentOutOfRangeException(nameof(keyObject), $"Unsupported asymmetric key entry encountered while trying to resolve key from input object '{keyObject.GetType()}'."); + } + } } } diff --git a/tests/Testcontainers.Tests/Fixtures/Containers/Unix/DockerMTlsFixture.cs b/tests/Testcontainers.Tests/Fixtures/Containers/Unix/DockerMTls.cs similarity index 69% rename from tests/Testcontainers.Tests/Fixtures/Containers/Unix/DockerMTlsFixture.cs rename to tests/Testcontainers.Tests/Fixtures/Containers/Unix/DockerMTls.cs index c140635f4..84265df0f 100644 --- a/tests/Testcontainers.Tests/Fixtures/Containers/Unix/DockerMTlsFixture.cs +++ b/tests/Testcontainers.Tests/Fixtures/Containers/Unix/DockerMTls.cs @@ -2,13 +2,11 @@ namespace DotNet.Testcontainers.Tests.Fixtures { using System.Collections.Generic; using DotNet.Testcontainers.Builders; - using JetBrains.Annotations; - [UsedImplicitly] - public sealed class DockerMTlsFixture : ProtectDockerDaemonSocket + public abstract class DockerMTls : ProtectDockerDaemonSocket { - public DockerMTlsFixture() - : base(new ContainerBuilder()) + public DockerMTls(string dockerImageVersion) + : base(new ContainerBuilder(), dockerImageVersion) { } diff --git a/tests/Testcontainers.Tests/Fixtures/Containers/Unix/DockerTlsFixture.cs b/tests/Testcontainers.Tests/Fixtures/Containers/Unix/DockerTlsFixture.cs index a3c643606..1ed591185 100644 --- a/tests/Testcontainers.Tests/Fixtures/Containers/Unix/DockerTlsFixture.cs +++ b/tests/Testcontainers.Tests/Fixtures/Containers/Unix/DockerTlsFixture.cs @@ -9,7 +9,7 @@ public sealed class DockerTlsFixture : ProtectDockerDaemonSocket { public DockerTlsFixture() : base(new ContainerBuilder() - .WithCommand("--tlsverify=false")) + .WithCommand("--tlsverify=false"), "20.10.18") { } diff --git a/tests/Testcontainers.Tests/Fixtures/Containers/Unix/OpenSsl1_1_1Fixture.cs b/tests/Testcontainers.Tests/Fixtures/Containers/Unix/OpenSsl1_1_1Fixture.cs new file mode 100644 index 000000000..37705ec29 --- /dev/null +++ b/tests/Testcontainers.Tests/Fixtures/Containers/Unix/OpenSsl1_1_1Fixture.cs @@ -0,0 +1,12 @@ +namespace DotNet.Testcontainers.Tests.Fixtures +{ + using JetBrains.Annotations; + + [UsedImplicitly] + public sealed class OpenSsl1_1_1Fixture : DockerMTls + { + public OpenSsl1_1_1Fixture() : base("20.10.18") + { + } + } +} diff --git a/tests/Testcontainers.Tests/Fixtures/Containers/Unix/OpenSsl3_1Fixture.cs b/tests/Testcontainers.Tests/Fixtures/Containers/Unix/OpenSsl3_1Fixture.cs new file mode 100644 index 000000000..0a4768b96 --- /dev/null +++ b/tests/Testcontainers.Tests/Fixtures/Containers/Unix/OpenSsl3_1Fixture.cs @@ -0,0 +1,12 @@ +namespace DotNet.Testcontainers.Tests.Fixtures +{ + using JetBrains.Annotations; + + [UsedImplicitly] + public sealed class OpenSsl3_1Fixture : DockerMTls + { + public OpenSsl3_1Fixture() : base("24.0.5") + { + } + } +} diff --git a/tests/Testcontainers.Tests/Fixtures/Containers/Unix/ProtectDockerDaemonSocket.cs b/tests/Testcontainers.Tests/Fixtures/Containers/Unix/ProtectDockerDaemonSocket.cs index 1e0b88736..3c49167ca 100644 --- a/tests/Testcontainers.Tests/Fixtures/Containers/Unix/ProtectDockerDaemonSocket.cs +++ b/tests/Testcontainers.Tests/Fixtures/Containers/Unix/ProtectDockerDaemonSocket.cs @@ -8,12 +8,11 @@ namespace DotNet.Testcontainers.Tests.Fixtures using DotNet.Testcontainers.Configurations; using DotNet.Testcontainers.Containers; using DotNet.Testcontainers.Images; + using Org.BouncyCastle.OpenSsl; using Xunit; public abstract class ProtectDockerDaemonSocket : IAsyncLifetime { - public const string DockerVersion = "20.10.18"; - private const string CertsDirectoryName = "certs"; private const ushort TlsPort = 2376; @@ -22,14 +21,12 @@ public abstract class ProtectDockerDaemonSocket : IAsyncLifetime private readonly string _containerCertsDirectoryPath = Path.Combine("/", CertsDirectoryName); - private readonly IImage _image = new DockerImage(string.Empty, "docker", DockerVersion + "-dind"); - private readonly IContainer _container; - protected ProtectDockerDaemonSocket(ContainerBuilder containerConfiguration) + protected ProtectDockerDaemonSocket(ContainerBuilder containerConfiguration, string dockerImageVersion) { _container = containerConfiguration - .WithImage(_image) + .WithImage(new DockerImage(string.Empty, "docker", dockerImageVersion + "-dind")) .WithPrivileged(true) .WithPortBinding(TlsPort, true) .WithBindMount(_hostCertsDirectoryPath, _containerCertsDirectoryPath, AccessMode.ReadWrite) @@ -42,17 +39,28 @@ public virtual IList CustomProperties get { var customProperties = new List(); - customProperties.Add($"docker.host={TcpEndpoint}"); + customProperties.Add($"docker.host={new UriBuilder("tcp", _container.Hostname, _container.GetMappedPublicPort(TlsPort))}"); customProperties.Add($"docker.cert.path={Path.Combine(_hostCertsDirectoryPath, "client")}"); return customProperties; } } - private Uri TcpEndpoint + public IImage Image + { + get + { + return _container.Image; + } + } + + public object TlsKey { get { - return new UriBuilder("tcp", _container.Hostname, _container.GetMappedPublicPort(TlsPort)).Uri; + using (var tlsKeyStream = new StreamReader(Path.Combine(_hostCertsDirectoryPath, "client", "key.pem"))) + { + return new PemReader(tlsKeyStream).ReadObject(); + } } } diff --git a/tests/Testcontainers.Tests/Unit/Containers/Unix/ProtectDockerDaemonSocketTest.cs b/tests/Testcontainers.Tests/Unit/Containers/Unix/ProtectDockerDaemonSocketTest.cs index e4f10ea46..5a11e2e82 100644 --- a/tests/Testcontainers.Tests/Unit/Containers/Unix/ProtectDockerDaemonSocketTest.cs +++ b/tests/Testcontainers.Tests/Unit/Containers/Unix/ProtectDockerDaemonSocketTest.cs @@ -8,6 +8,8 @@ namespace DotNet.Testcontainers.Tests.Unit using DotNet.Testcontainers.Configurations; using DotNet.Testcontainers.Tests.Fixtures; using Microsoft.Extensions.Logging.Abstractions; + using Org.BouncyCastle.Crypto; + using Org.BouncyCastle.Crypto.Parameters; using Xunit; public static class ProtectDockerDaemonSocketTest @@ -18,12 +20,43 @@ private static IDockerEndpointAuthenticationConfiguration GetAuthConfig(ProtectD return new IDockerEndpointAuthenticationProvider[] { new MTlsEndpointAuthenticationProvider(customConfiguration), new TlsEndpointAuthenticationProvider(customConfiguration) }.First(authProvider => authProvider.IsApplicable()).GetAuthConfig(); } - public sealed class MTls : IClassFixture + public sealed class MTlsOpenSsl1_1_1 : IClassFixture { + private readonly ProtectDockerDaemonSocket _fixture; + + private readonly IDockerEndpointAuthenticationConfiguration _authConfig; + + public MTlsOpenSsl1_1_1(OpenSsl1_1_1Fixture dockerMTlsFixture) + { + _fixture = dockerMTlsFixture; + _authConfig = GetAuthConfig(dockerMTlsFixture); + } + + [Fact] + public async Task GetVersionReturnsVersion() + { + // Given + var client = new TestcontainersClient(Guid.Empty, _authConfig, NullLogger.Instance); + + // When + var version = await client.System.GetVersionAsync() + .ConfigureAwait(false); + + // Then + Assert.StartsWith(version.Version, _fixture.Image.Tag); + Assert.IsType(_fixture.TlsKey); + } + } + + public sealed class MTlsOpenSsl3_1 : IClassFixture + { + private readonly ProtectDockerDaemonSocket _fixture; + private readonly IDockerEndpointAuthenticationConfiguration _authConfig; - public MTls(DockerMTlsFixture dockerMTlsFixture) + public MTlsOpenSsl3_1(OpenSsl3_1Fixture dockerMTlsFixture) { + _fixture = dockerMTlsFixture; _authConfig = GetAuthConfig(dockerMTlsFixture); } @@ -38,16 +71,20 @@ public async Task GetVersionReturnsVersion() .ConfigureAwait(false); // Then - Assert.Equal(ProtectDockerDaemonSocket.DockerVersion, version.Version); + Assert.StartsWith(version.Version, _fixture.Image.Tag); + Assert.IsType(_fixture.TlsKey); } } public sealed class Tls : IClassFixture { + private readonly ProtectDockerDaemonSocket _fixture; + private readonly IDockerEndpointAuthenticationConfiguration _authConfig; public Tls(DockerTlsFixture dockerTlsFixture) { + _fixture = dockerTlsFixture; _authConfig = GetAuthConfig(dockerTlsFixture); } @@ -62,7 +99,7 @@ public async Task GetVersionReturnsVersion() .ConfigureAwait(false); // Then - Assert.Equal(ProtectDockerDaemonSocket.DockerVersion, version.Version); + Assert.StartsWith(version.Version, _fixture.Image.Tag); } } }