Skip to content

Commit

Permalink
Hent Altinn-tilganger via Fager sitt API (#832)
Browse files Browse the repository at this point in the history
Bakgrunn
Vi ønsker å gå over til Fager sitt API for henting av Altinn-tilganger for å gjøre fremtidig flytting av tilganger fra Altinn 2 til Altinn 3 enklere. (Fager sitt API henter og syr sammen tilganger fra både Altinn 2 og Altinn 3.)

Løsning
Bruk ny versjon av AltinnClient (Altinn3M2MClient), som henter rettigheter fra Fager sitt API ved hjelp av M2M-/Azure-token.

Commits:
* Bytt til Fager sitt API for å hente Altinn-tilganger

* Legg til manglende konfig for å få Fager sitt Altinn-API til å virke pluss fiks integrasjonstester

* Rens vekk gammel Maskinporten-moro som vi ikke trenger lenger

* Fjern altinn fra external hosts fordi vi ikke lenger gjør kall direkte til Altinn

* Bruk snapshotversjon av aller nyeste altinnklient

* Deploy im altinn for å hente ny snapshotversjon av altinnclient med logging som forhåpentligvis fungerer

* Deploy (igjen) for å forsøke å få med logging i dev

* Oppgrader til nyeste AltinnClient
  • Loading branch information
magnusae authored Jan 23, 2025
1 parent 2f2fde8 commit b35f7ef
Show file tree
Hide file tree
Showing 15 changed files with 73 additions and 159 deletions.
4 changes: 0 additions & 4 deletions apps/altinn/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,11 +1,7 @@
dependencies {
val altinnClientVersion: String by project
val maskinportenClientVersion: String by project
val mockwebserverVersion: String by project
val nimbusJoseJwtVersion: String by project

implementation("no.nav.helsearbeidsgiver:altinn-client:$altinnClientVersion")
implementation("no.nav.helsearbeidsgiver:maskinporten-client:$maskinportenClientVersion")
testImplementation("com.nimbusds:nimbus-jose-jwt:$nimbusJoseJwtVersion")
testImplementation("com.squareup.okhttp3:mockwebserver:$mockwebserverVersion")
}
4 changes: 1 addition & 3 deletions apps/altinn/gradle.properties
Original file line number Diff line number Diff line change
@@ -1,4 +1,2 @@
altinnClientVersion=0.4.0
maskinportenClientVersion=0.1.9
altinnClientVersion=1.0.0
mockwebserverVersion=5.0.0-alpha.14
nimbusJoseJwtVersion=9.47
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package no.nav.helsearbeidsgiver.inntektsmelding.altinn

import kotlinx.serialization.builtins.serializer
import kotlinx.serialization.json.JsonElement
import no.nav.helsearbeidsgiver.altinn.AltinnClient
import no.nav.helsearbeidsgiver.altinn.Altinn3M2MClient
import no.nav.helsearbeidsgiver.felles.BehovType
import no.nav.helsearbeidsgiver.felles.EventName
import no.nav.helsearbeidsgiver.felles.Key
Expand Down Expand Up @@ -33,7 +33,7 @@ data class Melding(
)

class AltinnRiver(
private val altinnClient: AltinnClient,
private val altinnClient: Altinn3M2MClient,
) : ObjectRiver<Melding>() {
private val logger = logger()
private val sikkerLogger = sikkerLogger()
Expand All @@ -58,11 +58,8 @@ class AltinnRiver(

override fun Melding.haandter(json: Map<Key, JsonElement>): Map<Key, JsonElement> {
val rettigheterForenklet =
Metrics.altinnRequest.recordTime(altinnClient::hentRettighetOrganisasjoner) {
altinnClient
.hentRettighetOrganisasjoner(fnr.verdi)
.mapNotNull { it.orgnr }
.toSet()
Metrics.altinnRequest.recordTime(altinnClient::hentTilganger) {
altinnClient.hentTilganger(fnr.verdi)
}

return mapOf(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
package no.nav.helsearbeidsgiver.inntektsmelding.altinn

import com.github.navikt.tbd_libs.rapids_and_rivers_api.RapidsConnection
import kotlinx.coroutines.runBlocking
import no.nav.helse.rapids_rivers.RapidApplication
import no.nav.helsearbeidsgiver.altinn.AltinnClient
import no.nav.helsearbeidsgiver.altinn.Altinn3M2MClient
import no.nav.helsearbeidsgiver.altinn.CacheConfig
import no.nav.helsearbeidsgiver.maskinporten.MaskinportenClient
import no.nav.helsearbeidsgiver.maskinporten.MaskinportenClientConfig
import no.nav.helsearbeidsgiver.tokenprovider.oauth2ClientCredentialsTokenGetter
import no.nav.helsearbeidsgiver.utils.log.logger
import kotlin.time.Duration.Companion.minutes

Expand All @@ -19,7 +17,7 @@ fun main() {
.start()
}

fun RapidsConnection.createAltinn(altinnClient: AltinnClient): RapidsConnection =
fun RapidsConnection.createAltinn(altinnClient: Altinn3M2MClient): RapidsConnection =
also {
logger.info("Starter ${TilgangRiver::class.simpleName}...")
TilgangRiver(altinnClient).connect(this)
Expand All @@ -28,29 +26,10 @@ fun RapidsConnection.createAltinn(altinnClient: AltinnClient): RapidsConnection
AltinnRiver(altinnClient).connect(this)
}

private fun createAltinnClient(): AltinnClient {
val maskinportenClient = createMaskinportenClient()
return AltinnClient(
url = Env.url,
private fun createAltinnClient(): Altinn3M2MClient =
Altinn3M2MClient(
baseUrl = Env.altinnTilgangerBaseUrl,
serviceCode = Env.serviceCode,
getToken = maskinportenClient::getToken,
altinnApiKey = Env.altinnApiKey,
getToken = oauth2ClientCredentialsTokenGetter(Env.oauth2Environment),
cacheConfig = CacheConfig(60.minutes, 100),
)
}

private fun createMaskinportenClient(): MaskinportenClient =
MaskinportenClient(
MaskinportenClientConfig(
scope = Env.Maskinporten.altinnScope,
endpoint = Env.Maskinporten.endpoint,
clientJwk = Env.Maskinporten.clientJwk,
issuer = Env.Maskinporten.issuer,
clientId = Env.Maskinporten.clientId,
),
)

private fun MaskinportenClient.getToken() =
runBlocking {
fetchNewAccessToken().tokenResponse.accessToken
}
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
package no.nav.helsearbeidsgiver.inntektsmelding.altinn

import no.nav.helsearbeidsgiver.felles.utils.fromEnv
import no.nav.helsearbeidsgiver.tokenprovider.OAuth2Environment

object Env {
val url = "ALTINN_URL".fromEnv()
val serviceCode = "ALTINN_SERVICE_CODE".fromEnv()
val altinnApiKey = "ALTINN_API_KEY".fromEnv()
val altinnTilgangerBaseUrl = "ALTINN_TILGANGER_BASE_URL".fromEnv()

object Maskinporten {
val endpoint: String = "MASKINPORTEN_TOKEN_ENDPOINT".fromEnv()
val issuer: String = "MASKINPORTEN_ISSUER".fromEnv()
val clientJwk: String = "MASKINPORTEN_CLIENT_JWK".fromEnv()
val clientId: String = "MASKINPORTEN_CLIENT_ID".fromEnv()
val altinnScope: String = "ALTINN_SCOPE".fromEnv()
}
val oauth2Environment =
OAuth2Environment(
scope = "ALTINN_TILGANGER_SCOPE".fromEnv(),
wellKnownUrl = "AZURE_APP_WELL_KNOWN_URL".fromEnv(),
tokenEndpointUrl = "AZURE_OPENID_CONFIG_TOKEN_ENDPOINT".fromEnv(),
clientId = "AZURE_APP_CLIENT_ID".fromEnv(),
clientSecret = "AZURE_APP_CLIENT_SECRET".fromEnv(),
clientJwk = "AZURE_APP_JWK".fromEnv(),
)
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package no.nav.helsearbeidsgiver.inntektsmelding.altinn

import kotlinx.serialization.json.JsonElement
import no.nav.helsearbeidsgiver.altinn.AltinnClient
import no.nav.helsearbeidsgiver.altinn.Altinn3M2MClient
import no.nav.helsearbeidsgiver.felles.BehovType
import no.nav.helsearbeidsgiver.felles.EventName
import no.nav.helsearbeidsgiver.felles.Key
Expand Down Expand Up @@ -33,7 +33,7 @@ data class TilgangMelding(
)

class TilgangRiver(
private val altinnClient: AltinnClient,
private val altinnClient: Altinn3M2MClient,
) : ObjectRiver<TilgangMelding>() {
private val logger = logger()
private val sikkerLogger = sikkerLogger()
Expand All @@ -58,8 +58,8 @@ class TilgangRiver(

override fun TilgangMelding.haandter(json: Map<Key, JsonElement>): Map<Key, JsonElement> {
val harTilgang =
Metrics.altinnRequest.recordTime(altinnClient::harRettighetForOrganisasjon) {
altinnClient.harRettighetForOrganisasjon(fnr.verdi, orgnr.verdi)
Metrics.altinnRequest.recordTime(altinnClient::harTilgangTilOrganisasjon) {
altinnClient.harTilgangTilOrganisasjon(fnr = fnr.verdi, orgnr = orgnr.verdi)
}

val tilgang = if (harTilgang) Tilgang.HAR_TILGANG else Tilgang.IKKE_TILGANG
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package no.nav.helsearbeidsgiver.inntektsmelding.altinn

import com.github.navikt.tbd_libs.rapids_and_rivers.test_support.TestRapid
import com.nimbusds.jose.jwk.gen.RSAKeyGenerator
import io.kotest.core.spec.style.FunSpec
import io.kotest.matchers.shouldBe
import io.kotest.matchers.string.shouldStartWith
Expand All @@ -10,14 +9,13 @@ import io.mockk.every
import io.mockk.mockkObject
import io.mockk.mockkStatic
import io.mockk.unmockkStatic
import kotlinx.serialization.builtins.serializer
import no.nav.helse.rapids_rivers.RapidApplication
import no.nav.helsearbeidsgiver.altinn.AltinnOrganisasjon
import no.nav.helsearbeidsgiver.felles.test.rapidsrivers.sendJson
import no.nav.helsearbeidsgiver.felles.utils.fromEnv
import no.nav.helsearbeidsgiver.inntektsmelding.altinn.Mock.altinnOrganisasjoner
import no.nav.helsearbeidsgiver.inntektsmelding.altinn.Mock.innkommendeMelding
import no.nav.helsearbeidsgiver.inntektsmelding.altinn.Mock.toMap
import no.nav.helsearbeidsgiver.maskinporten.TokenResponse
import no.nav.helsearbeidsgiver.utils.json.serializer.set
import no.nav.helsearbeidsgiver.utils.json.toJson
import okhttp3.mockwebserver.MockResponse
Expand All @@ -44,14 +42,11 @@ class AltinnAppTest :
mockkObject(RapidApplication)
every { RapidApplication.create(any()) } returns testRapid

val maskinportenToken = TokenResponse("test_token", "Bearer", 3600, "test:test1")
val tokenResponse = maskinportenToken.toJson(TokenResponse.serializer()).toString()
server.enqueue(
MockResponse()
.setBody(tokenResponse)
.addHeader("Content-Type", "application/json"),
)
val altinnResponse = altinnOrganisasjoner.toJson(AltinnOrganisasjon.serializer().set()).toString()
val altinnResponse = altinnOrganisasjoner.toJson(String.serializer().set()).toString()
val mockResponse =
MockResponse()
.setBody(altinnResponse)
Expand Down Expand Up @@ -79,14 +74,7 @@ class AltinnAppTest :
private fun mockEnv(server: MockWebServer) {
mockkStatic("no.nav.helsearbeidsgiver.felles.utils.EnvUtilsKt")

every { "ALTINN_URL".fromEnv() } returns server.url("/altinn").toString()
every { "ALTINN_TILGANGER_BASE_URL".fromEnv() } returns server.url("/altinn").toString()
every { "ALTINN_SERVICE_CODE".fromEnv() } returns "4936"
every { "MASKINPORTEN_TOKEN_ENDPOINT".fromEnv() } returns server.url("/token").toString()
every { "MASKINPORTEN_ISSUER".fromEnv() } returns "https://test.test.no/"
every { "MASKINPORTEN_CLIENT_JWK".fromEnv() } returns generateJWK()
every { "MASKINPORTEN_CLIENT_ID".fromEnv() } returns "TEST_CLIENT_ID"
every { "ALTINN_SCOPE".fromEnv() } returns "test:test/test"
every { "ALTINN_API_KEY".fromEnv() } returns "mocked_value"
every { "ALTINN_TILGANGER_SCOPE".fromEnv() } returns "test:test/test"
}

private fun generateJWK() = RSAKeyGenerator(2048).keyID("test-key-id").generate().toString()
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import io.mockk.coVerify
import io.mockk.coVerifySequence
import io.mockk.mockk
import kotlinx.serialization.builtins.serializer
import no.nav.helsearbeidsgiver.altinn.AltinnClient
import no.nav.helsearbeidsgiver.altinn.Altinn3M2MClient
import no.nav.helsearbeidsgiver.felles.BehovType
import no.nav.helsearbeidsgiver.felles.Key
import no.nav.helsearbeidsgiver.felles.json.toJson
Expand All @@ -27,7 +27,7 @@ class AltinnRiverTest :
FunSpec({
val testRapid = TestRapid()

val mockAltinnClient = mockk<AltinnClient>(relaxed = true)
val mockAltinnClient = mockk<Altinn3M2MClient>(relaxed = true)

AltinnRiver(mockAltinnClient).connect(testRapid)

Expand All @@ -39,16 +39,13 @@ class AltinnRiverTest :
test("henter organisasjonsrettigheter med id fra behov") {
val innkommendeMelding = Mock.innkommendeMelding()

coEvery { mockAltinnClient.hentRettighetOrganisasjoner(any()) } returns Mock.altinnOrganisasjoner
coEvery { mockAltinnClient.hentTilganger(any()) } returns Mock.altinnOrganisasjoner

testRapid.sendJson(innkommendeMelding.toMap())

testRapid.inspektør.size shouldBeExactly 1

val altinnOrgnr =
Mock.altinnOrganisasjoner
.mapNotNull { it.orgnr }
.toSet()
val altinnOrgnr = Mock.altinnOrganisasjoner

testRapid.firstMessage().toMap() shouldContainExactly
mapOf(
Expand All @@ -62,7 +59,7 @@ class AltinnRiverTest :
)

coVerifySequence {
mockAltinnClient.hentRettighetOrganisasjoner(innkommendeMelding.fnr.verdi)
mockAltinnClient.hentTilganger(innkommendeMelding.fnr.verdi)
}
}

Expand All @@ -78,7 +75,7 @@ class AltinnRiverTest :
utloesendeMelding = innkommendeJsonMap,
)

coEvery { mockAltinnClient.hentRettighetOrganisasjoner(any()) } throws NullPointerException()
coEvery { mockAltinnClient.hentTilganger(any()) } throws NullPointerException()

testRapid.sendJson(innkommendeJsonMap)

Expand All @@ -87,7 +84,7 @@ class AltinnRiverTest :
testRapid.firstMessage().toMap() shouldContainExactly forventetFail.tilMelding()

coVerifySequence {
mockAltinnClient.hentRettighetOrganisasjoner(innkommendeMelding.fnr.verdi)
mockAltinnClient.hentTilganger(innkommendeMelding.fnr.verdi)
}
}

Expand All @@ -109,7 +106,7 @@ class AltinnRiverTest :
testRapid.inspektør.size shouldBeExactly 0

coVerify(exactly = 0) {
mockAltinnClient.hentRettighetOrganisasjoner(any())
mockAltinnClient.hentTilganger(any())
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package no.nav.helsearbeidsgiver.inntektsmelding.altinn

import kotlinx.serialization.json.JsonElement
import no.nav.helsearbeidsgiver.altinn.AltinnOrganisasjon
import no.nav.helsearbeidsgiver.felles.BehovType
import no.nav.helsearbeidsgiver.felles.EventName
import no.nav.helsearbeidsgiver.felles.Key
Expand All @@ -11,6 +10,7 @@ import no.nav.helsearbeidsgiver.felles.test.mock.mockFail
import no.nav.helsearbeidsgiver.utils.json.toJson
import no.nav.helsearbeidsgiver.utils.test.wrapper.genererGyldig
import no.nav.helsearbeidsgiver.utils.wrapper.Fnr
import no.nav.helsearbeidsgiver.utils.wrapper.Orgnr
import java.util.UUID

object Mock {
Expand Down Expand Up @@ -42,11 +42,5 @@ object Mock {

val fail = mockFail("One does not simply walk into Mordor.", EventName.AKTIVE_ORGNR_REQUESTED)

val altinnOrganisasjoner =
setOf(
AltinnOrganisasjon(
navn = "Pippin's Breakfast & Breakfast",
type = "gluttonous",
),
)
val altinnOrganisasjoner = setOf(Orgnr.genererGyldig().verdi)
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import io.mockk.coVerify
import io.mockk.coVerifySequence
import io.mockk.mockk
import kotlinx.serialization.json.JsonElement
import no.nav.helsearbeidsgiver.altinn.AltinnClient
import no.nav.helsearbeidsgiver.altinn.Altinn3M2MClient
import no.nav.helsearbeidsgiver.felles.BehovType
import no.nav.helsearbeidsgiver.felles.EventName
import no.nav.helsearbeidsgiver.felles.Key
Expand All @@ -33,9 +33,9 @@ import java.util.UUID
class TilgangRiverTest :
FunSpec({
val testRapid = TestRapid()
val mockAltinnClient = mockk<AltinnClient>()
val mockAltinn3M2MClient = mockk<Altinn3M2MClient>()

TilgangRiver(mockAltinnClient).connect(testRapid)
TilgangRiver(mockAltinn3M2MClient).connect(testRapid)

beforeTest {
testRapid.reset()
Expand All @@ -49,7 +49,7 @@ class TilgangRiverTest :
"ikke tilgang" to row(false, Tilgang.IKKE_TILGANG),
),
) { (altinnSvar, forventetTilgang) ->
coEvery { mockAltinnClient.harRettighetForOrganisasjon(any(), any()) } returns altinnSvar
coEvery { mockAltinn3M2MClient.harTilgangTilOrganisasjon(any(), any()) } returns altinnSvar

val innkommendeMelding = MockTilgang.innkommendeMelding()

Expand All @@ -68,13 +68,13 @@ class TilgangRiverTest :
)

coVerifySequence {
mockAltinnClient.harRettighetForOrganisasjon(innkommendeMelding.fnr.verdi, innkommendeMelding.orgnr.verdi)
mockAltinn3M2MClient.harTilgangTilOrganisasjon(innkommendeMelding.fnr.verdi, innkommendeMelding.orgnr.verdi)
}
}
}

test("håndterer feil") {
coEvery { mockAltinnClient.harRettighetForOrganisasjon(any(), any()) } throws NullPointerException()
coEvery { mockAltinn3M2MClient.harTilgangTilOrganisasjon(any(), any()) } throws NullPointerException()

val innkommendeMelding = MockTilgang.innkommendeMelding()

Expand All @@ -92,7 +92,7 @@ class TilgangRiverTest :
testRapid.firstMessage().toMap() shouldContainExactly forventetFail.tilMelding()

coVerifySequence {
mockAltinnClient.harRettighetForOrganisasjon(innkommendeMelding.fnr.verdi, innkommendeMelding.orgnr.verdi)
mockAltinn3M2MClient.harTilgangTilOrganisasjon(innkommendeMelding.fnr.verdi, innkommendeMelding.orgnr.verdi)
}
}

Expand All @@ -114,7 +114,7 @@ class TilgangRiverTest :
testRapid.inspektør.size shouldBeExactly 0

coVerify(exactly = 0) {
mockAltinnClient.harRettighetForOrganisasjon(any(), any())
mockAltinn3M2MClient.harTilgangTilOrganisasjon(any(), any())
}
}
}
Expand Down
Loading

0 comments on commit b35f7ef

Please sign in to comment.