diff --git a/sample/terraform/main.tf b/sample/terraform/main.tf index 11bb80b5a..1503ba594 100644 --- a/sample/terraform/main.tf +++ b/sample/terraform/main.tf @@ -99,6 +99,16 @@ locals { } # enable wave on config change deploymentAnnotations = local.deploymentAnnotations + + # ingress annotations + ingress = { + annotations = { + "kubernetes.io/ingress.class" = "nginx" + "cert-manager.io/cluster-issuer" = "letsencrypt" + "nginx.ingress.kubernetes.io/auth-tls-pass-certificate-to-upstream" = "true" + "nginx.ingress.kubernetes.io/auth-tls-verify-client" = "off" + } + } appSettings = { file = { # override certificate authentication options @@ -111,6 +121,7 @@ locals { IdentityServerOptions = { MutualTls = { Enabled = true + PEMHeader = "ssl-client-cert" } EnableServerSideSession = true ServerSideSessions = { @@ -233,18 +244,6 @@ resource "helm_release" "nginx_ingress" { name = "controller.extraArgs.enable-ssl-passthrough" value = true } - - # Specify that certificates are to be passed on - set { - name = "nginx.ingress.kubernetes.io/auth-tls-pass-certificate-to-upstream" - value = true - } - - # Don't request client certificates and don't do client certificate verification - set { - name = "nginx.ingress.kubernetes.io/auth-tls-verify-client" - value = "off" - } wait = local.wait } diff --git a/src/Aguacongas.TheIdServer.Duende/appsettings.json b/src/Aguacongas.TheIdServer.Duende/appsettings.json index 86b371ac0..06e735b21 100644 --- a/src/Aguacongas.TheIdServer.Duende/appsettings.json +++ b/src/Aguacongas.TheIdServer.Duende/appsettings.json @@ -30,7 +30,8 @@ }, "IdentityServerOptions": { "MutualTls": { - "Enabled": true + "Enabled": true, + "PEMHeader": "ssl-client-cert" }, "EnableServerSideSession": true, "ServerSideSessions": { diff --git a/src/Aguacongas.TheIdServer.Shared/Extensions/ApplicationBuilderExtensions.cs b/src/Aguacongas.TheIdServer.Shared/Extensions/ApplicationBuilderExtensions.cs index 488f79cea..a4e04da82 100644 --- a/src/Aguacongas.TheIdServer.Shared/Extensions/ApplicationBuilderExtensions.cs +++ b/src/Aguacongas.TheIdServer.Shared/Extensions/ApplicationBuilderExtensions.cs @@ -13,6 +13,9 @@ using Aguacongas.TheIdServer.Options.OpenTelemetry; #if DUENDE using Duende.IdentityServer.Hosting; +using Duende.IdentityServer.Configuration; +#else +using IdentityServer4.Configuration; #endif using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.AspNetCore.Components.WebAssembly.Authentication; @@ -28,16 +31,19 @@ using Microsoft.Extensions.Diagnostics.HealthChecks; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Options; +using Microsoft.Extensions.Primitives; using Serilog; using System.Collections.Generic; using System.Globalization; using System.IO; using System.Linq; using System.Net; +using System.Security.Cryptography.X509Certificates; using System.Text; using System.Text.Json; using System.Text.Json.Serialization; using System.Threading.Tasks; +using System; namespace Microsoft.AspNetCore.Builder { @@ -118,6 +124,17 @@ public static IApplicationBuilder UseTheIdServer(this IApplicationBuilder app, I }) .UseRouting(); + app.Use((context, next) => + { + var certificateHeader = configuration.GetValue($"{nameof(IdentityServerOptions)}:{nameof(IdentityServerOptions.MutualTls)}:PEMHeader"); + if (!string.IsNullOrEmpty(certificateHeader) && + context.Request.Headers.TryGetValue(certificateHeader, out StringValues values)) + { + context.Connection.ClientCertificate = X509Certificate2.CreateFromPem(Uri.UnescapeDataString(values.First())); + } + return next(); + }); + #if DUENDE app.UseMiddleware() .ConfigureCors(); @@ -132,7 +149,7 @@ public static IApplicationBuilder UseTheIdServer(this IApplicationBuilder app, I if (!isProxy) { - app.UseIdentityServerAdminAuthentication(" /providerhub", JwtBearerDefaults.AuthenticationScheme); + app.UseIdentityServerAdminAuthentication("/providerhub", JwtBearerDefaults.AuthenticationScheme); } app.UseAuthorization() diff --git a/test/Duende/Aguacongas.TheIdServer.Integration.Duende.Test/Aguacongas.TheIdServer.Integration.Duende.Test.csproj b/test/Duende/Aguacongas.TheIdServer.Integration.Duende.Test/Aguacongas.TheIdServer.Integration.Duende.Test.csproj index cb3017e0e..e9dc6c9be 100644 --- a/test/Duende/Aguacongas.TheIdServer.Integration.Duende.Test/Aguacongas.TheIdServer.Integration.Duende.Test.csproj +++ b/test/Duende/Aguacongas.TheIdServer.Integration.Duende.Test/Aguacongas.TheIdServer.Integration.Duende.Test.csproj @@ -83,6 +83,9 @@ Always + + PreserveNewest + diff --git a/test/Duende/Aguacongas.TheIdServer.Integration.Duende.Test/appsettings.json b/test/Duende/Aguacongas.TheIdServer.Integration.Duende.Test/appsettings.json index c6ebd44c0..ef3e2bb81 100644 --- a/test/Duende/Aguacongas.TheIdServer.Integration.Duende.Test/appsettings.json +++ b/test/Duende/Aguacongas.TheIdServer.Integration.Duende.Test/appsettings.json @@ -24,10 +24,14 @@ } }, "IdentityServerOptions": { + "MutualTls": { + "Enabled": true, + "PEMHeader": "ssl-client-cert" + }, "EnableServerSideSession": true, "ServerSideSessions": { "UserDisplayNameClaimType": "name", - "ExpiredSessionsTriggerBackchannelLogout": true + "ExpiredSessionsTriggerBackchannelLogout": true }, "Endpoints": { "EnableJwtRequestUri": false diff --git a/test/Duende/Aguacongas.TheIdServer.Integration.Duende.Test/test.pem b/test/Duende/Aguacongas.TheIdServer.Integration.Duende.Test/test.pem new file mode 100644 index 000000000..177346c15 --- /dev/null +++ b/test/Duende/Aguacongas.TheIdServer.Integration.Duende.Test/test.pem @@ -0,0 +1,12 @@ +-----BEGIN CERTIFICATE----- +MIIBwTCCAUegAwIBAgIQXaDIvEoqig0+NPNA+RC3fTAKBggqhkjOPQQDAzAiMSAw +HgYDVQQDExdjZXJ0LW1hbmFnZXItd2ViaG9vay1jYTAeFw0yMjA0MDQxMzA0MDda +Fw0yMzA0MDQxMzA0MDdaMCIxIDAeBgNVBAMTF2NlcnQtbWFuYWdlci13ZWJob29r +LWNhMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAED92pPSkT9GsE2/d2UWFookvzA8cV +Wu0lcsnXywm3zp1b9XVjCVOYsDi/LbQEektmF0LfmVLrPQr/UOnVRuDo0yYGZ2/d +NuQLvbh1kIHaPEOCCsWnVi85W6C79VH6W56eo0IwQDAOBgNVHQ8BAf8EBAMCAqQw +DwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUR6pr0tyvFI+9/YbAniHgPmXAuIsw +CgYIKoZIzj0EAwMDaAAwZQIwKWHhHqqDNg9hyZLpKfKQpwK8WRzUfmwDjgeT2mbw +l6r6WVq+k6Qgrewtqg3MB5ytAjEA/ESZ5hiXWE1iP8YnxwKJTrh2CXxEKm+f6VMD +Rt9roAyFSvK2KUmsqLH5C0gPUNwL +-----END CERTIFICATE----- diff --git a/test/IS4/Aguacongas.TheIdServer.Integration.IS4.Test/Aguacongas.TheIdServer.Integration.IS4.Test.csproj b/test/IS4/Aguacongas.TheIdServer.Integration.IS4.Test/Aguacongas.TheIdServer.Integration.IS4.Test.csproj index 9a856763f..bab45680a 100644 --- a/test/IS4/Aguacongas.TheIdServer.Integration.IS4.Test/Aguacongas.TheIdServer.Integration.IS4.Test.csproj +++ b/test/IS4/Aguacongas.TheIdServer.Integration.IS4.Test/Aguacongas.TheIdServer.Integration.IS4.Test.csproj @@ -82,6 +82,9 @@ Always + + PreserveNewest + diff --git a/test/IS4/Aguacongas.TheIdServer.Integration.IS4.Test/appsettings.json b/test/IS4/Aguacongas.TheIdServer.Integration.IS4.Test/appsettings.json index 6110b8d0a..f7fef11f0 100644 --- a/test/IS4/Aguacongas.TheIdServer.Integration.IS4.Test/appsettings.json +++ b/test/IS4/Aguacongas.TheIdServer.Integration.IS4.Test/appsettings.json @@ -24,6 +24,10 @@ } }, "IdentityServerOptions": { + "MutualTls": { + "Enabled": true, + "PEMHeader": "ssl-client-cert" + }, "Endpoints": { "EnableJwtRequestUri": true } diff --git a/test/IS4/Aguacongas.TheIdServer.Integration.IS4.Test/test.pem b/test/IS4/Aguacongas.TheIdServer.Integration.IS4.Test/test.pem new file mode 100644 index 000000000..177346c15 --- /dev/null +++ b/test/IS4/Aguacongas.TheIdServer.Integration.IS4.Test/test.pem @@ -0,0 +1,12 @@ +-----BEGIN CERTIFICATE----- +MIIBwTCCAUegAwIBAgIQXaDIvEoqig0+NPNA+RC3fTAKBggqhkjOPQQDAzAiMSAw +HgYDVQQDExdjZXJ0LW1hbmFnZXItd2ViaG9vay1jYTAeFw0yMjA0MDQxMzA0MDda +Fw0yMzA0MDQxMzA0MDdaMCIxIDAeBgNVBAMTF2NlcnQtbWFuYWdlci13ZWJob29r +LWNhMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAED92pPSkT9GsE2/d2UWFookvzA8cV +Wu0lcsnXywm3zp1b9XVjCVOYsDi/LbQEektmF0LfmVLrPQr/UOnVRuDo0yYGZ2/d +NuQLvbh1kIHaPEOCCsWnVi85W6C79VH6W56eo0IwQDAOBgNVHQ8BAf8EBAMCAqQw +DwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUR6pr0tyvFI+9/YbAniHgPmXAuIsw +CgYIKoZIzj0EAwMDaAAwZQIwKWHhHqqDNg9hyZLpKfKQpwK8WRzUfmwDjgeT2mbw +l6r6WVq+k6Qgrewtqg3MB5ytAjEA/ESZ5hiXWE1iP8YnxwKJTrh2CXxEKm+f6VMD +Rt9roAyFSvK2KUmsqLH5C0gPUNwL +-----END CERTIFICATE----- diff --git a/test/Shared/Aguacongas.TheIdServer.IntegrationTest.Shared/StartupTest.cs b/test/Shared/Aguacongas.TheIdServer.IntegrationTest.Shared/StartupTest.cs index b255fdcd4..fef92b5ce 100644 --- a/test/Shared/Aguacongas.TheIdServer.IntegrationTest.Shared/StartupTest.cs +++ b/test/Shared/Aguacongas.TheIdServer.IntegrationTest.Shared/StartupTest.cs @@ -30,11 +30,26 @@ using Microsoft.Extensions.Primitives; using Aguacongas.IdentityServer.Abstractions; using Microsoft.AspNetCore.Identity; +using Aguacongas.TheIdServer.IntegrationTest.BlazorApp; +using System.Net.Http; +using System.Net; namespace Aguacongas.TheIdServer.IntegrationTest { public class ServiceCollectionExtensionsTest { + [Fact] + public async Task Configure_should_add_get_certificate_from_header_middleware() + { + using var factory = new TheIdServerFactory(); + using var client = factory.CreateClient(); + using var request = new HttpRequestMessage(HttpMethod.Get, "/connect"); + request.Headers.Add("ssl-client-cert", Uri.EscapeDataString(File.ReadAllText("test.pem"))); + using var response = await client.SendAsync(request).ConfigureAwait(false); + + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + } + [Fact] public async Task SeedData_should_seed_data() {