diff --git a/auth/README.md b/auth/README.md new file mode 100644 index 00000000..79c5ceeb --- /dev/null +++ b/auth/README.md @@ -0,0 +1 @@ +# Authn/Authz Util diff --git a/auth/compose.yaml b/auth/compose.yaml new file mode 100644 index 00000000..a2fff04b --- /dev/null +++ b/auth/compose.yaml @@ -0,0 +1,23 @@ +name: fts-auth + +services: + keycloak: + image: quay.io/keycloak/keycloak:25.0.6 + command: [ "start-dev" ] + environment: + KEYCLOAK_ADMIN: admin + KEYCLOAK_ADMIN_PASSWORD: admin + ports: + - "8080:8080" + networks: [ "clinical-domain", "research-domain", "trust-center" ] + +networks: + clinical-domain: + external: true + name: fts-test_clinical-domain + research-domain: + external: true + name: fts-test_research-domain + trust-center: + external: true + name: fts-test_trust-center diff --git a/clinical-domain-agent/application-auth:oauth2.yaml b/clinical-domain-agent/application-auth:oauth2.yaml new file mode 100644 index 00000000..87ebc33e --- /dev/null +++ b/clinical-domain-agent/application-auth:oauth2.yaml @@ -0,0 +1,31 @@ +server: + port: 9090 + +projects: + directory: "../.github/test/cd-agent/projects" + +security: + auth: + oauth2: + issuer: http://localhost:8080/realms/master + +spring: + security: + oauth2: + client: + registration: + agent: + authorizationGrantType: client_credentials + clientId: fts/cd-agent + clientSecret: eA4xj1zFxsVYZGdLah9KnkcmHYDBjojr + provider: keycloak + provider: + keycloak: + issuer-uri: http://localhost:8080/realms/master + +test: + webclient: + default: + auth: + oauth2: + registration: agent diff --git a/clinical-domain-agent/src/main/java/care/smith/fts/cda/ClinicalDomainAgent.java b/clinical-domain-agent/src/main/java/care/smith/fts/cda/ClinicalDomainAgent.java index ee8f5bc4..a7b2b846 100644 --- a/clinical-domain-agent/src/main/java/care/smith/fts/cda/ClinicalDomainAgent.java +++ b/clinical-domain-agent/src/main/java/care/smith/fts/cda/ClinicalDomainAgent.java @@ -1,18 +1,10 @@ package care.smith.fts.cda; -import static java.time.Duration.ofSeconds; - -import ca.uhn.fhir.context.FhirContext; -import care.smith.fts.util.CustomErrorHandler; -import care.smith.fts.util.FhirCodecConfiguration; -import care.smith.fts.util.MetricsConfig; -import care.smith.fts.util.WebClientDefaults; -import care.smith.fts.util.auth.HttpServerAuthConfig; +import care.smith.fts.util.AgentConfiguration; import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.dataformat.yaml.YAMLFactory; import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; -import java.net.http.HttpClient; import java.nio.file.Path; import java.nio.file.Paths; import lombok.extern.slf4j.Slf4j; @@ -22,40 +14,17 @@ import org.springframework.boot.context.properties.ConfigurationPropertiesScan; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Import; -import org.springframework.context.annotation.Primary; @Slf4j @SpringBootApplication @ConfigurationPropertiesScan -@Import({ - WebClientDefaults.class, - FhirCodecConfiguration.class, - MetricsConfig.class, - HttpServerAuthConfig.class, - CustomErrorHandler.class, -}) +@Import(AgentConfiguration.class) public class ClinicalDomainAgent { public static void main(String... args) { SpringApplication.run(ClinicalDomainAgent.class, args); } - @Bean - public FhirContext fhirContext() { - return FhirContext.forR4(); - } - - @Bean - public HttpClient httpClient() { - return HttpClient.newBuilder().connectTimeout(ofSeconds(10)).build(); - } - - @Bean - @Primary - public ObjectMapper defaultObjectMapper() { - return new ObjectMapper().registerModule(new JavaTimeModule()); - } - @Bean public ObjectMapper transferProcessObjectMapper() { return new ObjectMapper(new YAMLFactory()) diff --git a/clinical-domain-agent/src/main/java/care/smith/fts/cda/impl/DeidentifhirStepFactory.java b/clinical-domain-agent/src/main/java/care/smith/fts/cda/impl/DeidentifhirStepFactory.java index 221f3d99..51f0ffbe 100644 --- a/clinical-domain-agent/src/main/java/care/smith/fts/cda/impl/DeidentifhirStepFactory.java +++ b/clinical-domain-agent/src/main/java/care/smith/fts/cda/impl/DeidentifhirStepFactory.java @@ -4,22 +4,19 @@ import static java.util.Objects.requireNonNull; import care.smith.fts.api.cda.Deidentificator; +import care.smith.fts.util.HttpClientFactory; import io.micrometer.core.instrument.MeterRegistry; -import org.springframework.boot.autoconfigure.web.reactive.function.client.WebClientSsl; import org.springframework.stereotype.Component; -import org.springframework.web.reactive.function.client.WebClient; @Component("deidentifhirDeidentificator") public class DeidentifhirStepFactory implements Deidentificator.Factory { - private final WebClient.Builder builder; - private final WebClientSsl ssl; + private final HttpClientFactory clientProvider; private final MeterRegistry meterRegistry; public DeidentifhirStepFactory( - WebClient.Builder builder, WebClientSsl ssl, MeterRegistry meterRegistry) { - this.builder = builder; - this.ssl = ssl; + HttpClientFactory clientProvider, MeterRegistry meterRegistry) { + this.clientProvider = clientProvider; this.meterRegistry = meterRegistry; } @@ -31,7 +28,7 @@ public Class getConfigType() { @Override public Deidentificator create( Deidentificator.Config commonConfig, DeidentifhirStepConfig implConfig) { - var httpClient = implConfig.trustCenterAgent().server().createClient(builder, ssl); + var httpClient = clientProvider.createClient(implConfig.trustCenterAgent().server()); return new DeidentifhirStep( httpClient, diff --git a/clinical-domain-agent/src/main/java/care/smith/fts/cda/impl/EverythingDataSelectorFactory.java b/clinical-domain-agent/src/main/java/care/smith/fts/cda/impl/EverythingDataSelectorFactory.java index 4f26d867..609e510c 100644 --- a/clinical-domain-agent/src/main/java/care/smith/fts/cda/impl/EverythingDataSelectorFactory.java +++ b/clinical-domain-agent/src/main/java/care/smith/fts/cda/impl/EverythingDataSelectorFactory.java @@ -2,10 +2,9 @@ import care.smith.fts.api.cda.DataSelector; import care.smith.fts.cda.services.PatientIdResolver; +import care.smith.fts.util.HttpClientFactory; import io.micrometer.core.instrument.MeterRegistry; import org.hl7.fhir.r4.model.IdType; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.autoconfigure.web.reactive.function.client.WebClientSsl; import org.springframework.stereotype.Component; import org.springframework.web.reactive.function.client.WebClient; import reactor.core.publisher.Mono; @@ -14,14 +13,12 @@ public class EverythingDataSelectorFactory implements DataSelector.Factory { - private final WebClient.Builder clientBuilder; - private final WebClientSsl ssl; + private final HttpClientFactory clientProvider; private final MeterRegistry meterRegistry; public EverythingDataSelectorFactory( - WebClient.Builder clientBuilder, WebClientSsl ssl, MeterRegistry meterRegistry) { - this.clientBuilder = clientBuilder; - this.ssl = ssl; + HttpClientFactory clientProvider, MeterRegistry meterRegistry) { + this.clientProvider = clientProvider; this.meterRegistry = meterRegistry; } @@ -32,7 +29,7 @@ public Class getConfigType() { @Override public DataSelector create(DataSelector.Config common, EverythingDataSelectorConfig config) { - var client = config.fhirServer().createClient(clientBuilder, ssl); + var client = clientProvider.createClient(config.fhirServer()); PatientIdResolver resolver = createResolver(config, client); return new EverythingDataSelector(common, client, resolver, meterRegistry); } diff --git a/clinical-domain-agent/src/main/java/care/smith/fts/cda/impl/RDABundleSenderFactory.java b/clinical-domain-agent/src/main/java/care/smith/fts/cda/impl/RDABundleSenderFactory.java index f1d4fcc4..ff08ab16 100644 --- a/clinical-domain-agent/src/main/java/care/smith/fts/cda/impl/RDABundleSenderFactory.java +++ b/clinical-domain-agent/src/main/java/care/smith/fts/cda/impl/RDABundleSenderFactory.java @@ -1,22 +1,18 @@ package care.smith.fts.cda.impl; import care.smith.fts.api.cda.BundleSender; +import care.smith.fts.util.HttpClientFactory; import io.micrometer.core.instrument.MeterRegistry; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.autoconfigure.web.reactive.function.client.WebClientSsl; import org.springframework.stereotype.Component; -import org.springframework.web.reactive.function.client.WebClient; @Component("researchDomainAgentBundleSender") public class RDABundleSenderFactory implements BundleSender.Factory { - private final WebClient.Builder builder; - private final WebClientSsl ssl; + private final HttpClientFactory clientProvider; private final MeterRegistry meterRegistry; - public RDABundleSenderFactory(WebClient.Builder builder, WebClientSsl ssl, MeterRegistry meterRegistry) { - this.builder = builder; - this.ssl = ssl; + public RDABundleSenderFactory(HttpClientFactory clientProvider, MeterRegistry meterRegistry) { + this.clientProvider = clientProvider; this.meterRegistry = meterRegistry; } @@ -28,6 +24,6 @@ public Class getConfigType() { @Override public BundleSender create(BundleSender.Config commonConfig, RDABundleSenderConfig implConfig) { return new RDABundleSender( - implConfig, implConfig.server().createClient(builder, ssl), meterRegistry); + implConfig, clientProvider.createClient(implConfig.server()), meterRegistry); } } diff --git a/clinical-domain-agent/src/main/java/care/smith/fts/cda/impl/TCACohortSelectorFactory.java b/clinical-domain-agent/src/main/java/care/smith/fts/cda/impl/TCACohortSelectorFactory.java index fdc3b159..4a4e1dc3 100644 --- a/clinical-domain-agent/src/main/java/care/smith/fts/cda/impl/TCACohortSelectorFactory.java +++ b/clinical-domain-agent/src/main/java/care/smith/fts/cda/impl/TCACohortSelectorFactory.java @@ -3,26 +3,22 @@ import static java.util.Objects.requireNonNull; import care.smith.fts.api.cda.CohortSelector; +import care.smith.fts.util.HttpClientFactory; import io.micrometer.core.instrument.MeterRegistry; import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.autoconfigure.web.reactive.function.client.WebClientSsl; import org.springframework.stereotype.Component; -import org.springframework.web.reactive.function.client.WebClient; @Slf4j @Component("trustCenterAgentCohortSelector") public class TCACohortSelectorFactory implements CohortSelector.Factory { - private final WebClient.Builder clientBuilder; - private final WebClientSsl ssl; + + private final HttpClientFactory clientProvider; private final MeterRegistry meterRegistry; - public TCACohortSelectorFactory( - WebClient.Builder clientBuilder, WebClientSsl ssl, MeterRegistry meterRegistry) { - this.ssl = ssl; + public TCACohortSelectorFactory(HttpClientFactory clientProvider, MeterRegistry meterRegistry) { + this.clientProvider = clientProvider; this.meterRegistry = meterRegistry; - log.info("Factory client {}", clientBuilder); - this.clientBuilder = requireNonNull(clientBuilder); + log.info("Factory client {}", clientProvider); } @Override @@ -32,7 +28,7 @@ public Class getConfigType() { @Override public CohortSelector create(CohortSelector.Config ignored, TCACohortSelectorConfig config) { - var client = config.server().createClient(clientBuilder, ssl); + var client = clientProvider.createClient(config.server()); log.info("Created Client {}", client); return new TCACohortSelector(config, client, meterRegistry); } diff --git a/clinical-domain-agent/src/main/java/care/smith/fts/cda/rest/TransferProcessController.java b/clinical-domain-agent/src/main/java/care/smith/fts/cda/rest/TransferProcessController.java index 770c81c0..d464e529 100644 --- a/clinical-domain-agent/src/main/java/care/smith/fts/cda/rest/TransferProcessController.java +++ b/clinical-domain-agent/src/main/java/care/smith/fts/cda/rest/TransferProcessController.java @@ -41,7 +41,7 @@ Mono> start( @RequestBody(required = false) List pids) { var process = findProcess(project); if (process.isPresent()) { - log.debug("Running process: {}", process.get()); + log.debug("Running process for project: {}", process.get().project()); var id = processRunner.start(process.get(), Optional.ofNullable(pids).orElse(List.of())); var jobUri = generateJobUri(uriBuilder, id); diff --git a/clinical-domain-agent/src/main/resources/application.yaml b/clinical-domain-agent/src/main/resources/application.yaml index 8b41d293..24f5b5a5 100644 --- a/clinical-domain-agent/src/main/resources/application.yaml +++ b/clinical-domain-agent/src/main/resources/application.yaml @@ -1,3 +1,7 @@ +spring: + mustache: + checkTemplateLocation: false + management: endpoints: web: diff --git a/clinical-domain-agent/src/test/java/care/smith/fts/cda/impl/DeidentifhirStepFactoryTest.java b/clinical-domain-agent/src/test/java/care/smith/fts/cda/impl/DeidentifhirStepFactoryTest.java index a99c5dad..fd53c234 100644 --- a/clinical-domain-agent/src/test/java/care/smith/fts/cda/impl/DeidentifhirStepFactoryTest.java +++ b/clinical-domain-agent/src/test/java/care/smith/fts/cda/impl/DeidentifhirStepFactoryTest.java @@ -6,27 +6,26 @@ import care.smith.fts.api.cda.Deidentificator; import care.smith.fts.cda.impl.DeidentifhirStepConfig.TCAConfig; import care.smith.fts.util.HttpClientConfig; +import care.smith.fts.util.HttpClientFactory; import care.smith.fts.util.tca.TCADomains; import io.micrometer.core.instrument.MeterRegistry; import java.io.File; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.autoconfigure.web.reactive.function.client.WebClientSsl; import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.web.reactive.function.client.WebClient; @SpringBootTest class DeidentifhirStepFactoryTest { @Autowired private MeterRegistry meterRegistry; - @Autowired private WebClientSsl ssl; + @Autowired private HttpClientFactory clientProvider; private DeidentifhirStepFactory factory; @BeforeEach void setUp() { - factory = new DeidentifhirStepFactory(WebClient.builder(), ssl, meterRegistry); + factory = new DeidentifhirStepFactory(clientProvider, meterRegistry); } @Test diff --git a/clinical-domain-agent/src/test/java/care/smith/fts/cda/impl/DeidentifhirStepTest.java b/clinical-domain-agent/src/test/java/care/smith/fts/cda/impl/DeidentifhirStepTest.java index 3165ffed..5c068f8a 100644 --- a/clinical-domain-agent/src/test/java/care/smith/fts/cda/impl/DeidentifhirStepTest.java +++ b/clinical-domain-agent/src/test/java/care/smith/fts/cda/impl/DeidentifhirStepTest.java @@ -1,5 +1,6 @@ package care.smith.fts.cda.impl; +import static care.smith.fts.test.MockServerUtil.clientConfig; import static care.smith.fts.test.TestPatientGenerator.generateOnePatient; import static com.typesafe.config.ConfigFactory.parseResources; import static java.time.Duration.ofDays; @@ -11,8 +12,9 @@ import care.smith.fts.api.ConsentedPatient; import care.smith.fts.api.ConsentedPatientBundle; +import care.smith.fts.cda.ClinicalDomainAgent; import care.smith.fts.cda.services.deidentifhir.DeidentifhirUtils; -import care.smith.fts.test.MockServerUtil; +import care.smith.fts.util.HttpClientFactory; import care.smith.fts.util.tca.TCADomains; import io.micrometer.core.instrument.MeterRegistry; import java.io.IOException; @@ -25,9 +27,8 @@ import org.mockserver.junit.jupiter.MockServerExtension; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.web.reactive.function.client.WebClient; -@SpringBootTest +@SpringBootTest(classes = ClinicalDomainAgent.class) @ExtendWith(MockServerExtension.class) class DeidentifhirStepTest { @@ -35,12 +36,11 @@ class DeidentifhirStepTest { private DeidentifhirStep step; @BeforeEach - void setUp(MockServerClient mockServer) { + void setUp(MockServerClient mockServer, @Autowired HttpClientFactory clientProvider) { var scraperConfig = parseResources(DeidentifhirUtils.class, "IDScraper.profile"); var deidentifhirConfig = parseResources(DeidentifhirUtils.class, "CDtoTransport.profile"); - var server = MockServerUtil.clientConfig(mockServer); var domains = new TCADomains("domain", "domain", "domain"); - var client = server.createClient(WebClient.builder(), null); + var client = clientProvider.createClient(clientConfig(mockServer)); step = new DeidentifhirStep( client, domains, ofDays(14), deidentifhirConfig, scraperConfig, meterRegistry); @@ -100,7 +100,7 @@ void deidentifySucceeds(MockServerClient mockServer) throws IOException { json( """ { - "resarchMappingName": "resarchMappingName", + "transferId": "transferId", "transportMapping": { "id1.identifier.identifierSystem:id1": "tident1", "id1.Patient:id1": "tid1" }, "dateShiftValue": 1209600.000000000 diff --git a/clinical-domain-agent/src/test/java/care/smith/fts/cda/impl/EverythingDataSelectorFactoryTest.java b/clinical-domain-agent/src/test/java/care/smith/fts/cda/impl/EverythingDataSelectorFactoryTest.java index bb7a423c..e900274e 100644 --- a/clinical-domain-agent/src/test/java/care/smith/fts/cda/impl/EverythingDataSelectorFactoryTest.java +++ b/clinical-domain-agent/src/test/java/care/smith/fts/cda/impl/EverythingDataSelectorFactoryTest.java @@ -4,26 +4,24 @@ import care.smith.fts.cda.services.FhirResolveConfig; import care.smith.fts.util.HttpClientConfig; +import care.smith.fts.util.HttpClientFactory; import io.micrometer.core.instrument.MeterRegistry; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.autoconfigure.web.reactive.function.client.WebClientSsl; import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.web.reactive.function.client.WebClient; @SpringBootTest class EverythingDataSelectorFactoryTest { - @Autowired WebClient.Builder client; - @Autowired MeterRegistry meterRegistry; - @Autowired WebClientSsl ssl; + @Autowired private MeterRegistry meterRegistry; + @Autowired private HttpClientFactory clientProvider; private EverythingDataSelectorFactory factory; @BeforeEach void setUp() { - factory = new EverythingDataSelectorFactory(client, ssl, meterRegistry); + factory = new EverythingDataSelectorFactory(clientProvider, meterRegistry); } @Test diff --git a/clinical-domain-agent/src/test/java/care/smith/fts/cda/impl/EverythingDataSelectorTest.java b/clinical-domain-agent/src/test/java/care/smith/fts/cda/impl/EverythingDataSelectorTest.java index ea477d47..a75af71a 100644 --- a/clinical-domain-agent/src/test/java/care/smith/fts/cda/impl/EverythingDataSelectorTest.java +++ b/clinical-domain-agent/src/test/java/care/smith/fts/cda/impl/EverythingDataSelectorTest.java @@ -13,6 +13,7 @@ import care.smith.fts.api.cda.DataSelector; import care.smith.fts.cda.services.PatientIdResolver; import care.smith.fts.util.HttpClientConfig; +import care.smith.fts.util.HttpClientFactory; import io.micrometer.core.instrument.MeterRegistry; import java.io.InputStream; import java.time.ZonedDateTime; @@ -32,6 +33,8 @@ class EverythingDataSelectorTest { @Autowired MeterRegistry meterRegistry; + @Autowired + HttpClientFactory clientProvider; private static final String PATIENT_ID = "patient-112348"; private static final PatientIdResolver patient = pid -> Mono.just(new IdType("Patient", pid)); @@ -43,7 +46,8 @@ class EverythingDataSelectorTest { void noConsentErrors() { var client = builder(); var dataSelector = - new EverythingDataSelector(common, server.createClient(client, null), patient, meterRegistry); + new EverythingDataSelector( + common, clientProvider.createClient(client, server), patient, meterRegistry); create(dataSelector.select(new ConsentedPatient(PATIENT_ID))).expectError().verify(); } @@ -53,22 +57,24 @@ void noConsentSucceedsIfConsentIgnored() { var client = builder().exchangeFunction(req -> Mono.just(ClientResponse.create(OK).build())); DataSelector.Config common = new DataSelector.Config(true, null); var dataSelector = - new EverythingDataSelector(common, server.createClient(client, null), patient, meterRegistry); + new EverythingDataSelector( + common, clientProvider.createClient(client, server), patient, meterRegistry); create(dataSelector.select(new ConsentedPatient(PATIENT_ID))).verifyComplete(); } @Test void selectionSucceeds() throws Exception { - var client = builder().exchangeFunction(req -> just(response)); + given(response.statusCode()).willReturn(OK); try (InputStream inStream = getClass().getResourceAsStream("patient.json")) { var bundle = FhirContext.forR4().newJsonParser().parseResource(Bundle.class, inStream); given(response.bodyToMono(Bundle.class)).willReturn(Mono.just(bundle)); } var dataSelector = - new EverythingDataSelector(common, server.createClient(client, null), patient, meterRegistry); + new EverythingDataSelector( + common, clientProvider.createClient(client, server), patient, meterRegistry); var consentedPolicies = new ConsentedPolicies(); consentedPolicies.put("pol", new Period(ZonedDateTime.now(), ZonedDateTime.now().plusYears(5))); diff --git a/clinical-domain-agent/src/test/java/care/smith/fts/cda/impl/RDABundleSenderFactoryTest.java b/clinical-domain-agent/src/test/java/care/smith/fts/cda/impl/RDABundleSenderFactoryTest.java index 1e02247d..22f60342 100644 --- a/clinical-domain-agent/src/test/java/care/smith/fts/cda/impl/RDABundleSenderFactoryTest.java +++ b/clinical-domain-agent/src/test/java/care/smith/fts/cda/impl/RDABundleSenderFactoryTest.java @@ -3,25 +3,24 @@ import static org.assertj.core.api.Assertions.assertThat; import care.smith.fts.util.HttpClientConfig; +import care.smith.fts.util.HttpClientFactory; import io.micrometer.core.instrument.MeterRegistry; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.autoconfigure.web.reactive.function.client.WebClientSsl; import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.web.reactive.function.client.WebClient; @SpringBootTest class RDABundleSenderFactoryTest { @Autowired MeterRegistry meterRegistry; - @Autowired WebClientSsl ssl; - private final WebClient.Builder clientBuilder = WebClient.builder(); + @Autowired private HttpClientFactory clientProvider; + private RDABundleSenderFactory factory; @BeforeEach void setUp() { - factory = new RDABundleSenderFactory(clientBuilder, ssl, meterRegistry); + factory = new RDABundleSenderFactory(clientProvider, meterRegistry); } @Test diff --git a/clinical-domain-agent/src/test/java/care/smith/fts/cda/impl/RDABundleSenderTest.java b/clinical-domain-agent/src/test/java/care/smith/fts/cda/impl/RDABundleSenderTest.java index 7cf13f9f..c65bd9e3 100644 --- a/clinical-domain-agent/src/test/java/care/smith/fts/cda/impl/RDABundleSenderTest.java +++ b/clinical-domain-agent/src/test/java/care/smith/fts/cda/impl/RDABundleSenderTest.java @@ -1,7 +1,6 @@ package care.smith.fts.cda.impl; import static care.smith.fts.util.FhirUtils.toBundle; -import static care.smith.fts.util.auth.HttpClientAuthMethod.AuthMethod.NONE; import static org.assertj.core.api.Assertions.assertThatExceptionOfType; import static org.mockserver.matchers.Times.once; import static org.mockserver.model.HttpRequest.request; @@ -19,6 +18,7 @@ import care.smith.fts.api.cda.BundleSender; import care.smith.fts.test.MockServerUtil; import care.smith.fts.util.HttpClientConfig; +import care.smith.fts.util.HttpClientFactory; import care.smith.fts.util.error.TransferProcessException; import io.micrometer.core.instrument.MeterRegistry; import java.util.stream.Stream; @@ -45,15 +45,15 @@ class RDABundleSenderTest { private static final String PATIENT_ID = "patient-102931"; private static final ConsentedPatient PATIENT = new ConsentedPatient(PATIENT_ID); - private final HttpClientConfig server = new HttpClientConfig("http://localhost", NONE); + private final HttpClientConfig server = new HttpClientConfig("http://localhost"); private final RDABundleSenderConfig config = new RDABundleSenderConfig(server, "example"); private WebClient client; @BeforeEach - void setUp(MockServerClient mockServer, @Autowired WebClient.Builder builder) { + void setUp(MockServerClient mockServer, @Autowired HttpClientFactory clientProvider) { var server = MockServerUtil.clientConfig(mockServer); - client = server.createClient(builder, null); + client = clientProvider.createClient(server); } @Test diff --git a/clinical-domain-agent/src/test/java/care/smith/fts/cda/impl/TCACohortSelectorFactoryTest.java b/clinical-domain-agent/src/test/java/care/smith/fts/cda/impl/TCACohortSelectorFactoryTest.java index e251f39b..34853b9a 100644 --- a/clinical-domain-agent/src/test/java/care/smith/fts/cda/impl/TCACohortSelectorFactoryTest.java +++ b/clinical-domain-agent/src/test/java/care/smith/fts/cda/impl/TCACohortSelectorFactoryTest.java @@ -3,25 +3,24 @@ import static org.assertj.core.api.Assertions.assertThat; import care.smith.fts.util.HttpClientConfig; +import care.smith.fts.util.HttpClientFactory; import io.micrometer.core.instrument.MeterRegistry; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.autoconfigure.web.reactive.function.client.WebClientSsl; import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.web.reactive.function.client.WebClient; @SpringBootTest class TCACohortSelectorFactoryTest { @Autowired MeterRegistry meterRegistry; - @Autowired WebClient.Builder client; - @Autowired WebClientSsl ssl; + @Autowired private HttpClientFactory clientProvider; + private TCACohortSelectorFactory factory; @BeforeEach void setUp() { - factory = new TCACohortSelectorFactory(client, ssl, meterRegistry); + factory = new TCACohortSelectorFactory(clientProvider, meterRegistry); } @Test diff --git a/clinical-domain-agent/src/test/java/care/smith/fts/cda/impl/TCACohortSelectorTest.java b/clinical-domain-agent/src/test/java/care/smith/fts/cda/impl/TCACohortSelectorTest.java index 031c3722..c6317a88 100644 --- a/clinical-domain-agent/src/test/java/care/smith/fts/cda/impl/TCACohortSelectorTest.java +++ b/clinical-domain-agent/src/test/java/care/smith/fts/cda/impl/TCACohortSelectorTest.java @@ -1,7 +1,6 @@ package care.smith.fts.cda.impl; import static care.smith.fts.util.FhirUtils.toBundle; -import static care.smith.fts.util.auth.HttpClientAuthMethod.AuthMethod.NONE; import static org.mockito.BDDMockito.given; import static org.springframework.http.HttpStatus.BAD_REQUEST; import static org.springframework.http.HttpStatus.OK; @@ -10,6 +9,7 @@ import static reactor.test.StepVerifier.create; import care.smith.fts.util.HttpClientConfig; +import care.smith.fts.util.HttpClientFactory; import io.micrometer.core.instrument.MeterRegistry; import java.util.Date; import java.util.List; @@ -47,13 +47,14 @@ class TCACohortSelectorTest { private TCACohortSelector cohortSelector; @BeforeEach - void setUp() { + void setUp(@Autowired HttpClientFactory clientProvider) { var address = "http://localhost"; - var server = new HttpClientConfig(address, NONE); + var server = new HttpClientConfig(address); var client = builder().exchangeFunction(req -> just(response)); var config = new TCACohortSelectorConfig(server, PID_SYSTEM, POLICY_SYSTEM, POLICIES, "MII"); cohortSelector = - new TCACohortSelector(config, config.server().createClient(client, null), meterRegistry); + new TCACohortSelector( + config, clientProvider.createClient(client, config.server()), meterRegistry); } @Test diff --git a/clinical-domain-agent/src/test/java/care/smith/fts/cda/rest/it/TransferProcessControllerIT.java b/clinical-domain-agent/src/test/java/care/smith/fts/cda/rest/it/TransferProcessControllerIT.java index 0c48b553..7231ed4e 100644 --- a/clinical-domain-agent/src/test/java/care/smith/fts/cda/rest/it/TransferProcessControllerIT.java +++ b/clinical-domain-agent/src/test/java/care/smith/fts/cda/rest/it/TransferProcessControllerIT.java @@ -90,7 +90,7 @@ public class TransferProcessControllerIT extends BaseIT { @BeforeEach void setUp(@LocalServerPort int port, @Autowired TestWebClientFactory factory) { this.port = port; - client = factory.webClient().baseUrl("https://localhost:" + port).build(); + client = factory.webClient("https://localhost:" + port); } @AfterEach diff --git a/clinical-domain-agent/src/test/java/care/smith/fts/cda/services/FhirResolveServiceTest.java b/clinical-domain-agent/src/test/java/care/smith/fts/cda/services/FhirResolveServiceTest.java index ddfddbcf..c897190a 100644 --- a/clinical-domain-agent/src/test/java/care/smith/fts/cda/services/FhirResolveServiceTest.java +++ b/clinical-domain-agent/src/test/java/care/smith/fts/cda/services/FhirResolveServiceTest.java @@ -7,7 +7,9 @@ import static org.mockserver.model.HttpResponse.response; import static reactor.test.StepVerifier.create; +import care.smith.fts.cda.ClinicalDomainAgent; import care.smith.fts.test.MockServerUtil; +import care.smith.fts.util.HttpClientFactory; import io.micrometer.core.instrument.MeterRegistry; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; @@ -18,9 +20,8 @@ import org.mockserver.model.Header; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.web.reactive.function.client.WebClient; -@SpringBootTest +@SpringBootTest(classes = ClinicalDomainAgent.class) @ExtendWith(MockServerExtension.class) class FhirResolveServiceTest { @@ -28,14 +29,13 @@ class FhirResolveServiceTest { private static final Header CONTENT_JSON = new Header("Content-Type", "application/json"); private static final String KDS_PATIENT = "https://some.example.com/pid"; - @Autowired WebClient.Builder builder; @Autowired MeterRegistry meterRegistry; private FhirResolveService service; @BeforeEach - void setUp(MockServerClient mockServer) throws Exception { - var client = clientConfig(mockServer).createClient(builder, null); + void setUp(MockServerClient mockServer, @Autowired HttpClientFactory configurer) throws Exception { + var client = configurer.createClient(clientConfig(mockServer)); this.service = new FhirResolveService(KDS_PATIENT, client, meterRegistry); try (var inStream = MockServerUtil.getResourceAsStream("metadata.json")) { var capStatement = requireNonNull(inStream).readAllBytes(); diff --git a/research-domain-agent/src/main/java/care/smith/fts/rda/ResearchDomainAgent.java b/research-domain-agent/src/main/java/care/smith/fts/rda/ResearchDomainAgent.java index 79662bfc..3524a3a4 100644 --- a/research-domain-agent/src/main/java/care/smith/fts/rda/ResearchDomainAgent.java +++ b/research-domain-agent/src/main/java/care/smith/fts/rda/ResearchDomainAgent.java @@ -1,18 +1,10 @@ package care.smith.fts.rda; -import static java.time.Duration.ofSeconds; - -import ca.uhn.fhir.context.FhirContext; -import care.smith.fts.util.CustomErrorHandler; -import care.smith.fts.util.FhirCodecConfiguration; -import care.smith.fts.util.MetricsConfig; -import care.smith.fts.util.WebClientDefaults; -import care.smith.fts.util.auth.HttpServerAuthConfig; +import care.smith.fts.util.AgentConfiguration; import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.dataformat.yaml.YAMLFactory; import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; -import java.net.http.HttpClient; import java.nio.file.Path; import java.nio.file.Paths; import lombok.extern.slf4j.Slf4j; @@ -22,40 +14,17 @@ import org.springframework.boot.context.properties.ConfigurationPropertiesScan; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Import; -import org.springframework.context.annotation.Primary; @Slf4j @SpringBootApplication @ConfigurationPropertiesScan -@Import({ - WebClientDefaults.class, - FhirCodecConfiguration.class, - MetricsConfig.class, - HttpServerAuthConfig.class, - CustomErrorHandler.class, -}) +@Import(AgentConfiguration.class) public class ResearchDomainAgent { public static void main(String... args) { SpringApplication.run(ResearchDomainAgent.class, args); } - @Bean - public FhirContext fhirContext() { - return FhirContext.forR4(); - } - - @Bean - public HttpClient httpClient() { - return HttpClient.newBuilder().connectTimeout(ofSeconds(10)).build(); - } - - @Bean - @Primary - public ObjectMapper defaultObjectMapper() { - return new ObjectMapper().registerModule(new JavaTimeModule()); - } - @Bean public ObjectMapper transferProcessObjectMapper() { return new ObjectMapper(new YAMLFactory()) diff --git a/research-domain-agent/src/main/java/care/smith/fts/rda/impl/DeidentifhirStepFactory.java b/research-domain-agent/src/main/java/care/smith/fts/rda/impl/DeidentifhirStepFactory.java index ac473a0b..bb74e6a3 100644 --- a/research-domain-agent/src/main/java/care/smith/fts/rda/impl/DeidentifhirStepFactory.java +++ b/research-domain-agent/src/main/java/care/smith/fts/rda/impl/DeidentifhirStepFactory.java @@ -3,23 +3,20 @@ import static java.util.Objects.requireNonNull; import care.smith.fts.api.rda.Deidentificator; +import care.smith.fts.util.HttpClientFactory; import com.typesafe.config.ConfigFactory; import io.micrometer.core.instrument.MeterRegistry; -import org.springframework.boot.autoconfigure.web.reactive.function.client.WebClientSsl; import org.springframework.stereotype.Component; -import org.springframework.web.reactive.function.client.WebClient; @Component("deidentifhirDeidentificator") public class DeidentifhirStepFactory implements Deidentificator.Factory { - private final WebClient.Builder builder; - private final WebClientSsl ssl; + private final HttpClientFactory clientProvider; private final MeterRegistry meterRegistry; public DeidentifhirStepFactory( - WebClient.Builder builder, WebClientSsl ssl, MeterRegistry meterRegistry) { - this.builder = builder; - this.ssl = ssl; + HttpClientFactory clientProvider, MeterRegistry meterRegistry) { + this.clientProvider = clientProvider; this.meterRegistry = meterRegistry; } @@ -32,7 +29,7 @@ public Class getConfigType() { public Deidentificator create( Deidentificator.Config commonConfig, DeidentifhirStepConfig implConfig) { - var httpClient = implConfig.trustCenterAgent().server().createClient(builder, ssl); + var httpClient = clientProvider.createClient(implConfig.trustCenterAgent().server()); var config = ConfigFactory.parseFile(requireNonNull(implConfig.deidentifhirConfig())); return new DeidentifhirStep(config, httpClient, meterRegistry); } diff --git a/research-domain-agent/src/main/java/care/smith/fts/rda/impl/FhirStoreBundleSenderFactory.java b/research-domain-agent/src/main/java/care/smith/fts/rda/impl/FhirStoreBundleSenderFactory.java index 06f56d67..ceeed819 100644 --- a/research-domain-agent/src/main/java/care/smith/fts/rda/impl/FhirStoreBundleSenderFactory.java +++ b/research-domain-agent/src/main/java/care/smith/fts/rda/impl/FhirStoreBundleSenderFactory.java @@ -1,23 +1,20 @@ package care.smith.fts.rda.impl; import care.smith.fts.api.rda.BundleSender; +import care.smith.fts.util.HttpClientFactory; import io.micrometer.core.instrument.MeterRegistry; -import org.springframework.boot.autoconfigure.web.reactive.function.client.WebClientSsl; import org.springframework.stereotype.Component; -import org.springframework.web.reactive.function.client.WebClient; @Component("fhirStoreBundleSender") public class FhirStoreBundleSenderFactory implements BundleSender.Factory { - private final WebClient.Builder builder; - private final WebClientSsl ssl; private final MeterRegistry meterRegistry; + private final HttpClientFactory clientProvider; public FhirStoreBundleSenderFactory( - WebClient.Builder builder, WebClientSsl ssl, MeterRegistry meterRegistry) { - this.builder = builder; - this.ssl = ssl; + HttpClientFactory clientProvider, MeterRegistry meterRegistry) { + this.clientProvider = clientProvider; this.meterRegistry = meterRegistry; } @@ -29,6 +26,7 @@ public Class getConfigType() { @Override public BundleSender create( BundleSender.Config commonConfig, FhirStoreBundleSenderConfig implConfig) { - return new FhirStoreBundleSender(implConfig.server().createClient(builder, ssl), meterRegistry); + var client = clientProvider.createClient(implConfig.server()); + return new FhirStoreBundleSender(client, meterRegistry); } } diff --git a/research-domain-agent/src/main/resources/application.yaml b/research-domain-agent/src/main/resources/application.yaml index 8720adb9..c7757bc3 100644 --- a/research-domain-agent/src/main/resources/application.yaml +++ b/research-domain-agent/src/main/resources/application.yaml @@ -1,3 +1,7 @@ +spring: + mustache: + checkTemplateLocation: false + management: endpoints: web: diff --git a/research-domain-agent/src/test/java/care/smith/fts/rda/impl/DeidentifhirStepFactoryTest.java b/research-domain-agent/src/test/java/care/smith/fts/rda/impl/DeidentifhirStepFactoryTest.java index b2b9907d..d6bf5202 100644 --- a/research-domain-agent/src/test/java/care/smith/fts/rda/impl/DeidentifhirStepFactoryTest.java +++ b/research-domain-agent/src/test/java/care/smith/fts/rda/impl/DeidentifhirStepFactoryTest.java @@ -6,25 +6,23 @@ import care.smith.fts.api.rda.Deidentificator; import care.smith.fts.rda.impl.DeidentifhirStepConfig.TCAConfig; import care.smith.fts.util.HttpClientConfig; +import care.smith.fts.util.HttpClientFactory; import io.micrometer.core.instrument.MeterRegistry; import java.io.File; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.autoconfigure.web.reactive.function.client.WebClientSsl; import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.web.reactive.function.client.WebClient; @SpringBootTest class DeidentifhirStepFactoryTest { @Autowired MeterRegistry meterRegistry; - @Autowired WebClientSsl ssl; private DeidentifhirStepFactory factory; @BeforeEach - void setUp() { - factory = new DeidentifhirStepFactory(WebClient.builder(), ssl, meterRegistry); + void setUp(@Autowired HttpClientFactory clientProvider) { + factory = new DeidentifhirStepFactory(clientProvider, meterRegistry); } @Test diff --git a/research-domain-agent/src/test/java/care/smith/fts/rda/impl/DeidentifhirStepTest.java b/research-domain-agent/src/test/java/care/smith/fts/rda/impl/DeidentifhirStepTest.java index 807656d8..c812b693 100644 --- a/research-domain-agent/src/test/java/care/smith/fts/rda/impl/DeidentifhirStepTest.java +++ b/research-domain-agent/src/test/java/care/smith/fts/rda/impl/DeidentifhirStepTest.java @@ -1,5 +1,6 @@ package care.smith.fts.rda.impl; +import static care.smith.fts.test.MockServerUtil.clientConfig; import static care.smith.fts.test.TestPatientGenerator.generateOnePatient; import static com.typesafe.config.ConfigFactory.parseResources; import static org.assertj.core.api.Assertions.assertThat; @@ -10,8 +11,7 @@ import care.smith.fts.api.TransportBundle; import care.smith.fts.rda.services.deidentifhir.DeidentifhirUtil; -import care.smith.fts.test.MockServerUtil; -import com.typesafe.config.Config; +import care.smith.fts.util.HttpClientFactory; import io.micrometer.core.instrument.MeterRegistry; import java.io.IOException; import org.hl7.fhir.r4.model.Bundle; @@ -24,7 +24,6 @@ import org.mockserver.junit.jupiter.MockServerExtension; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.web.reactive.function.client.WebClient; @SpringBootTest @ExtendWith(MockServerExtension.class) @@ -33,12 +32,10 @@ class DeidentifhirStepTest { private DeidentifhirStep step; @BeforeEach - void setUp(MockServerClient mockServer) { - Config config = parseResources(DeidentifhirUtil.class, "TransportToRD.profile"); - var server = MockServerUtil.clientConfig(mockServer); - - step = - new DeidentifhirStep(config, server.createClient(WebClient.builder(), null), meterRegistry); + void setUp(MockServerClient mockServer, @Autowired HttpClientFactory clientProvider) { + var config = parseResources(DeidentifhirUtil.class, "TransportToRD.profile"); + var client = clientProvider.createClient(clientConfig(mockServer)); + step = new DeidentifhirStep(config, client, meterRegistry); } @AfterEach diff --git a/research-domain-agent/src/test/java/care/smith/fts/rda/impl/FhirStoreBundleSenderFactoryTest.java b/research-domain-agent/src/test/java/care/smith/fts/rda/impl/FhirStoreBundleSenderFactoryTest.java index e5a08376..60c4323b 100644 --- a/research-domain-agent/src/test/java/care/smith/fts/rda/impl/FhirStoreBundleSenderFactoryTest.java +++ b/research-domain-agent/src/test/java/care/smith/fts/rda/impl/FhirStoreBundleSenderFactoryTest.java @@ -3,26 +3,25 @@ import static org.assertj.core.api.Assertions.assertThat; import care.smith.fts.util.HttpClientConfig; +import care.smith.fts.util.HttpClientFactory; import io.micrometer.core.instrument.MeterRegistry; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.autoconfigure.web.reactive.function.client.WebClientSsl; import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.web.reactive.function.client.WebClient; @SpringBootTest class FhirStoreBundleSenderFactoryTest { @Autowired MeterRegistry meterRegistry; - @Autowired WebClientSsl ssl; + @Autowired + HttpClientFactory clientProvider; - private final WebClient.Builder clientBuilder = WebClient.builder(); private FhirStoreBundleSenderFactory factory; @BeforeEach void setUp() { - factory = new FhirStoreBundleSenderFactory(clientBuilder, ssl, meterRegistry); + factory = new FhirStoreBundleSenderFactory(clientProvider, meterRegistry); } @Test diff --git a/research-domain-agent/src/test/java/care/smith/fts/rda/impl/FhirStoreBundleSenderTest.java b/research-domain-agent/src/test/java/care/smith/fts/rda/impl/FhirStoreBundleSenderTest.java index 0edf74a9..f78948b1 100644 --- a/research-domain-agent/src/test/java/care/smith/fts/rda/impl/FhirStoreBundleSenderTest.java +++ b/research-domain-agent/src/test/java/care/smith/fts/rda/impl/FhirStoreBundleSenderTest.java @@ -1,5 +1,6 @@ package care.smith.fts.rda.impl; +import static care.smith.fts.test.MockServerUtil.clientConfig; import static care.smith.fts.util.MediaTypes.APPLICATION_FHIR_JSON; import static org.mockserver.model.HttpRequest.request; import static org.mockserver.model.HttpResponse.response; @@ -8,7 +9,7 @@ import static reactor.test.StepVerifier.create; import care.smith.fts.api.rda.BundleSender; -import care.smith.fts.test.MockServerUtil; +import care.smith.fts.util.HttpClientFactory; import io.micrometer.core.instrument.MeterRegistry; import org.hl7.fhir.r4.model.Bundle; import org.junit.jupiter.api.AfterEach; @@ -19,10 +20,8 @@ import org.mockserver.junit.jupiter.MockServerExtension; import org.mockserver.model.MediaType; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.autoconfigure.web.reactive.function.client.WebClientSsl; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.web.reactive.function.client.WebClient; -import org.springframework.web.reactive.function.client.WebClient.Builder; @SpringBootTest @ExtendWith(MockServerExtension.class) @@ -32,9 +31,8 @@ class FhirStoreBundleSenderTest { private WebClient client; @BeforeEach - void setUp(MockServerClient mockServer, @Autowired Builder builder) { - var server = MockServerUtil.clientConfig(mockServer); - client = server.createClient(builder, null); + void setUp(MockServerClient mockServer, @Autowired HttpClientFactory clientProvider) { + client = clientProvider.createClient(clientConfig(mockServer)); } @Test diff --git a/research-domain-agent/src/test/java/care/smith/fts/rda/rest/it/TransferProcessControllerIT.java b/research-domain-agent/src/test/java/care/smith/fts/rda/rest/it/TransferProcessControllerIT.java index 8036e57d..df3804f8 100644 --- a/research-domain-agent/src/test/java/care/smith/fts/rda/rest/it/TransferProcessControllerIT.java +++ b/research-domain-agent/src/test/java/care/smith/fts/rda/rest/it/TransferProcessControllerIT.java @@ -62,7 +62,7 @@ public class TransferProcessControllerIT extends BaseIT { @BeforeEach void setUp(@LocalServerPort int port, @Autowired TestWebClientFactory factory) { this.port = port; - client = factory.webClient().baseUrl("https://localhost:" + port).build(); + client = factory.webClient("https://localhost:" + port); } @AfterEach diff --git a/research-domain-agent/src/test/java/care/smith/fts/rda/rest/it/mock/MockDeidentifier.java b/research-domain-agent/src/test/java/care/smith/fts/rda/rest/it/mock/MockDeidentifier.java index 64d429e3..b405ab85 100644 --- a/research-domain-agent/src/test/java/care/smith/fts/rda/rest/it/mock/MockDeidentifier.java +++ b/research-domain-agent/src/test/java/care/smith/fts/rda/rest/it/mock/MockDeidentifier.java @@ -6,6 +6,7 @@ import static org.mockserver.model.MediaType.APPLICATION_JSON; import care.smith.fts.util.tca.ResearchMappingResponse; +import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; import java.time.Duration; import java.util.LinkedList; @@ -41,7 +42,7 @@ public void success(List statusCodes) { .withContentType(APPLICATION_JSON)) .respond( request -> { - var tidPidMap = om.readValue(getTidPidMapAsJson(), Map.class); + var tidPidMap = om.readValue(getTidPidMapAsJson(), new TypeReference>() {}); var resolveResponse = new ResearchMappingResponse(tidPidMap, Duration.ofMillis(12345)); var body = om.writeValueAsString(resolveResponse); return Optional.ofNullable(rs.poll()) diff --git a/test-util/src/main/java/care/smith/fts/test/MockServerUtil.java b/test-util/src/main/java/care/smith/fts/test/MockServerUtil.java index 4080e120..42dd763f 100644 --- a/test-util/src/main/java/care/smith/fts/test/MockServerUtil.java +++ b/test-util/src/main/java/care/smith/fts/test/MockServerUtil.java @@ -1,6 +1,5 @@ package care.smith.fts.test; -import static care.smith.fts.util.auth.HttpClientAuthMethod.AuthMethod.NONE; import static org.mockserver.integration.ClientAndServer.startClientAndServer; import static org.mockserver.model.MediaType.create; @@ -18,7 +17,7 @@ public interface MockServerUtil { static HttpClientConfig clientConfig(MockServerClient server) { var address = "http://localhost:%d".formatted(server.getPort()); - return new HttpClientConfig(address, NONE); + return new HttpClientConfig(address); } static InputStream getResourceAsStream(String resourceName) { diff --git a/test-util/src/main/java/care/smith/fts/test/TestWebClientConfig.java b/test-util/src/main/java/care/smith/fts/test/TestWebClientConfig.java index 95caeff5..7d44db61 100644 --- a/test-util/src/main/java/care/smith/fts/test/TestWebClientConfig.java +++ b/test-util/src/main/java/care/smith/fts/test/TestWebClientConfig.java @@ -3,50 +3,33 @@ import static java.util.Optional.ofNullable; import care.smith.fts.util.HttpClientConfig; -import care.smith.fts.util.auth.HttpClientAuthMethod; +import care.smith.fts.util.HttpClientFactory; +import care.smith.fts.util.auth.HttpClientAuth.Config; import java.util.Map; import java.util.Optional; import lombok.Setter; import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.autoconfigure.web.reactive.function.client.WebClientSsl; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.test.context.TestConfiguration; -import org.springframework.web.reactive.function.client.WebClient; -import org.springframework.web.reactive.function.client.WebClient.Builder; +import org.springframework.context.annotation.Import; @Slf4j @TestConfiguration @ConfigurationProperties("test") +@Import(HttpClientFactory.class) @Setter public class TestWebClientConfig { private Map webclient; - private final WebClientSsl ssl; - - @Autowired - public TestWebClientConfig(WebClientSsl ssl) { - this.ssl = ssl; - } - @Override public String toString() { return "TestWebClientConfig{" + "webclient='" + webclient + '\'' + '}'; } - public void customize(WebClient.Builder base, String clientName) { - findConfigurationEntry(clientName).ifPresent(e -> e.customize(base, ssl)); - } - - private Optional findConfigurationEntry(String clientName) { + public Optional findConfigurationEntry(String clientName) { return ofNullable(webclient).flatMap(m -> ofNullable(m.get(clientName))); } - record Entry(HttpClientAuthMethod.AuthMethod auth, HttpClientConfig.Ssl ssl) { - public void customize(Builder base, WebClientSsl wCSsl) { - base.apply(b -> ofNullable(auth).ifPresent(a -> a.customize(b))) - .apply(wCSsl.fromBundle(ssl.bundle())); - } - } + public record Entry(Config auth, HttpClientConfig.Ssl ssl) {} } diff --git a/test-util/src/main/java/care/smith/fts/test/TestWebClientFactory.java b/test-util/src/main/java/care/smith/fts/test/TestWebClientFactory.java index 2092f10d..746e18f1 100644 --- a/test-util/src/main/java/care/smith/fts/test/TestWebClientFactory.java +++ b/test-util/src/main/java/care/smith/fts/test/TestWebClientFactory.java @@ -1,5 +1,7 @@ package care.smith.fts.test; +import care.smith.fts.util.HttpClientFactory; +import care.smith.fts.util.HttpClientConfig; import lombok.extern.slf4j.Slf4j; import org.springframework.boot.autoconfigure.ssl.SslAutoConfiguration; import org.springframework.boot.autoconfigure.web.reactive.function.client.ClientHttpConnectorAutoConfiguration; @@ -19,21 +21,22 @@ public class TestWebClientFactory { private final TestWebClientConfig config; - private final WebClient.Builder base; + private final HttpClientFactory clientProvider; - public TestWebClientFactory(TestWebClientConfig config, WebClient.Builder base) { + public TestWebClientFactory(TestWebClientConfig config, HttpClientFactory clientProvider) { this.config = config; - this.base = base; + this.clientProvider = clientProvider; log.info("TestWebClientFactory {}", config); } - public WebClient.Builder webClient() { - return webClient("default"); + public WebClient webClient(String baseUrl) { + return webClient(baseUrl, "default"); } - public WebClient.Builder webClient(String clientName) { - var builder = base.clone(); - config.customize(builder, clientName); - return builder; + public WebClient webClient(String baseUrl, String clientName) { + return config + .findConfigurationEntry(clientName) + .map(c -> clientProvider.createClient(new HttpClientConfig(baseUrl, c.auth(), c.ssl()))) + .orElseThrow(); } } diff --git a/trust-center-agent/src/main/java/care/smith/fts/tca/TrustCenterAgent.java b/trust-center-agent/src/main/java/care/smith/fts/tca/TrustCenterAgent.java index dc3d5921..ea33a92b 100644 --- a/trust-center-agent/src/main/java/care/smith/fts/tca/TrustCenterAgent.java +++ b/trust-center-agent/src/main/java/care/smith/fts/tca/TrustCenterAgent.java @@ -1,53 +1,19 @@ package care.smith.fts.tca; -import static java.time.Duration.ofSeconds; - -import ca.uhn.fhir.context.FhirContext; -import care.smith.fts.util.CustomErrorHandler; -import care.smith.fts.util.FhirCodecConfiguration; -import care.smith.fts.util.MetricsConfig; -import care.smith.fts.util.WebClientDefaults; -import care.smith.fts.util.auth.HttpServerAuthConfig; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; -import java.net.http.HttpClient; +import care.smith.fts.util.AgentConfiguration; import lombok.extern.slf4j.Slf4j; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.context.properties.ConfigurationPropertiesScan; -import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Import; -import org.springframework.context.annotation.Primary; @Slf4j @SpringBootApplication @ConfigurationPropertiesScan -@Import({ - WebClientDefaults.class, - FhirCodecConfiguration.class, - MetricsConfig.class, - HttpServerAuthConfig.class, - CustomErrorHandler.class, -}) +@Import(AgentConfiguration.class) public class TrustCenterAgent { public static void main(String... args) { SpringApplication.run(TrustCenterAgent.class, args); } - - @Bean - public FhirContext fhirContext() { - return FhirContext.forR4(); - } - - @Bean - public HttpClient httpClient() { - return HttpClient.newBuilder().connectTimeout(ofSeconds(10)).build(); - } - - @Bean - @Primary - public ObjectMapper defaultObjectMapper() { - return new ObjectMapper().registerModule(new JavaTimeModule()); - } } diff --git a/trust-center-agent/src/main/java/care/smith/fts/tca/consent/configuration/GicsFhirConfiguration.java b/trust-center-agent/src/main/java/care/smith/fts/tca/consent/configuration/GicsFhirConfiguration.java index 06eb188e..1c7aa7d7 100644 --- a/trust-center-agent/src/main/java/care/smith/fts/tca/consent/configuration/GicsFhirConfiguration.java +++ b/trust-center-agent/src/main/java/care/smith/fts/tca/consent/configuration/GicsFhirConfiguration.java @@ -2,25 +2,24 @@ import care.smith.fts.tca.consent.FhirConsentedPatientsProvider; import care.smith.fts.util.HttpClientConfig; -import care.smith.fts.util.auth.HttpClientAuthMethod; +import care.smith.fts.util.HttpClientFactory; +import care.smith.fts.util.auth.HttpClientAuth; import io.micrometer.core.instrument.MeterRegistry; import jakarta.validation.constraints.NotBlank; -import jakarta.validation.constraints.NotNull; import lombok.Data; -import org.springframework.boot.autoconfigure.web.reactive.function.client.WebClientSsl; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.reactive.function.client.WebClient; -import org.springframework.web.reactive.function.client.WebClient.Builder; @Configuration @ConfigurationProperties(prefix = "consent.gics.fhir") @Data public class GicsFhirConfiguration { - @NotBlank String baseUrl; - int defaultPageSize = 50; - @NotNull HttpClientAuthMethod.AuthMethod auth = HttpClientAuthMethod.AuthMethod.NONE; + private @NotBlank String baseUrl; + private HttpClientAuth.Config auth; + private HttpClientConfig.Ssl ssl; + private int defaultPageSize = 50; @Bean int defaultPageSize() { @@ -28,16 +27,16 @@ int defaultPageSize() { } @Bean("gicsFhirHttpClient") - public WebClient httpClient(WebClient.Builder builder, WebClientSsl ssl) { - HttpClientConfig httpClientConfig = new HttpClientConfig(baseUrl, auth); - return httpClientConfig.createClient(builder, ssl); + public WebClient httpClient(HttpClientFactory clientProvider) { + var config = new HttpClientConfig(baseUrl, auth, ssl); + return clientProvider.createClient(config); } @Bean FhirConsentedPatientsProvider fhirConsentedPatientsProvider( - Builder builder, MeterRegistry meterRegistry, WebClientSsl ssl) { - HttpClientConfig httpClientConfig = new HttpClientConfig(baseUrl, auth); - var client = httpClientConfig.createClient(builder, ssl); + HttpClientFactory clientProvider, MeterRegistry meterRegistry) { + var config = new HttpClientConfig(baseUrl, auth, ssl); + var client = clientProvider.createClient(config); return new FhirConsentedPatientsProvider(client, meterRegistry); } } diff --git a/trust-center-agent/src/main/java/care/smith/fts/tca/deidentification/configuration/DeIdentificationConfiguration.java b/trust-center-agent/src/main/java/care/smith/fts/tca/deidentification/configuration/DeIdentificationConfiguration.java index 4130d7d3..7ae7f894 100644 --- a/trust-center-agent/src/main/java/care/smith/fts/tca/deidentification/configuration/DeIdentificationConfiguration.java +++ b/trust-center-agent/src/main/java/care/smith/fts/tca/deidentification/configuration/DeIdentificationConfiguration.java @@ -2,6 +2,8 @@ import jakarta.validation.constraints.NotBlank; import lombok.Data; +import lombok.Getter; +import lombok.Setter; import lombok.extern.slf4j.Slf4j; import org.redisson.Redisson; import org.redisson.api.RedissonClient; @@ -15,7 +17,7 @@ @ConfigurationProperties("de-identification") @Data public class DeIdentificationConfiguration { - @NotBlank String keystoreUrl; + private @NotBlank String keystoreUrl; @Bean public RedissonClient redisClient() { diff --git a/trust-center-agent/src/main/java/care/smith/fts/tca/deidentification/configuration/GpasFhirDeIdentificationConfiguration.java b/trust-center-agent/src/main/java/care/smith/fts/tca/deidentification/configuration/GpasFhirDeIdentificationConfiguration.java index 5eca338a..9dfd05bb 100644 --- a/trust-center-agent/src/main/java/care/smith/fts/tca/deidentification/configuration/GpasFhirDeIdentificationConfiguration.java +++ b/trust-center-agent/src/main/java/care/smith/fts/tca/deidentification/configuration/GpasFhirDeIdentificationConfiguration.java @@ -1,14 +1,13 @@ package care.smith.fts.tca.deidentification.configuration; import care.smith.fts.util.HttpClientConfig; -import care.smith.fts.util.auth.HttpClientAuthMethod; +import care.smith.fts.util.HttpClientFactory; +import care.smith.fts.util.auth.HttpClientAuth; import com.fasterxml.jackson.databind.ObjectMapper; import jakarta.validation.constraints.NotBlank; -import jakarta.validation.constraints.NotNull; import java.security.SecureRandom; import java.util.random.RandomGenerator; import lombok.Data; -import org.springframework.boot.autoconfigure.web.reactive.function.client.WebClientSsl; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -18,8 +17,9 @@ @ConfigurationProperties(prefix = "de-identification.gpas.fhir") @Data public class GpasFhirDeIdentificationConfiguration { - @NotBlank String baseUrl; - @NotNull HttpClientAuthMethod.AuthMethod auth = HttpClientAuthMethod.AuthMethod.NONE; + private @NotBlank String baseUrl; + private HttpClientAuth.Config auth; + private HttpClientConfig.Ssl ssl; @Bean public ObjectMapper objectMapper() { @@ -27,9 +27,8 @@ public ObjectMapper objectMapper() { } @Bean("gpasFhirHttpClient") - public WebClient httpClient(WebClient.Builder builder, WebClientSsl ssl) { - HttpClientConfig httpClientConfig = new HttpClientConfig(baseUrl, auth); - return httpClientConfig.createClient(builder, ssl); + public WebClient httpClient(HttpClientFactory clientProvider) { + return clientProvider.createClient(new HttpClientConfig(baseUrl, auth, ssl)); } @Bean diff --git a/trust-center-agent/src/main/resources/application.yaml b/trust-center-agent/src/main/resources/application.yaml index 8d0e8d36..9d8faf8e 100644 --- a/trust-center-agent/src/main/resources/application.yaml +++ b/trust-center-agent/src/main/resources/application.yaml @@ -1,3 +1,7 @@ +spring: + mustache: + checkTemplateLocation: false + management: endpoints: web: diff --git a/trust-center-agent/src/test/java/care/smith/fts/tca/consent/FhirConsentedPatientsProviderFetchAllTest.java b/trust-center-agent/src/test/java/care/smith/fts/tca/consent/FhirConsentedPatientsProviderFetchAllTest.java index 9608e106..cc610371 100644 --- a/trust-center-agent/src/test/java/care/smith/fts/tca/consent/FhirConsentedPatientsProviderFetchAllTest.java +++ b/trust-center-agent/src/test/java/care/smith/fts/tca/consent/FhirConsentedPatientsProviderFetchAllTest.java @@ -43,6 +43,7 @@ import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.context.annotation.Import; +import org.springframework.test.context.bean.override.mockito.MockitoBean; import org.springframework.web.reactive.function.client.WebClient; @Slf4j @@ -53,7 +54,7 @@ class FhirConsentedPatientsProviderFetchAllTest { @Autowired WebClient.Builder httpClientBuilder; @Autowired MeterRegistry meterRegistry; - @MockBean + @MockitoBean RedissonClient redisClient; // We need to mock the redisClient otherwise the tests won't start private static final String POLICY_SYSTEM = diff --git a/trust-center-agent/src/test/java/care/smith/fts/tca/consent/FhirConsentedPatientsProviderFetchTest.java b/trust-center-agent/src/test/java/care/smith/fts/tca/consent/FhirConsentedPatientsProviderFetchTest.java index 768cb3f2..81e73a89 100644 --- a/trust-center-agent/src/test/java/care/smith/fts/tca/consent/FhirConsentedPatientsProviderFetchTest.java +++ b/trust-center-agent/src/test/java/care/smith/fts/tca/consent/FhirConsentedPatientsProviderFetchTest.java @@ -42,6 +42,7 @@ import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.context.annotation.Import; +import org.springframework.test.context.bean.override.mockito.MockitoBean; import org.springframework.web.reactive.function.client.WebClient; @Slf4j @@ -52,7 +53,7 @@ class FhirConsentedPatientsProviderFetchTest { @Autowired WebClient.Builder httpClientBuilder; @Autowired MeterRegistry meterRegistry; - @MockBean + @MockitoBean RedissonClient redisClient; // We need to mock the redisClient otherwise the tests won't start private static final String POLICY_SYSTEM = diff --git a/trust-center-agent/src/test/java/care/smith/fts/tca/consent/configuration/GicsFhirConfigurationTest.java b/trust-center-agent/src/test/java/care/smith/fts/tca/consent/configuration/GicsFhirConfigurationTest.java index acf518f2..c8600668 100644 --- a/trust-center-agent/src/test/java/care/smith/fts/tca/consent/configuration/GicsFhirConfigurationTest.java +++ b/trust-center-agent/src/test/java/care/smith/fts/tca/consent/configuration/GicsFhirConfigurationTest.java @@ -34,11 +34,6 @@ void getPageSize() { assertThat(gicsFhirConfiguration.getDefaultPageSize()).isEqualTo(200); } - @Test - void getAuth() { - assertThat(gicsFhirConfiguration.getAuth()).isNotNull(); - } - @Test void fhirConsentedPatientsProvider() { assertThat(fhirConsentProvider).isNotNull(); diff --git a/trust-center-agent/src/test/java/care/smith/fts/tca/deidentification/FhirMappingProviderTest.java b/trust-center-agent/src/test/java/care/smith/fts/tca/deidentification/FhirMappingProviderTest.java index a3ad5bc4..c01f51a7 100644 --- a/trust-center-agent/src/test/java/care/smith/fts/tca/deidentification/FhirMappingProviderTest.java +++ b/trust-center-agent/src/test/java/care/smith/fts/tca/deidentification/FhirMappingProviderTest.java @@ -45,6 +45,7 @@ import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.context.annotation.Import; +import org.springframework.test.context.bean.override.mockito.MockitoBean; import org.springframework.web.reactive.function.client.WebClient; import reactor.core.publisher.Mono; @@ -60,7 +61,7 @@ class FhirMappingProviderTest { new TransportMappingRequest("id1", Set.of("id1"), DEFAULT_DOMAINS, Duration.ofDays(14)); @Autowired WebClient.Builder httpClientBuilder; - @MockBean RedissonClient redisClient; + @MockitoBean RedissonClient redisClient; @Mock RedissonReactiveClient redis; @Mock RMapCacheReactive mapCache; @Autowired TransportMappingConfiguration transportMappingConfiguration; diff --git a/trust-center-agent/src/test/java/care/smith/fts/tca/deidentification/configuration/GpasFhirDeIdentificationConfigurationTest.java b/trust-center-agent/src/test/java/care/smith/fts/tca/deidentification/configuration/GpasFhirDeIdentificationConfigurationTest.java index 96039e0f..d7bb9bd8 100644 --- a/trust-center-agent/src/test/java/care/smith/fts/tca/deidentification/configuration/GpasFhirDeIdentificationConfigurationTest.java +++ b/trust-center-agent/src/test/java/care/smith/fts/tca/deidentification/configuration/GpasFhirDeIdentificationConfigurationTest.java @@ -22,6 +22,5 @@ class GpasFhirDeIdentificationConfigurationTest { @Test void configEntriesExist() { assertThat(gpasFhirDeIdentificationConfiguration.getBaseUrl()).isNotEmpty(); - assertThat(gpasFhirDeIdentificationConfiguration.getAuth()).isNotNull(); } } diff --git a/trust-center-agent/src/test/java/care/smith/fts/tca/deidentification/configuration/TransportMappingConfigurationTest.java b/trust-center-agent/src/test/java/care/smith/fts/tca/deidentification/configuration/TransportMappingConfigurationTest.java index 23b7207f..ba60bf78 100644 --- a/trust-center-agent/src/test/java/care/smith/fts/tca/deidentification/configuration/TransportMappingConfigurationTest.java +++ b/trust-center-agent/src/test/java/care/smith/fts/tca/deidentification/configuration/TransportMappingConfigurationTest.java @@ -10,13 +10,14 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.test.context.bean.override.mockito.MockitoBean; @SpringBootTest @ExtendWith(MockitoExtension.class) class TransportMappingConfigurationTest { @Autowired private TransportMappingConfiguration configuration; - @MockBean + @MockitoBean RedissonClient redisClient; // We need to mock the redisClient otherwise the tests won't start @Test diff --git a/trust-center-agent/src/test/java/care/smith/fts/tca/rest/DeIdentificationControllerIT.java b/trust-center-agent/src/test/java/care/smith/fts/tca/rest/DeIdentificationControllerIT.java index ebd86a60..93e6778a 100644 --- a/trust-center-agent/src/test/java/care/smith/fts/tca/rest/DeIdentificationControllerIT.java +++ b/trust-center-agent/src/test/java/care/smith/fts/tca/rest/DeIdentificationControllerIT.java @@ -51,8 +51,8 @@ class DeIdentificationControllerIT extends BaseIT { @BeforeAll static void setUp(@LocalServerPort int port, @Autowired TestWebClientFactory factory) { - cdClient = factory.webClient("cd-agent").baseUrl("https://localhost:" + port).build(); - rdClient = factory.webClient("rd-agent").baseUrl("https://localhost:" + port).build(); + cdClient = factory.webClient("https://localhost:" + port, "cd-agent"); + rdClient = factory.webClient("https://localhost:" + port, "rd-agent"); } @Test diff --git a/trust-center-agent/src/test/java/care/smith/fts/tca/rest/FetchAllConsentControllerIT.java b/trust-center-agent/src/test/java/care/smith/fts/tca/rest/FetchAllConsentControllerIT.java index 62a5c308..94bed3bd 100644 --- a/trust-center-agent/src/test/java/care/smith/fts/tca/rest/FetchAllConsentControllerIT.java +++ b/trust-center-agent/src/test/java/care/smith/fts/tca/rest/FetchAllConsentControllerIT.java @@ -40,7 +40,7 @@ class FetchAllConsentControllerIT extends BaseIT { @BeforeAll static void setUp(@LocalServerPort int port, @Autowired TestWebClientFactory factory) { - client = factory.webClient("cd-agent").baseUrl("https://localhost:" + port).build(); + client = factory.webClient("https://localhost:" + port, "cd-agent"); } @Test diff --git a/trust-center-agent/src/test/java/care/smith/fts/tca/rest/FetchConsentControllerIT.java b/trust-center-agent/src/test/java/care/smith/fts/tca/rest/FetchConsentControllerIT.java index c17e79e6..a82a22ee 100644 --- a/trust-center-agent/src/test/java/care/smith/fts/tca/rest/FetchConsentControllerIT.java +++ b/trust-center-agent/src/test/java/care/smith/fts/tca/rest/FetchConsentControllerIT.java @@ -40,7 +40,7 @@ class FetchConsentControllerIT extends BaseIT { @BeforeAll static void setUp(@LocalServerPort int port, @Autowired TestWebClientFactory factory) { - client = factory.webClient("cd-agent").baseUrl("https://localhost:" + port).build(); + client = factory.webClient("https://localhost:" + port, "cd-agent"); } @Test diff --git a/util/pom.xml b/util/pom.xml index d3e553ed..269eb42d 100644 --- a/util/pom.xml +++ b/util/pom.xml @@ -81,6 +81,21 @@ spring-boot-starter-security + + org.springframework.security + spring-security-oauth2-client + + + + org.springframework.security + spring-security-oauth2-resource-server + + + + org.springframework.security + spring-security-oauth2-jose + + org.mock-server mockserver-junit-jupiter diff --git a/util/src/main/java/care/smith/fts/util/AgentConfiguration.java b/util/src/main/java/care/smith/fts/util/AgentConfiguration.java new file mode 100644 index 00000000..4765f6fd --- /dev/null +++ b/util/src/main/java/care/smith/fts/util/AgentConfiguration.java @@ -0,0 +1,63 @@ +package care.smith.fts.util; + +import static java.time.Duration.ofSeconds; + +import ca.uhn.fhir.context.FhirContext; +import care.smith.fts.util.auth.HttpServerAuthConfig; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; +import java.net.http.HttpClient; +import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; +import org.springframework.context.annotation.Primary; +import org.springframework.security.oauth2.client.AuthorizedClientServiceReactiveOAuth2AuthorizedClientManager; +import org.springframework.security.oauth2.client.ReactiveOAuth2AuthorizedClientManager; +import org.springframework.security.oauth2.client.ReactiveOAuth2AuthorizedClientProviderBuilder; +import org.springframework.security.oauth2.client.ReactiveOAuth2AuthorizedClientService; +import org.springframework.security.oauth2.client.registration.ReactiveClientRegistrationRepository; + +@Configuration +@Import({ + WebClientDefaults.class, + FhirCodecConfiguration.class, + MetricsConfig.class, + HttpServerAuthConfig.class, + CustomErrorHandler.class, + HttpClientFactory.class, +}) +public class AgentConfiguration { + + @Bean + public FhirContext fhirContext() { + return FhirContext.forR4(); + } + + @Bean + public HttpClient httpClient() { + return HttpClient.newBuilder().connectTimeout(ofSeconds(10)).build(); + } + + @Bean + @Primary + public ObjectMapper defaultObjectMapper() { + return new ObjectMapper().registerModule(new JavaTimeModule()); + } + + @Bean + @ConditionalOnBean(ReactiveClientRegistrationRepository.class) + public ReactiveOAuth2AuthorizedClientManager authorizedClientManager( + ReactiveClientRegistrationRepository clientRegistrationRepository, + ReactiveOAuth2AuthorizedClientService authorizedClientService) { + var authorizedClientManager = + new AuthorizedClientServiceReactiveOAuth2AuthorizedClientManager( + clientRegistrationRepository, authorizedClientService); + + var authorizedClientProvider = + ReactiveOAuth2AuthorizedClientProviderBuilder.builder().clientCredentials().build(); + + authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider); + return authorizedClientManager; + } +} diff --git a/util/src/main/java/care/smith/fts/util/HttpClientConfig.java b/util/src/main/java/care/smith/fts/util/HttpClientConfig.java index c31746ad..3a3ffa5a 100644 --- a/util/src/main/java/care/smith/fts/util/HttpClientConfig.java +++ b/util/src/main/java/care/smith/fts/util/HttpClientConfig.java @@ -2,43 +2,27 @@ import static com.google.common.base.Strings.emptyToNull; import static java.util.Objects.requireNonNull; -import static java.util.Optional.ofNullable; -import care.smith.fts.util.auth.HttpClientAuthMethod.AuthMethod; +import care.smith.fts.util.auth.HttpClientAuth; import jakarta.annotation.Nullable; import jakarta.validation.constraints.NotBlank; -import jakarta.validation.constraints.NotNull; -import org.springframework.boot.autoconfigure.web.reactive.function.client.WebClientSsl; -import org.springframework.web.reactive.function.client.WebClient; public record HttpClientConfig( - @NotBlank String baseUrl, @NotNull AuthMethod auth, @Nullable Ssl ssl) { + @NotBlank String baseUrl, @Nullable HttpClientAuth.Config auth, @Nullable Ssl ssl) { - public HttpClientConfig(@NotBlank String baseUrl, AuthMethod auth, Ssl ssl) { + public HttpClientConfig(String baseUrl, HttpClientAuth.Config auth, Ssl ssl) { this.baseUrl = requireNonNull(emptyToNull(baseUrl), "Base URL must not be null"); - this.auth = ofNullable(auth).orElse(AuthMethod.NONE); + this.auth = auth; this.ssl = ssl; } - public HttpClientConfig(@NotBlank String baseUrl, AuthMethod auth) { + public HttpClientConfig(String baseUrl, HttpClientAuth.Config auth) { this(baseUrl, auth, null); } - public HttpClientConfig(@NotBlank String baseUrl) { - this(baseUrl, AuthMethod.NONE); + public HttpClientConfig(String baseUrl) { + this(baseUrl, null); } - public WebClient createClient(WebClient.Builder builder, WebClientSsl wcssl) { - return builder - .baseUrl(baseUrl()) - .apply(auth()::customize) - .apply(b -> ofNullable(ssl()).ifPresent(s -> s.customize(b, wcssl))) - .build(); - } - - public record Ssl(String bundle) { - void customize(WebClient.Builder client, WebClientSsl wcssl) { - client.apply(wcssl.fromBundle(bundle())); - } - } + public record Ssl(String bundle) {} } diff --git a/util/src/main/java/care/smith/fts/util/HttpClientFactory.java b/util/src/main/java/care/smith/fts/util/HttpClientFactory.java new file mode 100644 index 00000000..3d95367e --- /dev/null +++ b/util/src/main/java/care/smith/fts/util/HttpClientFactory.java @@ -0,0 +1,72 @@ +package care.smith.fts.util; + +import static java.util.Optional.ofNullable; + +import care.smith.fts.util.HttpClientConfig.Ssl; +import care.smith.fts.util.auth.HttpClientAuth; +import care.smith.fts.util.auth.HttpClientBasicAuth; +import care.smith.fts.util.auth.HttpClientCookieTokenAuth; +import care.smith.fts.util.auth.HttpClientOAuth2Auth; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.web.reactive.function.client.WebClientSsl; +import org.springframework.context.annotation.Import; +import org.springframework.stereotype.Component; +import org.springframework.web.reactive.function.client.WebClient; +import org.springframework.web.reactive.function.client.WebClient.Builder; + +@Component +@Import({HttpClientBasicAuth.class, HttpClientOAuth2Auth.class, HttpClientCookieTokenAuth.class}) +public class HttpClientFactory { + + private final Builder clientBuilder; + private final WebClientSsl ssl; + private final HttpClientBasicAuth basic; + private final HttpClientOAuth2Auth oauth2; + private final HttpClientCookieTokenAuth token; + + public HttpClientFactory( + WebClient.Builder clientBuilder, + WebClientSsl ssl, + @Autowired(required = false) HttpClientBasicAuth basic, + @Autowired(required = false) HttpClientOAuth2Auth oauth2, + @Autowired(required = false) HttpClientCookieTokenAuth token) { + this.clientBuilder = clientBuilder; + this.ssl = ssl; + this.basic = basic; + this.oauth2 = oauth2; + this.token = token; + } + + public WebClient createClient(HttpClientConfig config) { + return clientBuilder + .baseUrl(config.baseUrl()) + .apply(b -> configureAuth(b, config.auth())) + .apply(b -> configureSsl(b, config.ssl())) + .build(); + } + + public WebClient createClient(Builder builder, HttpClientConfig config) { + return builder + .baseUrl(config.baseUrl()) + .apply(b -> configureAuth(b, config.auth())) + .apply(b -> configureSsl(b, config.ssl())) + .build(); + } + + private void configureAuth(Builder builder, HttpClientAuth.Config auth) { + if (auth != null) { + builder + .apply(b -> configureAuth(b, basic, auth.basic())) + .apply(b -> configureAuth(b, oauth2, auth.oauth2())) + .apply(b -> configureAuth(b, token, auth.cookieToken())); + } + } + + private void configureAuth(Builder b, HttpClientAuth impl, C config) { + ofNullable(config).ifPresent(c -> impl.configure(c, b)); + } + + private void configureSsl(Builder b, Ssl ssl) { + ofNullable(ssl).ifPresent(s -> b.apply(this.ssl.fromBundle(s.bundle()))); + } +} diff --git a/util/src/main/java/care/smith/fts/util/MetricsConfig.java b/util/src/main/java/care/smith/fts/util/MetricsConfig.java index e835d490..c6864ebe 100644 --- a/util/src/main/java/care/smith/fts/util/MetricsConfig.java +++ b/util/src/main/java/care/smith/fts/util/MetricsConfig.java @@ -6,6 +6,7 @@ import io.micrometer.core.instrument.config.MeterFilter; import java.util.Arrays; import lombok.Data; +import lombok.Setter; import lombok.extern.slf4j.Slf4j; import org.springframework.boot.actuate.autoconfigure.metrics.MeterRegistryCustomizer; import org.springframework.boot.context.properties.ConfigurationProperties; @@ -15,7 +16,6 @@ @Slf4j @Configuration @ConfigurationProperties(prefix = "management.metrics.distribution") -@Data public class MetricsConfig { @Bean diff --git a/util/src/main/java/care/smith/fts/util/WebClientContext.java b/util/src/main/java/care/smith/fts/util/WebClientContext.java new file mode 100644 index 00000000..e5528318 --- /dev/null +++ b/util/src/main/java/care/smith/fts/util/WebClientContext.java @@ -0,0 +1,7 @@ +package care.smith.fts.util; + +import org.springframework.boot.autoconfigure.web.reactive.function.client.WebClientSsl; + +public record WebClientContext(WebClientSsl ssl) { + +} diff --git a/util/src/main/java/care/smith/fts/util/auth/HttpClientAuth.java b/util/src/main/java/care/smith/fts/util/auth/HttpClientAuth.java new file mode 100644 index 00000000..83e0aa9c --- /dev/null +++ b/util/src/main/java/care/smith/fts/util/auth/HttpClientAuth.java @@ -0,0 +1,13 @@ +package care.smith.fts.util.auth; + +import org.springframework.web.reactive.function.client.WebClient.Builder; + +public interface HttpClientAuth { + void configure(T config, Builder builder); + + record Config( + HttpClientBasicAuth.Config basic, + HttpClientOAuth2Auth.Config oauth2, + HttpClientCookieTokenAuth.Config cookieToken) { + } +} diff --git a/util/src/main/java/care/smith/fts/util/auth/HttpClientAuthMethod.java b/util/src/main/java/care/smith/fts/util/auth/HttpClientAuthMethod.java deleted file mode 100644 index c14b34db..00000000 --- a/util/src/main/java/care/smith/fts/util/auth/HttpClientAuthMethod.java +++ /dev/null @@ -1,25 +0,0 @@ -package care.smith.fts.util.auth; - -import java.util.Objects; -import java.util.stream.Stream; -import org.springframework.web.reactive.function.client.WebClient; - -public interface HttpClientAuthMethod { - void configure(WebClient.Builder builder); - - record AuthMethod( - HttpClientBasicAuth basic, - HttpClientCookieTokenAuth cookieToken, - HttpClientNoneAuth none) { - - public static AuthMethod NONE = new AuthMethod(null, null, HttpClientNoneAuth.NONE); - - public void customize(WebClient.Builder builder) { - Stream.of(basic(), cookieToken(), none()) - .filter(Objects::nonNull) - .findFirst() - .orElse(none()) - .configure(builder); - } - } -} diff --git a/util/src/main/java/care/smith/fts/util/auth/HttpClientBasicAuth.java b/util/src/main/java/care/smith/fts/util/auth/HttpClientBasicAuth.java index 0751a7a7..0de4f6dd 100644 --- a/util/src/main/java/care/smith/fts/util/auth/HttpClientBasicAuth.java +++ b/util/src/main/java/care/smith/fts/util/auth/HttpClientBasicAuth.java @@ -1,17 +1,21 @@ package care.smith.fts.util.auth; +import care.smith.fts.util.auth.HttpClientBasicAuth.Config; +import org.springframework.stereotype.Component; import org.springframework.web.reactive.function.client.WebClient; -public record HttpClientBasicAuth( - /* */ - String user, +@Component +public class HttpClientBasicAuth implements HttpClientAuth { - /* */ - String password) - implements HttpClientAuthMethod { + public record Config( + /* */ + String user, + + /* */ + String password) {} @Override - public void configure(WebClient.Builder builder) { - builder.defaultHeaders(headers -> headers.setBasicAuth(user, password)); + public void configure(Config config, WebClient.Builder builder) { + builder.defaultHeaders(headers -> headers.setBasicAuth(config.user(), config.password())); } } diff --git a/util/src/main/java/care/smith/fts/util/auth/HttpClientCookieTokenAuth.java b/util/src/main/java/care/smith/fts/util/auth/HttpClientCookieTokenAuth.java index b0c65ac0..e68a1106 100644 --- a/util/src/main/java/care/smith/fts/util/auth/HttpClientCookieTokenAuth.java +++ b/util/src/main/java/care/smith/fts/util/auth/HttpClientCookieTokenAuth.java @@ -2,15 +2,17 @@ import static org.springframework.http.HttpHeaders.COOKIE; -import org.springframework.boot.autoconfigure.web.reactive.function.client.WebClientSsl; +import care.smith.fts.util.auth.HttpClientCookieTokenAuth.Config; +import org.springframework.stereotype.Component; import org.springframework.web.reactive.function.client.WebClient; -public record HttpClientCookieTokenAuth( - /* */ - String token) implements HttpClientAuthMethod { +@Component +public class HttpClientCookieTokenAuth implements HttpClientAuth { + + public record Config(String token) {} @Override - public void configure(WebClient.Builder builder) { - builder.defaultHeaders(h -> h.set(COOKIE, token)); + public void configure(Config config, WebClient.Builder builder) { + builder.defaultHeaders(h -> h.set(COOKIE, config.token())); } } diff --git a/util/src/main/java/care/smith/fts/util/auth/HttpClientNoneAuth.java b/util/src/main/java/care/smith/fts/util/auth/HttpClientNoneAuth.java deleted file mode 100644 index f69af36b..00000000 --- a/util/src/main/java/care/smith/fts/util/auth/HttpClientNoneAuth.java +++ /dev/null @@ -1,13 +0,0 @@ -package care.smith.fts.util.auth; - -import java.util.HashMap; -import org.springframework.boot.autoconfigure.web.reactive.function.client.WebClientSsl; -import org.springframework.web.reactive.function.client.WebClient; - -public class HttpClientNoneAuth extends HashMap implements HttpClientAuthMethod { - - public static HttpClientNoneAuth NONE = new HttpClientNoneAuth(); - - @Override - public void configure(WebClient.Builder builder) {} -} diff --git a/util/src/main/java/care/smith/fts/util/auth/HttpClientOAuth2Auth.java b/util/src/main/java/care/smith/fts/util/auth/HttpClientOAuth2Auth.java new file mode 100644 index 00000000..ce067cdf --- /dev/null +++ b/util/src/main/java/care/smith/fts/util/auth/HttpClientOAuth2Auth.java @@ -0,0 +1,35 @@ +package care.smith.fts.util.auth; + +import care.smith.fts.util.auth.HttpClientOAuth2Auth.Config; +import lombok.extern.slf4j.Slf4j; +import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; +import org.springframework.security.oauth2.client.ReactiveOAuth2AuthorizedClientManager; +import org.springframework.security.oauth2.client.web.reactive.function.client.ServerOAuth2AuthorizedClientExchangeFilterFunction; +import org.springframework.stereotype.Component; +import org.springframework.web.reactive.function.client.WebClient.Builder; + +/** OAuth2 Authentication using oauth2 client credentials flow. */ +@Slf4j +@Component +@ConditionalOnBean(ReactiveOAuth2AuthorizedClientManager.class) +public class HttpClientOAuth2Auth implements HttpClientAuth { + + private final ReactiveOAuth2AuthorizedClientManager clientManager; + + public HttpClientOAuth2Auth(ReactiveOAuth2AuthorizedClientManager clientManager) { + this.clientManager = clientManager; + } + + public record Config(String registration) {} + + @Override + public void configure(Config config, Builder builder) { + log.debug( + "Configuring oauth2 client, registration '{}', clientManager: {}", + config.registration(), + clientManager); + var filter = new ServerOAuth2AuthorizedClientExchangeFilterFunction(clientManager); + filter.setDefaultClientRegistrationId(config.registration()); + builder.filter(filter); + } +} diff --git a/util/src/main/java/care/smith/fts/util/auth/HttpServerAuthConfig.java b/util/src/main/java/care/smith/fts/util/auth/HttpServerAuthConfig.java index 765fda66..a231c5cc 100644 --- a/util/src/main/java/care/smith/fts/util/auth/HttpServerAuthConfig.java +++ b/util/src/main/java/care/smith/fts/util/auth/HttpServerAuthConfig.java @@ -5,6 +5,7 @@ import java.util.Objects; import java.util.stream.Stream; import lombok.Data; +import lombok.Setter; import lombok.extern.slf4j.Slf4j; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.Bean; @@ -46,7 +47,7 @@ public ReactiveUserDetailsService userDetailsService() { private static HttpServerAuthMethod authMethod(AuthMethod auth) { var httpServerAuthMethodStream = - Stream.of(auth.clientCert(), auth.basic(), auth.none()) + Stream.of(auth.clientCert(), auth.basic(), auth.oauth2(), auth.none()) .filter(Objects::nonNull) .toList(); if (httpServerAuthMethodStream.size() == 1) { diff --git a/util/src/main/java/care/smith/fts/util/auth/HttpServerAuthMethod.java b/util/src/main/java/care/smith/fts/util/auth/HttpServerAuthMethod.java index 46210476..74d647b7 100644 --- a/util/src/main/java/care/smith/fts/util/auth/HttpServerAuthMethod.java +++ b/util/src/main/java/care/smith/fts/util/auth/HttpServerAuthMethod.java @@ -16,7 +16,10 @@ default ServerHttpSecurity filter(Endpoint endpoint, ServerHttpSecurity http) { ReactiveUserDetailsService configureUsers(); record AuthMethod( - HttpServerClientCertAuth clientCert, HttpServerBasicAuth basic, HttpServerNoneAuth none) {} + HttpServerClientCertAuth clientCert, + HttpServerBasicAuth basic, + HttpServerOAuth2Auth oauth2, + HttpServerNoneAuth none) {} - AuthMethod NONE = new AuthMethod(null, null, HttpServerNoneAuth.NONE); + AuthMethod NONE = new AuthMethod(null, null, null, HttpServerNoneAuth.NONE); } diff --git a/util/src/main/java/care/smith/fts/util/auth/HttpServerOAuth2Auth.java b/util/src/main/java/care/smith/fts/util/auth/HttpServerOAuth2Auth.java new file mode 100644 index 00000000..e4a48e56 --- /dev/null +++ b/util/src/main/java/care/smith/fts/util/auth/HttpServerOAuth2Auth.java @@ -0,0 +1,33 @@ +package care.smith.fts.util.auth; + +import static org.springframework.security.oauth2.jwt.ReactiveJwtDecoders.fromIssuerLocation; + +import care.smith.fts.util.auth.HttpServerAuthConfig.Endpoint; +import org.springframework.security.config.web.server.ServerHttpSecurity; +import org.springframework.security.core.userdetails.ReactiveUserDetailsService; + +public record HttpServerOAuth2Auth(String issuer) implements HttpServerAuthMethod { + + @Override + public ServerHttpSecurity configure(ServerHttpSecurity http) { + return http.oauth2ResourceServer( + oauth2 -> oauth2.jwt(jwt -> jwt.jwtDecoder(fromIssuerLocation(issuer)))); + } + + @Override + public ServerHttpSecurity filter(Endpoint endpoint, ServerHttpSecurity http) { + return http.authorizeExchange( + exchange -> exchange.pathMatchers(endpoint.path()).hasAuthority(endpoint.role())); + } + + @Override + public ReactiveUserDetailsService configureUsers() { + // Since it's client credentials, we don't configure users explicitly here. + return null; + } + + @Override + public String toString() { + return "OAuth2"; + } +} diff --git a/util/src/test/java/care/smith/fts/util/HttpClientConfigTest.java b/util/src/test/java/care/smith/fts/util/HttpClientConfigTest.java index e483f118..174a07e7 100644 --- a/util/src/test/java/care/smith/fts/util/HttpClientConfigTest.java +++ b/util/src/test/java/care/smith/fts/util/HttpClientConfigTest.java @@ -2,12 +2,10 @@ import static org.assertj.core.api.Assertions.*; -import care.smith.fts.util.auth.HttpClientAuthMethod.AuthMethod; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.dataformat.yaml.YAMLFactory; import org.junit.jupiter.api.Test; -import org.springframework.web.reactive.function.client.WebClient; public class HttpClientConfigTest { @@ -24,8 +22,13 @@ public void emptyBaseUrlThrows() { } @Test - public void nullAuthDoesntThrow() { - assertThat(new HttpClientConfig("http://localhost").auth()).isEqualTo(AuthMethod.NONE); + public void emptyAuthDoesntThrow() { + assertThatNoException().isThrownBy(() -> new HttpClientConfig("http://localhost", null, null)); + } + + @Test + public void emptySslDoesntThrow() { + assertThatNoException().isThrownBy(() -> new HttpClientConfig("http://localhost", null, null)); } @Test @@ -39,14 +42,6 @@ public void deserialization() throws JsonProcessingException { none: {} """; - assertThat(om.readValue(config, HttpClientConfig.class)).isNotNull(); - } - - @Test - public void clientCreated() { - HttpClientConfig config = new HttpClientConfig("http://localhost"); - WebClient client = config.createClient(WebClient.builder(), null); - - assertThat(client).isNotNull(); + assertThat(om.readValue(config, HttpClientFactory.class)).isNotNull(); } } diff --git a/util/src/test/java/care/smith/fts/util/auth/HTTPClientBasicAuthTest.java b/util/src/test/java/care/smith/fts/util/auth/HTTPClientBasicAuthTest.java index 3276ac0f..691d4602 100644 --- a/util/src/test/java/care/smith/fts/util/auth/HTTPClientBasicAuthTest.java +++ b/util/src/test/java/care/smith/fts/util/auth/HTTPClientBasicAuthTest.java @@ -3,6 +3,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatNoException; +import care.smith.fts.util.auth.HttpClientAuth.Config; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.dataformat.yaml.YAMLFactory; @@ -22,15 +23,16 @@ public void deserialization() throws JsonProcessingException { password: pass-090130 """; - assertThat(om.readValue(config, HttpClientAuthMethod.AuthMethod.class)).isNotNull(); + assertThat(om.readValue(config, Config.class)).isNotNull(); } @Test public void clientCreated() { - HttpClientBasicAuth config = new HttpClientBasicAuth("user-090058", "pass-090130"); + var config = new HttpClientBasicAuth.Config("user-090058", "pass-090130"); + var auth = new HttpClientBasicAuth(); var client = WebClient.builder(); - assertThatNoException().isThrownBy(() -> config.configure(client)); + assertThatNoException().isThrownBy(() -> auth.configure(config, client)); } } diff --git a/util/src/test/java/care/smith/fts/util/auth/HTTPClientCookieTokenAuthTest.java b/util/src/test/java/care/smith/fts/util/auth/HTTPClientCookieTokenAuthTest.java index c03fb792..9cdf2227 100644 --- a/util/src/test/java/care/smith/fts/util/auth/HTTPClientCookieTokenAuthTest.java +++ b/util/src/test/java/care/smith/fts/util/auth/HTTPClientCookieTokenAuthTest.java @@ -2,12 +2,13 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatNoException; +import static org.springframework.web.reactive.function.client.WebClient.builder; +import care.smith.fts.util.auth.HttpClientAuth.Config; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.dataformat.yaml.YAMLFactory; import org.junit.jupiter.api.Test; -import org.springframework.web.reactive.function.client.WebClient; public class HTTPClientCookieTokenAuthTest { @@ -21,13 +22,15 @@ public void deserialization() throws JsonProcessingException { token: token-090112 """; - assertThat(om.readValue(config, HttpClientAuthMethod.AuthMethod.class)).isNotNull(); + assertThat(om.readValue(config, Config.class)).isNotNull(); } @Test public void clientCreated() { - HttpClientCookieTokenAuth config = new HttpClientCookieTokenAuth("token-090112"); + var impl = new HttpClientCookieTokenAuth(); - assertThatNoException().isThrownBy(() -> config.configure(WebClient.builder())); + assertThatNoException() + .isThrownBy( + () -> impl.configure(new HttpClientCookieTokenAuth.Config("token-090112"), builder())); } } diff --git a/util/src/test/java/care/smith/fts/util/auth/HttpServerAuthConfigTest.java b/util/src/test/java/care/smith/fts/util/auth/HttpServerAuthConfigTest.java index 58abecf8..64e65e45 100644 --- a/util/src/test/java/care/smith/fts/util/auth/HttpServerAuthConfigTest.java +++ b/util/src/test/java/care/smith/fts/util/auth/HttpServerAuthConfigTest.java @@ -23,7 +23,7 @@ void multipleAuthMethodsThrow() { var config = new HttpServerAuthConfig(); config.setAuth( new AuthMethod( - null, new HttpServerBasicAuth(List.of()), new HttpServerNoneAuth())); + null, new HttpServerBasicAuth(List.of()), null, new HttpServerNoneAuth())); assertThatExceptionOfType(IllegalArgumentException.class) .isThrownBy(config::userDetailsService) @@ -33,7 +33,7 @@ void multipleAuthMethodsThrow() { @Test void noAuthMethodDefaultsToNone() { var config = new HttpServerAuthConfig(); - config.setAuth(new AuthMethod(null, null, null)); + config.setAuth(new AuthMethod(null, null, null, null)); var reactiveUserDetailsService = config.userDetailsService();