From 1f7a272f7694e51131abea881b14870b06b4fca3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Odd=20Andreas=20S=C3=B8rs=C3=A6ther?= Date: Fri, 1 Mar 2024 15:18:12 +0100 Subject: [PATCH 01/13] Oppgrader spring boot og token-support --- pom.xml | 4 ++-- .../tiltakrefusjon/SecurityClientConfiguration.kt | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pom.xml b/pom.xml index 6bc92148..51850bb2 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ org.springframework.boot spring-boot-starter-parent - 3.2.2 + 3.2.3 no.nav.arbeidsgiver @@ -16,7 +16,7 @@ 21 1.9.22 7.15.0 - 3.2.0 + 4.1.3 42.7.2 diff --git a/src/main/kotlin/no/nav/arbeidsgiver/tiltakrefusjon/SecurityClientConfiguration.kt b/src/main/kotlin/no/nav/arbeidsgiver/tiltakrefusjon/SecurityClientConfiguration.kt index 051971d4..7a73b361 100644 --- a/src/main/kotlin/no/nav/arbeidsgiver/tiltakrefusjon/SecurityClientConfiguration.kt +++ b/src/main/kotlin/no/nav/arbeidsgiver/tiltakrefusjon/SecurityClientConfiguration.kt @@ -48,7 +48,7 @@ class SecurityClientConfiguration( ): ClientHttpRequestInterceptor { return ClientHttpRequestInterceptor { request: HttpRequest, body: ByteArray, execution: ClientHttpRequestExecution -> val response = oAuth2AccessTokenService.getAccessToken(clientProperties) - request.headers.setBearerAuth(response.accessToken) + request.headers.setBearerAuth(response.accessToken!!) execution.execute(request, body) } } From 40f0747ac4b5b968d502b23d336cc8aaedefb557 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Odd=20Andreas=20S=C3=B8rs=C3=A6ther?= Date: Mon, 4 Mar 2024 15:42:16 +0100 Subject: [PATCH 02/13] =?UTF-8?q?Auditlogging=20-=20Logg=20oppslag=20fra?= =?UTF-8?q?=20arbeidsgiver=20p=C3=A5=20orgnr?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Når en arbeidsgiver slår opp på en deltaker, skal vi logge at et oppslag har funnet sted. Men vi bør logge oppslaget på avtalens bedriftsnummer ettersom det ikke er ønskelig å logge arbeidsgivers fødselsnummer. --- pom.xml | 2 +- .../tiltakrefusjon/AuditLoggingFilter.kt | 38 ++++++++-- .../autorisering/FakeGraphApiService.kt | 6 +- .../autorisering/InnloggetBrukerService.kt | 10 +-- .../utils/TokenValidationContextExtensions.kt | 11 +++ .../resources/application-dev-gcp-labs.yml | 2 - .../refusjon/RefusjonApiTest.kt | 69 +++++++++---------- .../resources/application-dockercompose.yml | 2 - src/test/resources/application-local.yml | 2 - 9 files changed, 85 insertions(+), 57 deletions(-) create mode 100644 src/main/kotlin/no/nav/arbeidsgiver/tiltakrefusjon/utils/TokenValidationContextExtensions.kt diff --git a/pom.xml b/pom.xml index 51850bb2..74499e41 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ org.springframework.boot spring-boot-starter-parent - 3.2.3 + 3.2.2 no.nav.arbeidsgiver diff --git a/src/main/kotlin/no/nav/arbeidsgiver/tiltakrefusjon/AuditLoggingFilter.kt b/src/main/kotlin/no/nav/arbeidsgiver/tiltakrefusjon/AuditLoggingFilter.kt index 98d41804..14ab56dc 100644 --- a/src/main/kotlin/no/nav/arbeidsgiver/tiltakrefusjon/AuditLoggingFilter.kt +++ b/src/main/kotlin/no/nav/arbeidsgiver/tiltakrefusjon/AuditLoggingFilter.kt @@ -45,13 +45,13 @@ class AuditLoggingFilter( if (response.contentType?.contains("application/json") == true && callId != null) { try { - val fnr: List = JsonPath.read?>(wrapper.contentInputStream, "$..deltakerFnr").distinct() - val utførtTid = Now.instant() - val brukerId = context.getTokenValidationContext().getClaims("tokenx")?.getStringClaim("pid") ?: context.getTokenValidationContext().getClaims("aad")?.getStringClaim("NAVident") + val brukerId = context.getClaims(Issuer.TOKEN_X)?.getStringClaim("pid") ?: context.getClaims(Issuer.AZURE)?.getStringClaim("NAVident") + if (brukerId != null && context.erAzureBruker()) { + val fnr: List = JsonPath.read?>(wrapper.contentInputStream, "$..deltakerFnr").distinct() + val utførtTid = Now.instant() - val uri = URI.create(request.requestURI) - // Logger kun oppslag dersom en innlogget bruker utførte oppslaget - if (brukerId != null) { + val uri = URI.create(request.requestURI) + // Logger kun oppslag dersom en innlogget bruker utførte oppslaget fnr.forEach { // Ikke logg at en bruker slår opp sin egen informasjon if (!brukerId.equals(it)) { @@ -70,6 +70,30 @@ class AuditLoggingFilter( auditLogger.logg(entry) } } + } else if (brukerId != null && context.erTokenXBruker()) { + val fnrOgOrgnr: List> = JsonPath.read>?>(wrapper.contentInputStream, "$..['deltakerFnr', 'bedriftNr']").distinct() + val utførtTid = Now.instant() + + val uri = URI.create(request.requestURI) + // Logger kun oppslag dersom en innlogget bruker utførte oppslaget + fnrOgOrgnr.forEach { + // Ikke logg at en bruker slår opp sin egen informasjon + if (it["bedriftNr"] != null && it["deltakerFnr"] != null && brukerId != it["deltakerFnr"]) { + val entry = AuditEntry( + "tiltak-refusjon-api", + brukerId, + it["bedriftNr"]!!, + EventType.READ, + true, + utførtTid, + msgForUri(uri), + uri, + request.method, + callId + ) + auditLogger.logg(entry) + } + } } } catch (ex: Exception) { log.error("$className: Logging feilet", ex) @@ -93,4 +117,4 @@ class AuditLoggingFilter( log.warn("${className}: Fant ikke en lesbar melding for uri: $uri") "Oppslag i refusjonsløsning" } -} \ No newline at end of file +} diff --git a/src/main/kotlin/no/nav/arbeidsgiver/tiltakrefusjon/autorisering/FakeGraphApiService.kt b/src/main/kotlin/no/nav/arbeidsgiver/tiltakrefusjon/autorisering/FakeGraphApiService.kt index cedbc7fc..8be21bfd 100644 --- a/src/main/kotlin/no/nav/arbeidsgiver/tiltakrefusjon/autorisering/FakeGraphApiService.kt +++ b/src/main/kotlin/no/nav/arbeidsgiver/tiltakrefusjon/autorisering/FakeGraphApiService.kt @@ -1,5 +1,7 @@ package no.nav.arbeidsgiver.tiltakrefusjon.autorisering +import no.nav.arbeidsgiver.tiltakrefusjon.utils.Issuer +import no.nav.arbeidsgiver.tiltakrefusjon.utils.getClaims import no.nav.security.token.support.core.context.TokenValidationContextHolder import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty import org.springframework.stereotype.Service @@ -8,7 +10,7 @@ import org.springframework.stereotype.Service @ConditionalOnProperty("tiltak-refusjon.graph-api.fake") class FakeGraphApiService(val context: TokenValidationContextHolder) : GraphApiService { override fun hent(): GraphApiService.GraphApiResponse { - val claims = context.getTokenValidationContext().getClaims("aad") - return GraphApiService.GraphApiResponse(claims.getStringClaim("NAVident"), "Navn Testnavn") + val claims = context.getClaims(Issuer.AZURE) + return GraphApiService.GraphApiResponse(claims!!.getStringClaim("NAVident"), "Navn Testnavn") } } \ No newline at end of file diff --git a/src/main/kotlin/no/nav/arbeidsgiver/tiltakrefusjon/autorisering/InnloggetBrukerService.kt b/src/main/kotlin/no/nav/arbeidsgiver/tiltakrefusjon/autorisering/InnloggetBrukerService.kt index 2a24d87e..fb640d30 100644 --- a/src/main/kotlin/no/nav/arbeidsgiver/tiltakrefusjon/autorisering/InnloggetBrukerService.kt +++ b/src/main/kotlin/no/nav/arbeidsgiver/tiltakrefusjon/autorisering/InnloggetBrukerService.kt @@ -7,6 +7,8 @@ import no.nav.arbeidsgiver.tiltakrefusjon.norg.NorgService import no.nav.arbeidsgiver.tiltakrefusjon.okonomi.KontoregisterService import no.nav.arbeidsgiver.tiltakrefusjon.organisasjon.EregClient import no.nav.arbeidsgiver.tiltakrefusjon.refusjon.* +import no.nav.arbeidsgiver.tiltakrefusjon.utils.Issuer +import no.nav.arbeidsgiver.tiltakrefusjon.utils.getClaims import no.nav.security.token.support.core.context.TokenValidationContextHolder import org.slf4j.Logger import org.slf4j.LoggerFactory @@ -38,7 +40,7 @@ class InnloggetBrukerService( } fun erBeslutter(): Boolean { - val groupClaim = context.getTokenValidationContext().getClaims("aad").get("groups") as List + val groupClaim = context.getClaims(Issuer.AZURE)?.get("groups") as List return erSaksbehandler() && groupClaim.contains(beslutterRolleConfig.id) } @@ -47,11 +49,11 @@ class InnloggetBrukerService( } fun navIdent(): String { - return context.getTokenValidationContext().getClaims("aad").getStringClaim("NAVident") + return context.getClaims(Issuer.AZURE)?.getStringClaim("NAVident") ?: throw IllegalArgumentException("Forsøker å hente navident for bruker som ikke er NAV-ansatt") } fun displayName(): String { - val displayNameClaim = context.getTokenValidationContext().getClaims("aad").get("name") + val displayNameClaim = context.getClaims(Issuer.AZURE)?.get("name") if (displayNameClaim != null) { return displayNameClaim as String } @@ -61,7 +63,7 @@ class InnloggetBrukerService( fun hentInnloggetArbeidsgiver(): InnloggetArbeidsgiver { return when { erArbeidsgiver() -> { - val fnr = Fnr(context.getTokenValidationContext().getClaims("tokenx").getStringClaim("pid")) + val fnr = Fnr(context.getClaims(Issuer.TOKEN_X)?.getStringClaim("pid") ?: throw IllegalArgumentException("Forsøker å hente pid for bruker som ikke er arbeidsgiver")) InnloggetArbeidsgiver(fnr.verdi, altinnTilgangsstyringService, refusjonRepository, korreksjonRepository, refusjonService, eregClient) } diff --git a/src/main/kotlin/no/nav/arbeidsgiver/tiltakrefusjon/utils/TokenValidationContextExtensions.kt b/src/main/kotlin/no/nav/arbeidsgiver/tiltakrefusjon/utils/TokenValidationContextExtensions.kt new file mode 100644 index 00000000..01189182 --- /dev/null +++ b/src/main/kotlin/no/nav/arbeidsgiver/tiltakrefusjon/utils/TokenValidationContextExtensions.kt @@ -0,0 +1,11 @@ +package no.nav.arbeidsgiver.tiltakrefusjon.utils + +import no.nav.security.token.support.core.context.TokenValidationContextHolder + +enum class Issuer(public val iss: String) { + TOKEN_X("tokenx"), AZURE("aad") +} + +fun TokenValidationContextHolder.getClaims(issuer: Issuer) = if (this.getTokenValidationContext().hasTokenFor(issuer.iss)) this.getTokenValidationContext().getClaims(issuer.iss) else null +fun TokenValidationContextHolder.erAzureBruker(): Boolean = this.getTokenValidationContext().hasTokenFor(Issuer.AZURE.iss) +fun TokenValidationContextHolder.erTokenXBruker(): Boolean = this.getTokenValidationContext().hasTokenFor(Issuer.TOKEN_X.iss) diff --git a/src/main/resources/application-dev-gcp-labs.yml b/src/main/resources/application-dev-gcp-labs.yml index 0c2cb35c..2468c62e 100644 --- a/src/main/resources/application-dev-gcp-labs.yml +++ b/src/main/resources/application-dev-gcp-labs.yml @@ -17,11 +17,9 @@ no.nav.security.jwt: aad: discoveryurl: http://tiltak-fakelogin/metadata?issuer=aad accepted_audience: aud-aad - cookie_name: aad-token tokenx: discoveryurl: http://tiltak-fakelogin/metadata?issuer=tokenx accepted_audience: aud-tokenx - cookie_name: tokenx-token client: null tiltak-refusjon: diff --git a/src/test/kotlin/no/nav/arbeidsgiver/tiltakrefusjon/refusjon/RefusjonApiTest.kt b/src/test/kotlin/no/nav/arbeidsgiver/tiltakrefusjon/refusjon/RefusjonApiTest.kt index 5930af52..130b7c89 100644 --- a/src/test/kotlin/no/nav/arbeidsgiver/tiltakrefusjon/refusjon/RefusjonApiTest.kt +++ b/src/test/kotlin/no/nav/arbeidsgiver/tiltakrefusjon/refusjon/RefusjonApiTest.kt @@ -6,7 +6,6 @@ import com.ninjasquad.springmockk.SpykBean import io.mockk.every import io.mockk.verify import io.mockk.clearMocks -import jakarta.servlet.http.Cookie import no.nav.arbeidsgiver.tiltakrefusjon.Feilkode import no.nav.arbeidsgiver.tiltakrefusjon.altinn.Organisasjon import no.nav.arbeidsgiver.tiltakrefusjon.audit.AuditConsoleLogger @@ -41,7 +40,6 @@ import java.net.http.HttpClient import java.net.http.HttpRequest import java.net.http.HttpResponse.BodyHandlers import java.nio.charset.StandardCharsets -import java.time.LocalDate data class InnloggetBrukerTest(val identifikator: String, val organisasjoner: Set) data class RefusjonlistFraFlereOrgTest( @@ -69,14 +67,11 @@ class RefusjonApiTest( @Autowired val korreksjonRepository: KorreksjonRepository, @Autowired val varslingRepository: VarslingRepository ) { - private final val TOKEN_X_COOKIE_NAVN = "tokenx-token" - private final val AAD_COOKIE_NAVN = "aad-token" - @SpykBean lateinit var consoleLogger: AuditConsoleLogger - val navCookie = Cookie(AAD_COOKIE_NAVN, lagTokenForNavId("Z123456")) - val arbGiverCookie = Cookie(TOKEN_X_COOKIE_NAVN, lagTokenForFnr("16120102137")) + val navToken = lagTokenForNavId("Z123456") + val arbGiverToken = lagTokenForFnr("16120102137") @BeforeEach fun setUp() { @@ -105,7 +100,7 @@ class RefusjonApiTest( @Test fun `hentAlle() er tilgjengelig for saksbehandler`() { - val json = sendRequest(get("$REQUEST_MAPPING_SAKSBEHANDLER_REFUSJON?enhet=1000"), navCookie) + val json = sendRequest(get("$REQUEST_MAPPING_SAKSBEHANDLER_REFUSJON?enhet=1000"), navToken) val liste = mapper.readValue(json, object : TypeReference>() {}) val refusjoner = liste.get("refusjoner") as List> assertFalse(refusjoner.isEmpty()) @@ -122,7 +117,7 @@ class RefusjonApiTest( get(REQUEST_MAPPING_ARBEIDSGIVER_REFUSJON) .contentType(MediaType.APPLICATION_JSON) .accept(MediaType.APPLICATION_JSON) - .cookie(arbGiverCookie) + .header("authorization", "Bearer $arbGiverToken") ) .andExpect(status().isBadRequest) } @@ -133,7 +128,7 @@ class RefusjonApiTest( val bedriftNr = "998877665" // NÅR - val json = sendRequest(get("$REQUEST_MAPPING_ARBEIDSGIVER_REFUSJON?bedriftNr=$bedriftNr"), arbGiverCookie) + val json = sendRequest(get("$REQUEST_MAPPING_ARBEIDSGIVER_REFUSJON?bedriftNr=$bedriftNr"), arbGiverToken) val liste = mapper.readValue(json, object : TypeReference>() {}) // DA @@ -154,26 +149,26 @@ class RefusjonApiTest( val BEDRIFT_NR2 = "999999999" // NÅR - val brukerJson = sendRequest(get("$REQUEST_MAPPING_INNLOGGET_ARBEIDSGIVER/innlogget-bruker"), arbGiverCookie) + val brukerJson = sendRequest(get("$REQUEST_MAPPING_INNLOGGET_ARBEIDSGIVER/innlogget-bruker"), arbGiverToken) val bruker: InnloggetBrukerTest = mapper.readValue(brukerJson, object : TypeReference() {}) val refusjonJson = - sendRequest(get("$REQUEST_MAPPING_ARBEIDSGIVER_REFUSJON/hentliste?page=0&size=3"), arbGiverCookie) + sendRequest(get("$REQUEST_MAPPING_ARBEIDSGIVER_REFUSJON/hentliste?page=0&size=3"), arbGiverToken) val refusjonlist: RefusjonlistFraFlereOrgTest = mapper.readValue(refusjonJson, object : TypeReference() {}) - verify(exactly = refusjonlist.refusjoner.map { it.deltakerFnr }.toSet().size) { + verify(exactly = refusjonlist.refusjoner.map { mapOf("deltaker" to it.deltakerFnr, "bedrift" to it.bedriftNr) }.toSet().size) { consoleLogger.logg(any()) } resetAuditCount() val refusjonJson2 = - sendRequest(get("$REQUEST_MAPPING_ARBEIDSGIVER_REFUSJON/hentliste?page=1&size=3"), arbGiverCookie) + sendRequest(get("$REQUEST_MAPPING_ARBEIDSGIVER_REFUSJON/hentliste?page=1&size=3"), arbGiverToken) val refusjonlist2: RefusjonlistFraFlereOrgTest = mapper.readValue(refusjonJson2, object : TypeReference() {}) - verify(exactly = refusjonlist2.refusjoner.map { it.deltakerFnr }.toSet().size) { + verify(exactly = refusjonlist2.refusjoner.map { mapOf("deltaker" to it.deltakerFnr, "bedrift" to it.bedriftNr) }.toSet().size) { consoleLogger.logg(any()) } resetAuditCount() val refusjonJson3 = - sendRequest(get("$REQUEST_MAPPING_ARBEIDSGIVER_REFUSJON/hentliste?page=0&size=6"), arbGiverCookie) + sendRequest(get("$REQUEST_MAPPING_ARBEIDSGIVER_REFUSJON/hentliste?page=0&size=6"), arbGiverToken) val refusjonlist3: RefusjonlistFraFlereOrgTest = mapper.readValue(refusjonJson3, object : TypeReference() {}) - verify(exactly = refusjonlist3.refusjoner.map { it.deltakerFnr }.toSet().size) { + verify(exactly = refusjonlist3.refusjoner.map { mapOf("deltaker" to it.deltakerFnr, "bedrift" to it.bedriftNr) }.toSet().size) { consoleLogger.logg(any()) } @@ -192,7 +187,7 @@ class RefusjonApiTest( // NÅR val json4 = sendRequest( get("$REQUEST_MAPPING_ARBEIDSGIVER_REFUSJON/hentliste?bedriftNr=$BEDRIFT_NR1,$BEDRIFT_NR2&page=0&size=6"), - arbGiverCookie + arbGiverToken ) val refusjonlist4: RefusjonlistFraFlereOrgTest = mapper.readValue(json4, object : TypeReference() {}) @@ -206,7 +201,7 @@ class RefusjonApiTest( fun `hent() - Arbeidsgiver henter refusjon med id`() { val id = refusjonRepository.findAll().find { it.deltakerFnr == "07098142678" }?.id - val json = sendRequest(get("$REQUEST_MAPPING_ARBEIDSGIVER_REFUSJON/$id"), arbGiverCookie) + val json = sendRequest(get("$REQUEST_MAPPING_ARBEIDSGIVER_REFUSJON/$id"), arbGiverToken) val refusjon = mapper.readValue(json, Refusjon::class.java) assertEquals(id, refusjon.id) @@ -219,14 +214,14 @@ class RefusjonApiTest( fun `hent() - Arbeidsgiver mangler tilgang til refusjon med id`() { val id = refusjonRepository.findAll().find { it.deltakerFnr == "23119409195" }?.id - sendRequest(get("$REQUEST_MAPPING_ARBEIDSGIVER_REFUSJON/$id"), arbGiverCookie, status().isUnauthorized) + sendRequest(get("$REQUEST_MAPPING_ARBEIDSGIVER_REFUSJON/$id"), arbGiverToken, status().isUnauthorized) } @Test fun `hent() - Saksbehandler henter refusjon med id`() { val id = refusjonRepository.findAll().find { it.deltakerFnr == "28128521498" }?.id - val json = sendRequest(get("$REQUEST_MAPPING_SAKSBEHANDLER_REFUSJON/$id"), navCookie) + val json = sendRequest(get("$REQUEST_MAPPING_SAKSBEHANDLER_REFUSJON/$id"), navToken) val refusjon = mapper.readValue(json, Refusjon::class.java) assertEquals(id, refusjon.id) @@ -238,7 +233,7 @@ class RefusjonApiTest( @Test fun `hent() - Saksbehandler mangler tilgang til henter refusjon med id`() { val id = refusjonRepository.findAll().find { it.deltakerFnr == "07098142678" }?.id - sendRequest(get("$REQUEST_MAPPING_SAKSBEHANDLER_REFUSJON/$id"), navCookie, status().isUnauthorized) + sendRequest(get("$REQUEST_MAPPING_SAKSBEHANDLER_REFUSJON/$id"), navToken, status().isUnauthorized) } @Test @@ -280,7 +275,7 @@ class RefusjonApiTest( // Svarer på spørsmål om alle inntekter er fra tiltaket sendRequest( post("$REQUEST_MAPPING_ARBEIDSGIVER_REFUSJON/$id/endre-bruttolønn"), - arbGiverCookie, + arbGiverToken, EndreBruttolønnRequest(true, null) ) val refusjonEtterInntektsspørsmål = hentRefusjon(id) @@ -290,7 +285,7 @@ class RefusjonApiTest( assertTrue(harLagretHendelselogg) // Godkjenn - sendRequest(post("$REQUEST_MAPPING_ARBEIDSGIVER_REFUSJON/$id/godkjenn"), arbGiverCookie) + sendRequest(post("$REQUEST_MAPPING_ARBEIDSGIVER_REFUSJON/$id/godkjenn"), arbGiverToken) val refusjonEtterGodkjennelse = hentRefusjon(id) assertThat(refusjonEtterGodkjennelse.godkjentAvArbeidsgiver).isNotNull() } @@ -305,7 +300,7 @@ class RefusjonApiTest( .contentType(MediaType.APPLICATION_JSON) .accept(MediaType.APPLICATION_JSON) .header("If-Unmodified-Since", Now.instant()) - .cookie(arbGiverCookie) + .header("authorization", "Bearer $arbGiverToken") ) .andExpect(status().isBadRequest) .andExpect(header().string("feilkode", Feilkode.INGEN_INNTEKTER.toString())) @@ -314,32 +309,32 @@ class RefusjonApiTest( private fun setInntektslinjeOpptjentIPeriode(refusjonId: String, inntektslinjeId: String, erOpptjentIPeriode: Boolean) { val json = sendRequest( post("$REQUEST_MAPPING_ARBEIDSGIVER_REFUSJON/$refusjonId/set-inntektslinje-opptjent-i-periode"), - arbGiverCookie, + arbGiverToken, EndreRefundertInntektslinjeRequest(inntektslinjeId, erOpptjentIPeriode) ) } private fun hentRefusjon(id: String?): Refusjon { - val json = sendRequest(get("$REQUEST_MAPPING_ARBEIDSGIVER_REFUSJON/$id"), arbGiverCookie) + val json = sendRequest(get("$REQUEST_MAPPING_ARBEIDSGIVER_REFUSJON/$id"), arbGiverToken) return mapper.readValue(json, Refusjon::class.java) } private fun oppdaterRefusjonMedKontonrOgInntekter(id: String) { - sendRequest(post("$REQUEST_MAPPING_ARBEIDSGIVER_REFUSJON/$id/sett-kontonummer-og-inntekter"), arbGiverCookie) + sendRequest(post("$REQUEST_MAPPING_ARBEIDSGIVER_REFUSJON/$id/sett-kontonummer-og-inntekter"), arbGiverToken) } - private fun sendRequest(request: MockHttpServletRequestBuilder, cookie: Cookie): String { - return sendRequest(request, cookie, null) + private fun sendRequest(request: MockHttpServletRequestBuilder, token: String): String { + return sendRequest(request, token, null) } private fun sendRequest( request: MockHttpServletRequestBuilder, - cookie: Cookie, + token: String, content: Any?, status: ResultMatcher = status().isOk ): String { if (content != null) { - request.content(mapper.writeValueAsString(content)) + request.content(mapper.writeValueAsString(content)).contentType(MediaType.APPLICATION_JSON) } return mockMvc.perform( @@ -347,25 +342,25 @@ class RefusjonApiTest( .contentType(MediaType.APPLICATION_JSON) .accept(MediaType.APPLICATION_JSON) .header("If-Unmodified-Since", Now.instant()) - .cookie(cookie) + .header("authorization", "Bearer $token") ) .andExpect(status) .andReturn() .response.getContentAsString(StandardCharsets.UTF_8) } - private fun sendRequest(request: MockHttpServletRequestBuilder, cookie: Cookie, forventetStatus: ResultMatcher) { + private fun sendRequest(request: MockHttpServletRequestBuilder, token: String, forventetStatus: ResultMatcher) { mockMvc.perform( request .contentType(MediaType.APPLICATION_JSON) .accept(MediaType.APPLICATION_JSON) .header("If-Unmodified-Since", Now.instant()) - .cookie(cookie) + .header("authorization", "Bearer $token") ) .andExpect(forventetStatus) } - private final fun lagTokenForFnr(fnr: String): String? { + private final fun lagTokenForFnr(fnr: String): String { return HttpClient.newHttpClient().send( HttpRequest.newBuilder() .GET() @@ -374,7 +369,7 @@ class RefusjonApiTest( ).body() } - private final fun lagTokenForNavId(navId: String): String? { + private final fun lagTokenForNavId(navId: String): String { return HttpClient.newHttpClient().send( HttpRequest.newBuilder() .GET() diff --git a/src/test/resources/application-dockercompose.yml b/src/test/resources/application-dockercompose.yml index 7b741b6b..5da2505f 100644 --- a/src/test/resources/application-dockercompose.yml +++ b/src/test/resources/application-dockercompose.yml @@ -21,11 +21,9 @@ no.nav.security.jwt: aad: discoveryurl: https://tiltak-fakelogin.ekstern.dev.nav.no/metadata?issuer=aad accepted_audience: aud-aad - cookie_name: aad-token tokenx: discoveryurl: https://tiltak-fakelogin.ekstern.dev.nav.no/metadata?issuer=tokenx accepted_audience: aud-tokenx - cookie_name: tokenx-token client: null logging: diff --git a/src/test/resources/application-local.yml b/src/test/resources/application-local.yml index 953ce33f..799383dd 100644 --- a/src/test/resources/application-local.yml +++ b/src/test/resources/application-local.yml @@ -38,11 +38,9 @@ no.nav.security.jwt: aad: discoveryurl: https://tiltak-fakelogin.ekstern.dev.nav.no/metadata?issuer=aad accepted_audience: aud-aad - cookie_name: aad-token tokenx: discoveryurl: https://tiltak-fakelogin.ekstern.dev.nav.no/metadata?issuer=tokenx accepted_audience: aud-tokenx - cookie_name: tokenx-token client: null logging: From 1ddb65f249dddfc9a3e7c4a385c18a157e46d864 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Odd=20Andreas=20S=C3=B8rs=C3=A6ther?= Date: Tue, 5 Mar 2024 16:16:01 +0100 Subject: [PATCH 03/13] Fiks manglende imports --- .../no/nav/arbeidsgiver/tiltakrefusjon/AuditLoggingFilter.kt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main/kotlin/no/nav/arbeidsgiver/tiltakrefusjon/AuditLoggingFilter.kt b/src/main/kotlin/no/nav/arbeidsgiver/tiltakrefusjon/AuditLoggingFilter.kt index 14ab56dc..61b7cfd7 100644 --- a/src/main/kotlin/no/nav/arbeidsgiver/tiltakrefusjon/AuditLoggingFilter.kt +++ b/src/main/kotlin/no/nav/arbeidsgiver/tiltakrefusjon/AuditLoggingFilter.kt @@ -7,7 +7,11 @@ import jakarta.servlet.http.HttpServletResponse import no.nav.arbeidsgiver.tiltakrefusjon.audit.AuditLogger import no.nav.arbeidsgiver.tiltakrefusjon.refusjon.events.AuditEntry import no.nav.arbeidsgiver.tiltakrefusjon.refusjon.events.EventType +import no.nav.arbeidsgiver.tiltakrefusjon.utils.Issuer import no.nav.arbeidsgiver.tiltakrefusjon.utils.Now +import no.nav.arbeidsgiver.tiltakrefusjon.utils.erAzureBruker +import no.nav.arbeidsgiver.tiltakrefusjon.utils.erTokenXBruker +import no.nav.arbeidsgiver.tiltakrefusjon.utils.getClaims import no.nav.security.token.support.core.context.TokenValidationContextHolder import org.slf4j.LoggerFactory import org.springframework.core.Ordered From 540cec1a4c5c0bbfd45c744103c66820d0612627 Mon Sep 17 00:00:00 2001 From: MagnusRom <65652609+MagnusRom@users.noreply.github.com> Date: Fri, 8 Mar 2024 15:22:18 +0100 Subject: [PATCH 04/13] =?UTF-8?q?laget=20test=20p=C3=A5=20utregning=20av?= =?UTF-8?q?=20sumUtgifter=20at=20den=20er=20lik=20som=20i=20tiltaksgjennom?= =?UTF-8?q?foring=20(#107)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../inntekt/RefusjonsberegnerTest.kt | 38 +++++++++++++++++-- 1 file changed, 34 insertions(+), 4 deletions(-) diff --git a/src/test/kotlin/no/nav/arbeidsgiver/tiltakrefusjon/inntekt/RefusjonsberegnerTest.kt b/src/test/kotlin/no/nav/arbeidsgiver/tiltakrefusjon/inntekt/RefusjonsberegnerTest.kt index 6a2a8269..9158ff58 100644 --- a/src/test/kotlin/no/nav/arbeidsgiver/tiltakrefusjon/inntekt/RefusjonsberegnerTest.kt +++ b/src/test/kotlin/no/nav/arbeidsgiver/tiltakrefusjon/inntekt/RefusjonsberegnerTest.kt @@ -13,6 +13,8 @@ class RefusjonsberegnerTest { lateinit var juni: Inntektslinje lateinit var juli: Inntektslinje + lateinit var september: Inntektslinje + lateinit var enInntektslinje: Inntektsgrunnlag lateinit var juniUregelmessig: Inntektslinje lateinit var inntektsliste: List lateinit var inntektsgrunnlag: Inntektsgrunnlag @@ -24,6 +26,11 @@ class RefusjonsberegnerTest { lagEnInntektslinje(20000.00, YearMonth.of(2023, 7), LocalDate.of(2023, 6, 1), LocalDate.of(2023, 6, 30)) juli = lagEnInntektslinje(20000.00, YearMonth.of(2023, 7), LocalDate.of(2023, 7, 1), LocalDate.of(2023, 7, 31)) + september = + lagEnInntektslinje(16666.00, YearMonth.of(2023, 9), LocalDate.of(2023, 9, 1), LocalDate.of(2023, 9, 30)) + + enInntektslinje = Inntektsgrunnlag(listOf(september), "repons fra Inntekt") + inntektsliste = listOf(juni, juli) inntektsgrunnlag = Inntektsgrunnlag(inntektsliste, "repons fra Inntekt") @@ -52,7 +59,7 @@ class RefusjonsberegnerTest { bedriftNavn = "Kiwi Majorstuen", bedriftNr = "", otpSats = 0.02, - feriepengerSats = 0.12, + feriepengerSats = 0.102, arbeidsgiveravgiftSats = 0.141, lønnstilskuddsprosent = 40, tilskuddFom = tilskuddFom, @@ -118,7 +125,7 @@ class RefusjonsberegnerTest { tilskuddFom = LocalDate.of(2023,6,1), harFerietrekkForSammeMåned = false ) - val beregnetBeløpHeleInntektsgrunnlaget = 20856 + val beregnetBeløpHeleInntektsgrunnlaget = 20520 assertThat(beregning.refusjonsbeløp).isEqualTo(beregnetBeløpHeleInntektsgrunnlaget) } @@ -138,7 +145,7 @@ class RefusjonsberegnerTest { tilskuddFom = LocalDate.of(2023,6,1), harFerietrekkForSammeMåned = false ) - val beregnetBeløpAvAntallDagerJobbetInnenforInntektsgrunnlaget = 20856 + val beregnetBeløpAvAntallDagerJobbetInnenforInntektsgrunnlaget = 20520 assertThat(beregning.refusjonsbeløp).isEqualTo(beregnetBeløpAvAntallDagerJobbetInnenforInntektsgrunnlaget) } @@ -173,7 +180,30 @@ class RefusjonsberegnerTest { // Beregning uten 5G-sjekk skal gi et refusjonsbeløp på 20856 // Med 590000 allerede utbetalt så vil dette være over tilgjengelig sum assertThat(beregning.refusjonsbeløp).isEqualTo(3100) - assertThat(beregning2.refusjonsbeløp).isEqualTo(20856) + assertThat(beregning2.refusjonsbeløp).isEqualTo(20520) + + } + + @Test + fun `Beregning_av_refusjongrunnlag_sumUtgifter`(){ + val tilskuddsgrunnlagLønnstilskudd = lagEtTilskuddsgrunnlag( + LocalDate.of(2023, 9, 1), + LocalDate.of(2023, 9, 30), + Tiltakstype.VARIG_LONNSTILSKUDD, + 10000 + ) + + val beregning = beregnRefusjonsbeløp( + enInntektslinje.inntekter.toList(), + tilskuddsgrunnlagLønnstilskudd, + 0, + null, + tilskuddFom = LocalDate.of(2023,9,1), + sumUtbetaltVarig = 16666, + harFerietrekkForSammeMåned = false + ) + + assertThat(beregning.sumUtgifter).isEqualTo(21375) } } \ No newline at end of file From 50b416198cd76a3c4eb5e5b557dc30c8b82f8260 Mon Sep 17 00:00:00 2001 From: Odd A <3494925+Oddsor@users.noreply.github.com> Date: Thu, 14 Mar 2024 09:43:43 +0100 Subject: [PATCH 05/13] Fang opp sist endret i body (#109) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Test hypotese på "sistEndret"-avvik for api-kall Et API-kall som inneholder "if-unmodified-since"-header produserer merkelige resultater; klienten påstår at refusjonen ble sist endret for flere måneder siden! For å utelukke at problemet skyldes tukling med headere, enten fra bruker sin klient eller på vei fra klient til server, er det fint å logge samme tidspunkt fra header og body. * Legg til et filter som logger header-verdi Vi har lyst til å vite den "rå" header-verdien til if-unmodified-since før den treffer restcontrolleren --- .../tiltakrefusjon/RequestDebugFilter.kt | 22 +++++++++++++ .../ArbeidsgiverRefusjonController.kt | 33 +++++++++++++++++-- 2 files changed, 53 insertions(+), 2 deletions(-) create mode 100644 src/main/kotlin/no/nav/arbeidsgiver/tiltakrefusjon/RequestDebugFilter.kt diff --git a/src/main/kotlin/no/nav/arbeidsgiver/tiltakrefusjon/RequestDebugFilter.kt b/src/main/kotlin/no/nav/arbeidsgiver/tiltakrefusjon/RequestDebugFilter.kt new file mode 100644 index 00000000..d9006dea --- /dev/null +++ b/src/main/kotlin/no/nav/arbeidsgiver/tiltakrefusjon/RequestDebugFilter.kt @@ -0,0 +1,22 @@ +package no.nav.arbeidsgiver.tiltakrefusjon + +import jakarta.servlet.FilterChain +import jakarta.servlet.http.HttpServletRequest +import jakarta.servlet.http.HttpServletResponse +import org.slf4j.LoggerFactory +import org.springframework.core.Ordered +import org.springframework.core.annotation.Order +import org.springframework.stereotype.Component +import org.springframework.web.filter.OncePerRequestFilter + +@Order(Ordered.HIGHEST_PRECEDENCE + 5) +@Component +class RequestDebugFilter: OncePerRequestFilter() { + val log = LoggerFactory.getLogger(javaClass) + override fun doFilterInternal(request: HttpServletRequest, response: HttpServletResponse, filterChain: FilterChain) { + if (request.getHeader("if-unmodified-since") != null) { + log.info("if-unmodified-since fra header: ${request.getHeader("if-unmodified-since")}") + } + filterChain.doFilter(request, response) + } +} diff --git a/src/main/kotlin/no/nav/arbeidsgiver/tiltakrefusjon/refusjon/ArbeidsgiverRefusjonController.kt b/src/main/kotlin/no/nav/arbeidsgiver/tiltakrefusjon/refusjon/ArbeidsgiverRefusjonController.kt index fe920406..37746081 100644 --- a/src/main/kotlin/no/nav/arbeidsgiver/tiltakrefusjon/refusjon/ArbeidsgiverRefusjonController.kt +++ b/src/main/kotlin/no/nav/arbeidsgiver/tiltakrefusjon/refusjon/ArbeidsgiverRefusjonController.kt @@ -4,11 +4,25 @@ import no.nav.arbeidsgiver.tiltakrefusjon.UgyldigRequestException import no.nav.arbeidsgiver.tiltakrefusjon.autorisering.InnloggetBrukerService import no.nav.arbeidsgiver.tiltakrefusjon.dokgen.DokgenService import no.nav.security.token.support.core.api.ProtectedWithClaims +import org.slf4j.Logger +import org.slf4j.LoggerFactory import org.springframework.data.domain.Page -import org.springframework.http.* +import org.springframework.http.HttpEntity +import org.springframework.http.HttpHeaders +import org.springframework.http.HttpStatus +import org.springframework.http.MediaType +import org.springframework.http.ResponseEntity import org.springframework.transaction.annotation.Transactional -import org.springframework.web.bind.annotation.* +import org.springframework.web.bind.annotation.GetMapping +import org.springframework.web.bind.annotation.PathVariable +import org.springframework.web.bind.annotation.PostMapping +import org.springframework.web.bind.annotation.RequestBody +import org.springframework.web.bind.annotation.RequestHeader +import org.springframework.web.bind.annotation.RequestMapping +import org.springframework.web.bind.annotation.RestController +import java.time.Duration import java.time.Instant +import java.time.temporal.ChronoField const val REQUEST_MAPPING_ARBEIDSGIVER_REFUSJON = "/api/arbeidsgiver/refusjon" @@ -28,6 +42,8 @@ class ArbeidsgiverRefusjonController( val innloggetBrukerService: InnloggetBrukerService, val dokgenService: DokgenService ) { + var logger: Logger = LoggerFactory.getLogger(javaClass) + @GetMapping fun hentAlle(queryParametre: HentArbeidsgiverRefusjonerQueryParametre): List { if (queryParametre.bedriftNr == null) { @@ -88,6 +104,19 @@ class ArbeidsgiverRefusjonController( arbeidsgiver.settKontonummerOgInntekterPåRefusjon(id, sistEndret); } + @PostMapping("{id}/sett-kontonummer-og-inntekter", consumes = ["application/json"]) + @Transactional + fun settKontonummerOgInntekterPåRefusjon(@PathVariable id: String, @RequestHeader(HttpHeaders.IF_UNMODIFIED_SINCE) sistEndret: Instant?, @RequestBody body: SistEndretBody?) { + if (body?.sistEndret != null && sistEndret != null && Duration.between(sistEndret, body.sistEndret).toMinutes() > 1) { + val avvik = Duration.between(sistEndret, body.sistEndret).toMinutes() > 1 + logger.warn("SistEndret-tid i body og header divergerer for refusjon $id med $avvik minutter") + } + val arbeidsgiver = innloggetBrukerService.hentInnloggetArbeidsgiver() + arbeidsgiver.settKontonummerOgInntekterPåRefusjon(id, sistEndret) + } + + data class SistEndretBody(val sistEndret: Instant?) + @PostMapping("/{id}/endre-bruttolønn") @Transactional fun endreBruttolønn(@PathVariable id: String, @RequestBody request: EndreBruttolønnRequest, @RequestHeader(HttpHeaders.IF_UNMODIFIED_SINCE) sistEndret: Instant) { From 67c7d7eb4d5ac989446fe4ed525c693874ee4a2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Odd=20Andreas=20S=C3=B8rs=C3=A6ther?= Date: Tue, 12 Mar 2024 15:27:41 +0100 Subject: [PATCH 06/13] CookieTokenFilter for lokal utvikling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Siste oppgradering av token-validation-spring (v4) fjernet støtte for tokens som ligger i en cookie. Det var vår måte å "logge inn" på i lokal utvikling. Ved å redusere "presedensen" til valideringsfilteret og sette inn et "CookieTokenFilter" foran, kan vi manuelt sette inn et token i auth-header som fanges opp av valideringsfilteret senere. --- .../tiltakrefusjon/CookieTokenFilter.kt | 49 +++++++++++++++++++ .../resources/application-dockercompose.yml | 5 +- src/test/resources/application-local.yml | 5 +- 3 files changed, 57 insertions(+), 2 deletions(-) create mode 100644 src/test/kotlin/no/nav/arbeidsgiver/tiltakrefusjon/CookieTokenFilter.kt diff --git a/src/test/kotlin/no/nav/arbeidsgiver/tiltakrefusjon/CookieTokenFilter.kt b/src/test/kotlin/no/nav/arbeidsgiver/tiltakrefusjon/CookieTokenFilter.kt new file mode 100644 index 00000000..ef71b04c --- /dev/null +++ b/src/test/kotlin/no/nav/arbeidsgiver/tiltakrefusjon/CookieTokenFilter.kt @@ -0,0 +1,49 @@ +package no.nav.arbeidsgiver.tiltakrefusjon + +import jakarta.servlet.FilterChain +import jakarta.servlet.http.HttpServletRequest +import jakarta.servlet.http.HttpServletRequestWrapper +import jakarta.servlet.http.HttpServletResponse +import org.springframework.core.Ordered +import org.springframework.core.annotation.Order +import org.springframework.stereotype.Component +import org.springframework.web.filter.OncePerRequestFilter + +/** + * Dette filteret gjør at lokalkjøring av applikasjonen fortsatt fungerer med cookie-baserte + * jwt-tokens. Frontendene har en lokal login-mekanisme når man kjører i dev-modus som henter + * et fake JWT access-token og legger det i en cookie. + * + * Tidligere ble denne cookien plukket opp av token-validation-biblioteket, men siden versjon 4 + * har støtte for cookies blitt fjernet. + * + * Ved å sørge for at dette filteret kjører før TokenValidationFilter sniker vi inn en auth-header + * som deretter plukkes opp av token-validering senere. + */ +@Component +@Order(Ordered.HIGHEST_PRECEDENCE) +class CookieTokenFilter: OncePerRequestFilter() { + override fun doFilterInternal(request: HttpServletRequest, response: HttpServletResponse, filterChain: FilterChain) { + val aadToken = request.cookies?.find { it.name == "aad-token" }?.value + val tokenxToken = request.cookies?.find { it.name == "tokenx-token" }?.value + + if (request.requestURI.startsWith("/api/arbeidsgiver") && tokenxToken != null) { + val wrappedRequest = RequestMedToken(request, tokenxToken) + filterChain.doFilter(wrappedRequest, response) + } else if (request.requestURI.startsWith("/api/saksbehandler") && aadToken != null) { + val wrappedRequest = RequestMedToken(request, aadToken) + filterChain.doFilter(wrappedRequest, response) + } else { + filterChain.doFilter(request, response); + } + } +} + +private class RequestMedToken(request: HttpServletRequest, val token: String): HttpServletRequestWrapper(request) { + override fun getHeader(name: String?): String? { + if (name?.lowercase() == "authorization") { + return "Bearer $token" + } + return super.getHeader(name) + } +} diff --git a/src/test/resources/application-dockercompose.yml b/src/test/resources/application-dockercompose.yml index 5da2505f..7fb5188b 100644 --- a/src/test/resources/application-dockercompose.yml +++ b/src/test/resources/application-dockercompose.yml @@ -17,6 +17,9 @@ spring: datasource: url: "jdbc:postgresql://localhost:7432/sample?user=sample&password=sample" no.nav.security.jwt: + tokenvalidationfilter: + # Gå vekk fra "highest presedence" slik at CookieTokenFilter får kjøre først + order: -10000 issuer: aad: discoveryurl: https://tiltak-fakelogin.ekstern.dev.nav.no/metadata?issuer=aad @@ -64,4 +67,4 @@ server: port: 8081 wiremock: - port: 8091 \ No newline at end of file + port: 8091 diff --git a/src/test/resources/application-local.yml b/src/test/resources/application-local.yml index 799383dd..2cae20ce 100644 --- a/src/test/resources/application-local.yml +++ b/src/test/resources/application-local.yml @@ -34,6 +34,9 @@ management: enabled: false no.nav.security.jwt: + tokenvalidationfilter: + # Gå vekk fra "highest presedence" slik at CookieTokenFilter får kjøre først + order: -10000 issuer: aad: discoveryurl: https://tiltak-fakelogin.ekstern.dev.nav.no/metadata?issuer=aad @@ -90,4 +93,4 @@ server: wiremock: port: 8091 -NAIS_APP_IMAGE: ghcr.io/navikt/tiltak-refusjon-api/tiltak-refusjon-api:804742e2ce6cffec5d1b51715215c6734642cb30 \ No newline at end of file +NAIS_APP_IMAGE: ghcr.io/navikt/tiltak-refusjon-api/tiltak-refusjon-api:804742e2ce6cffec5d1b51715215c6734642cb30 From e432aff1ff7d266016d197f8f6baadf4d5a9a30b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Odd=20Andreas=20S=C3=B8rs=C3=A6ther?= Date: Fri, 15 Mar 2024 15:45:20 +0100 Subject: [PATCH 07/13] Fjern GraphApiService MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ettersom navnet til NAV-ansatte ligger i JWT-token behøver vi aldri kalle graph-api'et til Microsoft. --- .nais/wiremock.yml | 4 +-- .../autorisering/FakeGraphApiService.kt | 16 ------------ .../autorisering/GraphApiService.kt | 6 ----- .../autorisering/GraphApiServiceImpl.kt | 21 --------------- .../resources/application-dev-gcp-labs.yml | 3 --- src/main/resources/application.yml | 2 -- .../autorisering/GraphApiServiceTest.kt | 26 ------------------- .../resources/application-dockercompose.yml | 3 --- src/test/resources/application-local.yml | 3 --- .../mappings/{graph-api.json => health.json} | 5 ++-- 10 files changed, 4 insertions(+), 85 deletions(-) delete mode 100644 src/main/kotlin/no/nav/arbeidsgiver/tiltakrefusjon/autorisering/FakeGraphApiService.kt delete mode 100644 src/main/kotlin/no/nav/arbeidsgiver/tiltakrefusjon/autorisering/GraphApiService.kt delete mode 100644 src/main/kotlin/no/nav/arbeidsgiver/tiltakrefusjon/autorisering/GraphApiServiceImpl.kt delete mode 100644 src/test/kotlin/no/nav/arbeidsgiver/tiltakrefusjon/autorisering/GraphApiServiceTest.kt rename src/test/resources/mappings/{graph-api.json => health.json} (66%) diff --git a/.nais/wiremock.yml b/.nais/wiremock.yml index 2a992d49..dc057e60 100644 --- a/.nais/wiremock.yml +++ b/.nais/wiremock.yml @@ -12,13 +12,13 @@ spec: max: 1 port: 8080 liveness: - path: /graph-api + path: /health initialDelay: 1 timeout: 1 periodSeconds: 10 failureThreshold: 3 readiness: - path: /graph-api + path: /health initialDelay: 1 timeout: 1 periodSeconds: 10 diff --git a/src/main/kotlin/no/nav/arbeidsgiver/tiltakrefusjon/autorisering/FakeGraphApiService.kt b/src/main/kotlin/no/nav/arbeidsgiver/tiltakrefusjon/autorisering/FakeGraphApiService.kt deleted file mode 100644 index 8be21bfd..00000000 --- a/src/main/kotlin/no/nav/arbeidsgiver/tiltakrefusjon/autorisering/FakeGraphApiService.kt +++ /dev/null @@ -1,16 +0,0 @@ -package no.nav.arbeidsgiver.tiltakrefusjon.autorisering - -import no.nav.arbeidsgiver.tiltakrefusjon.utils.Issuer -import no.nav.arbeidsgiver.tiltakrefusjon.utils.getClaims -import no.nav.security.token.support.core.context.TokenValidationContextHolder -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty -import org.springframework.stereotype.Service - -@Service -@ConditionalOnProperty("tiltak-refusjon.graph-api.fake") -class FakeGraphApiService(val context: TokenValidationContextHolder) : GraphApiService { - override fun hent(): GraphApiService.GraphApiResponse { - val claims = context.getClaims(Issuer.AZURE) - return GraphApiService.GraphApiResponse(claims!!.getStringClaim("NAVident"), "Navn Testnavn") - } -} \ No newline at end of file diff --git a/src/main/kotlin/no/nav/arbeidsgiver/tiltakrefusjon/autorisering/GraphApiService.kt b/src/main/kotlin/no/nav/arbeidsgiver/tiltakrefusjon/autorisering/GraphApiService.kt deleted file mode 100644 index 7946f134..00000000 --- a/src/main/kotlin/no/nav/arbeidsgiver/tiltakrefusjon/autorisering/GraphApiService.kt +++ /dev/null @@ -1,6 +0,0 @@ -package no.nav.arbeidsgiver.tiltakrefusjon.autorisering - -interface GraphApiService { - fun hent(): GraphApiResponse - data class GraphApiResponse(val onPremisesSamAccountName: String, val displayName: String) -} \ No newline at end of file diff --git a/src/main/kotlin/no/nav/arbeidsgiver/tiltakrefusjon/autorisering/GraphApiServiceImpl.kt b/src/main/kotlin/no/nav/arbeidsgiver/tiltakrefusjon/autorisering/GraphApiServiceImpl.kt deleted file mode 100644 index 73eed2a5..00000000 --- a/src/main/kotlin/no/nav/arbeidsgiver/tiltakrefusjon/autorisering/GraphApiServiceImpl.kt +++ /dev/null @@ -1,21 +0,0 @@ -package no.nav.arbeidsgiver.tiltakrefusjon.autorisering - -import no.nav.arbeidsgiver.tiltakrefusjon.utils.ConditionalOnPropertyNotEmpty -import org.springframework.beans.factory.annotation.Qualifier -import org.springframework.beans.factory.annotation.Value -import org.springframework.stereotype.Service -import org.springframework.web.client.RestTemplate -import java.net.URI - -@Service -@ConditionalOnPropertyNotEmpty("tiltak-refusjon.graph-api.uri") -class GraphApiServiceImpl( - @Qualifier("påVegneAvSaksbehandlerGraphRestTemplate") - val påVegneAvSaksbehandlerGraphRestTemplate: RestTemplate, - @Value("\${tiltak-refusjon.graph-api.uri}") val graphApiUri: URI -) : GraphApiService { - override fun hent(): GraphApiService.GraphApiResponse { - return påVegneAvSaksbehandlerGraphRestTemplate.getForObject(graphApiUri, GraphApiService.GraphApiResponse::class.java) - ?: throw RuntimeException("Feil ved graph api") - } -} \ No newline at end of file diff --git a/src/main/resources/application-dev-gcp-labs.yml b/src/main/resources/application-dev-gcp-labs.yml index 2468c62e..1f4e7960 100644 --- a/src/main/resources/application-dev-gcp-labs.yml +++ b/src/main/resources/application-dev-gcp-labs.yml @@ -26,9 +26,6 @@ tiltak-refusjon: kafka: enabled: false fake: true - graph-api: - uri: "" - fake: true ereg: uri: http://tiltak-refusjon-api-wiremock/ereg consumer-id: "tiltak-refusjon-api" diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 1b67b156..60632f12 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -114,7 +114,5 @@ tiltak-refusjon: antall: 500 altinnApiKey: ${ALTINN_API_KEY} apiGwApiKey: ${ALTINN_API_GW_API_KEY} - graph-api: - uri: "https://graph.microsoft.com/v1.0/me?$select=onPremisesSamAccountName,displayName" dokgen: uri: "http://tiltak-dokgen/template/tiltak-refusjon/create-pdf" diff --git a/src/test/kotlin/no/nav/arbeidsgiver/tiltakrefusjon/autorisering/GraphApiServiceTest.kt b/src/test/kotlin/no/nav/arbeidsgiver/tiltakrefusjon/autorisering/GraphApiServiceTest.kt deleted file mode 100644 index 1669a728..00000000 --- a/src/test/kotlin/no/nav/arbeidsgiver/tiltakrefusjon/autorisering/GraphApiServiceTest.kt +++ /dev/null @@ -1,26 +0,0 @@ -package no.nav.arbeidsgiver.tiltakrefusjon.autorisering - -import org.assertj.core.api.Assertions.assertThat -import org.junit.jupiter.api.Test -import org.springframework.beans.factory.annotation.Autowired -import org.springframework.boot.test.context.SpringBootTest -import org.springframework.cloud.contract.wiremock.AutoConfigureWireMock -import org.springframework.test.context.ActiveProfiles - -@SpringBootTest(properties = [ - "tiltak-refusjon.graph-api.uri=http://localhost:8090/graph-api", - "tiltak-refusjon.graph-api.fake=false" -]) -@ActiveProfiles("local") -@AutoConfigureWireMock(port = 8090) -class GraphApiServiceTest { - @Autowired - lateinit var graphApiService: GraphApiServiceImpl - - @Test - fun `kan gjøre GET`() { - val response = graphApiService.hent() - assertThat(response.onPremisesSamAccountName).isEqualTo("X123456") - assertThat(response.displayName).isEqualTo("Navn Navnesen") - } -} \ No newline at end of file diff --git a/src/test/resources/application-dockercompose.yml b/src/test/resources/application-dockercompose.yml index 7fb5188b..c243ebb8 100644 --- a/src/test/resources/application-dockercompose.yml +++ b/src/test/resources/application-dockercompose.yml @@ -54,9 +54,6 @@ tiltak-refusjon: uri: http://localhost:${wiremock.port}/abac-tilgangstyring username: na password: na - graph-api: - uri: "" - fake: true unleash: mock: true norg: diff --git a/src/test/resources/application-local.yml b/src/test/resources/application-local.yml index 2cae20ce..ead1d586 100644 --- a/src/test/resources/application-local.yml +++ b/src/test/resources/application-local.yml @@ -76,9 +76,6 @@ tiltak-refusjon: serviceEdition: 1 abac-tilgangstyring: uri: http://localhost:${wiremock.port}/abac-tilgangstyring - graph-api: - uri: "" - fake: true unleash: mock: true varsling: diff --git a/src/test/resources/mappings/graph-api.json b/src/test/resources/mappings/health.json similarity index 66% rename from src/test/resources/mappings/graph-api.json rename to src/test/resources/mappings/health.json index 5ece5737..0a6c28c9 100644 --- a/src/test/resources/mappings/graph-api.json +++ b/src/test/resources/mappings/health.json @@ -3,7 +3,7 @@ { "request": { "method": "GET", - "urlPattern": "/graph-api" + "urlPattern": "/health" }, "response": { "status": 200, @@ -11,8 +11,7 @@ "Content-Type": "application/json" }, "jsonBody": { - "onPremisesSamAccountName": "X123456", - "displayName": "Navn Navnesen" + "status": "UP" } } } From e2652ba26c23d4b9f274d7f9e5a3544a54d8e96c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Odd=20Andreas=20S=C3=B8rs=C3=A6ther?= Date: Fri, 15 Mar 2024 15:47:21 +0100 Subject: [PATCH 08/13] OpenTelemetry-opprydding - bruk autoInstrumentation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ny funksjonalitet i nais-platformen gjør at vi kan droppe manuell instrumenteringslogikk. --- .nais/dev-gcp-labs.yml | 5 +- .nais/nais.yml | 3 +- pom.xml | 14 ----- .../OpenTelemetryConfiguration.kt | 60 ------------------- src/main/resources/application.yml | 4 -- src/test/resources/application-local.yml | 4 -- 6 files changed, 3 insertions(+), 87 deletions(-) delete mode 100644 src/main/kotlin/no/nav/arbeidsgiver/tiltakrefusjon/OpenTelemetryConfiguration.kt diff --git a/.nais/dev-gcp-labs.yml b/.nais/dev-gcp-labs.yml index 1375290e..0eb13ca6 100644 --- a/.nais/dev-gcp-labs.yml +++ b/.nais/dev-gcp-labs.yml @@ -22,9 +22,6 @@ spec: replicas: min: 1 max: 1 - observability: - tracing: - enabled: true accessPolicy: inbound: rules: @@ -34,4 +31,4 @@ spec: outbound: rules: - application: tiltak-fakelogin - - application: tiltak-refusjon-api-wiremock \ No newline at end of file + - application: tiltak-refusjon-api-wiremock diff --git a/.nais/nais.yml b/.nais/nais.yml index 873d19d7..9310ede6 100644 --- a/.nais/nais.yml +++ b/.nais/nais.yml @@ -71,5 +71,6 @@ spec: enabled: true path: /internal/actuator/prometheus observability: - tracing: + autoInstrumentation: enabled: true + runtime: java diff --git a/pom.xml b/pom.xml index 74499e41..ac0e247d 100644 --- a/pom.xml +++ b/pom.xml @@ -182,20 +182,6 @@ unleash-client-java 8.3.0 - - - - io.micrometer - micrometer-tracing - - - io.micrometer - micrometer-tracing-bridge-otel - - - io.opentelemetry - opentelemetry-exporter-otlp - diff --git a/src/main/kotlin/no/nav/arbeidsgiver/tiltakrefusjon/OpenTelemetryConfiguration.kt b/src/main/kotlin/no/nav/arbeidsgiver/tiltakrefusjon/OpenTelemetryConfiguration.kt deleted file mode 100644 index 8130fefb..00000000 --- a/src/main/kotlin/no/nav/arbeidsgiver/tiltakrefusjon/OpenTelemetryConfiguration.kt +++ /dev/null @@ -1,60 +0,0 @@ -package no.nav.arbeidsgiver.tiltakrefusjon - -import io.micrometer.observation.Observation -import io.micrometer.observation.ObservationPredicate -import io.micrometer.observation.ObservationRegistry -import io.micrometer.observation.aop.ObservedAspect -import io.opentelemetry.exporter.otlp.trace.OtlpGrpcSpanExporter -import org.springframework.beans.factory.annotation.Value -import org.springframework.boot.web.servlet.FilterRegistrationBean -import org.springframework.context.annotation.Bean -import org.springframework.context.annotation.Configuration -import org.springframework.context.annotation.Profile -import org.springframework.core.Ordered -import org.springframework.http.server.observation.ServerRequestObservationContext -import org.springframework.web.filter.ServerHttpObservationFilter - -/** - * Alt man trenger for å ha tracing i applikasjonen! - * I application.yaml legger man til følgende: - * - management.tracing.enabled: true - * - management.tracing.sampling.probability: 1.0 - * - * I nais.yaml legger man til: - * - spec.observability.tracing.enabled: true - */ -@Profile("!local & !dockercompose") -@Configuration -class OpenTelemetryConfiguration { - - // Nais forventer at man bruker grpc-protokollen mot endepunktet - @Bean - fun otlpExporter(@Value("\${OTEL_EXPORTER_OTLP_ENDPOINT}") otelEndpoint: String): OtlpGrpcSpanExporter { - return OtlpGrpcSpanExporter.builder() - .setEndpoint(otelEndpoint) - .build() - } - - // "@Observed"-annotasjoner fungerer ikke uten denne - // OBS: @Observed fungerer kun på spring-komponenter (@Service, @Component...) - @Bean - fun observedAspect(observationRegistry: ObservationRegistry) = ObservedAspect(observationRegistry) - - // Observer http-requester mot tjenesten - @Bean - fun httpObservationFilter(registry: ObservationRegistry): FilterRegistrationBean { - val bean = FilterRegistrationBean(ServerHttpObservationFilter(registry)) - // Vi ønsker at observation-filter kjører først slik at vi får fanget opp trace-id i AuditLoggingFilter - bean.order = Ordered.HIGHEST_PRECEDENCE - return bean - } - - // Legg til et predikat slik at kall mot internal og actuator ikke observeres - @Bean - fun serverContextPredicate() = ObservationPredicate { name: String, context: Observation.Context -> - if (name == "http.server.requests" && context is ServerRequestObservationContext) { - return@ObservationPredicate !context.carrier.requestURI.startsWith("/actuator") && !context.carrier.requestURI.startsWith("/internal") - } - return@ObservationPredicate true - } -} \ No newline at end of file diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 60632f12..0d100327 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -50,10 +50,6 @@ management: exposure: include: info, health, metrics, prometheus base-path: /internal/actuator - tracing: - enabled: true - sampling: - probability: 0.33 no.nav.security.jwt: issuer: diff --git a/src/test/resources/application-local.yml b/src/test/resources/application-local.yml index ead1d586..b2c6f6d7 100644 --- a/src/test/resources/application-local.yml +++ b/src/test/resources/application-local.yml @@ -29,10 +29,6 @@ spring: enabled: true path: /h2-console -management: - tracing: - enabled: false - no.nav.security.jwt: tokenvalidationfilter: # Gå vekk fra "highest presedence" slik at CookieTokenFilter får kjøre først From b704ec553edbd42a7f5646accca4a7dfdbc9de26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Odd=20Andreas=20S=C3=B8rs=C3=A6ther?= Date: Fri, 15 Mar 2024 15:48:20 +0100 Subject: [PATCH 09/13] Fiks yaml-config for sql-platform i labs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Brukte bare forslag fra editoren på denne --- src/main/resources/application-dev-gcp-labs.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/resources/application-dev-gcp-labs.yml b/src/main/resources/application-dev-gcp-labs.yml index 1f4e7960..4f21ff83 100644 --- a/src/main/resources/application-dev-gcp-labs.yml +++ b/src/main/resources/application-dev-gcp-labs.yml @@ -1,6 +1,5 @@ spring: datasource: - platform: postgres url: jdbc:h2:mem:db;DB_CLOSE_DELAY=-1;MODE=PostgreSQL username: sa password: sa @@ -11,6 +10,9 @@ spring: path: /h2-console main: banner-mode: "console" + sql: + init: + platform: postgres no.nav.security.jwt: issuer: From 953d1dfd077dd377cef1b230a8da3608185317c0 Mon Sep 17 00:00:00 2001 From: MagnusRom <65652609+MagnusRom@users.noreply.github.com> Date: Mon, 18 Mar 2024 10:12:00 +0100 Subject: [PATCH 10/13] Hent inntekter lenger frem fix (#110) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * CookieTokenFilter for lokal utvikling Siste oppgradering av token-validation-spring (v4) fjernet støtte for tokens som ligger i en cookie. Det var vår måte å "logge inn" på i lokal utvikling. Ved å redusere "presedensen" til valideringsfilteret og sette inn et "CookieTokenFilter" foran, kan vi manuelt sette inn et token i auth-header som fanges opp av valideringsfilteret senere. * lagt til nye funksjoner for unntak om inntekter to mnd frem * fjernet dobble funksjoner --------- Co-authored-by: Odd Andreas Sørsæther --- .../autorisering/InnloggetSaksbehandler.kt | 4 ++-- .../arbeidsgiver/tiltakrefusjon/refusjon/Refusjon.kt | 2 +- .../refusjon/SaksbehandlerRefusjonController.kt | 11 +++++++++-- .../arbeidsgiver/tiltakrefusjon/CookieTokenFilter.kt | 1 + .../tiltakrefusjon/refusjon/RefusjonServiceTest.kt | 4 ++-- .../tiltakrefusjon/refusjon/RefusjonTest.kt | 2 +- 6 files changed, 16 insertions(+), 8 deletions(-) diff --git a/src/main/kotlin/no/nav/arbeidsgiver/tiltakrefusjon/autorisering/InnloggetSaksbehandler.kt b/src/main/kotlin/no/nav/arbeidsgiver/tiltakrefusjon/autorisering/InnloggetSaksbehandler.kt index 1dc805a7..593879f1 100644 --- a/src/main/kotlin/no/nav/arbeidsgiver/tiltakrefusjon/autorisering/InnloggetSaksbehandler.kt +++ b/src/main/kotlin/no/nav/arbeidsgiver/tiltakrefusjon/autorisering/InnloggetSaksbehandler.kt @@ -223,9 +223,9 @@ data class InnloggetSaksbehandler( return refusjon } - fun merkForUnntakOmInntekterToMånederFrem(id: String, merking: Int) { + fun merkForUnntakOmInntekterFremITid(id: String, merking: Int) { val refusjon = finnRefusjon(id) - refusjon.merkForUnntakOmInntekterToMånederFrem(merking, this) + refusjon.merkForUnntakOmInntekterFremITid(merking, this) refusjonRepository.save(refusjon) } diff --git a/src/main/kotlin/no/nav/arbeidsgiver/tiltakrefusjon/refusjon/Refusjon.kt b/src/main/kotlin/no/nav/arbeidsgiver/tiltakrefusjon/refusjon/Refusjon.kt index 0458a6fa..0e09ca0a 100644 --- a/src/main/kotlin/no/nav/arbeidsgiver/tiltakrefusjon/refusjon/Refusjon.kt +++ b/src/main/kotlin/no/nav/arbeidsgiver/tiltakrefusjon/refusjon/Refusjon.kt @@ -363,7 +363,7 @@ class Refusjon( return id.hashCode() } - fun merkForUnntakOmInntekterToMånederFrem(merking: Int, utførtAv: InnloggetBruker) { + fun merkForUnntakOmInntekterFremITid(merking: Int, utførtAv: InnloggetBruker) { krevStatus(RefusjonStatus.FOR_TIDLIG, RefusjonStatus.KLAR_FOR_INNSENDING) if(merking == 1 && hentInntekterLengerFrem != null) { throw FeilkodeException(Feilkode.HAR_ALLERDE_UNNTAK_OM_INNTEKTER_1_MND_FREM) diff --git a/src/main/kotlin/no/nav/arbeidsgiver/tiltakrefusjon/refusjon/SaksbehandlerRefusjonController.kt b/src/main/kotlin/no/nav/arbeidsgiver/tiltakrefusjon/refusjon/SaksbehandlerRefusjonController.kt index c3c60991..3e34fc4d 100644 --- a/src/main/kotlin/no/nav/arbeidsgiver/tiltakrefusjon/refusjon/SaksbehandlerRefusjonController.kt +++ b/src/main/kotlin/no/nav/arbeidsgiver/tiltakrefusjon/refusjon/SaksbehandlerRefusjonController.kt @@ -59,9 +59,16 @@ class SaksbehandlerRefusjonController( @PostMapping("/{id}/merk-for-unntak-om-inntekter-to-mnd-frem") fun merkForUnntakOmInntekterToMånederFrem(@PathVariable id: String, @RequestBody request: MerkForUnntakOmInntekterToMånederFremRequest) { val saksbehandler = innloggetBrukerService.hentInnloggetSaksbehandler() - saksbehandler.merkForUnntakOmInntekterToMånederFrem(id, request.merking) + saksbehandler.merkForUnntakOmInntekterFremITid(id, request.merking) } - + + @PostMapping("/{id}/merk-for-unntak-om-inntekter-frem-i-tid") + fun merkForUnntakOmInntekterFremITid(@PathVariable id: String, @RequestBody request: MerkForUnntakOmInntekterToMånederFremRequest) { + val saksbehandler = innloggetBrukerService.hentInnloggetSaksbehandler() + saksbehandler.merkForUnntakOmInntekterFremITid(id, request.merking) + } + + @PostMapping("reberegn-dry/{id}") fun reberegnDryRun(@PathVariable id: String, @RequestBody request: ReberegnRequest): Beregning { val saksbehandler = innloggetBrukerService.hentInnloggetSaksbehandler() diff --git a/src/test/kotlin/no/nav/arbeidsgiver/tiltakrefusjon/CookieTokenFilter.kt b/src/test/kotlin/no/nav/arbeidsgiver/tiltakrefusjon/CookieTokenFilter.kt index ef71b04c..22e843a2 100644 --- a/src/test/kotlin/no/nav/arbeidsgiver/tiltakrefusjon/CookieTokenFilter.kt +++ b/src/test/kotlin/no/nav/arbeidsgiver/tiltakrefusjon/CookieTokenFilter.kt @@ -24,6 +24,7 @@ import org.springframework.web.filter.OncePerRequestFilter @Order(Ordered.HIGHEST_PRECEDENCE) class CookieTokenFilter: OncePerRequestFilter() { override fun doFilterInternal(request: HttpServletRequest, response: HttpServletResponse, filterChain: FilterChain) { + val aadToken = request.cookies?.find { it.name == "aad-token" }?.value val tokenxToken = request.cookies?.find { it.name == "tokenx-token" }?.value diff --git a/src/test/kotlin/no/nav/arbeidsgiver/tiltakrefusjon/refusjon/RefusjonServiceTest.kt b/src/test/kotlin/no/nav/arbeidsgiver/tiltakrefusjon/refusjon/RefusjonServiceTest.kt index 5c22ce2e..6b25b90f 100644 --- a/src/test/kotlin/no/nav/arbeidsgiver/tiltakrefusjon/refusjon/RefusjonServiceTest.kt +++ b/src/test/kotlin/no/nav/arbeidsgiver/tiltakrefusjon/refusjon/RefusjonServiceTest.kt @@ -371,7 +371,7 @@ class RefusjonServiceTest( } Now.fixedDate(LocalDate.now().plusDays(1)) - refusjon.merkForUnntakOmInntekterToMånederFrem(2, innloggetSaksbehandler) + refusjon.merkForUnntakOmInntekterFremITid(2, innloggetSaksbehandler) refusjonService.gjørInntektsoppslag(refusjon, innloggetArbeidsgiver) verify { inntektskomponentService.hentInntekter(tilskuddMelding.deltakerFnr, tilskuddMelding.bedriftNr, tilskuddMelding.tilskuddFom, tilskuddMelding.tilskuddTom.plusMonths(2)) @@ -462,7 +462,7 @@ class RefusjonServiceTest( inntektskomponentService.hentInntekter(tilskuddMelding.deltakerFnr, tilskuddMelding.bedriftNr, tilskuddMelding.tilskuddFom, tilskuddMelding.tilskuddTom.plusMonths(0)) } Now.fixedDate(LocalDate.now().plusDays(1)) - refusjon.merkForUnntakOmInntekterToMånederFrem(2, innloggetSaksbehandler) + refusjon.merkForUnntakOmInntekterFremITid(2, innloggetSaksbehandler) refusjonService.gjørInntektsoppslag(refusjon, innloggetArbeidsgiver) verify { inntektskomponentService.hentInntekter(tilskuddMelding.deltakerFnr, tilskuddMelding.bedriftNr, tilskuddMelding.tilskuddFom, tilskuddMelding.tilskuddTom.plusMonths(2)) diff --git a/src/test/kotlin/no/nav/arbeidsgiver/tiltakrefusjon/refusjon/RefusjonTest.kt b/src/test/kotlin/no/nav/arbeidsgiver/tiltakrefusjon/refusjon/RefusjonTest.kt index fbbfe63f..b4e5cd7e 100644 --- a/src/test/kotlin/no/nav/arbeidsgiver/tiltakrefusjon/refusjon/RefusjonTest.kt +++ b/src/test/kotlin/no/nav/arbeidsgiver/tiltakrefusjon/refusjon/RefusjonTest.kt @@ -408,7 +408,7 @@ internal class RefusjonTest { @Test internal fun `merk refusjon for henting av inntekt frem skal ikke gå når den allerde er merket med unntak om 2 måneder av saksbehandler`() { val refusjon = enRefusjon().medInntektsgrunnlag().medBedriftKontonummer() - refusjon.merkForUnntakOmInntekterToMånederFrem(2, innloggetVeileder) + refusjon.merkForUnntakOmInntekterFremITid(2, innloggetVeileder) assertFeilkode(Feilkode.HAR_ALLERDE_UNNTAK_OM_INNTEKTER_2_MND_FREM) { refusjon.merkForHentInntekterFrem( true, From c05fdef6adf4b02749e53dfcdef307201afcbf27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Odd=20Andreas=20S=C3=B8rs=C3=A6ther?= Date: Wed, 3 Apr 2024 11:18:51 +0200 Subject: [PATCH 11/13] Admin-endepunkt for resending av refusjon godkjent --- .../tiltakrefusjon/AdminController.kt | 48 ++++++++++++++++--- .../refusjon/RefusjonKafkaProducer.kt | 27 +++++------ 2 files changed, 53 insertions(+), 22 deletions(-) diff --git a/src/main/kotlin/no/nav/arbeidsgiver/tiltakrefusjon/AdminController.kt b/src/main/kotlin/no/nav/arbeidsgiver/tiltakrefusjon/AdminController.kt index b0c38deb..d50cf85e 100644 --- a/src/main/kotlin/no/nav/arbeidsgiver/tiltakrefusjon/AdminController.kt +++ b/src/main/kotlin/no/nav/arbeidsgiver/tiltakrefusjon/AdminController.kt @@ -2,7 +2,16 @@ package no.nav.arbeidsgiver.tiltakrefusjon import no.nav.arbeidsgiver.tiltakrefusjon.autorisering.ADMIN_BRUKER import no.nav.arbeidsgiver.tiltakrefusjon.leader.LeaderPodCheck -import no.nav.arbeidsgiver.tiltakrefusjon.refusjon.* +import no.nav.arbeidsgiver.tiltakrefusjon.refusjon.Beregning +import no.nav.arbeidsgiver.tiltakrefusjon.refusjon.Korreksjonsgrunn +import no.nav.arbeidsgiver.tiltakrefusjon.refusjon.Refusjon +import no.nav.arbeidsgiver.tiltakrefusjon.refusjon.RefusjonKafkaProducer +import no.nav.arbeidsgiver.tiltakrefusjon.refusjon.RefusjonRepository +import no.nav.arbeidsgiver.tiltakrefusjon.refusjon.RefusjonService +import no.nav.arbeidsgiver.tiltakrefusjon.refusjon.RefusjonStatus +import no.nav.arbeidsgiver.tiltakrefusjon.refusjon.StatusJobb +import no.nav.arbeidsgiver.tiltakrefusjon.refusjon.beregnRefusjonsbeløp +import no.nav.arbeidsgiver.tiltakrefusjon.refusjon.events.RefusjonEndretStatus import no.nav.arbeidsgiver.tiltakrefusjon.tilskuddsperiode.MidlerFrigjortÅrsak import no.nav.arbeidsgiver.tiltakrefusjon.tilskuddsperiode.TilskuddsperiodeForkortetMelding import no.nav.arbeidsgiver.tiltakrefusjon.tilskuddsperiode.TilskuddsperiodeGodkjentMelding @@ -11,8 +20,14 @@ import org.slf4j.LoggerFactory import org.springframework.data.domain.PageRequest import org.springframework.data.domain.Sort import org.springframework.data.repository.findByIdOrNull +import org.springframework.http.ResponseEntity import org.springframework.transaction.annotation.Transactional -import org.springframework.web.bind.annotation.* +import org.springframework.web.bind.annotation.GetMapping +import org.springframework.web.bind.annotation.PathVariable +import org.springframework.web.bind.annotation.PostMapping +import org.springframework.web.bind.annotation.RequestBody +import org.springframework.web.bind.annotation.RequestMapping +import org.springframework.web.bind.annotation.RestController import java.time.LocalDate @RestController @@ -21,7 +36,8 @@ class AdminController( val service: RefusjonService, val refusjonRepository: RefusjonRepository, val refusjonService: RefusjonService, - val leaderPodCheck: LeaderPodCheck + val leaderPodCheck: LeaderPodCheck, + val refusjonKafkaProducer: RefusjonKafkaProducer? ) { val logger = LoggerFactory.getLogger(javaClass) @@ -172,7 +188,7 @@ class AdminController( tilskuddsgrunnlag = refusjon.refusjonsgrunnlag.tilskuddsgrunnlag, tidligereUtbetalt = 0, korrigertBruttoLønn = refusjon.refusjonsgrunnlag.endretBruttoLønn, - fratrekkRefunderbarSum =refusjon.refusjonsgrunnlag.refunderbarBeløp, + fratrekkRefunderbarSum = refusjon.refusjonsgrunnlag.refunderbarBeløp, forrigeRefusjonMinusBeløp = request.minusBeløp, tilskuddFom = refusjon.refusjonsgrunnlag.tilskuddsgrunnlag.tilskuddFom, harFerietrekkForSammeMåned = request.harFerietrekkForSammeMåned, @@ -186,7 +202,7 @@ class AdminController( @Transactional fun reberegn(@PathVariable id: String, @RequestBody request: ReberegnRequest): Beregning { val refusjon: Refusjon = refusjonRepository.findByIdOrNull(id) ?: throw RessursFinnesIkkeException() - val beregning = beregnRefusjonsbeløp( + val beregning = beregnRefusjonsbeløp( inntekter = refusjon.refusjonsgrunnlag.inntektsgrunnlag!!.inntekter.toList(), tilskuddsgrunnlag = refusjon.refusjonsgrunnlag.tilskuddsgrunnlag, tidligereUtbetalt = 0, @@ -207,7 +223,7 @@ class AdminController( @Unprotected @GetMapping("hent-refusjoner-med-status-sendt") - fun hentRefusjonerMedStatusSendtKrav() = refusjonRepository.findAllByStatus(RefusjonStatus.SENDT_KRAV) + fun hentRefusjonerMedStatusSendtKrav() = refusjonRepository.findAllByStatus(RefusjonStatus.SENDT_KRAV) @Unprotected @PostMapping("oppdater-alle-refusjoner-klar-med-data/{page}") @@ -232,9 +248,26 @@ class AdminController( alleForTidlig.forEach { refusjonService.oppdaterRefusjon(it, ADMIN_BRUKER) } - } + @Unprotected + @PostMapping("send-refusjon-godkjent-melding") + @Transactional + fun sendRefusjonGodkjentMelding(@RequestBody refusjonGodkjentRequest: RefusjonGodkjentRequest): ResponseEntity { + val refusjon = refusjonRepository.findById(refusjonGodkjentRequest.refusjonId).orElseThrow() + + refusjonKafkaProducer!!.refusjonEndretStatus(RefusjonEndretStatus(refusjon)) + if (refusjon.refusjonsgrunnlag.refusjonsgrunnlagetErNullSomIZero()) { + refusjonKafkaProducer!!.annullerTilskuddsperiodeEtterNullEllerMinusBeløp(refusjon, MidlerFrigjortÅrsak.REFUSJON_GODKJENT_NULL_BELØP) + return ResponseEntity.ok("Sendt godkjent nullbeløp-melding for ${refusjon.id}") + } else if (!refusjon.refusjonsgrunnlag.refusjonsgrunnlagetErPositivt()) { + refusjonKafkaProducer!!.annullerTilskuddsperiodeEtterNullEllerMinusBeløp(refusjon, MidlerFrigjortÅrsak.REFUSJON_MINUS_BELØP) + return ResponseEntity.ok("Sendt godkjent minusbeløp-melding for ${refusjon.id}") + } else { + refusjonKafkaProducer!!.sendRefusjonGodkjentMelding(refusjon) + return ResponseEntity.ok("Sendt godkjent-melding for ${refusjon.id}") + } + } } data class ReberegnRequest(val harFerietrekkForSammeMåned: Boolean, val minusBeløp: Int, val ferieTrekk: Int) @@ -242,3 +275,4 @@ data class KorreksjonRequest(val refusjonIder: List, val korreksjonsgrun data class ForlengFristerRequest(val refusjonIder: List, val nyFrist: LocalDate, val årsak: String, val enforce: Boolean) data class ForlengFristerTilOgMedRequest(val tilDato: LocalDate, val nyFrist: LocalDate, val årsak: String, val enforce: Boolean) data class AnnullerRefusjon(val tilskuddsperiodeId: String) +data class RefusjonGodkjentRequest(val refusjonId: String) diff --git a/src/main/kotlin/no/nav/arbeidsgiver/tiltakrefusjon/refusjon/RefusjonKafkaProducer.kt b/src/main/kotlin/no/nav/arbeidsgiver/tiltakrefusjon/refusjon/RefusjonKafkaProducer.kt index 941a2904..6086d8ad 100644 --- a/src/main/kotlin/no/nav/arbeidsgiver/tiltakrefusjon/refusjon/RefusjonKafkaProducer.kt +++ b/src/main/kotlin/no/nav/arbeidsgiver/tiltakrefusjon/refusjon/RefusjonKafkaProducer.kt @@ -24,14 +24,16 @@ class RefusjonKafkaProducer( var log: Logger = LoggerFactory.getLogger(javaClass) @TransactionalEventListener - fun refusjonGodkjent(event: GodkjentAvArbeidsgiver) { - val melding = create(event.refusjon) - refusjonGodkjentkafkaTemplate.send(Topics.REFUSJON_GODKJENT, event.refusjon.id, melding) + fun refusjonGodkjentLytter(event: GodkjentAvArbeidsgiver) = sendRefusjonGodkjentMelding(event.refusjon) + + fun sendRefusjonGodkjentMelding(refusjon: Refusjon) { + val melding = create(refusjon) + refusjonGodkjentkafkaTemplate.send(Topics.REFUSJON_GODKJENT, refusjon.id, melding) .whenComplete { it, ex -> if (ex != null) { log.error( "Melding med id {} kunne ikke sendes til Kafka topic {}", - event.refusjon.id, + refusjon.id, Topics.REFUSJON_GODKJENT, ex ) @@ -120,25 +122,20 @@ class RefusjonKafkaProducer( } @TransactionalEventListener - fun refusjonGodkjentMinusBeløp(event: RefusjonGodkjentMinusBeløp) { - log.info("Godkjent refusjon ${event.refusjon.id} med minusbeløp, sender annullering") - annullerTilskuddsperiodeEtterNullEllerMinusBeløp(event.refusjon.refusjonsgrunnlag.tilskuddsgrunnlag.tilskuddsperiodeId, MidlerFrigjortÅrsak.REFUSJON_MINUS_BELØP) - } + fun refusjonGodkjentMinusBeløpLytter(event: RefusjonGodkjentMinusBeløp) = annullerTilskuddsperiodeEtterNullEllerMinusBeløp(event.refusjon, MidlerFrigjortÅrsak.REFUSJON_MINUS_BELØP) @TransactionalEventListener - fun refusjonGodkjentNullBeløp(event: RefusjonGodkjentNullBeløp) { - log.info("Godkjent refusjon ${event.refusjon.id} med nullbeløp, sender annullering") - annullerTilskuddsperiodeEtterNullEllerMinusBeløp(event.refusjon.refusjonsgrunnlag.tilskuddsgrunnlag.tilskuddsperiodeId, MidlerFrigjortÅrsak.REFUSJON_GODKJENT_NULL_BELØP) - } + fun refusjonGodkjentNullBeløpLytter(event: RefusjonGodkjentNullBeløp) = annullerTilskuddsperiodeEtterNullEllerMinusBeløp(event.refusjon, MidlerFrigjortÅrsak.REFUSJON_GODKJENT_NULL_BELØP) - private fun annullerTilskuddsperiodeEtterNullEllerMinusBeløp(tilskuddsperiodeId: String, årsak: MidlerFrigjortÅrsak) { + fun annullerTilskuddsperiodeEtterNullEllerMinusBeløp(refusjon: Refusjon, årsak: MidlerFrigjortÅrsak) { + log.info("Godkjent refusjon ${refusjon.id} uten positivt beløp, sender annullering med årsak ${årsak.name}") val tilskuddperiodeAnnullertMelding = TilskuddsperiodeAnnullertMelding( - tilskuddsperiodeId = tilskuddsperiodeId, + tilskuddsperiodeId = refusjon.refusjonsgrunnlag.tilskuddsgrunnlag.tilskuddsperiodeId, årsak = årsak ) tilskuddperiodeAnnullertKafkaTemplate.send( Topics.TILSKUDDSPERIODE_ANNULLERT, - tilskuddsperiodeId, + refusjon.refusjonsgrunnlag.tilskuddsgrunnlag.tilskuddsperiodeId, tilskuddperiodeAnnullertMelding ).whenComplete { it, ex -> if (ex != null) { From f599317c55012d56eab7a3083ff2a7e09dae5d7c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Odd=20Andreas=20S=C3=B8rs=C3=A6ther?= Date: Wed, 3 Apr 2024 13:10:20 +0200 Subject: [PATCH 12/13] Admin-endepunkt for resending av tilskuddsperiode annullert-melding --- .../tiltakrefusjon/AdminController.kt | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/main/kotlin/no/nav/arbeidsgiver/tiltakrefusjon/AdminController.kt b/src/main/kotlin/no/nav/arbeidsgiver/tiltakrefusjon/AdminController.kt index d50cf85e..e6af0e6c 100644 --- a/src/main/kotlin/no/nav/arbeidsgiver/tiltakrefusjon/AdminController.kt +++ b/src/main/kotlin/no/nav/arbeidsgiver/tiltakrefusjon/AdminController.kt @@ -268,6 +268,28 @@ class AdminController( return ResponseEntity.ok("Sendt godkjent-melding for ${refusjon.id}") } } + + @Unprotected + @PostMapping("send-tilskuddsperiode-annullert-melding") + @Transactional + fun sentTilskuddsperiodeAnnullertMelding(@RequestBody annullerRefusjon: AnnullerRefusjon): ResponseEntity { + val refusjoner = refusjonRepository.findAllByRefusjonsgrunnlag_Tilskuddsgrunnlag_TilskuddsperiodeId(annullerRefusjon.tilskuddsperiodeId) + if (refusjoner.size > 1) { + return ResponseEntity.badRequest().body("Fant flere refusjoner med tilskuddsperiodeId ${annullerRefusjon.tilskuddsperiodeId}") + } + val refusjon = refusjoner.firstOrNull() ?: return ResponseEntity.badRequest().body("Fant ingen refusjon med tilskuddsperiodeId ${annullerRefusjon.tilskuddsperiodeId}") + + refusjonKafkaProducer!!.refusjonEndretStatus(RefusjonEndretStatus(refusjon)) + if (refusjon.refusjonsgrunnlag.refusjonsgrunnlagetErNullSomIZero()) { + refusjonKafkaProducer!!.annullerTilskuddsperiodeEtterNullEllerMinusBeløp(refusjon, MidlerFrigjortÅrsak.REFUSJON_GODKJENT_NULL_BELØP) + return ResponseEntity.ok("Sendt godkjent nullbeløp-melding for ${refusjon.id}") + } else if (!refusjon.refusjonsgrunnlag.refusjonsgrunnlagetErPositivt()) { + refusjonKafkaProducer!!.annullerTilskuddsperiodeEtterNullEllerMinusBeløp(refusjon, MidlerFrigjortÅrsak.REFUSJON_MINUS_BELØP) + return ResponseEntity.ok("Sendt godkjent minusbeløp-melding for ${refusjon.id}") + } else { + return ResponseEntity.ok("Kunne ikke annullere refusjon ${refusjon.id}") + } + } } data class ReberegnRequest(val harFerietrekkForSammeMåned: Boolean, val minusBeløp: Int, val ferieTrekk: Int) From 7005cfe32a68baa9d583159c14461ad11ca9da93 Mon Sep 17 00:00:00 2001 From: Odd A <3494925+Oddsor@users.noreply.github.com> Date: Mon, 13 May 2024 14:03:51 +0200 Subject: [PATCH 13/13] Mer eksplisitt auditlogging (#113) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fjern gammelt auditlogging-filter, og opprett et AuditLoggingAspect som behandler endepunkter som er annotert med en AuditLogging-annotasjon. --------- Co-authored-by: Sindre Dahl Løken --- .../tiltakrefusjon/AuditLoggingFilter.kt | 124 ---------------- .../tiltakrefusjon/audit/AuditLogging.kt | 5 + .../audit/AuditLoggingAspect.kt | 138 ++++++++++++++++++ .../tiltakrefusjon/audit/FnrOgBedrift.kt | 6 + .../audit/RefusjonMedFnrOgBedrift.kt | 5 + .../ArbeidsgiverKorreksjonController.kt | 2 + .../ArbeidsgiverRefusjonController.kt | 4 + .../tiltakrefusjon/refusjon/Korreksjon.kt | 18 ++- .../tiltakrefusjon/refusjon/Refusjon.kt | 56 ++++--- .../SaksbehandlerKorreksjonController.kt | 4 +- .../SaksbehandlerRefusjonController.kt | 3 + 11 files changed, 218 insertions(+), 147 deletions(-) delete mode 100644 src/main/kotlin/no/nav/arbeidsgiver/tiltakrefusjon/AuditLoggingFilter.kt create mode 100644 src/main/kotlin/no/nav/arbeidsgiver/tiltakrefusjon/audit/AuditLogging.kt create mode 100644 src/main/kotlin/no/nav/arbeidsgiver/tiltakrefusjon/audit/AuditLoggingAspect.kt create mode 100644 src/main/kotlin/no/nav/arbeidsgiver/tiltakrefusjon/audit/FnrOgBedrift.kt create mode 100644 src/main/kotlin/no/nav/arbeidsgiver/tiltakrefusjon/audit/RefusjonMedFnrOgBedrift.kt diff --git a/src/main/kotlin/no/nav/arbeidsgiver/tiltakrefusjon/AuditLoggingFilter.kt b/src/main/kotlin/no/nav/arbeidsgiver/tiltakrefusjon/AuditLoggingFilter.kt deleted file mode 100644 index 61b7cfd7..00000000 --- a/src/main/kotlin/no/nav/arbeidsgiver/tiltakrefusjon/AuditLoggingFilter.kt +++ /dev/null @@ -1,124 +0,0 @@ -package no.nav.arbeidsgiver.tiltakrefusjon - -import com.jayway.jsonpath.JsonPath -import jakarta.servlet.FilterChain -import jakarta.servlet.http.HttpServletRequest -import jakarta.servlet.http.HttpServletResponse -import no.nav.arbeidsgiver.tiltakrefusjon.audit.AuditLogger -import no.nav.arbeidsgiver.tiltakrefusjon.refusjon.events.AuditEntry -import no.nav.arbeidsgiver.tiltakrefusjon.refusjon.events.EventType -import no.nav.arbeidsgiver.tiltakrefusjon.utils.Issuer -import no.nav.arbeidsgiver.tiltakrefusjon.utils.Now -import no.nav.arbeidsgiver.tiltakrefusjon.utils.erAzureBruker -import no.nav.arbeidsgiver.tiltakrefusjon.utils.erTokenXBruker -import no.nav.arbeidsgiver.tiltakrefusjon.utils.getClaims -import no.nav.security.token.support.core.context.TokenValidationContextHolder -import org.slf4j.LoggerFactory -import org.springframework.core.Ordered -import org.springframework.core.annotation.Order -import org.springframework.stereotype.Component -import org.springframework.web.filter.OncePerRequestFilter -import org.springframework.web.util.ContentCachingResponseWrapper -import java.net.URI - -/** - * Dette filteret fanger opp alle responser fra APIet. - * Dersom en person (arbeidsgiver, saksbehandler) har gjort et oppslag - * og får returnert en JSON som inneholder "deltakerFnr" så vil dette - * resultere i en audit-hendelse. - * - * Spesifiserer at filteret skal kjøre sist for å garantere at det - * kjører etter observation-filteret som legger på en traceId. - */ -@Order(Ordered.LOWEST_PRECEDENCE) -@Component -class AuditLoggingFilter( - val context: TokenValidationContextHolder, - val auditLogger: AuditLogger -) : OncePerRequestFilter() { - val log = LoggerFactory.getLogger(javaClass) - val className = javaClass.name - override fun doFilterInternal(request: HttpServletRequest, response: HttpServletResponse, filterChain: FilterChain) { - val callId: String? = request.getAttribute(CALL_ID_HEADER) as String? - val wrapper = ContentCachingResponseWrapper(response) - filterChain.doFilter(request, wrapper) - - if (callId == null) { - log.error("$className: feilet pga manglende callId. Sjekk om CallIdFilter er riktig satt opp") - } - - if (response.contentType?.contains("application/json") == true && callId != null) { - try { - val brukerId = context.getClaims(Issuer.TOKEN_X)?.getStringClaim("pid") ?: context.getClaims(Issuer.AZURE)?.getStringClaim("NAVident") - if (brukerId != null && context.erAzureBruker()) { - val fnr: List = JsonPath.read?>(wrapper.contentInputStream, "$..deltakerFnr").distinct() - val utførtTid = Now.instant() - - val uri = URI.create(request.requestURI) - // Logger kun oppslag dersom en innlogget bruker utførte oppslaget - fnr.forEach { - // Ikke logg at en bruker slår opp sin egen informasjon - if (!brukerId.equals(it)) { - val entry = AuditEntry( - "tiltak-refusjon-api", - brukerId, - it, - EventType.READ, - true, - utførtTid, - msgForUri(uri), - uri, - request.method, - callId - ) - auditLogger.logg(entry) - } - } - } else if (brukerId != null && context.erTokenXBruker()) { - val fnrOgOrgnr: List> = JsonPath.read>?>(wrapper.contentInputStream, "$..['deltakerFnr', 'bedriftNr']").distinct() - val utførtTid = Now.instant() - - val uri = URI.create(request.requestURI) - // Logger kun oppslag dersom en innlogget bruker utførte oppslaget - fnrOgOrgnr.forEach { - // Ikke logg at en bruker slår opp sin egen informasjon - if (it["bedriftNr"] != null && it["deltakerFnr"] != null && brukerId != it["deltakerFnr"]) { - val entry = AuditEntry( - "tiltak-refusjon-api", - brukerId, - it["bedriftNr"]!!, - EventType.READ, - true, - utførtTid, - msgForUri(uri), - uri, - request.method, - callId - ) - auditLogger.logg(entry) - } - } - } - } catch (ex: Exception) { - log.error("$className: Logging feilet", ex) - } - } - wrapper.copyBodyToResponse() - } - - private fun msgForUri(uri: URI): String = - if (uri.toString().contains("/refusjon/hentliste")) { - "Oppslag på refusjoner" - } else if (uri.toString().contains(Regex("/refusjon/\\w+"))) { - "Hent detaljer om refusjon" - } else if (uri.toString().contains("/refusjon")) { - "Oppslag på refusjoner" - } else if (uri.toString().contains("/korreksjon")) { - "Oppslag på korreksjoner" - } else if (uri.toString().contains(Regex("/korreksjon/\\w+"))) { - "Hent detaljer om korreksjon" - } else { - log.warn("${className}: Fant ikke en lesbar melding for uri: $uri") - "Oppslag i refusjonsløsning" - } -} diff --git a/src/main/kotlin/no/nav/arbeidsgiver/tiltakrefusjon/audit/AuditLogging.kt b/src/main/kotlin/no/nav/arbeidsgiver/tiltakrefusjon/audit/AuditLogging.kt new file mode 100644 index 00000000..c9a42202 --- /dev/null +++ b/src/main/kotlin/no/nav/arbeidsgiver/tiltakrefusjon/audit/AuditLogging.kt @@ -0,0 +1,5 @@ +package no.nav.arbeidsgiver.tiltakrefusjon.audit + +@Target(AnnotationTarget.FUNCTION) +@Retention(AnnotationRetention.RUNTIME) +annotation class AuditLogging(val value: String) diff --git a/src/main/kotlin/no/nav/arbeidsgiver/tiltakrefusjon/audit/AuditLoggingAspect.kt b/src/main/kotlin/no/nav/arbeidsgiver/tiltakrefusjon/audit/AuditLoggingAspect.kt new file mode 100644 index 00000000..68b08361 --- /dev/null +++ b/src/main/kotlin/no/nav/arbeidsgiver/tiltakrefusjon/audit/AuditLoggingAspect.kt @@ -0,0 +1,138 @@ +package no.nav.arbeidsgiver.tiltakrefusjon.audit + +import jakarta.servlet.http.HttpServletRequest +import no.nav.arbeidsgiver.tiltakrefusjon.refusjon.erGyldigFnr +import no.nav.arbeidsgiver.tiltakrefusjon.refusjon.events.AuditEntry +import no.nav.arbeidsgiver.tiltakrefusjon.refusjon.events.EventType +import no.nav.arbeidsgiver.tiltakrefusjon.utils.Issuer +import no.nav.arbeidsgiver.tiltakrefusjon.utils.Now +import no.nav.arbeidsgiver.tiltakrefusjon.utils.getClaims +import no.nav.security.token.support.core.context.TokenValidationContextHolder +import org.aspectj.lang.JoinPoint +import org.aspectj.lang.annotation.AfterReturning +import org.aspectj.lang.annotation.Aspect +import org.aspectj.lang.reflect.MethodSignature +import org.slf4j.Logger +import org.slf4j.LoggerFactory +import org.springframework.http.ResponseEntity +import org.springframework.stereotype.Component +import org.springframework.web.context.request.RequestContextHolder +import org.springframework.web.context.request.ServletRequestAttributes +import java.net.URI + +@Aspect +@Component +class AuditLoggingAspect(val context: TokenValidationContextHolder, val auditLogger: AuditLogger) { + var log: Logger = LoggerFactory.getLogger(javaClass) + + /** + * Denne "handleren" kjøres etter at en controller-metode er ferdigkjørt, og brukes for å se om verdien som returneres + * er en eller flere refusjoner som kan logges. Hvis det er tilfellet, logges det et audit-event for hver unike kombinasjon + * av deltaker/bedrift. + * + * @param joinPoint Dette er punktet som denne handleren "henger" på. Brukes for å hente ut annotasjonsbeskrivelsen + * @param resultatFraEndepunkt Objektet som ble returnert av controller-metoden + */ + @AfterReturning(value = "@annotation(no.nav.arbeidsgiver.tiltakrefusjon.audit.AuditLogging)", returning = "resultatFraEndepunkt") + fun postProcess(joinPoint: JoinPoint, resultatFraEndepunkt: Any) { + val httpServletRequest = (RequestContextHolder.currentRequestAttributes() as ServletRequestAttributes).request; + + sendAuditmeldingerTilKafka(httpServletRequest, hentAuditLoggingAnnotasjonsverdi(joinPoint), hentEntiteterSomKanAuditlogges(resultatFraEndepunkt)); + } + + /** + * På grunn av at Collection, HashMap og ResponseEntity er generics, er vi nødt til å kverne igjennom mange + * instanceof-sjekker for å finne ut om responsen fra controller-metoden som wrappes av Auditlogging-annotasjonen + * faktisk inneholder en "auditerbar" avtale. + *
+ * Hvis returverdien er en ResponseEntity eller HashMap, så "unboxer" vi disse og kaller funksjonen igjen. + * I tilfellet hvor objektet er et HashMap prøver vi å hente ut refusjoner fra "refusjoner"-nøkkelen. + */ + private fun hentEntiteterSomKanAuditlogges(resultatobjekt: Any?): Set { + if (resultatobjekt is ResponseEntity<*>) { + // Rekursivt kall for å "unboxe" ResponseEntity + return hentEntiteterSomKanAuditlogges(resultatobjekt.body) + } else if (resultatobjekt is Map<*, *>) { + // Rekursivt kall for å "unboxe" HashMap (vil sannsynligvis da treffe Collection-branchen under) + return hentEntiteterSomKanAuditlogges(resultatobjekt["refusjoner"]) + } + + val entiteter = ArrayList() + if (resultatobjekt is Collection<*>) { + resultatobjekt.forEach { refusjon -> + if (refusjon is RefusjonMedFnrOgBedrift) { + entiteter.add(refusjon) + } + } + if (resultatobjekt.size != entiteter.size) { + log.error( + "AuditLoggingAspect fant en respons som ikke inneholdt refusjoner: {}", resultatobjekt.first()?.javaClass?.name ?: "null" + ) + } + } else if (resultatobjekt is RefusjonMedFnrOgBedrift) { + // Responsen var en enkelt auditentitet + entiteter.add(resultatobjekt) + } else { + log.error("AuditLoggingAspect støtter ikke denne typen responsobjekt: {}", resultatobjekt?.javaClass?.name ?: "null") + } + return hentOppslagsdata(entiteter) + } + + private fun hentAuditLoggingAnnotasjonsverdi(joinPoint: JoinPoint): String { + val methodSignature = joinPoint.signature as MethodSignature + return methodSignature.method.getAnnotation(AuditLogging::class.java).value + } + + /** + * Konverterer auditerbare refusjoner til et FnrOgBedrift-sett for å sikre at vi får ut unike + * oppslag (hvis vi ikke gjør dette vil man feks logge oppslag mot samme deltaker i to refusjoner dobbelt). + */ + private fun hentOppslagsdata(result: Collection): Set { + return result.map { + it.getFnrOgBedrift() + }.toSet() + } + + private fun sendAuditmeldingerTilKafka(request: HttpServletRequest, apiBeskrivelse: String, auditElementer: Set) { + try { + val innloggetBrukerId = context.getClaims(Issuer.TOKEN_X)?.getStringClaim("pid") ?: context.getClaims(Issuer.AZURE)?.getStringClaim("NAVident") + // Logger kun oppslag dersom en innlogget bruker utførte oppslaget + if (innloggetBrukerId != null) { + val uri = URI.create(request.requestURI) + val utførtTid = Now.instant() + + val innloggetBrukerErPrivatperson = erGyldigFnr(innloggetBrukerId) + auditElementer.forEach { fnrOgBedrift -> + // Vi er ikke interessert i oppslag som bruker gjør på seg selv + if (fnrOgBedrift.deltakerFnr.equals(innloggetBrukerId)) { + return + } + // Traceparent header-format: https://www.w3.org/TR/trace-context/#traceparent-header + // Eksempel: 00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01 + // Vi er interessert i del 2. + val traceHeader: String? = request.getHeader("traceparent")?.split("-")?.getOrNull(1) + if (traceHeader == null) { + log.error("traceparent header mangler i request!") + } + auditLogger.logg( + AuditEntry( + appNavn = "tiltak-refusjon-api", + // ArcSight vil ikke ha oppslag som er utført av en privatperson; oppslaget må derfor være "utført av" en bedrift + utførtAv = if (innloggetBrukerErPrivatperson) fnrOgBedrift.bedrift else innloggetBrukerId, + oppslagPå = fnrOgBedrift.deltakerFnr, + eventType = EventType.READ, + forespørselTillatt = true, + oppslagUtførtTid = utførtTid, + beskrivelse = apiBeskrivelse, + requestUrl = uri, + requestMethod = request.method, + correlationId = traceHeader ?: "" + ) + ) + } + } + } catch (ex: Exception) { + log.error("{}: Logging feilet", javaClass.name, ex); + } + } +} diff --git a/src/main/kotlin/no/nav/arbeidsgiver/tiltakrefusjon/audit/FnrOgBedrift.kt b/src/main/kotlin/no/nav/arbeidsgiver/tiltakrefusjon/audit/FnrOgBedrift.kt new file mode 100644 index 00000000..bfa97a4a --- /dev/null +++ b/src/main/kotlin/no/nav/arbeidsgiver/tiltakrefusjon/audit/FnrOgBedrift.kt @@ -0,0 +1,6 @@ +package no.nav.arbeidsgiver.tiltakrefusjon.audit + +data class FnrOgBedrift( + val deltakerFnr: String, + val bedrift: String +) diff --git a/src/main/kotlin/no/nav/arbeidsgiver/tiltakrefusjon/audit/RefusjonMedFnrOgBedrift.kt b/src/main/kotlin/no/nav/arbeidsgiver/tiltakrefusjon/audit/RefusjonMedFnrOgBedrift.kt new file mode 100644 index 00000000..cd175c71 --- /dev/null +++ b/src/main/kotlin/no/nav/arbeidsgiver/tiltakrefusjon/audit/RefusjonMedFnrOgBedrift.kt @@ -0,0 +1,5 @@ +package no.nav.arbeidsgiver.tiltakrefusjon.audit + +interface RefusjonMedFnrOgBedrift { + fun getFnrOgBedrift(): FnrOgBedrift +} diff --git a/src/main/kotlin/no/nav/arbeidsgiver/tiltakrefusjon/refusjon/ArbeidsgiverKorreksjonController.kt b/src/main/kotlin/no/nav/arbeidsgiver/tiltakrefusjon/refusjon/ArbeidsgiverKorreksjonController.kt index f4c53716..aae2f4dc 100644 --- a/src/main/kotlin/no/nav/arbeidsgiver/tiltakrefusjon/refusjon/ArbeidsgiverKorreksjonController.kt +++ b/src/main/kotlin/no/nav/arbeidsgiver/tiltakrefusjon/refusjon/ArbeidsgiverKorreksjonController.kt @@ -1,5 +1,6 @@ package no.nav.arbeidsgiver.tiltakrefusjon.refusjon +import no.nav.arbeidsgiver.tiltakrefusjon.audit.AuditLogging import no.nav.arbeidsgiver.tiltakrefusjon.autorisering.InnloggetBrukerService import no.nav.security.token.support.core.api.ProtectedWithClaims import org.springframework.web.bind.annotation.GetMapping @@ -15,6 +16,7 @@ const val REQUEST_MAPPING_ARBEIDSGIVER_KORREKSJON = "/api/arbeidsgiver/korreksjo class ArbeidsgiverKorreksjonController( val innloggetBrukerService: InnloggetBrukerService, ) { + @AuditLogging("Hent detaljer om korreksjon") @GetMapping("/{id}") fun hent(@PathVariable id: String): Korreksjon? { val arbeidsgiver = innloggetBrukerService.hentInnloggetArbeidsgiver() diff --git a/src/main/kotlin/no/nav/arbeidsgiver/tiltakrefusjon/refusjon/ArbeidsgiverRefusjonController.kt b/src/main/kotlin/no/nav/arbeidsgiver/tiltakrefusjon/refusjon/ArbeidsgiverRefusjonController.kt index 37746081..5bc19e56 100644 --- a/src/main/kotlin/no/nav/arbeidsgiver/tiltakrefusjon/refusjon/ArbeidsgiverRefusjonController.kt +++ b/src/main/kotlin/no/nav/arbeidsgiver/tiltakrefusjon/refusjon/ArbeidsgiverRefusjonController.kt @@ -1,6 +1,7 @@ package no.nav.arbeidsgiver.tiltakrefusjon.refusjon import no.nav.arbeidsgiver.tiltakrefusjon.UgyldigRequestException +import no.nav.arbeidsgiver.tiltakrefusjon.audit.AuditLogging import no.nav.arbeidsgiver.tiltakrefusjon.autorisering.InnloggetBrukerService import no.nav.arbeidsgiver.tiltakrefusjon.dokgen.DokgenService import no.nav.security.token.support.core.api.ProtectedWithClaims @@ -44,6 +45,7 @@ class ArbeidsgiverRefusjonController( ) { var logger: Logger = LoggerFactory.getLogger(javaClass) + @AuditLogging("Oversikt over refusjoner") @GetMapping fun hentAlle(queryParametre: HentArbeidsgiverRefusjonerQueryParametre): List { if (queryParametre.bedriftNr == null) { @@ -70,6 +72,7 @@ class ArbeidsgiverRefusjonController( } + @AuditLogging("Oversikt over refusjoner") @GetMapping("/hentliste") fun hentListAvBedrifter(queryParametre: HentArbeidsgiverRefusjonerQueryParametre): ResponseEntity> { val arbeidsgiver = innloggetBrukerService.hentInnloggetArbeidsgiver() @@ -91,6 +94,7 @@ class ArbeidsgiverRefusjonController( return ResponseEntity>(response, HttpStatus.OK) } + @AuditLogging("Hent detaljer om en refusjon") @GetMapping("/{id}") fun hent(@PathVariable id: String): Refusjon? { val arbeidsgiver = innloggetBrukerService.hentInnloggetArbeidsgiver() diff --git a/src/main/kotlin/no/nav/arbeidsgiver/tiltakrefusjon/refusjon/Korreksjon.kt b/src/main/kotlin/no/nav/arbeidsgiver/tiltakrefusjon/refusjon/Korreksjon.kt index 17c934f1..72f5fcf9 100644 --- a/src/main/kotlin/no/nav/arbeidsgiver/tiltakrefusjon/refusjon/Korreksjon.kt +++ b/src/main/kotlin/no/nav/arbeidsgiver/tiltakrefusjon/refusjon/Korreksjon.kt @@ -1,11 +1,19 @@ package no.nav.arbeidsgiver.tiltakrefusjon.refusjon import com.fasterxml.jackson.annotation.JsonProperty -import jakarta.persistence.* +import jakarta.persistence.CascadeType +import jakarta.persistence.ElementCollection +import jakarta.persistence.Entity +import jakarta.persistence.EnumType +import jakarta.persistence.Enumerated +import jakarta.persistence.FetchType +import jakarta.persistence.Id +import jakarta.persistence.OneToOne import no.nav.arbeidsgiver.tiltakrefusjon.Feilkode import no.nav.arbeidsgiver.tiltakrefusjon.FeilkodeException +import no.nav.arbeidsgiver.tiltakrefusjon.audit.FnrOgBedrift +import no.nav.arbeidsgiver.tiltakrefusjon.audit.RefusjonMedFnrOgBedrift import no.nav.arbeidsgiver.tiltakrefusjon.autorisering.InnloggetBruker -import no.nav.arbeidsgiver.tiltakrefusjon.refusjon.events.KorreksjonBeregningUtført import no.nav.arbeidsgiver.tiltakrefusjon.refusjon.events.KorreksjonMerketForOppgjort import no.nav.arbeidsgiver.tiltakrefusjon.refusjon.events.KorreksjonMerketForTilbakekreving import no.nav.arbeidsgiver.tiltakrefusjon.refusjon.events.KorreksjonSendtTilUtbetaling @@ -25,7 +33,7 @@ class Korreksjon( val bedriftNr: String, val unntakOmInntekterFremitid: Int?, val annenGrunn: String? -) : AbstractAggregateRoot() { +) : AbstractAggregateRoot(), RefusjonMedFnrOgBedrift { constructor( korrigererRefusjonId: String, korreksjonsnummer: Int, @@ -75,6 +83,8 @@ class Korreksjon( @JsonProperty fun harTattStillingTilAlleInntektslinjer(): Boolean = refusjonsgrunnlag.inntektsgrunnlag?.inntekter?.filter { it.erMedIInntektsgrunnlag() }?.find { inntekt -> inntekt.erOpptjentIPeriode === null } === null + override fun getFnrOgBedrift(): FnrOgBedrift = FnrOgBedrift(deltakerFnr, bedriftNr) + override fun equals(other: Any?): Boolean { if (this === other) return true if (javaClass != other?.javaClass) return false @@ -213,4 +223,4 @@ class Korreksjon( } } -} \ No newline at end of file +} diff --git a/src/main/kotlin/no/nav/arbeidsgiver/tiltakrefusjon/refusjon/Refusjon.kt b/src/main/kotlin/no/nav/arbeidsgiver/tiltakrefusjon/refusjon/Refusjon.kt index 0e09ca0a..fd294090 100644 --- a/src/main/kotlin/no/nav/arbeidsgiver/tiltakrefusjon/refusjon/Refusjon.kt +++ b/src/main/kotlin/no/nav/arbeidsgiver/tiltakrefusjon/refusjon/Refusjon.kt @@ -1,13 +1,30 @@ package no.nav.arbeidsgiver.tiltakrefusjon.refusjon import com.fasterxml.jackson.annotation.JsonProperty -import jakarta.persistence.* +import jakarta.persistence.CascadeType +import jakarta.persistence.Entity +import jakarta.persistence.EnumType +import jakarta.persistence.Enumerated +import jakarta.persistence.Id +import jakarta.persistence.OneToOne import no.nav.arbeidsgiver.tiltakrefusjon.Feilkode import no.nav.arbeidsgiver.tiltakrefusjon.FeilkodeException +import no.nav.arbeidsgiver.tiltakrefusjon.audit.FnrOgBedrift +import no.nav.arbeidsgiver.tiltakrefusjon.audit.RefusjonMedFnrOgBedrift import no.nav.arbeidsgiver.tiltakrefusjon.autorisering.InnloggetBruker import no.nav.arbeidsgiver.tiltakrefusjon.autorisering.KAFKA_BRUKER import no.nav.arbeidsgiver.tiltakrefusjon.autorisering.SYSTEM_BRUKER -import no.nav.arbeidsgiver.tiltakrefusjon.refusjon.events.* +import no.nav.arbeidsgiver.tiltakrefusjon.refusjon.events.FristForlenget +import no.nav.arbeidsgiver.tiltakrefusjon.refusjon.events.GodkjentAvArbeidsgiver +import no.nav.arbeidsgiver.tiltakrefusjon.refusjon.events.MerketForInntekterFrem +import no.nav.arbeidsgiver.tiltakrefusjon.refusjon.events.RefusjonAnnullert +import no.nav.arbeidsgiver.tiltakrefusjon.refusjon.events.RefusjonEndretStatus +import no.nav.arbeidsgiver.tiltakrefusjon.refusjon.events.RefusjonForkortet +import no.nav.arbeidsgiver.tiltakrefusjon.refusjon.events.RefusjonGodkjentMinusBeløp +import no.nav.arbeidsgiver.tiltakrefusjon.refusjon.events.RefusjonGodkjentNullBeløp +import no.nav.arbeidsgiver.tiltakrefusjon.refusjon.events.RefusjonOpprettet +import no.nav.arbeidsgiver.tiltakrefusjon.refusjon.events.RefusjonUtgått +import no.nav.arbeidsgiver.tiltakrefusjon.refusjon.events.SaksbehandlerMerketForInntekterLengerFrem import no.nav.arbeidsgiver.tiltakrefusjon.tilskuddsperiode.MidlerFrigjortÅrsak import no.nav.arbeidsgiver.tiltakrefusjon.utils.KidValidator import no.nav.arbeidsgiver.tiltakrefusjon.utils.Now @@ -24,7 +41,7 @@ class Refusjon( val refusjonsgrunnlag: Refusjonsgrunnlag, val bedriftNr: String, val deltakerFnr: String -) : AbstractAggregateRoot() { +) : AbstractAggregateRoot(), RefusjonMedFnrOgBedrift { constructor( tilskuddsgrunnlag: Tilskuddsgrunnlag, bedriftNr: String, @@ -59,15 +76,17 @@ class Refusjon( val inntekterKunFraTiltaket: Boolean? get() = refusjonsgrunnlag.inntekterKunFraTiltaket var utbetaltTidspunkt: Instant? = null var åpnetFørsteGang: Instant? = null + @OneToOne(orphanRemoval = true, cascade = [CascadeType.ALL]) var minusbelop: Minusbelop? = null var sistEndret: Instant? = null + init { oppdaterStatus() registerEvent(RefusjonOpprettet(this, SYSTEM_BRUKER)) } - fun lagFristForGodkjenning() : LocalDate { + fun lagFristForGodkjenning(): LocalDate { if (refusjonsgrunnlag.tilskuddsgrunnlag.godkjentAvBeslutterTidspunkt == null) { return antallMånederEtter(refusjonsgrunnlag.tilskuddsgrunnlag.tilskuddTom, 2) } @@ -140,7 +159,7 @@ class Refusjon( refusjonsgrunnlag.endreBruttolønn(inntekterKunFraTiltaket, bruttoLønn) } - fun endreBedriftKID( bedriftKID: String?) { + fun endreBedriftKID(bedriftKID: String?) { oppdaterStatus() krevStatus(RefusjonStatus.KLAR_FOR_INNSENDING) refusjonsgrunnlag.bedriftKid = bedriftKID @@ -150,7 +169,7 @@ class Refusjon( oppdaterStatus() krevStatus(RefusjonStatus.KLAR_FOR_INNSENDING) - if(!refusjonsgrunnlag.bedriftKid?.trim().isNullOrEmpty()){ + if (!refusjonsgrunnlag.bedriftKid?.trim().isNullOrEmpty()) { KidValidator(refusjonsgrunnlag.bedriftKid) } if (refusjonsgrunnlag.inntektsgrunnlag == null || refusjonsgrunnlag.inntektsgrunnlag!!.inntekter.isEmpty()) { @@ -168,10 +187,10 @@ class Refusjon( godkjentAvArbeidsgiver = Now.instant() status = RefusjonStatus.SENDT_KRAV - if(refusjonsgrunnlag.refusjonsgrunnlagetErNullSomIZero()) { + if (refusjonsgrunnlag.refusjonsgrunnlagetErNullSomIZero()) { status = RefusjonStatus.GODKJENT_NULLBELØP registerEvent(RefusjonGodkjentNullBeløp(this, utførtAv)) - } else if(!refusjonsgrunnlag.refusjonsgrunnlagetErPositivt()) { + } else if (!refusjonsgrunnlag.refusjonsgrunnlagetErPositivt()) { status = RefusjonStatus.GODKJENT_MINUSBELØP registerEvent(RefusjonGodkjentMinusBeløp(this, utførtAv)) } else { @@ -185,7 +204,7 @@ class Refusjon( oppdaterStatus() krevStatus(RefusjonStatus.KLAR_FOR_INNSENDING) - if(!refusjonsgrunnlag.bedriftKid?.trim().isNullOrEmpty()){ + if (!refusjonsgrunnlag.bedriftKid?.trim().isNullOrEmpty()) { KidValidator(refusjonsgrunnlag.bedriftKid) } godkjentAvArbeidsgiver = Now.instant() @@ -223,6 +242,7 @@ class Refusjon( registerEvent(RefusjonEndretStatus(this)) } } + fun gjørRefusjonUtgått() { krevStatus(RefusjonStatus.KLAR_FOR_INNSENDING) if (Now.localDate().isAfter(fristForGodkjenning)) { @@ -241,22 +261,20 @@ class Refusjon( registerEvent(RefusjonForkortet(this, KAFKA_BRUKER)) } - fun korreksjongrunnerInnholdSjekk(korreksjonsgrunner: Set) : Int{ - if(korreksjonsgrunner.contains(Korreksjonsgrunn.UTBETALT_HELE_TILSKUDDSBELØP)){ + fun korreksjongrunnerInnholdSjekk(korreksjonsgrunner: Set): Int { + if (korreksjonsgrunner.contains(Korreksjonsgrunn.UTBETALT_HELE_TILSKUDDSBELØP)) { return refusjonsgrunnlag.tilskuddsgrunnlag.tilskuddsbeløp - } - else { - if(refusjonsgrunnlag.beregning == null){ + } else { + if (refusjonsgrunnlag.beregning == null) { return 0; - } - else { + } else { return refusjonsgrunnlag.beregning!!.refusjonsbeløp } } } fun opprettKorreksjonsutkast(korreksjonsgrunner: Set, unntakOmInntekterFremitid: Int?, annenGrunn: String?): Korreksjon { - krevStatus(RefusjonStatus.UTBETALT, RefusjonStatus.SENDT_KRAV,RefusjonStatus.GODKJENT_MINUSBELØP, RefusjonStatus.UTGÅTT, RefusjonStatus.GODKJENT_NULLBELØP) + krevStatus(RefusjonStatus.UTBETALT, RefusjonStatus.SENDT_KRAV, RefusjonStatus.GODKJENT_MINUSBELØP, RefusjonStatus.UTGÅTT, RefusjonStatus.GODKJENT_NULLBELØP) if (korreksjonId != null) { throw FeilkodeException(Feilkode.HAR_KORREKSJON) } @@ -348,6 +366,8 @@ class Refusjon( return innhentetTidspunkt == null || innhentetTidspunkt.isBefore(Now.localDateTime().minusMinutes(1)) } + override fun getFnrOgBedrift(): FnrOgBedrift = FnrOgBedrift(deltakerFnr, bedriftNr) + override fun equals(other: Any?): Boolean { if (this === other) return true if (javaClass != other?.javaClass) return false @@ -365,7 +385,7 @@ class Refusjon( fun merkForUnntakOmInntekterFremITid(merking: Int, utførtAv: InnloggetBruker) { krevStatus(RefusjonStatus.FOR_TIDLIG, RefusjonStatus.KLAR_FOR_INNSENDING) - if(merking == 1 && hentInntekterLengerFrem != null) { + if (merking == 1 && hentInntekterLengerFrem != null) { throw FeilkodeException(Feilkode.HAR_ALLERDE_UNNTAK_OM_INNTEKTER_1_MND_FREM) } unntakOmInntekterFremitid = merking diff --git a/src/main/kotlin/no/nav/arbeidsgiver/tiltakrefusjon/refusjon/SaksbehandlerKorreksjonController.kt b/src/main/kotlin/no/nav/arbeidsgiver/tiltakrefusjon/refusjon/SaksbehandlerKorreksjonController.kt index 76306d40..0310402b 100644 --- a/src/main/kotlin/no/nav/arbeidsgiver/tiltakrefusjon/refusjon/SaksbehandlerKorreksjonController.kt +++ b/src/main/kotlin/no/nav/arbeidsgiver/tiltakrefusjon/refusjon/SaksbehandlerKorreksjonController.kt @@ -1,5 +1,6 @@ package no.nav.arbeidsgiver.tiltakrefusjon.refusjon +import no.nav.arbeidsgiver.tiltakrefusjon.audit.AuditLogging import no.nav.arbeidsgiver.tiltakrefusjon.autorisering.InnloggetBrukerService import no.nav.security.token.support.core.api.ProtectedWithClaims import org.springframework.transaction.annotation.Transactional @@ -13,6 +14,7 @@ const val REQUEST_MAPPING_SAKSBEHANDLER_KORREKSJON = "/api/saksbehandler/korreks class SaksbehandlerKorreksjonController( val innloggetBrukerService: InnloggetBrukerService, ) { + @AuditLogging("Hent detaljer om en korreksjon") @GetMapping("/{id}") fun hent(@PathVariable id: String): Korreksjon? { val saksbehandler = innloggetBrukerService.hentInnloggetSaksbehandler() @@ -102,4 +104,4 @@ data class MinusbeløpRequest( data class HarFerietrekkForSammeMånedRequest( val harFerietrekkForSammeMåned: Boolean -) \ No newline at end of file +) diff --git a/src/main/kotlin/no/nav/arbeidsgiver/tiltakrefusjon/refusjon/SaksbehandlerRefusjonController.kt b/src/main/kotlin/no/nav/arbeidsgiver/tiltakrefusjon/refusjon/SaksbehandlerRefusjonController.kt index 3e34fc4d..c8e3271f 100644 --- a/src/main/kotlin/no/nav/arbeidsgiver/tiltakrefusjon/refusjon/SaksbehandlerRefusjonController.kt +++ b/src/main/kotlin/no/nav/arbeidsgiver/tiltakrefusjon/refusjon/SaksbehandlerRefusjonController.kt @@ -1,6 +1,7 @@ package no.nav.arbeidsgiver.tiltakrefusjon.refusjon import no.nav.arbeidsgiver.tiltakrefusjon.ReberegnRequest +import no.nav.arbeidsgiver.tiltakrefusjon.audit.AuditLogging import no.nav.arbeidsgiver.tiltakrefusjon.autorisering.InnloggetBrukerService import no.nav.arbeidsgiver.tiltakrefusjon.hendelseslogg.HendelsesloggDTO import no.nav.arbeidsgiver.tiltakrefusjon.hendelseslogg.HendelsesloggRepository @@ -31,12 +32,14 @@ class SaksbehandlerRefusjonController( val innloggetBrukerService: InnloggetBrukerService, val hendelsesloggRepository: HendelsesloggRepository, ) { + @AuditLogging("Oversiktsbilde over refusjoner") @GetMapping fun hentAlle(queryParametre: HentSaksbehandlerRefusjonerQueryParametre): Map { val saksbehandler = innloggetBrukerService.hentInnloggetSaksbehandler() return saksbehandler.finnAlle(queryParametre) } + @AuditLogging("Hent detaljer om en refusjon") @GetMapping("/{id}") fun hent(@PathVariable id: String): Refusjon? { val saksbehandler = innloggetBrukerService.hentInnloggetSaksbehandler()