Skip to content

Commit

Permalink
FDP-2728: formatted
Browse files Browse the repository at this point in the history
  • Loading branch information
loesimmens committed Oct 28, 2024
1 parent 10fb05c commit c6e0ef5
Show file tree
Hide file tree
Showing 24 changed files with 200 additions and 203 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ and re-issue the SOAP request over there.

![](docs/proxy.svg)

- `Servce X` will try to call Service Y. You've configured X to make the request to the proxy instead
- `Service X` will try to call Service Y. You've configured X to make the request to the proxy instead
- `Proxy A` will
- store the HTTP connection used to receive the request and keep it open
- receive the SOAP body and some meta data
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
// SPDX-FileCopyrightText: Copyright Contributors to the GXF project
//
// SPDX-License-Identifier: Apache-2.0

package org.gxf.soapbridge

import com.github.tomakehurst.wiremock.client.WireMock.*
import com.github.tomakehurst.wiremock.core.WireMockConfiguration.wireMockConfig
import com.github.tomakehurst.wiremock.junit5.WireMockExtension
import java.net.http.HttpClient
import java.time.Duration
import org.assertj.core.api.Assertions.assertThat
import org.gxf.soapbridge.application.factories.SslContextFactory
import org.junit.jupiter.api.BeforeEach
Expand All @@ -15,14 +16,9 @@ import org.junit.jupiter.api.extension.RegisterExtension
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.boot.test.web.server.LocalServerPort
import org.springframework.context.ApplicationContext
import org.springframework.context.annotation.ComponentScan
import org.springframework.http.client.reactive.JdkClientHttpConnector
import org.springframework.kafka.test.context.EmbeddedKafka
import org.springframework.web.reactive.function.client.WebClient
import java.net.http.HttpClient
import java.time.Duration


@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@EmbeddedKafka(topics = ["requests", "responses"])
Expand All @@ -37,37 +33,33 @@ class EndToEndTest(
@BeforeEach
fun setUp() {
wireMockExtension.stubFor(
post(methodPath)
.withRequestBody(equalToXml(soapBody))
.willReturn(
ok().withBody(soapResponse)
)
post(methodPath).withRequestBody(equalToXml(soapBody)).willReturn(ok().withBody(soapResponse))
)
}

@Test
fun testRequestResponse() {
// Arrange an SSL context for organisation "testClient" using its client certificate
val sslContextForOrganisation = sslContextFactory.createSslContext("testClient")
val httpClient = HttpClient.newBuilder()
.sslContext(sslContextForOrganisation)
.build()
val webClient = WebClient.builder()
.clientConnector(JdkClientHttpConnector(httpClient))
.build()
val httpClient = HttpClient.newBuilder().sslContext(sslContextForOrganisation).build()
val webClient = WebClient.builder().clientConnector(JdkClientHttpConnector(httpClient)).build()

// Act: send SOAP request and get the answer
val responseBody = webClient.post().uri(callUrl)
.bodyValue(soapBody)
.exchangeToMono { it.bodyToMono(String::class.java) }
.timeout(Duration.ofSeconds(10))
.block()
val responseBody =
webClient
.post()
.uri(callUrl)
.bodyValue(soapBody)
.exchangeToMono { it.bodyToMono(String::class.java) }
.timeout(Duration.ofSeconds(10))
.block()

// Assert
assertThat(responseBody).isEqualTo(soapResponse)
}

val soapBody = """
val soapBody =
"""
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:m="http://www.example.org">
<soap:Header>
</soap:Header>
Expand All @@ -77,25 +69,29 @@ class EndToEndTest(
</m:GetStockPrice>
</soap:Body>
</soap:Envelope>
""".trimIndent()
"""
.trimIndent()

val soapResponse = "Read This Fine Message"

companion object {
@JvmField
@RegisterExtension
val wireMockExtension: WireMockExtension =
WireMockExtension.newInstance().options(
wireMockConfig()
.httpDisabled(true).httpsPort(8888)
.keystorePath("src/integrationTest/resources/proxy.keystore.jks")
.keystorePassword("123456")
.keyManagerPassword("123456")
.keystoreType("PKCS12")
.trustStorePath("src/integrationTest/resources/proxy.truststore.jks")
.trustStorePassword("123456")
.trustStoreType("PKCS12")
.needClientAuth(true)
).build()
WireMockExtension.newInstance()
.options(
wireMockConfig()
.httpDisabled(true)
.httpsPort(8888)
.keystorePath("src/integrationTest/resources/proxy.keystore.jks")
.keystorePassword("123456")
.keyManagerPassword("123456")
.keystoreType("PKCS12")
.trustStorePath("src/integrationTest/resources/proxy.truststore.jks")
.trustStorePassword("123456")
.trustStoreType("PKCS12")
.needClientAuth(true)
)
.build()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@
import static org.gxf.soapbridge.configuration.properties.HostnameVerificationStrategy.BROWSER_COMPATIBLE_HOSTNAMES;

import javax.net.ssl.HostnameVerifier;
import org.apache.http.conn.ssl.DefaultHostnameVerifier;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.hc.client5.http.ssl.DefaultHostnameVerifier;
import org.apache.hc.client5.http.ssl.NoopHostnameVerifier;
import org.gxf.soapbridge.configuration.properties.SoapConfigurationProperties;
import org.gxf.soapbridge.soap.exceptions.ProxyServerException;
import org.springframework.stereotype.Component;
Expand All @@ -23,9 +23,9 @@ public HostnameVerifierFactory(final SoapConfigurationProperties soapConfigurati
}

public HostnameVerifier getHostnameVerifier() throws ProxyServerException {
if (soapConfiguration.getHostnameVerificationStrategy() == ALLOW_ALL_HOSTNAMES) {
if (this.soapConfiguration.getHostnameVerificationStrategy() == ALLOW_ALL_HOSTNAMES) {
return new NoopHostnameVerifier();
} else if (soapConfiguration.getHostnameVerificationStrategy()
} else if (this.soapConfiguration.getHostnameVerificationStrategy()
== BROWSER_COMPATIBLE_HOSTNAMES) {
return new DefaultHostnameVerifier();
} else {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
// SPDX-FileCopyrightText: Copyright Contributors to the GXF project
//
// SPDX-License-Identifier: Apache-2.0

package org.gxf.soapbridge

import org.springframework.boot.autoconfigure.SpringBootApplication
Expand All @@ -10,11 +9,7 @@ import org.springframework.boot.runApplication
import org.springframework.scheduling.annotation.EnableAsync
import org.springframework.web.servlet.config.annotation.EnableWebMvc

@SpringBootApplication
@EnableWebMvc
@EnableAsync
@ConfigurationPropertiesScan
class SoapBridgeApplication
@SpringBootApplication @EnableWebMvc @EnableAsync @ConfigurationPropertiesScan class SoapBridgeApplication

fun main(args: Array<String>) {
runApplication<SoapBridgeApplication>(*args)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
// SPDX-FileCopyrightText: Copyright Contributors to the GXF project
//
// SPDX-License-Identifier: Apache-2.0

package org.gxf.soapbridge.configuration

import org.springframework.context.annotation.Bean
Expand All @@ -16,26 +15,15 @@ class SecurityConfiguration {

@Bean
fun filterChain(http: HttpSecurity): SecurityFilterChain =
http.authorizeHttpRequests {
it
.requestMatchers("/actuator/**").permitAll()
.anyRequest().authenticated()
}.x509 {
it
.subjectPrincipalRegex("CN=(.*?)(?:,|$)")
.userDetailsService(userDetailsService())
}.csrf { it.disable() }
http
.authorizeHttpRequests { it.requestMatchers("/actuator/**").permitAll().anyRequest().authenticated() }
.x509 { it.subjectPrincipalRegex("CN=(.*?)(?:,|$)").userDetailsService(userDetailsService()) }
.csrf { it.disable() }
.build()


/**
* Uses the CN of the client certificate as the username for Springs Principal object
*/
/** Uses the CN of the client certificate as the username for Springs Principal object */
@Bean
fun userDetailsService(): UserDetailsService =
UserDetailsService { username ->
return@UserDetailsService User(
username, "", emptyList()
)
}
fun userDetailsService(): UserDetailsService = UserDetailsService { username ->
return@UserDetailsService User(username, "", emptyList())
}
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright Contributors to the GXF project
//
// SPDX-License-Identifier: Apache-2.0
package org.gxf.soapbridge.configuration.kafka

import org.springframework.context.annotation.Bean
Expand All @@ -8,11 +11,9 @@ import org.springframework.util.backoff.FixedBackOff
@Configuration
class KafkaConfiguration {

/**
* Retry messages two times before giving up on the message
*/
/** Retry messages two times before giving up on the message */
@Bean
fun errorHandler(): DefaultErrorHandler {
return DefaultErrorHandler(FixedBackOff(0, 2L))
}
}
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
// SPDX-FileCopyrightText: Copyright Contributors to the GXF project
//
// SPDX-License-Identifier: Apache-2.0

package org.gxf.soapbridge.configuration.properties

import io.github.oshai.kotlinlogging.KotlinLogging
import org.springframework.boot.context.properties.ConfigurationProperties
import java.io.IOException
import java.nio.file.Files
import java.nio.file.Paths
Expand All @@ -14,6 +12,7 @@ import java.security.PrivateKey
import java.security.PublicKey
import java.security.spec.PKCS8EncodedKeySpec
import java.security.spec.X509EncodedKeySpec
import org.springframework.boot.context.properties.ConfigurationProperties

@ConfigurationProperties("security")
class SecurityConfigurationProperties(
Expand All @@ -22,12 +21,7 @@ class SecurityConfigurationProperties(
val signing: SigningConfigurationProperties
)

class StoreConfigurationProperties(
val location: String,
val password: String,
val type: String
)

class StoreConfigurationProperties(val location: String, val password: String, val type: String)

class SigningConfigurationProperties(
keyType: String,
Expand All @@ -46,9 +40,7 @@ class SigningConfigurationProperties(
/** Public key used for verification. */
val verifyKey = createPublicKey(verifyKeyFile, keyType, provider)

private fun createPrivateKey(
keyPath: String, keyType: String, provider: String
): PrivateKey? {
private fun createPrivateKey(keyPath: String, keyType: String, provider: String): PrivateKey? {
return try {
val key = readKeyFromDisk(keyPath)
val privateKeySpec = PKCS8EncodedKeySpec(key)
Expand All @@ -60,9 +52,7 @@ class SigningConfigurationProperties(
}
}

private fun createPublicKey(
keyPath: String, keyType: String, provider: String
): PublicKey? {
private fun createPublicKey(keyPath: String, keyType: String, provider: String): PublicKey? {
return try {
val key = readKeyFromDisk(keyPath)
val publicKeySpec = X509EncodedKeySpec(key)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
// SPDX-FileCopyrightText: Copyright Contributors to the GXF project
//
// SPDX-License-Identifier: Apache-2.0

package org.gxf.soapbridge.configuration.properties

import org.springframework.boot.context.properties.ConfigurationProperties
Expand All @@ -10,35 +9,31 @@ import org.springframework.boot.context.properties.ConfigurationProperties
class SoapConfigurationProperties(
val hostnameVerificationStrategy: HostnameVerificationStrategy,
/**
* Maximum number of seconds this {@link SoapEndpoint} will wait for a response from the other end
* before terminating the connection with the client application.
* Maximum number of seconds this {@link SoapEndpoint} will wait for a response from the other end before
* terminating the connection with the client application.
*/
val timeout: Int,
/**
* Timeouts for specific functions.
*/
/** Timeouts for specific functions. */
val customTimeouts: Map<String, Int> = emptyMap(),
/**
* TODO Can we search for certificates on both sides
*
* Property to set common name based on the organisation on requests published to Kafka.
*
* If set to false the other listening proxy doesn't search for certificates by [org.gxf.soapbridge.valueobjects.ProxyServerRequestMessage.commonName].
* Instead, the other proxy will generate a new ssl context.
* If set to false the other listening proxy doesn't search for certificates by
* [org.gxf.soapbridge.valueobjects.ProxyServerRequestMessage.commonName]. Instead, the other proxy will generate a
* new ssl context.
*/
val useOrganisationFromRequest: Boolean = true,
val callEndpoint: SoapEndpointConfiguration,
)

enum class HostnameVerificationStrategy {
ALLOW_ALL_HOSTNAMES, BROWSER_COMPATIBLE_HOSTNAMES
ALLOW_ALL_HOSTNAMES,
BROWSER_COMPATIBLE_HOSTNAMES
}

class SoapEndpointConfiguration(
host: String,
port: Int,
protocol: String
) {
class SoapEndpointConfiguration(host: String, port: Int, protocol: String) {
// TODO Use java.net.URI class
val hostAndPort = "$host:$port"
val uri = "$protocol://${hostAndPort}"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
// SPDX-FileCopyrightText: Copyright Contributors to the GXF project
//
// SPDX-License-Identifier: Apache-2.0

package org.gxf.soapbridge.exceptions


class ProxyMessageException(message: String?) : Exception(message)
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
// SPDX-FileCopyrightText: Copyright Contributors to the GXF project
//
// SPDX-License-Identifier: Apache-2.0

package org.gxf.soapbridge.kafka.listeners

import io.github.oshai.kotlinlogging.KotlinLogging
Expand All @@ -13,7 +12,7 @@ import org.springframework.stereotype.Component

@Component
class ProxyRequestKafkaListener(private val platformCommunicationService: PlatformCommunicationService) {
private val logger = KotlinLogging.logger { }
private val logger = KotlinLogging.logger {}

@KafkaListener(
id = "gxf-request-consumer",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
// SPDX-FileCopyrightText: Copyright Contributors to the GXF project
//
// SPDX-License-Identifier: Apache-2.0

package org.gxf.soapbridge.kafka.listeners

import io.github.oshai.kotlinlogging.KotlinLogging
Expand All @@ -13,7 +12,7 @@ import org.springframework.stereotype.Component

@Component
class ProxyResponseKafkaListener(private val clientCommunicationService: ClientCommunicationService) {
private val logger = KotlinLogging.logger { }
private val logger = KotlinLogging.logger {}

@KafkaListener(
id = "gxf-response-consumer",
Expand Down
Loading

0 comments on commit c6e0ef5

Please sign in to comment.