-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Flytt over relevant kode fra familie-felles http
- Loading branch information
Showing
19 changed files
with
356 additions
and
67 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
36 changes: 36 additions & 0 deletions
36
src/main/kotlin/no/nav/familie/tilbake/config/HttpClientConfig.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
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() | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
32 changes: 32 additions & 0 deletions
32
src/main/kotlin/no/nav/familie/tilbake/http/AbstractBearerTokenInterceptor.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
package no.nav.familie.tilbake.http | ||
|
||
import com.nimbusds.oauth2.sdk.GrantType | ||
import java.net.URI | ||
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 | ||
|
||
abstract class AbstractBearerTokenInterceptor( | ||
protected val oAuth2AccessTokenService: OAuth2AccessTokenService, | ||
protected val clientConfigurationProperties: ClientConfigurationProperties, | ||
) : ClientHttpRequestInterceptor { | ||
protected fun genererAccessToken(clientProperties: ClientProperties): String { | ||
return 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<ClientProperties>, | ||
grantType: GrantType, | ||
uri: URI, | ||
): ClientProperties = | ||
values.firstOrNull { grantType == it.grantType } | ||
?: error("could not find oauth2 client config for uri=$uri and grant type=$grantType") | ||
} |
115 changes: 115 additions & 0 deletions
115
src/main/kotlin/no/nav/familie/tilbake/http/AbstractPingableRestClient.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 java.net.URI | ||
import java.util.concurrent.TimeUnit | ||
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 | ||
|
||
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 <reified T : Any> getForEntity( | ||
uri: URI, | ||
httpHeaders: HttpHeaders? = null, | ||
): T = executeMedMetrics(uri) { operations.exchange<T>(uri, HttpMethod.GET, HttpEntity(null, httpHeaders)) } | ||
|
||
inline fun <reified T : Any> postForEntity( | ||
uri: URI, | ||
payload: Any, | ||
httpHeaders: HttpHeaders? = null, | ||
): T = executeMedMetrics(uri) { operations.exchange<T>(uri, HttpMethod.POST, HttpEntity(payload, httpHeaders)) } | ||
|
||
inline fun <reified T : Any> putForEntity( | ||
uri: URI, | ||
payload: Any, | ||
httpHeaders: HttpHeaders? = null, | ||
): T = executeMedMetrics(uri) { operations.exchange<T>(uri, HttpMethod.PUT, HttpEntity(payload, httpHeaders)) } | ||
|
||
inline fun <reified T : Any> patchForEntity( | ||
uri: URI, | ||
payload: Any, | ||
httpHeaders: HttpHeaders? = null, | ||
): T = executeMedMetrics(uri) { operations.exchange<T>(uri, HttpMethod.PATCH, HttpEntity(payload, httpHeaders)) } | ||
|
||
inline fun <reified T : Any> deleteForEntity( | ||
uri: URI, | ||
payload: Any? = null, | ||
httpHeaders: HttpHeaders? = null, | ||
): T = executeMedMetrics(uri) { operations.exchange<T>(uri, HttpMethod.DELETE, HttpEntity(payload, httpHeaders)) } | ||
|
||
private fun <T> validerOgPakkUt( | ||
respons: ResponseEntity<T>, | ||
uri: URI, | ||
): T { | ||
if (!respons.statusCode.is2xxSuccessful) { | ||
secureLogger.info("Kall mot $uri feilet: ${respons.body}") | ||
log.info("Kall mot $uri feilet: ${respons.statusCode}") | ||
throw HttpServerErrorException(respons.statusCode, "", respons.body?.toString()?.toByteArray(), Charsets.UTF_8) | ||
} | ||
return respons.body as T | ||
} | ||
|
||
fun <T> executeMedMetrics( | ||
uri: URI, | ||
function: () -> ResponseEntity<T>, | ||
): 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", e) | ||
lesRessurs(e)?.let { throw RessursException(it, e) } ?: throw e | ||
} catch (e: HttpClientErrorException) { | ||
responsFailure.increment() | ||
secureLogger.warn("HttpClientErrorException ved kall mot uri=$uri", e) | ||
lesRessurs(e)?.let { throw RessursException(it, e) } ?: throw e | ||
} catch (e: ResourceAccessException) { | ||
responsFailure.increment() | ||
secureLogger.warn("ResourceAccessException ved kall mot uri=$uri", e) | ||
throw e | ||
} catch (e: Exception) { | ||
responsFailure.increment() | ||
secureLogger.warn("Feil ved kall mot uri=$uri", e) | ||
throw RuntimeException("Feil ved kall mot uri=$uri", e) | ||
} | ||
} | ||
|
||
private fun lesRessurs(e: RestClientResponseException): Ressurs<Any>? = | ||
try { | ||
if (e.responseBodyAsString.contains("status")) { | ||
objectMapper.readValue<Ressurs<Any>>(e.responseBodyAsString) | ||
} else { | ||
null | ||
} | ||
} catch (ex: Exception) { | ||
null | ||
} | ||
|
||
override fun toString(): String = this::class.simpleName + " [operations=" + operations + "]" | ||
} |
27 changes: 27 additions & 0 deletions
27
src/main/kotlin/no/nav/familie/tilbake/http/BearerTokenClientCredentialClientInterceptor.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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) | ||
} | ||
} |
Oops, something went wrong.