From 4a55242ccb87f7ecd73561b2c3e258393163639d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Z=C3=B6ller?= Date: Mon, 1 Dec 2025 11:00:06 +0100 Subject: [PATCH] Fix federation --- .../operaton/fitpub/FitPubApplication.java | 20 ++++++++++++++++++- .../fitpub/service/FederationService.java | 5 +++-- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/operaton/fitpub/FitPubApplication.java b/src/main/java/org/operaton/fitpub/FitPubApplication.java index 54bbee4..8625f6c 100644 --- a/src/main/java/org/operaton/fitpub/FitPubApplication.java +++ b/src/main/java/org/operaton/fitpub/FitPubApplication.java @@ -1,11 +1,16 @@ package org.operaton.fitpub; import lombok.extern.slf4j.Slf4j; +import org.apache.hc.client5.http.classic.HttpClient; +import org.apache.hc.client5.http.impl.classic.HttpClientBuilder; +import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManagerBuilder; +import org.apache.hc.client5.http.io.HttpClientConnectionManager; import org.operaton.fitpub.config.TestcontainersConfiguration; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Import; +import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; import org.springframework.scheduling.annotation.EnableAsync; import org.springframework.web.client.RestTemplate; @@ -28,9 +33,22 @@ public class FitPubApplication { /** * REST template for making HTTP requests to remote ActivityPub servers. + * Configured to not suppress HTTP headers, which is critical for HTTP Signature authentication. */ @Bean public RestTemplate restTemplate() { - return new RestTemplate(); + // Use Apache HttpClient with custom configuration + // This prevents automatic Host header overwriting which breaks HTTP Signatures + HttpClientConnectionManager connectionManager = PoolingHttpClientConnectionManagerBuilder.create() + .build(); + + HttpClient httpClient = HttpClientBuilder.create() + .setConnectionManager(connectionManager) + .disableRedirectHandling() // Don't follow redirects (important for federation) + .build(); + + HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory(httpClient); + + return new RestTemplate(requestFactory); } } diff --git a/src/main/java/org/operaton/fitpub/service/FederationService.java b/src/main/java/org/operaton/fitpub/service/FederationService.java index b8ed2d5..68eadd6 100644 --- a/src/main/java/org/operaton/fitpub/service/FederationService.java +++ b/src/main/java/org/operaton/fitpub/service/FederationService.java @@ -179,8 +179,9 @@ public class FederationService { headers.set("Content-Type", "application/activity+json"); headers.set("Accept", "application/activity+json"); - // Add all signature-related headers - headers.set("Host", signatureHeaders.host); + // Add signature-related headers + // NOTE: We do NOT set the Host header manually - RestTemplate/HttpClient sets it automatically + // The signature was calculated with the correct host from the URL, so it will match headers.set("Date", signatureHeaders.date); headers.set("Digest", signatureHeaders.digest); headers.set("Signature", signatureHeaders.signature);