Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

test ny altinn-tilganger tjeneste i dev #734

Merged
merged 5 commits into from
Sep 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions app/nais/dev-gcp-bruker-api.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ spec:
rules:
- application: altinn-rettigheter-proxy
namespace: arbeidsgiver
- application: arbeidsgiver-altinn-tilganger
external:
- host: fakedings.intern.dev.nav.no # fakedings login
- host: api-gw-q1.oera.no # fallback for altinn-rettigheter-proxy-client
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
package no.nav.arbeidsgiver.notifikasjon.bruker

import io.micrometer.core.instrument.search.MeterNotFoundException
import kotlinx.coroutines.*
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.async
import kotlinx.coroutines.delay
import kotlinx.coroutines.runBlocking
import no.nav.arbeidsgiver.notifikasjon.infrastruktur.*
import no.nav.arbeidsgiver.notifikasjon.infrastruktur.Database.Companion.openDatabaseAsync
import no.nav.arbeidsgiver.notifikasjon.infrastruktur.altinn.Altinn
import no.nav.arbeidsgiver.notifikasjon.infrastruktur.altinn.AltinnCachedImpl
import no.nav.arbeidsgiver.notifikasjon.infrastruktur.altinn.SuspendingAltinnClient
import no.nav.arbeidsgiver.notifikasjon.infrastruktur.altinn.*
import no.nav.arbeidsgiver.notifikasjon.infrastruktur.http.HttpAuthProviders
import no.nav.arbeidsgiver.notifikasjon.infrastruktur.http.JWTAuthentication
import no.nav.arbeidsgiver.notifikasjon.infrastruktur.http.extractBrukerContext
Expand Down Expand Up @@ -41,7 +42,10 @@ object Bruker {
suspendingAltinnClient: SuspendingAltinnClient = SuspendingAltinnClient(
observer = virksomhetsinfoService::altinnObserver
),
altinn: Altinn = AltinnCachedImpl(suspendingAltinnClient),
altinn: Altinn = basedOnEnv(
prod = { AltinnCachedImpl(suspendingAltinnClient) },
other = { AltinnTilgangerImpl(AltinnTilgangerClient()) }
),
httpPort: Int = 8080
) {
runBlocking(Dispatchers.Default) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,48 @@ interface Altinn {
): Tilganger
}

class AltinnTilgangerImpl(
private val altinnTilgangerClient: AltinnTilgangerClient
): Altinn {
private val cache = Caffeine.newBuilder()
.expireAfterWrite(Duration.ofMinutes(10))
.maximumSize(10_000)
.buildAsync<String, AltinnTilganger>()

override suspend fun hentTilganger(
fnr: String,
selvbetjeningsToken: String,
tjenester: Iterable<ServicecodeDefinisjon>
): Tilganger {
val tilganger = cache.getAsync(fnr) { _ ->
altinnTilgangerClient.hentTilganger(selvbetjeningsToken)
}

if (tilganger.harFeil) {
cache.synchronous().invalidate(fnr)
}

return Tilganger(
harFeil = tilganger.harFeil,
tjenestetilganger = tilganger.tilganger.map {
// skjuler altinn3 detaljene for nå ved å mappe begge til samme eksisterende modell
when (it) {
is AltinnTilgang.Altinn2 -> BrukerModel.Tilgang.Altinn(
virksomhet = it.orgNr,
servicecode = it.serviceCode,
serviceedition = it.serviceEdition
)
is AltinnTilgang.Altinn3 -> BrukerModel.Tilgang.Altinn(
virksomhet = it.orgNr,
servicecode = it.ressurs,
serviceedition = ""
)
}
}
)
}
}

class AltinnImpl(
private val klient: SuspendingAltinnClient,
) : Altinn {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
package no.nav.arbeidsgiver.notifikasjon.infrastruktur.altinn

import com.fasterxml.jackson.annotation.JsonIgnoreProperties
import io.ktor.client.*
import io.ktor.client.call.*
import io.ktor.client.engine.*
import io.ktor.client.engine.apache.*
import io.ktor.client.plugins.*
import io.ktor.client.plugins.contentnegotiation.*
import io.ktor.client.request.*
import io.ktor.http.*
import io.ktor.network.sockets.*
import io.ktor.serialization.jackson.*
import no.nav.arbeidsgiver.notifikasjon.infrastruktur.HttpClientMetricsFeature
import no.nav.arbeidsgiver.notifikasjon.infrastruktur.Metrics
import no.nav.arbeidsgiver.notifikasjon.infrastruktur.NaisEnvironment
import no.nav.arbeidsgiver.notifikasjon.infrastruktur.PropagateFromMDCPlugin
import no.nav.arbeidsgiver.notifikasjon.infrastruktur.tokenx.TokenXClient
import no.nav.arbeidsgiver.notifikasjon.infrastruktur.tokenx.TokenXClientImpl
import org.apache.http.ConnectionClosedException
import javax.net.ssl.SSLHandshakeException

class AltinnTilgangerClient(
private val baseUrl: String? = null,
private val tokenXClient: TokenXClient = TokenXClientImpl(),
engine: HttpClientEngine = Apache.create(),
) {

private val httpClient = HttpClient(engine) {
defaultRequest {
url(baseUrl ?: "http://arbeidsgiver-altinn-tilganger")
}
install(ContentNegotiation) {
jackson()
}
install(PropagateFromMDCPlugin) {
propagate("x_correlation_id")
}
install(HttpClientMetricsFeature) {
registry = Metrics.meterRegistry
}
install(HttpRequestRetry) {
maxRetries = 3
retryOnExceptionIf { _, cause ->
cause is ConnectionClosedException ||
cause is SocketTimeoutException ||
cause is SSLHandshakeException
}
delayMillis { 250L }
}
}

private val targetAudience = "${NaisEnvironment.clusterName}:fager:arbeidsgiver-altinn-tilganger"

suspend fun hentTilganger(subjectToken: String): AltinnTilganger {
val dto = httpClient.post {
url {
path("/altinn-tilganger")
}
accept(ContentType.Application.Json)
bearerAuth(
tokenXClient.exchange(
subjectToken,
targetAudience
)
)
}.body<AltinnTilgangerClientResponse>()

return AltinnTilganger(
harFeil = dto.isError,
tilganger = dto.orgNrTilTilganger.flatMap { (orgNr, tilganger) ->
tilganger.map { AltinnTilgang.parse(orgNr, it) }
}
)
}

}

@JsonIgnoreProperties(ignoreUnknown = true)
private data class AltinnTilgangerClientResponse(
val isError: Boolean,
val orgNrTilTilganger: Map<String, List<String>>,
)

data class AltinnTilganger(
val harFeil: Boolean,
val tilganger: List<AltinnTilgang>,
)

sealed class AltinnTilgang {
data class Altinn2(val orgNr: String, val serviceCode: String, val serviceEdition: String) : AltinnTilgang()
data class Altinn3(val orgNr: String, val ressurs: String) : AltinnTilgang()

companion object {
fun parse(orgNr: String, tilgang: String) =
if (tilgang.matches(Regex("""\d+:\d+"""))) {
val (code, edition) = tilgang.split(":")
Altinn2(orgNr = orgNr, serviceCode = code, serviceEdition = edition)
} else {
Altinn3(orgNr = orgNr, ressurs = tilgang)
}
}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package no.nav.arbeidsgiver.notifikasjon.infrastruktur.altinn

import io.kotest.core.spec.style.DescribeSpec
import io.kotest.matchers.collections.shouldContainExactlyInAnyOrder
import io.kotest.matchers.shouldBe
import io.ktor.client.engine.mock.*
import io.ktor.http.*
import io.ktor.utils.io.*
import no.nav.arbeidsgiver.notifikasjon.infrastruktur.tokenx.TokenXClientStub

class AltinnTilgangerClientTest : DescribeSpec({
describe("AltinnTilgangerClient") {

val client = AltinnTilgangerClient(
tokenXClient = TokenXClientStub(),
engine = MockEngine { _ ->
respond(
content = ByteReadChannel(altinnTilgangerResponse),
status = HttpStatusCode.OK,
headers = headersOf(HttpHeaders.ContentType, "application/json")
)
}
)

it("returns all tilganger") {
client.hentTilganger("fake tolkien").also {
it.harFeil shouldBe true
it.tilganger shouldContainExactlyInAnyOrder listOf(
AltinnTilgang.Altinn3("910825496", "test-fager"),
AltinnTilgang.Altinn2("910825496", "4936", "1"),
)
}
}
}

})

private val altinnTilgangerResponse = """
{
"isError": true,
"hierarki": [
{
"orgNr": "810825472",
"altinn3Tilganger": [],
"altinn2Tilganger": [],
"underenheter": [
{
"orgNr": "910825496",
"altinn3Tilganger": [
"test-fager"
],
"altinn2Tilganger": [
"4936:1"
],
"underenheter": []
}
]
}
],
"orgNrTilTilganger": {
"910825496": [
"test-fager",
"4936:1"
]
},
"tilgangTilOrgNr": {
"test-fager": [
"910825496"
],
"4936:1": [
"910825496"
]
}
}
""".trimIndent()
Loading