mirror of
https://github.com/pcvolkmer/etl-processor.git
synced 2025-04-19 17:26:51 +00:00
feat: remove SSL-CA-Location config (#99)
This commit is contained in:
parent
9d4786fae3
commit
66cc818755
@ -52,8 +52,6 @@ Soll noch das alte bwHC-Backend verwendet werden, so ist die Umgebungsvariable
|
|||||||
|
|
||||||
In Versionen des ETL-Processors **nach Version 0.10** werden die folgenden Konfigurationsoptionen entfernt:
|
In Versionen des ETL-Processors **nach Version 0.10** werden die folgenden Konfigurationsoptionen entfernt:
|
||||||
|
|
||||||
* `APP_PSEUDONYMIZE_GPAS_SSLCALOCATION`: Nutzen Sie hier, wie unter [_Integration eines eigenen Root CA
|
|
||||||
Zertifikats_](#integration-eines-eigenen-root-ca-zertifikats) beschrieben, das Einbinden eigener Zertifikate.
|
|
||||||
* `APP_KAFKA_TOPIC`: Nutzen Sie nun die Konfigurationsoption `APP_KAFKA_OUTPUT_TOPIC`
|
* `APP_KAFKA_TOPIC`: Nutzen Sie nun die Konfigurationsoption `APP_KAFKA_OUTPUT_TOPIC`
|
||||||
* `APP_KAFKA_RESPONSE_TOPIC`: Nutzen Sie nun die Konfigurationsoption `APP_KAFKA_OUTPUT_RESPONSE_TOPIC`
|
* `APP_KAFKA_RESPONSE_TOPIC`: Nutzen Sie nun die Konfigurationsoption `APP_KAFKA_OUTPUT_RESPONSE_TOPIC`
|
||||||
|
|
||||||
@ -90,13 +88,6 @@ Wurde die Verwendung von gPAS konfiguriert, so sind weitere Angaben zu konfiguri
|
|||||||
* `APP_PSEUDONYMIZE_GPAS_TARGET`: gPas Domänenname
|
* `APP_PSEUDONYMIZE_GPAS_TARGET`: gPas Domänenname
|
||||||
* `APP_PSEUDONYMIZE_GPAS_USERNAME`: gPas Basic-Auth Benutzername
|
* `APP_PSEUDONYMIZE_GPAS_USERNAME`: gPas Basic-Auth Benutzername
|
||||||
* `APP_PSEUDONYMIZE_GPAS_PASSWORD`: gPas Basic-Auth Passwort
|
* `APP_PSEUDONYMIZE_GPAS_PASSWORD`: gPas Basic-Auth Passwort
|
||||||
* ~~`APP_PSEUDONYMIZE_GPAS_SSLCALOCATION`~~: **Veraltet** - Root Zertifikat für gPas, falls es dediziert hinzugefügt werden muss.
|
|
||||||
**Wird in nach Version 0.10 entfernt**
|
|
||||||
|
|
||||||
Der Konfigurationsparameter `APP_PSEUDONYMIZE_GPAS_SSLCALOCATION` sollte nicht mehr verwendet werden und wird nach
|
|
||||||
Version 0.10 entfernt.
|
|
||||||
Stattdessen sollte das Root Zertifikat wie unter [_Integration eines eigenen Root CA
|
|
||||||
Zertifikats_](#integration-eines-eigenen-root-ca-zertifikats) beschrieben eingebunden werden.
|
|
||||||
|
|
||||||
### Anmeldung mit einem Passwort
|
### Anmeldung mit einem Passwort
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of ETL-Processor
|
* This file is part of ETL-Processor
|
||||||
*
|
*
|
||||||
* Copyright (c) 2024 Comprehensive Cancer Center Mainfranken, Datenintegrationszentrum Philipps-Universität Marburg and Contributors
|
* Copyright (c) 2025 Comprehensive Cancer Center Mainfranken, Datenintegrationszentrum Philipps-Universität Marburg and Contributors
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU Affero General Public License as published
|
* it under the terms of the GNU Affero General Public License as published
|
||||||
@ -47,10 +47,9 @@ class GpasPseudonymGeneratorTest {
|
|||||||
fun setup() {
|
fun setup() {
|
||||||
val retryTemplate = RetryTemplateBuilder().customPolicy(SimpleRetryPolicy(1)).build()
|
val retryTemplate = RetryTemplateBuilder().customPolicy(SimpleRetryPolicy(1)).build()
|
||||||
val gPasConfigProperties = GPasConfigProperties(
|
val gPasConfigProperties = GPasConfigProperties(
|
||||||
"http://localhost/ttp-fhir/fhir/gpas/\$pseudonymizeAllowCreate",
|
"https://localhost/ttp-fhir/fhir/gpas/\$pseudonymizeAllowCreate",
|
||||||
"test",
|
"test",
|
||||||
null,
|
null,
|
||||||
null,
|
|
||||||
null
|
null
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -63,7 +62,7 @@ class GpasPseudonymGeneratorTest {
|
|||||||
fun shouldReturnExpectedPseudonym() {
|
fun shouldReturnExpectedPseudonym() {
|
||||||
this.mockRestServiceServer.expect {
|
this.mockRestServiceServer.expect {
|
||||||
method(HttpMethod.POST)
|
method(HttpMethod.POST)
|
||||||
requestTo("http://localhost/ttp-fhir/fhir/gpas/\$pseudonymizeAllowCreate")
|
requestTo("https://localhost/ttp-fhir/fhir/gpas/\$pseudonymizeAllowCreate")
|
||||||
}.andRespond {
|
}.andRespond {
|
||||||
withStatus(HttpStatus.OK).body(getDummyResponseBody("1234", "test", "test1234ABCDEF567890"))
|
withStatus(HttpStatus.OK).body(getDummyResponseBody("1234", "test", "test1234ABCDEF567890"))
|
||||||
.createResponse(it)
|
.createResponse(it)
|
||||||
@ -76,7 +75,7 @@ class GpasPseudonymGeneratorTest {
|
|||||||
fun shouldThrowExceptionIfGpasNotAvailable() {
|
fun shouldThrowExceptionIfGpasNotAvailable() {
|
||||||
this.mockRestServiceServer.expect {
|
this.mockRestServiceServer.expect {
|
||||||
method(HttpMethod.POST)
|
method(HttpMethod.POST)
|
||||||
requestTo("http://localhost/ttp-fhir/fhir/gpas/\$pseudonymizeAllowCreate")
|
requestTo("https://localhost/ttp-fhir/fhir/gpas/\$pseudonymizeAllowCreate")
|
||||||
}.andRespond {
|
}.andRespond {
|
||||||
withException(IOException("Simulated IO error")).createResponse(it)
|
withException(IOException("Simulated IO error")).createResponse(it)
|
||||||
}
|
}
|
||||||
@ -88,7 +87,7 @@ class GpasPseudonymGeneratorTest {
|
|||||||
fun shouldThrowExceptionIfGpasDoesNotReturn2xxResponse() {
|
fun shouldThrowExceptionIfGpasDoesNotReturn2xxResponse() {
|
||||||
this.mockRestServiceServer.expect {
|
this.mockRestServiceServer.expect {
|
||||||
method(HttpMethod.POST)
|
method(HttpMethod.POST)
|
||||||
requestTo("http://localhost/ttp-fhir/fhir/gpas/\$pseudonymizeAllowCreate")
|
requestTo("https://localhost/ttp-fhir/fhir/gpas/\$pseudonymizeAllowCreate")
|
||||||
}.andRespond {
|
}.andRespond {
|
||||||
withStatus(HttpStatus.FOUND)
|
withStatus(HttpStatus.FOUND)
|
||||||
.header(HttpHeaders.LOCATION, "https://localhost/ttp-fhir/fhir/gpas/\$pseudonymizeAllowCreate")
|
.header(HttpHeaders.LOCATION, "https://localhost/ttp-fhir/fhir/gpas/\$pseudonymizeAllowCreate")
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of ETL-Processor
|
* This file is part of ETL-Processor
|
||||||
*
|
*
|
||||||
* Copyright (c) 2024 Comprehensive Cancer Center Mainfranken, Datenintegrationszentrum Philipps-Universität Marburg and Contributors
|
* Copyright (c) 2025 Comprehensive Cancer Center Mainfranken, Datenintegrationszentrum Philipps-Universität Marburg and Contributors
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU Affero General Public License as published
|
* it under the terms of the GNU Affero General Public License as published
|
||||||
@ -56,10 +56,6 @@ data class GPasConfigProperties(
|
|||||||
val target: String = "etl-processor",
|
val target: String = "etl-processor",
|
||||||
val username: String?,
|
val username: String?,
|
||||||
val password: String?,
|
val password: String?,
|
||||||
@get:DeprecatedConfigurationProperty(
|
|
||||||
reason = "Deprecated in favor of including Root CA"
|
|
||||||
)
|
|
||||||
val sslCaLocation: String?
|
|
||||||
) {
|
) {
|
||||||
companion object {
|
companion object {
|
||||||
const val NAME = "app.pseudonymize.gpas"
|
const val NAME = "app.pseudonymize.gpas"
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of ETL-Processor
|
* This file is part of ETL-Processor
|
||||||
*
|
*
|
||||||
* Copyright (c) 2024 Comprehensive Cancer Center Mainfranken, Datenintegrationszentrum Philipps-Universität Marburg and Contributors
|
* Copyright (c) 2025 Comprehensive Cancer Center Mainfranken, Datenintegrationszentrum Philipps-Universität Marburg and Contributors
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU Affero General Public License as published
|
* it under the terms of the GNU Affero General Public License as published
|
||||||
@ -32,12 +32,6 @@ import dev.dnpm.etl.processor.security.TokenRepository
|
|||||||
import dev.dnpm.etl.processor.security.TokenService
|
import dev.dnpm.etl.processor.security.TokenService
|
||||||
import dev.dnpm.etl.processor.services.Transformation
|
import dev.dnpm.etl.processor.services.Transformation
|
||||||
import dev.dnpm.etl.processor.services.TransformationService
|
import dev.dnpm.etl.processor.services.TransformationService
|
||||||
import org.apache.hc.client5.http.impl.classic.HttpClients
|
|
||||||
import org.apache.hc.client5.http.impl.io.BasicHttpClientConnectionManager
|
|
||||||
import org.apache.hc.client5.http.socket.ConnectionSocketFactory
|
|
||||||
import org.apache.hc.client5.http.socket.PlainConnectionSocketFactory
|
|
||||||
import org.apache.hc.client5.http.ssl.SSLConnectionSocketFactory
|
|
||||||
import org.apache.hc.core5.http.config.RegistryBuilder
|
|
||||||
import org.slf4j.LoggerFactory
|
import org.slf4j.LoggerFactory
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty
|
||||||
@ -45,7 +39,6 @@ import org.springframework.boot.context.properties.EnableConfigurationProperties
|
|||||||
import org.springframework.context.annotation.Bean
|
import org.springframework.context.annotation.Bean
|
||||||
import org.springframework.context.annotation.Configuration
|
import org.springframework.context.annotation.Configuration
|
||||||
import org.springframework.data.jdbc.repository.config.AbstractJdbcConfiguration
|
import org.springframework.data.jdbc.repository.config.AbstractJdbcConfiguration
|
||||||
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory
|
|
||||||
import org.springframework.retry.RetryCallback
|
import org.springframework.retry.RetryCallback
|
||||||
import org.springframework.retry.RetryContext
|
import org.springframework.retry.RetryContext
|
||||||
import org.springframework.retry.RetryListener
|
import org.springframework.retry.RetryListener
|
||||||
@ -58,13 +51,6 @@ import org.springframework.security.provisioning.InMemoryUserDetailsManager
|
|||||||
import org.springframework.web.client.HttpClientErrorException
|
import org.springframework.web.client.HttpClientErrorException
|
||||||
import org.springframework.web.client.RestTemplate
|
import org.springframework.web.client.RestTemplate
|
||||||
import reactor.core.publisher.Sinks
|
import reactor.core.publisher.Sinks
|
||||||
import java.io.BufferedInputStream
|
|
||||||
import java.io.FileInputStream
|
|
||||||
import java.security.KeyStore
|
|
||||||
import java.security.cert.CertificateFactory
|
|
||||||
import java.security.cert.X509Certificate
|
|
||||||
import javax.net.ssl.SSLContext
|
|
||||||
import javax.net.ssl.TrustManagerFactory
|
|
||||||
import kotlin.time.Duration.Companion.seconds
|
import kotlin.time.Duration.Companion.seconds
|
||||||
import kotlin.time.toJavaDuration
|
import kotlin.time.toJavaDuration
|
||||||
|
|
||||||
@ -90,18 +76,6 @@ class AppConfiguration {
|
|||||||
@ConditionalOnProperty(value = ["app.pseudonymize.generator"], havingValue = "GPAS")
|
@ConditionalOnProperty(value = ["app.pseudonymize.generator"], havingValue = "GPAS")
|
||||||
@Bean
|
@Bean
|
||||||
fun gpasPseudonymGenerator(configProperties: GPasConfigProperties, retryTemplate: RetryTemplate, restTemplate: RestTemplate): Generator {
|
fun gpasPseudonymGenerator(configProperties: GPasConfigProperties, retryTemplate: RetryTemplate, restTemplate: RestTemplate): Generator {
|
||||||
try {
|
|
||||||
if (!configProperties.sslCaLocation.isNullOrBlank()) {
|
|
||||||
return GpasPseudonymGenerator(
|
|
||||||
configProperties,
|
|
||||||
retryTemplate,
|
|
||||||
createCustomGpasRestTemplate(configProperties)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
} catch (e: Exception) {
|
|
||||||
throw RuntimeException(e)
|
|
||||||
}
|
|
||||||
|
|
||||||
return GpasPseudonymGenerator(configProperties, retryTemplate, restTemplate)
|
return GpasPseudonymGenerator(configProperties, retryTemplate, restTemplate)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -115,81 +89,9 @@ class AppConfiguration {
|
|||||||
@ConditionalOnMissingBean
|
@ConditionalOnMissingBean
|
||||||
@Bean
|
@Bean
|
||||||
fun gpasPseudonymGeneratorOnDeprecatedProperty(configProperties: GPasConfigProperties, retryTemplate: RetryTemplate, restTemplate: RestTemplate): Generator {
|
fun gpasPseudonymGeneratorOnDeprecatedProperty(configProperties: GPasConfigProperties, retryTemplate: RetryTemplate, restTemplate: RestTemplate): Generator {
|
||||||
try {
|
|
||||||
if (!configProperties.sslCaLocation.isNullOrBlank()) {
|
|
||||||
return GpasPseudonymGenerator(
|
|
||||||
configProperties,
|
|
||||||
retryTemplate,
|
|
||||||
createCustomGpasRestTemplate(configProperties)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
} catch (e: Exception) {
|
|
||||||
throw RuntimeException(e)
|
|
||||||
}
|
|
||||||
|
|
||||||
return GpasPseudonymGenerator(configProperties, retryTemplate, restTemplate)
|
return GpasPseudonymGenerator(configProperties, retryTemplate, restTemplate)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun createCustomGpasRestTemplate(configProperties: GPasConfigProperties): RestTemplate {
|
|
||||||
fun getSslContext(certificateLocation: String): SSLContext? {
|
|
||||||
val ks = KeyStore.getInstance(KeyStore.getDefaultType())
|
|
||||||
|
|
||||||
val fis = FileInputStream(certificateLocation)
|
|
||||||
val ca = CertificateFactory.getInstance("X.509")
|
|
||||||
.generateCertificate(BufferedInputStream(fis)) as X509Certificate
|
|
||||||
|
|
||||||
ks.load(null, null)
|
|
||||||
ks.setCertificateEntry(1.toString(), ca)
|
|
||||||
|
|
||||||
val tmf = TrustManagerFactory.getInstance(
|
|
||||||
TrustManagerFactory.getDefaultAlgorithm()
|
|
||||||
)
|
|
||||||
tmf.init(ks)
|
|
||||||
|
|
||||||
val sslContext = SSLContext.getInstance("TLS")
|
|
||||||
sslContext.init(null, tmf.trustManagers, null)
|
|
||||||
|
|
||||||
return sslContext
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getCustomRestTemplate(customSslContext: SSLContext): RestTemplate {
|
|
||||||
val sslsf = SSLConnectionSocketFactory(customSslContext)
|
|
||||||
val socketFactoryRegistry = RegistryBuilder.create<ConnectionSocketFactory>()
|
|
||||||
.register("https", sslsf).register("http", PlainConnectionSocketFactory()).build()
|
|
||||||
|
|
||||||
val connectionManager = BasicHttpClientConnectionManager(
|
|
||||||
socketFactoryRegistry
|
|
||||||
)
|
|
||||||
val httpClient = HttpClients.custom()
|
|
||||||
.setConnectionManager(connectionManager).build()
|
|
||||||
|
|
||||||
val requestFactory = HttpComponentsClientHttpRequestFactory(
|
|
||||||
httpClient
|
|
||||||
)
|
|
||||||
return RestTemplate(requestFactory)
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
if (!configProperties.sslCaLocation.isNullOrBlank()) {
|
|
||||||
val customSslContext = getSslContext(configProperties.sslCaLocation)
|
|
||||||
logger.warn(
|
|
||||||
String.format(
|
|
||||||
"%s has been initialized with SSL certificate %s. This is deprecated in favor of including Root CA.",
|
|
||||||
this.javaClass.name, configProperties.sslCaLocation
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
if (customSslContext != null) {
|
|
||||||
return getCustomRestTemplate(customSslContext)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (e: Exception) {
|
|
||||||
throw RuntimeException(e)
|
|
||||||
}
|
|
||||||
|
|
||||||
throw RuntimeException("Custom SSL configuration for gPAS not usable")
|
|
||||||
}
|
|
||||||
|
|
||||||
@ConditionalOnProperty(value = ["app.pseudonymizer"], havingValue = "BUILDIN")
|
@ConditionalOnProperty(value = ["app.pseudonymizer"], havingValue = "BUILDIN")
|
||||||
@ConditionalOnMissingBean
|
@ConditionalOnMissingBean
|
||||||
@Bean
|
@Bean
|
||||||
|
Loading…
x
Reference in New Issue
Block a user