diff --git a/pom.xml b/pom.xml
index 3c0eefc97..5052bc294 100644
--- a/pom.xml
+++ b/pom.xml
@@ -239,14 +239,19 @@
no.nav.security
- token-validation-core
+ token-client-spring
${token-validation-spring.version}
no.nav.familie.felles
- http-client
+ log
${felles.version}
+
+ no.nav.security
+ token-validation-core
+ ${token-validation-spring.version}
+
ch.qos.logback
logback-classic
diff --git a/src/main/kotlin/no/nav/familie/tilbake/config/ApplicationConfig.kt b/src/main/kotlin/no/nav/familie/tilbake/config/ApplicationConfig.kt
index 2c129488d..1aee4a0c6 100644
--- a/src/main/kotlin/no/nav/familie/tilbake/config/ApplicationConfig.kt
+++ b/src/main/kotlin/no/nav/familie/tilbake/config/ApplicationConfig.kt
@@ -2,12 +2,8 @@ package no.nav.familie.tilbake.config
import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.module.kotlin.KotlinModule
-import no.nav.familie.http.client.RetryOAuth2HttpClient
-import no.nav.familie.http.config.RestTemplateAzure
import no.nav.familie.log.filter.LogFilter
import no.nav.familie.prosessering.config.ProsesseringInfoProvider
-import no.nav.security.token.support.client.core.http.OAuth2HttpClient
-import no.nav.security.token.support.client.core.oauth2.OAuth2AccessTokenResponse
import no.nav.security.token.support.client.spring.oauth2.EnableOAuth2Client
import no.nav.security.token.support.spring.SpringTokenValidationContextHolder
import no.nav.security.token.support.spring.api.EnableJwtTokenValidation
@@ -21,19 +17,16 @@ import org.springframework.boot.web.servlet.server.ServletWebServerFactory
import org.springframework.cache.annotation.EnableCaching
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.ComponentScan
-import org.springframework.context.annotation.Import
import org.springframework.context.annotation.Primary
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter
import org.springframework.scheduling.annotation.EnableScheduling
-import org.springframework.web.client.RestClient
import org.springframework.web.client.RestTemplate
import java.time.Duration
import java.time.temporal.ChronoUnit
@SpringBootConfiguration
-@ComponentScan(ApplicationConfig.PAKKE_NAVN, "no.nav.familie.sikkerhet", "no.nav.familie.prosessering", "no.nav.familie.unleash")
+@ComponentScan(ApplicationConfig.PAKKE_NAVN, "no.nav.familie.prosessering", "no.nav.familie.unleash")
@EnableJwtTokenValidation(ignore = ["org.springframework", "org.springdoc"])
-@Import(RestTemplateAzure::class)
@EnableOAuth2Client(cacheEnabled = true)
@EnableScheduling
@EnableCaching
@@ -65,28 +58,11 @@ class ApplicationConfig {
fun restTemplateBuilder(objectMapper: ObjectMapper): RestTemplateBuilder {
val jackson2HttpMessageConverter = MappingJackson2HttpMessageConverter(objectMapper)
return RestTemplateBuilder()
- .setConnectTimeout(Duration.of(2, ChronoUnit.SECONDS))
- .setReadTimeout(Duration.of(30, ChronoUnit.SECONDS))
+ .connectTimeout(Duration.of(2, ChronoUnit.SECONDS))
+ .readTimeout(Duration.of(30, ChronoUnit.SECONDS))
.additionalMessageConverters(listOf(jackson2HttpMessageConverter) + RestTemplate().messageConverters)
}
- /**
- * Overskriver OAuth2HttpClient som settes opp i token-support som ikke kan få med objectMapper fra felles
- * pga. .setVisibility(PropertyAccessor.SETTER, JsonAutoDetect.Visibility.NONE)
- * og [OAuth2AccessTokenResponse] som burde settes med setters, då feltnavn heter noe annet enn feltet i json
- */
- @Bean
- @Primary
- fun oAuth2HttpClient(): OAuth2HttpClient =
- RetryOAuth2HttpClient(
- RestClient.create(
- RestTemplateBuilder()
- .setConnectTimeout(Duration.of(2, ChronoUnit.SECONDS))
- .setReadTimeout(Duration.of(4, ChronoUnit.SECONDS))
- .build(),
- ),
- )
-
@Bean
fun prosesseringInfoProvider(
@Value("\${rolle.prosessering}") prosesseringRolle: String,
diff --git a/src/main/kotlin/no/nav/familie/tilbake/config/HttpClientConfig.kt b/src/main/kotlin/no/nav/familie/tilbake/config/HttpClientConfig.kt
new file mode 100644
index 000000000..ca159fedf
--- /dev/null
+++ b/src/main/kotlin/no/nav/familie/tilbake/config/HttpClientConfig.kt
@@ -0,0 +1,38 @@
+package no.nav.familie.tilbake.config
+
+import no.nav.familie.tilbake.http.BearerTokenClientInterceptor
+import no.nav.familie.tilbake.http.ConsumerIdClientInterceptor
+import no.nav.familie.tilbake.http.MdcValuesPropagatingClientInterceptor
+import org.springframework.boot.web.client.RestTemplateBuilder
+import org.springframework.context.annotation.Bean
+import org.springframework.context.annotation.Configuration
+import org.springframework.web.client.RestOperations
+
+@Configuration
+class HttpClientConfig {
+ private val restTemplateBuilder = RestTemplateBuilder()
+
+ @Bean("azure")
+ fun restTemplateEntraIDBearer(
+ consumerIdClientInterceptor: ConsumerIdClientInterceptor,
+ bearerTokenClientInterceptor: BearerTokenClientInterceptor,
+ ): RestOperations =
+ restTemplateBuilder
+ .additionalInterceptors(
+ consumerIdClientInterceptor,
+ bearerTokenClientInterceptor,
+ MdcValuesPropagatingClientInterceptor(),
+ ).build()
+
+ @Bean("azureClientCredential")
+ fun restTemplateClientCredentialEntraIdBearer(
+ consumerIdClientInterceptor: ConsumerIdClientInterceptor,
+ bearerTokenClientInterceptor: BearerTokenClientInterceptor,
+ ): RestOperations =
+ restTemplateBuilder
+ .additionalInterceptors(
+ consumerIdClientInterceptor,
+ bearerTokenClientInterceptor,
+ MdcValuesPropagatingClientInterceptor(),
+ ).build()
+}
diff --git "a/src/main/kotlin/no/nav/familie/tilbake/dokumentbestilling/felles/pdf/Journalf\303\270ringService.kt" "b/src/main/kotlin/no/nav/familie/tilbake/dokumentbestilling/felles/pdf/Journalf\303\270ringService.kt"
index f9673706e..30bee6094 100644
--- "a/src/main/kotlin/no/nav/familie/tilbake/dokumentbestilling/felles/pdf/Journalf\303\270ringService.kt"
+++ "b/src/main/kotlin/no/nav/familie/tilbake/dokumentbestilling/felles/pdf/Journalf\303\270ringService.kt"
@@ -44,6 +44,7 @@ class JournalføringService(
fun hentJournalposter(behandlingId: UUID): List {
val behandling = behandlingRepository.findById(behandlingId).orElseThrow()
val fagsak = behandling.let { fagsakRepository.findById(it.fagsakId).orElseThrow() }
+ val logContext = SecureLog.Context.medBehandling(fagsak.eksternFagsakId, behandling.id.toString())
val journalposter =
fagsak.let {
integrasjonerClient.hentJournalposterForBruker(
@@ -56,6 +57,7 @@ class JournalføringService(
),
tema = listOf(hentTema(fagsystem = fagsak.fagsystem)),
),
+ logContext,
)
}
return journalposter.filter { it.sak?.fagsakId == fagsak.eksternFagsakId }
diff --git a/src/main/kotlin/no/nav/familie/tilbake/dokumentbestilling/felles/pdf/PdfBrevService.kt b/src/main/kotlin/no/nav/familie/tilbake/dokumentbestilling/felles/pdf/PdfBrevService.kt
index 102b72fb2..c8775c751 100644
--- a/src/main/kotlin/no/nav/familie/tilbake/dokumentbestilling/felles/pdf/PdfBrevService.kt
+++ b/src/main/kotlin/no/nav/familie/tilbake/dokumentbestilling/felles/pdf/PdfBrevService.kt
@@ -1,6 +1,5 @@
package no.nav.familie.tilbake.dokumentbestilling.felles.pdf
-import no.nav.familie.http.client.RessursException
import no.nav.familie.kontrakter.felles.dokdist.Distribusjonstidspunkt
import no.nav.familie.kontrakter.felles.dokdist.Distribusjonstype
import no.nav.familie.kontrakter.felles.objectMapper
@@ -16,6 +15,7 @@ import no.nav.familie.tilbake.dokumentbestilling.felles.header.TekstformatererHe
import no.nav.familie.tilbake.dokumentbestilling.felles.task.PubliserJournalpostTask
import no.nav.familie.tilbake.dokumentbestilling.felles.task.PubliserJournalpostTaskData
import no.nav.familie.tilbake.dokumentbestilling.fritekstbrev.JournalpostIdOgDokumentId
+import no.nav.familie.tilbake.http.RessursException
import no.nav.familie.tilbake.log.SecureLog
import no.nav.familie.tilbake.micrometer.TellerService
import no.nav.familie.tilbake.pdfgen.Dokumentvariant
diff --git "a/src/main/kotlin/no/nav/familie/tilbake/dokumentbestilling/felles/task/DistribuerDokumentVedD\303\270dsfallTask.kt" "b/src/main/kotlin/no/nav/familie/tilbake/dokumentbestilling/felles/task/DistribuerDokumentVedD\303\270dsfallTask.kt"
index 1b23efd45..9a61106f0 100644
--- "a/src/main/kotlin/no/nav/familie/tilbake/dokumentbestilling/felles/task/DistribuerDokumentVedD\303\270dsfallTask.kt"
+++ "b/src/main/kotlin/no/nav/familie/tilbake/dokumentbestilling/felles/task/DistribuerDokumentVedD\303\270dsfallTask.kt"
@@ -1,6 +1,5 @@
package no.nav.familie.tilbake.dokumentbestilling.felles.task
-import no.nav.familie.http.client.RessursException
import no.nav.familie.kontrakter.felles.Fagsystem
import no.nav.familie.kontrakter.felles.dokdist.Distribusjonstidspunkt
import no.nav.familie.kontrakter.felles.dokdist.Distribusjonstype
@@ -12,6 +11,7 @@ import no.nav.familie.tilbake.dokumentbestilling.felles.Brevmottager
import no.nav.familie.tilbake.dokumentbestilling.felles.domain.Brevtype
import no.nav.familie.tilbake.historikkinnslag.HistorikkService
import no.nav.familie.tilbake.historikkinnslag.TilbakekrevingHistorikkinnslagstype
+import no.nav.familie.tilbake.http.RessursException
import no.nav.familie.tilbake.integration.familie.IntegrasjonerClient
import no.nav.familie.tilbake.log.SecureLog.Context.Companion.logContext
import no.nav.familie.tilbake.log.TracedLogger
diff --git a/src/main/kotlin/no/nav/familie/tilbake/dokumentbestilling/felles/task/PubliserJournalpostTask.kt b/src/main/kotlin/no/nav/familie/tilbake/dokumentbestilling/felles/task/PubliserJournalpostTask.kt
index fb1fe3a1a..2a52cd606 100644
--- a/src/main/kotlin/no/nav/familie/tilbake/dokumentbestilling/felles/task/PubliserJournalpostTask.kt
+++ b/src/main/kotlin/no/nav/familie/tilbake/dokumentbestilling/felles/task/PubliserJournalpostTask.kt
@@ -1,6 +1,5 @@
package no.nav.familie.tilbake.dokumentbestilling.felles.task
-import no.nav.familie.http.client.RessursException
import no.nav.familie.kontrakter.felles.Fagsystem
import no.nav.familie.kontrakter.felles.dokdist.Distribusjonstidspunkt
import no.nav.familie.kontrakter.felles.dokdist.Distribusjonstype
@@ -10,6 +9,7 @@ import no.nav.familie.prosessering.AsyncTaskStep
import no.nav.familie.prosessering.TaskStepBeskrivelse
import no.nav.familie.prosessering.domene.Task
import no.nav.familie.tilbake.behandling.task.TracableTaskService
+import no.nav.familie.tilbake.http.RessursException
import no.nav.familie.tilbake.integration.familie.IntegrasjonerClient
import no.nav.familie.tilbake.log.SecureLog
import no.nav.familie.tilbake.log.SecureLog.Context.Companion.logContext
diff --git a/src/main/kotlin/no/nav/familie/tilbake/http/AbstractBearerTokenInterceptor.kt b/src/main/kotlin/no/nav/familie/tilbake/http/AbstractBearerTokenInterceptor.kt
new file mode 100644
index 000000000..54f8d7ddc
--- /dev/null
+++ b/src/main/kotlin/no/nav/familie/tilbake/http/AbstractBearerTokenInterceptor.kt
@@ -0,0 +1,32 @@
+package no.nav.familie.tilbake.http
+
+import com.nimbusds.oauth2.sdk.GrantType
+import no.nav.security.token.support.client.core.ClientProperties
+import no.nav.security.token.support.client.core.oauth2.OAuth2AccessTokenService
+import no.nav.security.token.support.client.spring.ClientConfigurationProperties
+import no.nav.security.token.support.core.exceptions.JwtTokenValidatorException
+import org.springframework.http.client.ClientHttpRequestInterceptor
+import java.net.URI
+
+abstract class AbstractBearerTokenInterceptor(
+ protected val oAuth2AccessTokenService: OAuth2AccessTokenService,
+ protected val clientConfigurationProperties: ClientConfigurationProperties,
+) : ClientHttpRequestInterceptor {
+ protected fun genererAccessToken(clientProperties: ClientProperties): String =
+ oAuth2AccessTokenService
+ .getAccessToken(clientProperties)
+ .access_token ?: throw JwtTokenValidatorException("Kunne ikke hente accesstoken")
+
+ protected fun ClientConfigurationProperties.findByURI(uri: URI) =
+ registration
+ .values
+ .filter { uri.toString().startsWith(it.resourceUrl.toString()) }
+
+ protected fun clientPropertiesForGrantType(
+ values: List,
+ grantType: GrantType,
+ uri: URI,
+ ): ClientProperties =
+ values.firstOrNull { grantType == it.grantType }
+ ?: error("could not find oauth2 client config for uri=$uri and grant type=$grantType")
+}
diff --git a/src/main/kotlin/no/nav/familie/tilbake/http/AbstractPingableRestClient.kt b/src/main/kotlin/no/nav/familie/tilbake/http/AbstractPingableRestClient.kt
new file mode 100644
index 000000000..3caa1d990
--- /dev/null
+++ b/src/main/kotlin/no/nav/familie/tilbake/http/AbstractPingableRestClient.kt
@@ -0,0 +1,115 @@
+import com.fasterxml.jackson.module.kotlin.readValue
+import io.micrometer.core.instrument.Counter
+import io.micrometer.core.instrument.Metrics
+import io.micrometer.core.instrument.Timer
+import no.nav.familie.kontrakter.felles.Ressurs
+import no.nav.familie.kontrakter.felles.objectMapper
+import no.nav.familie.tilbake.http.RessursException
+import org.slf4j.Logger
+import org.slf4j.LoggerFactory
+import org.springframework.http.HttpEntity
+import org.springframework.http.HttpHeaders
+import org.springframework.http.HttpMethod
+import org.springframework.http.ResponseEntity
+import org.springframework.web.client.HttpClientErrorException
+import org.springframework.web.client.HttpServerErrorException
+import org.springframework.web.client.ResourceAccessException
+import org.springframework.web.client.RestClientResponseException
+import org.springframework.web.client.RestOperations
+import org.springframework.web.client.exchange
+import java.net.URI
+import java.util.concurrent.TimeUnit
+
+abstract class AbstractPingableRestClient(
+ val operations: RestOperations,
+ metricsPrefix: String,
+) {
+ private val secureLogger = LoggerFactory.getLogger("secureLogger")
+ protected val log: Logger = LoggerFactory.getLogger(this::class.java)
+ private val responstid: Timer = Metrics.timer("$metricsPrefix.tid")
+ private val responsSuccess: Counter = Metrics.counter("$metricsPrefix.response", "status", "success")
+ private val responsFailure: Counter = Metrics.counter("$metricsPrefix.response", "status", "failure")
+
+ inline fun getForEntity(
+ uri: URI,
+ httpHeaders: HttpHeaders? = null,
+ ): T = executeMedMetrics(uri) { operations.exchange(uri, HttpMethod.GET, HttpEntity(null, httpHeaders)) }
+
+ inline fun postForEntity(
+ uri: URI,
+ payload: Any,
+ httpHeaders: HttpHeaders? = null,
+ ): T = executeMedMetrics(uri) { operations.exchange(uri, HttpMethod.POST, HttpEntity(payload, httpHeaders)) }
+
+ inline fun putForEntity(
+ uri: URI,
+ payload: Any,
+ httpHeaders: HttpHeaders? = null,
+ ): T = executeMedMetrics(uri) { operations.exchange(uri, HttpMethod.PUT, HttpEntity(payload, httpHeaders)) }
+
+ inline fun patchForEntity(
+ uri: URI,
+ payload: Any,
+ httpHeaders: HttpHeaders? = null,
+ ): T = executeMedMetrics(uri) { operations.exchange(uri, HttpMethod.PATCH, HttpEntity(payload, httpHeaders)) }
+
+ inline fun deleteForEntity(
+ uri: URI,
+ payload: Any? = null,
+ httpHeaders: HttpHeaders? = null,
+ ): T = executeMedMetrics(uri) { operations.exchange(uri, HttpMethod.DELETE, HttpEntity(payload, httpHeaders)) }
+
+ private fun validerOgPakkUt(
+ response: ResponseEntity,
+ uri: URI,
+ ): T {
+ if (!response.statusCode.is2xxSuccessful) {
+ secureLogger.info("Kall mot {} feilet: {}", uri.toString(), response.body?.toString())
+ log.info("Kall mot {} feilet: {}", uri.toString(), response.statusCode.toString())
+ throw HttpServerErrorException(response.statusCode, "", response.body?.toString()?.toByteArray(), Charsets.UTF_8)
+ }
+ return response.body as T
+ }
+
+ fun executeMedMetrics(
+ uri: URI,
+ function: () -> ResponseEntity,
+ ): T {
+ try {
+ val startTime = System.nanoTime()
+ val responseEntity = function.invoke()
+ responstid.record(System.nanoTime() - startTime, TimeUnit.NANOSECONDS)
+ responsSuccess.increment()
+ return validerOgPakkUt(responseEntity, uri)
+ } catch (e: RestClientResponseException) {
+ responsFailure.increment()
+ secureLogger.warn("RestClientResponseException ved kall mot uri={}", uri.toString(), e)
+ lesRessurs(e)?.let { throw RessursException(it, e) } ?: throw e
+ } catch (e: HttpClientErrorException) {
+ responsFailure.increment()
+ secureLogger.warn("HttpClientErrorException ved kall mot uri={}", uri.toString(), e)
+ lesRessurs(e)?.let { throw RessursException(it, e) } ?: throw e
+ } catch (e: ResourceAccessException) {
+ responsFailure.increment()
+ secureLogger.warn("ResourceAccessException ved kall mot uri={}", uri.toString(), e)
+ throw e
+ } catch (e: Exception) {
+ responsFailure.increment()
+ secureLogger.warn("Feil ved kall mot uri={}", uri.toString(), e)
+ throw RuntimeException("Feil ved kall mot uri=$uri", e)
+ }
+ }
+
+ private fun lesRessurs(e: RestClientResponseException): Ressurs? =
+ try {
+ if (e.responseBodyAsString.contains("status")) {
+ objectMapper.readValue>(e.responseBodyAsString)
+ } else {
+ null
+ }
+ } catch (ex: Exception) {
+ null
+ }
+
+ override fun toString(): String = this::class.simpleName + " [operations=" + operations + "]"
+}
diff --git a/src/main/kotlin/no/nav/familie/tilbake/http/BearerTokenClientCredentialsClientInterceptor.kt b/src/main/kotlin/no/nav/familie/tilbake/http/BearerTokenClientCredentialsClientInterceptor.kt
new file mode 100644
index 000000000..7617d7cc4
--- /dev/null
+++ b/src/main/kotlin/no/nav/familie/tilbake/http/BearerTokenClientCredentialsClientInterceptor.kt
@@ -0,0 +1,27 @@
+package no.nav.familie.tilbake.http
+
+import com.nimbusds.oauth2.sdk.GrantType
+import no.nav.security.token.support.client.core.oauth2.OAuth2AccessTokenService
+import no.nav.security.token.support.client.spring.ClientConfigurationProperties
+import org.springframework.http.HttpRequest
+import org.springframework.http.client.ClientHttpRequestExecution
+import org.springframework.http.client.ClientHttpResponse
+import org.springframework.stereotype.Component
+
+@Component
+class BearerTokenClientCredentialsClientInterceptor(
+ oAuth2AccessTokenService: OAuth2AccessTokenService,
+ clientConfigurationProperties: ClientConfigurationProperties,
+) : AbstractBearerTokenInterceptor(oAuth2AccessTokenService, clientConfigurationProperties) {
+ override fun intercept(
+ request: HttpRequest,
+ body: ByteArray,
+ execution: ClientHttpRequestExecution,
+ ): ClientHttpResponse {
+ val clientProperties = clientPropertiesForGrantType(clientConfigurationProperties.findByURI(request.uri), GrantType.CLIENT_CREDENTIALS, request.uri)
+ request.headers.setBearerAuth(
+ genererAccessToken(clientProperties),
+ )
+ return execution.execute(request, body)
+ }
+}
diff --git a/src/main/kotlin/no/nav/familie/tilbake/http/BearerTokenClientInterceptor.kt b/src/main/kotlin/no/nav/familie/tilbake/http/BearerTokenClientInterceptor.kt
new file mode 100644
index 000000000..af244691d
--- /dev/null
+++ b/src/main/kotlin/no/nav/familie/tilbake/http/BearerTokenClientInterceptor.kt
@@ -0,0 +1,49 @@
+package no.nav.familie.tilbake.http
+
+import com.nimbusds.oauth2.sdk.GrantType
+import no.nav.security.token.support.client.core.ClientProperties
+import no.nav.security.token.support.client.core.oauth2.OAuth2AccessTokenService
+import no.nav.security.token.support.client.spring.ClientConfigurationProperties
+import no.nav.security.token.support.spring.SpringTokenValidationContextHolder
+import org.springframework.http.HttpRequest
+import org.springframework.http.client.ClientHttpRequestExecution
+import org.springframework.http.client.ClientHttpResponse
+import org.springframework.stereotype.Component
+import java.net.URI
+
+@Component("entraTokenInterceptor")
+class BearerTokenClientInterceptor(
+ oAuth2AccessTokenService: OAuth2AccessTokenService,
+ clientConfigurationProperties: ClientConfigurationProperties,
+) : AbstractBearerTokenInterceptor(oAuth2AccessTokenService, clientConfigurationProperties) {
+ override fun intercept(
+ request: HttpRequest,
+ body: ByteArray,
+ execution: ClientHttpRequestExecution,
+ ): ClientHttpResponse {
+ request.headers.setBearerAuth(genererAccessToken(clientPropertiesFor(request.uri)))
+ return execution.execute(request, body)
+ }
+
+ private fun clientPropertiesFor(uri: URI): ClientProperties {
+ val clientProperties = clientConfigurationProperties.findByURI(uri)
+ return if (clientProperties.size == 1) {
+ clientProperties.first()
+ } else {
+ clientPropertiesForGrantType(clientProperties, clientCredentialOrJwtBearer(), uri)
+ }
+ }
+
+ private fun clientCredentialOrJwtBearer() = if (erSystembruker()) GrantType.CLIENT_CREDENTIALS else GrantType.JWT_BEARER
+
+ private fun erSystembruker(): Boolean {
+ return try {
+ val preferredUsername =
+ SpringTokenValidationContextHolder().getTokenValidationContext().getClaims("azuread").get("preferred_username")
+ return preferredUsername == null
+ } catch (e: Throwable) {
+ // Ingen request context. Skjer ved kall som har opphav i kjørende applikasjon. Ping etc.
+ true
+ }
+ }
+}
diff --git a/src/main/kotlin/no/nav/familie/tilbake/http/ConsumerIdClientInterceptor.kt b/src/main/kotlin/no/nav/familie/tilbake/http/ConsumerIdClientInterceptor.kt
new file mode 100644
index 000000000..6dcb7267e
--- /dev/null
+++ b/src/main/kotlin/no/nav/familie/tilbake/http/ConsumerIdClientInterceptor.kt
@@ -0,0 +1,22 @@
+package no.nav.familie.tilbake.http
+
+import org.springframework.beans.factory.annotation.Value
+import org.springframework.http.HttpRequest
+import org.springframework.http.client.ClientHttpRequestExecution
+import org.springframework.http.client.ClientHttpRequestInterceptor
+import org.springframework.http.client.ClientHttpResponse
+import org.springframework.stereotype.Component
+
+@Component
+class ConsumerIdClientInterceptor(
+ @Value("\${application.name}") private val appName: String,
+) : ClientHttpRequestInterceptor {
+ override fun intercept(
+ request: HttpRequest,
+ body: ByteArray,
+ execution: ClientHttpRequestExecution,
+ ): ClientHttpResponse {
+ request.headers.add("Nav-Consumer-Id", appName)
+ return execution.execute(request, body)
+ }
+}
diff --git a/src/main/kotlin/no/nav/familie/tilbake/http/MdcValuesPropagatingClientInterceptor.kt b/src/main/kotlin/no/nav/familie/tilbake/http/MdcValuesPropagatingClientInterceptor.kt
new file mode 100644
index 000000000..1a49c6423
--- /dev/null
+++ b/src/main/kotlin/no/nav/familie/tilbake/http/MdcValuesPropagatingClientInterceptor.kt
@@ -0,0 +1,23 @@
+package no.nav.familie.tilbake.http
+
+import org.slf4j.MDC
+import org.springframework.http.HttpRequest
+import org.springframework.http.client.ClientHttpRequestExecution
+import org.springframework.http.client.ClientHttpRequestInterceptor
+import org.springframework.http.client.ClientHttpResponse
+import java.util.UUID
+
+class MdcValuesPropagatingClientInterceptor : ClientHttpRequestInterceptor {
+ override fun intercept(
+ request: HttpRequest,
+ body: ByteArray,
+ execution: ClientHttpRequestExecution,
+ ): ClientHttpResponse {
+ val callId = MDC.get("callId") ?: UUID.randomUUID().toString()
+ val requestId = MDC.get("requestId") ?: callId
+ request.headers.add("Nav-Call-Id", callId)
+ request.headers.add("X-Request-ID", requestId)
+
+ return execution.execute(request, body)
+ }
+}
diff --git a/src/main/kotlin/no/nav/familie/tilbake/http/RessursException.kt b/src/main/kotlin/no/nav/familie/tilbake/http/RessursException.kt
new file mode 100644
index 000000000..7456afe7f
--- /dev/null
+++ b/src/main/kotlin/no/nav/familie/tilbake/http/RessursException.kt
@@ -0,0 +1,11 @@
+package no.nav.familie.tilbake.http
+
+import no.nav.familie.kontrakter.felles.Ressurs
+import org.springframework.http.HttpStatus
+import org.springframework.web.client.RestClientResponseException
+
+class RessursException(
+ val ressurs: Ressurs,
+ cause: RestClientResponseException,
+ val httpStatus: HttpStatus = HttpStatus.valueOf(cause.statusCode.value()),
+) : RuntimeException(cause)
diff --git a/src/main/kotlin/no/nav/familie/tilbake/integration/familie/IntegrasjonerClient.kt b/src/main/kotlin/no/nav/familie/tilbake/integration/familie/IntegrasjonerClient.kt
index c08c7ae89..d22df78dd 100644
--- a/src/main/kotlin/no/nav/familie/tilbake/integration/familie/IntegrasjonerClient.kt
+++ b/src/main/kotlin/no/nav/familie/tilbake/integration/familie/IntegrasjonerClient.kt
@@ -1,6 +1,6 @@
package no.nav.familie.tilbake.integration.familie
-import no.nav.familie.http.client.AbstractPingableRestClient
+import AbstractPingableRestClient
import no.nav.familie.kontrakter.felles.Fagsystem
import no.nav.familie.kontrakter.felles.Fil
import no.nav.familie.kontrakter.felles.Ressurs
@@ -25,6 +25,7 @@ import no.nav.familie.kontrakter.felles.organisasjon.Organisasjon
import no.nav.familie.kontrakter.felles.saksbehandler.Saksbehandler
import no.nav.familie.kontrakter.felles.tilgangskontroll.Tilgang
import no.nav.familie.tilbake.config.IntegrasjonerConfig
+import no.nav.familie.tilbake.log.SecureLog
import org.springframework.beans.factory.annotation.Qualifier
import org.springframework.cache.annotation.Cacheable
import org.springframework.http.HttpHeaders
@@ -40,13 +41,6 @@ class IntegrasjonerClient(
@Qualifier("azure") restOperations: RestOperations,
private val integrasjonerConfig: IntegrasjonerConfig,
) : AbstractPingableRestClient(restOperations, "familie.integrasjoner") {
- override val pingUri: URI =
- UriComponentsBuilder
- .fromUri(integrasjonerConfig.integrasjonUri)
- .path(IntegrasjonerConfig.PATH_PING)
- .build()
- .toUri()
-
private val arkiverUri: URI =
UriComponentsBuilder
.fromUri(integrasjonerConfig.integrasjonUri)
@@ -265,11 +259,17 @@ class IntegrasjonerClient(
)
}
- fun hentJournalposterForBruker(journalposterForBrukerRequest: JournalposterForBrukerRequest): List {
- secureLogger.info(
- "henter journalposter for bruker med ident ${journalposterForBrukerRequest.brukerId} " +
- "og data $journalposterForBrukerRequest",
- )
+ fun hentJournalposterForBruker(
+ journalposterForBrukerRequest: JournalposterForBrukerRequest,
+ logContext: SecureLog.Context,
+ ): List {
+ SecureLog.medContext(logContext) {
+ info(
+ "henter journalposter for bruker med ident {} og data {}",
+ journalposterForBrukerRequest.brukerId,
+ journalposterForBrukerRequest.toString(),
+ )
+ }
return postForEntity>>(hentJournalpostUri(), journalposterForBrukerRequest).getDataOrThrow()
}
diff --git a/src/main/kotlin/no/nav/familie/tilbake/integration/pdl/PdlClient.kt b/src/main/kotlin/no/nav/familie/tilbake/integration/pdl/PdlClient.kt
index 065b068a0..08f4cac9e 100644
--- a/src/main/kotlin/no/nav/familie/tilbake/integration/pdl/PdlClient.kt
+++ b/src/main/kotlin/no/nav/familie/tilbake/integration/pdl/PdlClient.kt
@@ -1,6 +1,6 @@
package no.nav.familie.tilbake.integration.pdl
-import no.nav.familie.http.client.AbstractPingableRestClient
+import AbstractPingableRestClient
import no.nav.familie.kontrakter.felles.Fagsystem
import no.nav.familie.kontrakter.felles.Tema
import no.nav.familie.kontrakter.felles.objectMapper
@@ -24,7 +24,6 @@ import org.springframework.http.HttpHeaders
import org.springframework.http.HttpStatus
import org.springframework.stereotype.Service
import org.springframework.web.client.RestOperations
-import java.net.URI
import java.time.LocalDate
@Service
@@ -44,20 +43,22 @@ class PdlClient(
variables = PdlPersonRequestVariables(ident),
query = PdlConfig.hentEnkelPersonQuery,
)
- val respons: PdlHentPersonResponse =
+ val response: PdlHentPersonResponse =
postForEntity(
pdlConfig.pdlUri,
pdlPersonRequest,
httpHeaders(mapTilTema(fagsystem)),
)
- if (respons.harAdvarsel()) {
+ if (response.harAdvarsel()) {
logger.medContext(logContext) {
warn("Advarsel ved henting av personinfo fra PDL. Se securelogs for detaljer.")
}
- secureLogger.warn("Advarsel ved henting av personinfo fra PDL: ${respons.extensions?.warnings}")
+ SecureLog.medContext(logContext) {
+ warn("Advarsel ved henting av personinfo fra PDL: {}", response.extensions?.warnings.toString())
+ }
}
- if (!respons.harFeil()) {
- return respons.data.person!!.let {
+ if (!response.harFeil()) {
+ return response.data.person!!.let {
val aktivtIdent = it.identer.first().identifikasjonsnummer ?: error("Kan ikke hente aktivt ident fra PDL")
Personinfo(
ident = aktivtIdent,
@@ -69,11 +70,11 @@ class PdlClient(
}
} else {
logger.medContext(logContext) {
- warn("Respons fra PDL:${objectMapper.writeValueAsString(respons)}")
+ warn("Response fra PDL: {}", objectMapper.writeValueAsString(response))
}
throw Feil(
- message = "Feil ved oppslag på person: ${respons.errorMessages()}",
- frontendFeilmelding = "Feil ved oppslag på person $ident: ${respons.errorMessages()}",
+ message = "Feil ved oppslag på person: ${response.errorMessages()}",
+ frontendFeilmelding = "Feil ved oppslag på person $ident: ${response.errorMessages()}",
logContext = logContext,
httpStatus = HttpStatus.INTERNAL_SERVER_ERROR,
)
@@ -100,7 +101,9 @@ class PdlClient(
logger.medContext(logContext) {
warn("Advarsel ved henting av personidenter fra PDL. Se securelogs for detaljer.")
}
- secureLogger.warn("Advarsel ved henting av personidenter fra PDL: ${response.extensions?.warnings}")
+ SecureLog.medContext(logContext) {
+ warn("Advarsel ved henting av personidenter fra PDL: {}", response.extensions?.warnings.toString())
+ }
}
if (!response.harFeil()) return response
throw Feil(
@@ -139,13 +142,6 @@ class PdlClient(
add("behandlingsnummer", tema.behandlingsnummer)
}
- override val pingUri: URI
- get() = pdlConfig.pdlUri
-
- override fun ping() {
- operations.optionsForAllow(pingUri)
- }
-
private fun mapTilTema(fagsystem: Fagsystem): Tema =
when (fagsystem) {
Fagsystem.EF -> Tema.ENF
diff --git "a/src/main/kotlin/no/nav/familie/tilbake/integration/\303\270konomi/OppdragClient.kt" "b/src/main/kotlin/no/nav/familie/tilbake/integration/\303\270konomi/OppdragClient.kt"
index 853d26181..5258db750 100644
--- "a/src/main/kotlin/no/nav/familie/tilbake/integration/\303\270konomi/OppdragClient.kt"
+++ "b/src/main/kotlin/no/nav/familie/tilbake/integration/\303\270konomi/OppdragClient.kt"
@@ -1,6 +1,6 @@
package no.nav.familie.tilbake.integration.økonomi
-import no.nav.familie.http.client.AbstractPingableRestClient
+import AbstractPingableRestClient
import no.nav.familie.kontrakter.felles.Ressurs
import no.nav.familie.kontrakter.felles.getDataOrThrow
import no.nav.familie.kontrakter.felles.objectMapper
@@ -83,13 +83,6 @@ class DefaultOppdragClient(
OppdragClient {
private val logger = TracedLogger.getLogger()
- override val pingUri: URI =
- UriComponentsBuilder
- .fromUri(familieOppdragUrl)
- .path(PING_PATH)
- .build()
- .toUri()
-
private fun iverksettelseUri(behandlingId: UUID): URI =
UriComponentsBuilder
.fromUri(familieOppdragUrl)
diff --git a/src/main/kotlin/no/nav/familie/tilbake/sikkerhet/OIDCUtil.kt b/src/main/kotlin/no/nav/familie/tilbake/sikkerhet/OIDCUtil.kt
new file mode 100644
index 000000000..81e168964
--- /dev/null
+++ b/src/main/kotlin/no/nav/familie/tilbake/sikkerhet/OIDCUtil.kt
@@ -0,0 +1,3 @@
+package no.nav.familie.tilbake.sikkerhet
+
+class OIDCUtil
diff --git a/src/test/kotlin/no/nav/familie/tilbake/config/IntegrasjonerClientConfig.kt b/src/test/kotlin/no/nav/familie/tilbake/config/IntegrasjonerClientConfig.kt
index 39df503b9..9d817c396 100644
--- a/src/test/kotlin/no/nav/familie/tilbake/config/IntegrasjonerClientConfig.kt
+++ b/src/test/kotlin/no/nav/familie/tilbake/config/IntegrasjonerClientConfig.kt
@@ -5,7 +5,6 @@ import io.mockk.every
import io.mockk.just
import io.mockk.mockk
import io.mockk.slot
-import no.nav.familie.http.client.RessursException
import no.nav.familie.kontrakter.felles.Ressurs
import no.nav.familie.kontrakter.felles.dokarkiv.ArkiverDokumentResponse
import no.nav.familie.kontrakter.felles.dokarkiv.v2.ArkiverDokumentRequest
@@ -20,6 +19,7 @@ import no.nav.familie.kontrakter.felles.oppgave.Oppgave
import no.nav.familie.kontrakter.felles.oppgave.Oppgavetype
import no.nav.familie.kontrakter.felles.organisasjon.Organisasjon
import no.nav.familie.kontrakter.felles.saksbehandler.Saksbehandler
+import no.nav.familie.tilbake.http.RessursException
import no.nav.familie.tilbake.integration.familie.IntegrasjonerClient
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
@@ -100,7 +100,7 @@ class IntegrasjonerClientConfig {
every { integrasjonerClient.hentDokument(any(), any()) } returns readMockfileFromResources()
- every { integrasjonerClient.hentJournalposterForBruker(any()) }
+ every { integrasjonerClient.hentJournalposterForBruker(any(), any()) }
.returns(
listOf(
Journalpost(