Skip to content

Commit

Permalink
WIP Add oauth2 Client Credentials Flow
Browse files Browse the repository at this point in the history
  • Loading branch information
knoppiks committed Dec 9, 2024
1 parent 1128ee2 commit d098051
Show file tree
Hide file tree
Showing 66 changed files with 523 additions and 399 deletions.
1 change: 1 addition & 0 deletions auth/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# Authn/Authz Util
23 changes: 23 additions & 0 deletions auth/compose.yaml
Original file line number Diff line number Diff line change
@@ -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
31 changes: 31 additions & 0 deletions clinical-domain-agent/application-auth:oauth2.yaml
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<DeidentifhirStepConfig> {

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;
}

Expand All @@ -31,7 +28,7 @@ public Class<DeidentifhirStepConfig> 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,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -14,14 +13,12 @@
public class EverythingDataSelectorFactory
implements DataSelector.Factory<EverythingDataSelectorConfig> {

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;
}

Expand All @@ -32,7 +29,7 @@ public Class<EverythingDataSelectorConfig> 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);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -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<RDABundleSenderConfig> {

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;
}

Expand All @@ -28,6 +24,6 @@ public Class<RDABundleSenderConfig> 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);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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<TCACohortSelectorConfig> {
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);

Check notice

Code scanning / CodeQL

Use of default toString() Note

Default toString(): HttpClientFactory inherits toString() from Object, and so is not suitable for printing.
}

@Override
Expand All @@ -32,7 +28,7 @@ public Class<TCACohortSelectorConfig> 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);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ Mono<ResponseEntity<Object>> start(
@RequestBody(required = false) List<String> 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);
Expand Down
4 changes: 4 additions & 0 deletions clinical-domain-agent/src/main/resources/application.yaml
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
spring:
mustache:
checkTemplateLocation: false

management:
endpoints:
web:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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;
Expand All @@ -25,22 +27,20 @@
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 {

@Autowired MeterRegistry meterRegistry;
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);
Expand Down Expand Up @@ -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
Expand Down
Loading

0 comments on commit d098051

Please sign in to comment.