From 68769537152523fadb4d0ba7a205f2d40244a825 Mon Sep 17 00:00:00 2001 From: Thomas Richner Date: Tue, 15 Oct 2024 17:21:42 +0200 Subject: [PATCH] EPA-153: Refined mTLS usage to only required bits --- .../oviva/ehealthid/relyingparty/Main.java | 53 ++++++++++++++----- 1 file changed, 39 insertions(+), 14 deletions(-) diff --git a/ehealthid-rp/src/main/java/com/oviva/ehealthid/relyingparty/Main.java b/ehealthid-rp/src/main/java/com/oviva/ehealthid/relyingparty/Main.java index b4d41a9..a353cbd 100644 --- a/ehealthid-rp/src/main/java/com/oviva/ehealthid/relyingparty/Main.java +++ b/ehealthid-rp/src/main/java/com/oviva/ehealthid/relyingparty/Main.java @@ -2,6 +2,7 @@ import com.github.benmanes.caffeine.cache.Cache; import com.github.benmanes.caffeine.cache.Caffeine; +import com.nimbusds.jose.jwk.ECKey; import com.nimbusds.jose.jwk.JWKSet; import com.nimbusds.jose.jwk.source.JWKSourceBuilder; import com.oviva.ehealthid.auth.AuthenticationFlow; @@ -51,6 +52,7 @@ import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; +import java.util.regex.Pattern; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -65,6 +67,8 @@ public class Main implements AutoCloseable { \\____/|___/_/|___/\\_,_/ GesundheitsID OpenID Connect Relying-Party """; + private static final Pattern FEDMASTER_TEST_PATTERN = + Pattern.compile("app-(test|ref)\\.federationmaster\\.de"); private static final String CONFIG_PREFIX = "EHEALTHID_RP"; private final ConfigProvider configProvider; @@ -130,20 +134,14 @@ public void start() throws ExecutionException, InterruptedException { var sessionRepo = buildSessionRepo(config.sessionStore(), meterRegistry); // the relying party signing key is for mTLS - var sslContext = TlsContext.fromClientCertificate(config.federation().relyingPartySigningKey()); - - var httpClient = - HttpClient.newBuilder() - .connectTimeout(Duration.ofSeconds(10)) - .sslContext(sslContext) - .build(); + var mTlsClientCertificate = config.federation().relyingPartySigningKey(); var authFlow = buildAuthFlow( config.baseUri(), config.federation().federationMaster(), config.federation().relyingPartyKeys(), - httpClient); + mTlsClientCertificate); var discoveryHttpClient = HttpClient.newBuilder().connectTimeout(Duration.ofSeconds(10)).build(); @@ -229,15 +227,27 @@ private com.oviva.ehealthid.fedclient.api.HttpClient instrumentHttpClient( return client; } + private com.oviva.ehealthid.fedclient.api.HttpClient decorateWithGematikAuthorization( + URI fedmaster, com.oviva.ehealthid.fedclient.api.HttpClient client) { + if (FEDMASTER_TEST_PATTERN.matcher(fedmaster.getHost()).matches()) { + // setup the file `.env.properties` to provide the X-Authorization header for the Gematik + // test environment + // see: https://wiki.gematik.de/display/IDPKB/Fachdienste+Test-Umgebungen + return new GematikHeaderDecoratorHttpClient(client); + } + return client; + } + private AuthenticationFlow buildAuthFlow( - URI selfIssuer, URI fedmaster, JWKSet encJwks, HttpClient httpClient) { + URI selfIssuer, URI fedmaster, JWKSet encJwks, ECKey mTlsClientCert) { + + var timeout = Duration.ofSeconds(10); + + var httpClient = HttpClient.newBuilder().connectTimeout(timeout).build(); var client = instrumentHttpClient(new JavaHttpClient(httpClient)); - // setup the file `.env.properties` to provide the X-Authorization header for the Gematik - // test environment - // see: https://wiki.gematik.de/display/IDPKB/Fachdienste+Test-Umgebungen - var fedHttpClient = new GematikHeaderDecoratorHttpClient(client); + var fedHttpClient = decorateWithGematikAuthorization(fedmaster, client); // setup as needed var clock = Clock.systemUTC(); @@ -251,12 +261,27 @@ private AuthenticationFlow buildAuthFlow( new InMemoryCacheImpl<>(clock, ttl)); var fedmasterClient = new FederationMasterClientImpl(fedmaster, federationApiClient, clock); - var openIdClient = new OpenIdClient(fedHttpClient); + + var openIdClient = buildOpenIdClient(mTlsClientCert, timeout, fedmaster); return new AuthenticationFlow( selfIssuer, fedmasterClient, openIdClient, encJwks::getKeyByKeyId); } + private OpenIdClient buildOpenIdClient(ECKey mTlsClientKey, Duration timeout, URI fedmaster) { + + // the OpenID client needs a self-signed client certificate for mTLS + var context = TlsContext.fromClientCertificate(mTlsClientKey); + + var authenticatedHttpClient = + HttpClient.newBuilder().sslContext(context).connectTimeout(timeout).build(); + + var authenticatedClient = + decorateWithGematikAuthorization( + fedmaster, instrumentHttpClient(new JavaHttpClient(authenticatedHttpClient))); + return new OpenIdClient(authenticatedClient); + } + private SessionRepo buildSessionRepo( SessionStoreConfig config, PrometheusMeterRegistry meterRegistry) { Cache store = buildCache(config.ttl(), config.maxEntries());