Skip to content

Commit

Permalink
Merge pull request #37 from navikt/dev/inntektsforesporsel
Browse files Browse the repository at this point in the history
Dev/inntektsforesporsel
  • Loading branch information
RettIProd authored Sep 11, 2024
2 parents c0a23fb + 14f939b commit c467e44
Show file tree
Hide file tree
Showing 16 changed files with 3,427 additions and 28 deletions.
3 changes: 2 additions & 1 deletion cpa-repo/src/main/kotlin/no/nav/emottak/cpa/Routes.kt
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,8 @@ fun Route.validateCpa(cpaRepository: CPARepository) = post("/cpa/validate/{$CONT
val validateRequest = call.receive(ValidationRequest::class)
try {
log.info(validateRequest.marker(), "Validerer ebms mot CPA")
val cpa = cpaRepository.findCpa(validateRequest.cpaId) ?: throw NotFoundException("Fant ikke CPA (${validateRequest.cpaId})")
val cpa = cpaRepository.findCpa(validateRequest.cpaId)
?: throw NotFoundException("Fant ikke CPA (${validateRequest.cpaId})")
cpa.validate(validateRequest) // Delivery Failure
val partyInfo = cpa.getPartyInfoByTypeAndID(validateRequest.addressing.from.partyId) // Delivery Failure
val encryptionCertificate = partyInfo.getCertificateForEncryption() // Security Failure
Expand Down
2,900 changes: 2,900 additions & 0 deletions cpa-repo/src/main/resources/cpa/nav_qass_30823_modified.xml

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@ values ('Behandler', 'HarBorgerFrikort', 'EgenandelForesporsel',
('Fastlege', 'PasientlisteForesporsel', 'HentAbonnementStatus', false, false, TRUE, TRUE, TRUE, TRUE, null, 'Avvisning'),
('Fastlege', 'PasientlisteForesporsel', 'HentPasientliste', false, false, TRUE, TRUE, TRUE, TRUE, null, 'Avvisning'),
('Fastlege', 'PasientlisteForesporsel', 'StartAbonnement', false, false, TRUE, TRUE, TRUE, TRUE, null, 'Avvisning'),
('Fastlege', 'PasientlisteForesporsel', 'StoppAbonnement', false, false, TRUE, TRUE, TRUE, TRUE, null, 'Avvisning')
('Fastlege', 'PasientlisteForesporsel', 'StoppAbonnement', false, false, TRUE, TRUE, TRUE, TRUE, null, 'Avvisning'),
('Fordringshaver', 'Inntektsforesporsel', 'Foresporsel', true, false, TRUE, false, TRUE, TRUE, null, 'Avvisning')

on conflict (ROLE, SERVICE, ACTION) do update set KRYPTERING = EXCLUDED.KRYPTERING,
KOMPRIMERING = EXCLUDED.KOMPRIMERING,
SIGNERING = EXCLUDED.SIGNERING,
Expand Down
7 changes: 5 additions & 2 deletions ebms-provider/src/main/kotlin/no/nav/emottak/ebms/App.kt
Original file line number Diff line number Diff line change
Expand Up @@ -47,13 +47,15 @@ import no.nav.emottak.ebms.validation.MimeHeaders
import no.nav.emottak.ebms.validation.MimeValidationException
import no.nav.emottak.ebms.validation.validateMimeAttachment
import no.nav.emottak.ebms.validation.validateMimeSoapEnvelope
import no.nav.emottak.ebms.xml.asByteArray
import no.nav.emottak.ebms.xml.asString
import no.nav.emottak.ebms.xml.getDocumentBuilder
import no.nav.emottak.melding.model.EbmsAttachment
import no.nav.emottak.util.createUniqueMimeMessageId
import no.nav.emottak.util.getEnvVar
import org.slf4j.LoggerFactory
import java.io.ByteArrayInputStream
import java.nio.charset.StandardCharsets
import java.time.Duration
import java.time.Instant
import java.util.Base64
Expand Down Expand Up @@ -268,7 +270,7 @@ suspend fun ApplicationCall.respondEbmsDokument(ebmsDokument: EbMSDocument) {
this.append(MimeHeaders.SOAP_ACTION, "ebXML")
}
if (ebmsDokument.dokumentType() == DokumentType.PAYLOAD) {
val ebxml = Base64.getMimeEncoder().encodeToString(ebmsDokument.dokument.asString().toByteArray())
val ebxml = Base64.getMimeEncoder().encodeToString(ebmsDokument.dokument.asByteArray())
val contentId = createUniqueMimeMessageId()
val ebxmlFormItem = PartData.FormItem(
ebxml,
Expand All @@ -282,7 +284,8 @@ suspend fun ApplicationCall.respondEbmsDokument(ebmsDokument: EbMSDocument) {
val parts = mutableListOf<PartData>(ebxmlFormItem)
ebmsDokument.attachments.first().let {
PartData.FormItem(
Base64.getMimeEncoder().encodeToString(it.bytes),
// Base64.getMimeEncoder().encodeToString(it.bytes), // Implicit ISO_8859_1
String(Base64.getMimeEncoder().encode(it.bytes), StandardCharsets.UTF_8), // TODO verifiser
{},
HeadersBuilder().apply {
append(MimeHeaders.CONTENT_TRANSFER_ENCODING, "base64")
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package no.nav.emottak.ebms.xml

import org.w3c.dom.Document
import java.io.ByteArrayOutputStream
import java.io.StringWriter
import javax.xml.parsers.DocumentBuilder
import javax.xml.parsers.DocumentBuilderFactory
Expand Down Expand Up @@ -31,3 +32,11 @@ fun Document.asString(): String {
transformer.transform(domSource, sr)
return sw.toString()
}

fun Document.asByteArray(): ByteArray {
return ByteArrayOutputStream().use {
TransformerFactory.newInstance().newTransformer()
.transform(DOMSource(this), StreamResult(it))
it.toByteArray()
}
}
2 changes: 2 additions & 0 deletions ebms-send-in/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,10 @@ dependencies {
implementation(libs.ktor.server.auth.jvm)
implementation(libs.ktor.client.auth)
implementation("io.ktor:ktor-client-cio-jvm:2.3.4")
implementation("com.sun.xml.messaging.saaj:saaj-impl:1.5.1")
implementation(libs.bundles.cxf)
runtimeOnly("net.java.dev.jna:jna:5.12.1")
testImplementation("javax.activation:activation:1.1.1")
testImplementation(testLibs.ktor.server.test.host)
testImplementation(testLibs.junit.jupiter.api)
testImplementation(testLibs.mockk.jvm)
Expand Down
46 changes: 30 additions & 16 deletions ebms-send-in/src/main/kotlin/no/nav/emottak/ebms/App.kt
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import io.ktor.server.netty.Netty
import io.ktor.server.plugins.contentnegotiation.ContentNegotiation
import io.ktor.server.request.receive
import io.ktor.server.response.respond
import io.ktor.server.routing.get
import io.ktor.server.routing.post
import io.ktor.server.routing.routing
import io.micrometer.core.instrument.Timer.ResourceSample
Expand All @@ -25,15 +24,16 @@ import kotlinx.coroutines.withContext
import no.nav.emottak.auth.AZURE_AD_AUTH
import no.nav.emottak.auth.AuthConfig
import no.nav.emottak.fellesformat.wrapMessageInEIFellesFormat
import no.nav.emottak.frikort.frikortXmlMarshaller
import no.nav.emottak.frikort.frikortsporring
import no.nav.emottak.frikort.marshal
import no.nav.emottak.melding.model.SendInRequest
import no.nav.emottak.melding.model.SendInResponse
import no.nav.emottak.utbetaling.UtbetalingClient
import no.nav.emottak.utbetaling.utbetalingXmlMarshaller
import no.nav.emottak.util.getEnvVar
import no.nav.emottak.util.marker
import no.nav.security.token.support.v2.tokenValidationSupport
import org.slf4j.LoggerFactory
import java.util.Timer

internal val log = LoggerFactory.getLogger("no.nav.emottak.ebms.App")

Expand Down Expand Up @@ -77,26 +77,40 @@ fun Application.ebmsSendInModule() {
runCatching {
log.info(request.marker(), "Payload ${request.payloadId} videresendes til fagsystem")
withContext(Dispatchers.IO) {
timed(appMicrometerRegistry, "frikort-sporing") {
frikortsporring(wrapMessageInEIFellesFormat(request))
when (request.addressing.service) {
"Inntektsforesporsel" ->
timed(appMicrometerRegistry, "Inntektsforesporsel") {
UtbetalingClient.behandleInntektsforesporsel(request).let {
SendInResponse(
request.messageId,
request.conversationId,
request.addressing.replyTo(request.addressing.service, it.msgInfo.type.v),
utbetalingXmlMarshaller.marshalToByteArray(it)
)
}
}
else ->
timed(appMicrometerRegistry, "frikort-sporing") {
frikortsporring(wrapMessageInEIFellesFormat(request)).let {
SendInResponse(
request.messageId,
request.conversationId,
request.addressing.replyTo(
it.eiFellesformat.mottakenhetBlokk.ebService,
it.eiFellesformat.mottakenhetBlokk.ebAction
),
frikortXmlMarshaller.marshalToByteArray(it.eiFellesformat.msgHead)
)
}
}
}
}
}.onSuccess {
log.trace(
request.marker(),
"Payload ${request.payloadId} videresending til fagsystem ferdig, svar mottatt og returnerert"
)
call.respond(
SendInResponse(
request.messageId,
request.conversationId,
request.addressing.replayTo(
it.eiFellesformat.mottakenhetBlokk.ebService,
it.eiFellesformat.mottakenhetBlokk.ebAction
),
marshal(it.eiFellesformat.msgHead).toByteArray()
)
)
call.respond(it)
}.onFailure {
log.error(request.marker(), "Payload ${request.payloadId} videresending feilet", it)
call.respond(HttpStatusCode.BadRequest, it.localizedMessage)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ package no.nav.emottak.fellesformat

import no.kith.xmlstds.msghead._2006_05_24.MsgHead
import no.nav.emottak.ebms.log
import no.nav.emottak.frikort.frikortXmlMarshaller
import no.nav.emottak.frikort.unmarshal
import no.nav.emottak.frikort.xmlMarshaller
import no.nav.emottak.melding.model.Addressing
import no.nav.emottak.melding.model.Party
import no.nav.emottak.melding.model.PartyId
Expand Down Expand Up @@ -32,7 +32,7 @@ fun wrapMessageInEIFellesFormat(sendInRequest: SendInRequest): EIFellesformat =
it.msgHead = unmarshal(sendInRequest.payload.toString(Charsets.UTF_8), MsgHead::class.java)
}.also {
if (getEnvVar("NAIS_CLUSTER_NAME", "local") != "prod-fss") {
log.info("Sending in request to frikort with body " + xmlMarshaller.marshal(it))
log.info("Sending in request to frikort with body " + frikortXmlMarshaller.marshal(it))
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,6 @@ fun frikortsporring(fellesformat: EIFellesformat): FrikortsporringResponse = fri
frikortObjectFactory.createFrikortsporringRequest().also { it.eiFellesformat = fellesformat }
).also {
if (getEnvVar("NAIS_CLUSTER_NAME", "local") != "prod-fss") {
log.info("Send in Frikort response " + xmlMarshaller.marshal(it))
log.info("Send in Frikort response " + frikortXmlMarshaller.marshal(it))
}
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
package no.nav.emottak.frikort

import java.io.ByteArrayOutputStream
import java.io.StringWriter
import javax.xml.bind.JAXBContext
import javax.xml.stream.XMLInputFactory

val xmlMarshaller = XmlMarshaller()
val frikortXmlMarshaller = XmlMarshaller()

fun marshal(objekt: Any) = xmlMarshaller.marshal(objekt)
fun <T> unmarshal(xml: String, clazz: Class<T>): T = xmlMarshaller.unmarshal(xml, clazz)
fun marshal(objekt: Any) = frikortXmlMarshaller.marshal(objekt)
fun <T> unmarshal(xml: String, clazz: Class<T>): T = frikortXmlMarshaller.unmarshal(xml, clazz)

class XmlMarshaller {

Expand Down Expand Up @@ -36,6 +37,15 @@ class XmlMarshaller {
return writer.toString()
}

fun marshalToByteArray(objekt: Any): ByteArray {
return ByteArrayOutputStream().use {
synchronized(marshlingMonitor) {
marshaller.marshal(objekt, it)
}
it.toByteArray()
}
}

fun <T> unmarshal(xml: String, clazz: Class<T>): T {
val reader = XMLInputFactory.newInstance().createXMLStreamReader(xml.reader())
return synchronized(unmarshlingMonitor) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
package no.nav.emottak.utbetaling

import no.kith.xmlstds.msghead._2006_05_24.CS
import no.kith.xmlstds.msghead._2006_05_24.ConversationRef
import no.kith.xmlstds.msghead._2006_05_24.Document
import no.kith.xmlstds.msghead._2006_05_24.MsgHead
import no.kith.xmlstds.msghead._2006_05_24.RefDoc
import no.nav.ekstern.virkemiddelokonomi.tjenester.utbetaling.v1.FinnBrukersUtbetalteYtelser
import no.nav.ekstern.virkemiddelokonomi.tjenester.utbetaling.v1.FinnUtbetalingListe
import no.nav.ekstern.virkemiddelokonomi.tjenester.utbetaling.v1.FinnUtbetalingListeBaksystemIkkeTilgjengelig
import no.nav.ekstern.virkemiddelokonomi.tjenester.utbetaling.v1.FinnUtbetalingListeBrukerIkkeFunnet
import no.nav.ekstern.virkemiddelokonomi.tjenester.utbetaling.v1.FinnUtbetalingListeFeil
import no.nav.ekstern.virkemiddelokonomi.tjenester.utbetaling.v1.FinnUtbetalingListeIngenTilgangTilEnEllerFlereYtelser
import no.nav.ekstern.virkemiddelokonomi.tjenester.utbetaling.v1.FinnUtbetalingListeUgyldigDato
import no.nav.ekstern.virkemiddelokonomi.tjenester.utbetaling.v1.FinnUtbetalingListeUgyldigKombinasjonBrukerIdOgBrukertype
import no.nav.emottak.cxf.ServiceBuilder
import no.nav.emottak.melding.model.SendInRequest
import no.nav.emottak.util.getEnvVar
import no.nav.emottak.util.toXMLGregorianCalendar
import org.slf4j.LoggerFactory
import java.io.FileInputStream
import java.time.Instant
import java.util.UUID
import javax.xml.namespace.QName

object UtbetalingClient {

val log = LoggerFactory.getLogger(UtbetalingClient::class.java)

val utbetalingObjectFactory: no.nav.ekstern.virkemiddelokonomi.tjenester.utbetaling.v1.ObjectFactory =
no.nav.ekstern.virkemiddelokonomi.tjenester.utbetaling.v1.ObjectFactory()

val YRP_URL_TEST = "https://ytelser-rest-proxy.intern.dev.nav.no"
val YRP_URL_PROD = "https://ytelser-rest-proxy.intern.nav.no"
val RESOLVED_UTBETAL_URL =
when (getEnvVar("NAIS_CLUSTER_NAME", "local")) {
"local" -> YRP_URL_TEST
"dev-fss" -> YRP_URL_TEST
"prod-fss" -> YRP_URL_PROD
else -> YRP_URL_TEST
}
val UTBETAL_SOAP_ENDPOINT = RESOLVED_UTBETAL_URL + "/Utbetaling"

fun behandleInntektsforesporsel(sendInRequest: SendInRequest): MsgHead {
val msgHeadRequest = utbetalingXmlMarshaller.unmarshal(sendInRequest.payload.toString(Charsets.UTF_8), MsgHead::class.java)
val melding = msgHeadRequest.document.map { it.refDoc.content.any }
.also { if (it.size > 1) log.warn("Inntektsforesporsel refdoc har size >1") }
.first().also { if (it.size > 1) log.warn("Inntektsforesporsel content har size >1") }.first()
try {
val response: Any = when (melding) {
is FinnUtbetalingListe -> inntektsforesporselSoapEndpoint.finnUtbetalingListe(melding.request)
is FinnBrukersUtbetalteYtelser -> inntektsforesporselSoapEndpoint.finnBrukersUtbetalteYtelser(melding.request)
else -> throw IllegalStateException("Ukjent meldingstype. Classname: " + melding.javaClass.name)
}
return msgHeadResponse(msgHeadRequest, sendInRequest, marshal(response))
} catch (utbetalError: Throwable) {
log.info("Handling inntektsforesporsel error: " + utbetalError.message)
val feil = FinnUtbetalingListeFeil()
when (utbetalError) {
is FinnUtbetalingListeBrukerIkkeFunnet
-> feil.finnUtbetalingListebrukerIkkeFunnet = utbetalError.faultInfo
is FinnUtbetalingListeBaksystemIkkeTilgjengelig
-> feil.finnUtbetalingListebaksystemIkkeTilgjengelig = utbetalError.faultInfo
is FinnUtbetalingListeIngenTilgangTilEnEllerFlereYtelser
-> feil.finnUtbetalingListeingenTilgangTilEnEllerFlereYtelser = utbetalError.faultInfo
is FinnUtbetalingListeUgyldigDato
-> feil.finnUtbetalingListeugyldigDato = utbetalError.faultInfo
is FinnUtbetalingListeUgyldigKombinasjonBrukerIdOgBrukertype
-> feil.finnUtbetalingListeugyldigKombinasjonBrukerIdOgBrukertype = utbetalError.faultInfo
else ->
throw utbetalError.also { log.error("Ukjent feiltype: " + it.message, it) }
}
return msgHeadResponse(msgHeadRequest, sendInRequest, feil)
}
}
}

val inntektsforesporselSoapEndpoint: no.nav.ekstern.virkemiddelokonomi.tjenester.utbetaling.v1.Utbetaling =
ServiceBuilder(
no.nav.ekstern.virkemiddelokonomi.tjenester.utbetaling.v1.Utbetaling::class.java
)
.withAddress(getEnvVar("UTBETALING_URL", "https://ytelser-rest-proxy.dev.intern.nav.no/Utbetaling"))
.withWsdl(
"classpath:no.nav.ekstern.virkemiddelokonomi/tjenester/utbetaling/utbetaling.wsdl"
// "classpath:no.nav.ekstern.virkemiddelokonomi/tjenester.utbetaling/utbetaling.wsdl"
)
.withServiceName(QName("http://nav.no/ekstern/virkemiddelokonomi/tjenester/utbetaling/v1", "Utbetaling"))
.withEndpointName(QName("http://nav.no/ekstern/virkemiddelokonomi/tjenester/utbetaling/v1", "UtbetalingPort"))
.build()
.withUserNameToken(
when (getEnvVar("NAIS_CLUSTER_NAME", "local")) {
"local" -> "testUserName"
else -> String(FileInputStream("/secret/serviceuser/username").readAllBytes())
},
when (getEnvVar("NAIS_CLUSTER_NAME", "local")) {
"local" -> "testPassword"
else -> String(FileInputStream("/secret/serviceuser/password").readAllBytes())
}
)
.get()

fun msgHeadResponse(incomingMsgHead: MsgHead, sendInRequest: SendInRequest, fagmeldingResponse: Any): MsgHead {
return incomingMsgHead.apply {
msgInfo.apply {
type = CS().apply {
dn = "Svar på forespørsel om inntekt"
v = "InntektInformasjon"
}
genDate = Instant.now().toXMLGregorianCalendar()
msgId = UUID.randomUUID().toString()
ack = CS().apply {
v = "N"
dn = "Nei"
}
val newReceiver = sender
val newSender = receiver
sender.apply { organisation = newSender.organisation }
receiver.apply { organisation = newReceiver.organisation }
conversationRef = ConversationRef().apply {
refToParent = sendInRequest.messageId
refToConversation = sendInRequest.conversationId
}
}
document.clear()
document.add(
Document().apply {
refDoc = RefDoc().apply {
msgType = CS().apply {
v = "XML"
dn = "XML-instans"
}
mimeType = "text/xml"
content = RefDoc.Content().apply {
any.add(
fagmeldingResponse
)
}
}
}
)
signature = null // TODO? (Dette er ikke "send-in" sin jobb, blir gjort senere)
}
}
Loading

0 comments on commit c467e44

Please sign in to comment.