Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Implementert henting av epost-adresser ved Route.validateCpa #67

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 49 additions & 5 deletions cpa-repo/src/main/kotlin/no/nav/emottak/cpa/CPAUtil.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@ import no.nav.emottak.cpa.feil.CpaValidationException
import no.nav.emottak.cpa.feil.SecurityException
import no.nav.emottak.message.ebxml.EbXMLConstants.EBMS_SERVICE_URI
import no.nav.emottak.message.ebxml.PartyTypeEnum
import no.nav.emottak.message.model.EmailAddress
import no.nav.emottak.message.model.PartyId
import no.nav.emottak.message.model.SignatureDetails
import no.nav.emottak.message.model.ValidationRequest
import org.oasis_open.committees.ebxml_cppa.schema.cpp_cpa_2_0.Certificate
import org.oasis_open.committees.ebxml_cppa.schema.cpp_cpa_2_0.CollaborationProtocolAgreement
import org.oasis_open.committees.ebxml_cppa.schema.cpp_cpa_2_0.DeliveryChannel
Expand All @@ -17,7 +19,7 @@ import org.w3._2000._09.xmldsig_.X509DataType
import javax.xml.bind.JAXBElement

fun PartyInfo.getCertificateForEncryption(): ByteArray {
// @TODO match role service action. ".first()" er ikke nokk
// @TODO match role service action. ".first()" er ikke nok
val encryptionCert = this.collaborationRole.first().applicationCertificateRef.first().certId as Certificate
return encryptionCert.getX509Certificate()
}
Expand Down Expand Up @@ -49,13 +51,55 @@ fun PartyInfo.getSendDeliveryChannel(
}
}

fun PartyInfo.getReceiveDeliveryChannels(
role: String,
service: String,
action: String
): List<DeliveryChannel> {
return if (EBMS_SERVICE_URI == service) {
listOf(this.getDefaultDeliveryChannel(action))
} else {
val roles = this.collaborationRole.filter { it.role.name == role && it.serviceBinding.service.value == service }
val canReceive = roles.flatMap { it.serviceBinding.canReceive.filter { cs -> cs.thisPartyActionBinding.action == action } }
.also { if (it.size > 1) log.warn("Found more than 1 CanReceive (role='$role', service='$service', action='$action')") }
val channels = canReceive.firstOrNull()?.thisPartyActionBinding?.channelId
return channels?.map { it.value as DeliveryChannel } ?: emptyList()
}
}

private fun PartyInfo.getDefaultDeliveryChannel(
action: String
): DeliveryChannel {
return (this.overrideMshActionBinding.firstOrNull { it.action == action }?.channelId as DeliveryChannel?)
?: this.defaultMshChannelId as DeliveryChannel
}

fun PartyInfo.getReceiveEmailAddress(validateRequest: ValidationRequest): List<EmailAddress> {
val deliveryChannels = this.getReceiveDeliveryChannels(validateRequest.addressing.to.role, validateRequest.addressing.service, validateRequest.addressing.action)
return getReceiverEmailAddress(validateRequest, validateRequest.addressing.to.role, deliveryChannels)
}

fun PartyInfo.getSignalEmailAddress(validateRequest: ValidationRequest): List<EmailAddress> {
val deliveryChannels = listOf(this.getDefaultDeliveryChannel(validateRequest.addressing.action))
return getReceiverEmailAddress(validateRequest, validateRequest.addressing.from.role, deliveryChannels)
}

private fun getReceiverEmailAddress(req: ValidationRequest, role: String, deliveryChannels: List<DeliveryChannel>): List<EmailAddress> {
// TODO: I stedet for å logge ut warning: Hent heller ut alle epostadresser fra alle SMTP-kanaler.
val smtpChannel = deliveryChannels.filter {
it.getTransport().transportReceiver?.transportProtocol?.value == "SMTP"
}.also {
if (it.size > 1) {
log.warn(
"Found more than 1 SMTP Channels (cpaId: '${req.cpaId}', role='$role', service='${req.addressing.service}', action='${req.addressing.action}', transportIds: ${
it.map { channel -> "'${(channel.transportId as Transport).transportId}'" }
}) - using the first one."
)
}
}.firstOrNull()
return smtpChannel?.getTransport()?.transportReceiver?.endpoint?.map { EmailAddress(it.uri, it.type!!) } ?: emptyList()
}

fun DeliveryChannel.getSigningCertificate(): Certificate {
val docExchange = this.docExchangeId as DocExchange? ?: throw SecurityException("Fant ikke DocExchange")
return if (
Expand All @@ -69,14 +113,14 @@ fun DeliveryChannel.getSigningCertificate(): Certificate {
}
}

fun DeliveryChannel.getTransport(): Transport = this.transportId as Transport? ?: throw SecurityException("Fant ikke transportkanal")

fun DeliveryChannel.getSenderTransportProtocolType(): ProtocolType {
val transport = this.transportId as Transport? ?: throw SecurityException("Fant ikke transportkanal")
return transport.transportSender?.transportProtocol ?: throw SecurityException("Fant ikke transportkanal")
return this.getTransport().transportSender?.transportProtocol ?: throw SecurityException("Fant ikke transportkanal")
}

fun DeliveryChannel.getReceiverTransportProtocolType(): ProtocolType {
val transport = this.transportId as Transport? ?: throw CpaValidationException("Fant ikke transportkanal")
return transport.transportReceiver?.transportProtocol ?: throw CpaValidationException("Fant ikke transportkanal")
return this.getTransport().transportReceiver?.transportProtocol ?: throw CpaValidationException("Fant ikke transportkanal")
}

fun DeliveryChannel.getSignatureAlgorithm(): String {
Expand Down
16 changes: 11 additions & 5 deletions cpa-repo/src/main/kotlin/no/nav/emottak/cpa/Routes.kt
Original file line number Diff line number Diff line change
Expand Up @@ -182,21 +182,25 @@ fun Route.validateCpa(cpaRepository: CPARepository) = post("/cpa/validate/{$CONT
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 fromParty = cpa.getPartyInfoByTypeAndID(validateRequest.addressing.from.partyId) // Delivery Failure
val encryptionCertificate = when (validateRequest.direction) {
IN -> partyInfo.getCertificateForEncryption() // Security Failure
IN -> fromParty.getCertificateForEncryption() // Security Failure
OUT ->
cpa
.getPartyInfoByTypeAndID(validateRequest.addressing.to.partyId)
.getCertificateForEncryption()
}

val signingCertificate = partyInfo.getCertificateForSignatureValidation(
val signingCertificate = fromParty.getCertificateForSignatureValidation(
validateRequest.addressing.from.role,
validateRequest.addressing.service,
validateRequest.addressing.action
) // Security Failure

val signalEmails = fromParty.getSignalEmailAddress(validateRequest)
val toParty = cpa.getPartyInfoByTypeAndID(validateRequest.addressing.to.partyId) // Delivery Failure
val receiverEmails = toParty.getReceiveEmailAddress(validateRequest)

runCatching {
createX509Certificate(signingCertificate.certificate).validate()
}.onFailure {
Expand All @@ -215,7 +219,9 @@ fun Route.validateCpa(cpaRepository: CPARepository) = post("/cpa/validate/{$CONT
validateRequest.addressing.service,
validateRequest.addressing.action
)
)
),
signalEmails,
receiverEmails
)
)
} catch (ebmsEx: EbmsException) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ import io.ktor.client.request.headers
import io.ktor.client.request.post
import io.ktor.client.request.setBody
import io.ktor.client.statement.bodyAsText
import io.ktor.client.statement.readBytes
import io.ktor.http.ContentType.Application.Json
import io.ktor.http.HttpStatusCode
import io.ktor.http.contentType
Expand All @@ -29,21 +28,25 @@ import no.nav.emottak.cpa.auth.AuthConfig
import no.nav.emottak.cpa.databasetest.PostgresTest
import no.nav.emottak.message.model.Addressing
import no.nav.emottak.message.model.Direction.IN
import no.nav.emottak.message.model.EmailAddress
import no.nav.emottak.message.model.ErrorCode
import no.nav.emottak.message.model.Party
import no.nav.emottak.message.model.PartyId
import no.nav.emottak.message.model.SignatureDetails
import no.nav.emottak.message.model.SignatureDetailsRequest
import no.nav.emottak.message.model.ValidationRequest
import no.nav.emottak.message.model.ValidationResult
import no.nav.emottak.util.getEnvVar
import no.nav.security.mock.oauth2.MockOAuth2Server
import org.apache.commons.lang3.StringUtils
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.TestInstance
import org.oasis_open.committees.ebxml_cppa.schema.cpp_cpa_2_0.CollaborationProtocolAgreement
import org.oasis_open.committees.ebxml_cppa.schema.cpp_cpa_2_0.EndpointTypeType
import java.time.Instant
import java.time.temporal.ChronoUnit
import kotlin.test.assertContains
import kotlin.test.assertEquals
import kotlin.test.assertNotEquals
import kotlin.test.assertNotNull
import kotlin.test.assertTrue
Expand Down Expand Up @@ -109,11 +112,16 @@ class CPARepoIntegrationTest : PostgresTest() {
contentType(Json)
}

println(String(response.readBytes()))
val validationResult = response.body<ValidationResult>()
assertNotNull(validationResult)

assertEquals(1, validationResult.signalEmailAddress.size)
assertEquals("mailto://[email protected]", validationResult.signalEmailAddress.first().emailAddress)
assertTrue(validationResult.receiverEmailAddress.isEmpty()) // Channel-protokoll er HTTP
}

@Test
fun `Byt from og to - role service action matcher ikke`() = cpaRepoTestApp {
fun `Bytt from og to - role service action matcher ikke`() = cpaRepoTestApp {
val httpClient = createClient {
install(ContentNegotiation) {
json()
Expand All @@ -137,7 +145,115 @@ class CPARepoIntegrationTest : PostgresTest() {
contentType(Json)
}

println(String(response.readBytes()))
val validationResult = response.body<ValidationResult>()
assertNotNull(validationResult)

assertNotNull(validationResult.error)
assertEquals(validationResult.error?.size, 1)
assertEquals(validationResult.error?.first()?.code, ErrorCode.DELIVERY_FAILURE)
assertEquals(validationResult.error?.first()?.descriptionText, "Action EgenandelForesporsel matcher ikke service HarBorgerEgenandelFritak for sending party NAV")
}

@Test
fun `Test hente epost`() = cpaRepoTestApp {
val httpClient = createClient {
install(ContentNegotiation) {
json()
}
}

val validationRequest = ValidationRequest(
IN,
"e17eb03e-9e43-43fb-874c-1fde9a28c308",
"1234",
"nav:qass:31162",
Addressing(
Party(listOf(PartyId("HER", "79768")), "KontrollUtbetaler"),
Party(listOf(PartyId("HER", "8090595")), "Utleverer"),
"OppgjorsKontroll",
"Oppgjorskrav"
)
)
val response = httpClient.post("/cpa/validate/121212") {
setBody(validationRequest)
contentType(Json)
}

val validationResult = response.body<ValidationResult>()
assertNotNull(validationResult)

assertEquals(1, validationResult.signalEmailAddress.size)
assertEquals("mailto://[email protected]", validationResult.signalEmailAddress.first().emailAddress)
assertEquals(1, validationResult.receiverEmailAddress.size)
assertEquals("mailto://[email protected]", validationResult.receiverEmailAddress.first().emailAddress)
}

@Test
fun `Test hente epost - flere ChannelId'er og flere endpoints (epostadresser)`() = cpaRepoTestApp {
val httpClient = createClient {
install(ContentNegotiation) {
json()
}
}

val validationRequest = ValidationRequest(
IN,
"e17eb03e-9e43-43fb-874c-1fde9a28c308",
"1234",
"multiple_channels_and_multiple_endpoints",
Addressing(
Party(listOf(PartyId("HER", "79768")), "KontrollUtbetaler"),
Party(listOf(PartyId("HER", "8090595")), "Utleverer"),
"OppgjorsKontroll",
"Oppgjorskrav"
)
)
val response = httpClient.post("/cpa/validate/121212") {
setBody(validationRequest)
contentType(Json)
}

val validationResult = response.body<ValidationResult>()
assertNotNull(validationResult)

assertEquals(2, validationResult.signalEmailAddress.size)
assertContains(
validationResult.signalEmailAddress,
EmailAddress("mailto://[email protected]", EndpointTypeType.ALL_PURPOSE),
"''signalEmailAddress'' inneholdt IKKE allPurpose-epostadresse"
)
assertContains(
validationResult.signalEmailAddress,
EmailAddress("mailto://[email protected]", EndpointTypeType.ERROR),
"''signalEmailAddress'' inneholdt IKKE error-epostadresse"
)

assertEquals(4, validationResult.receiverEmailAddress.size)
/*assertContains(
validationResult.receiverEmailAddress,
EmailAddress("mailto://[email protected]", EndpointTypeType.ALL_PURPOSE),
"''receiverEmailAddress'' inneholdt IKKE allPurpose-epostadresse"
)*/
assertContains(
validationResult.receiverEmailAddress,
EmailAddress("mailto://[email protected]", EndpointTypeType.REQUEST),
"''receiverEmailAddress'' inneholdt IKKE request-epostadresse"
)
assertContains(
validationResult.receiverEmailAddress,
EmailAddress("mailto://[email protected]", EndpointTypeType.RESPONSE),
"''receiverEmailAddress'' inneholdt IKKE response-epostadresse"
)
assertContains(
validationResult.receiverEmailAddress,
EmailAddress("mailto://[email protected]", EndpointTypeType.ERROR),
"''receiverEmailAddress'' inneholdt IKKE error-epostadresse"
)
assertContains(
validationResult.receiverEmailAddress,
EmailAddress("mailto://[email protected]", EndpointTypeType.LOGIN),
"''receiverEmailAddress'' inneholdt IKKE login-epostadresse"
)
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ class PostgresTestSetup {
tables.forEach { it.deleteAll() }
}

val cpasToInsert = listOf("nav-qass-35065.xml", "nav-qass-31162.xml")
val cpasToInsert = listOf("nav-qass-35065.xml", "nav-qass-31162.xml", "nav-qass-31162_multipleChannels_and_multiple_endpoints.xml")
transaction(postgres.db) {
cpasToInsert.forEach { cpaToInsert ->
CPA.insert {
Expand Down
Loading