Skip to content

Commit

Permalink
Validator service plus flytting av logikk
Browse files Browse the repository at this point in the history
  • Loading branch information
alpet committed Oct 18, 2023
1 parent ed40067 commit 487760e
Show file tree
Hide file tree
Showing 9 changed files with 84 additions and 29 deletions.
3 changes: 3 additions & 0 deletions cpa-repo/src/main/kotlin/no/nav/emottak/cpa/App.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package no.nav.emottak.cpa

import io.ktor.http.*
import io.ktor.server.application.Application
import io.ktor.server.application.call
import io.ktor.server.engine.embeddedServer
Expand All @@ -13,6 +14,7 @@ import io.ktor.server.routing.get
import no.nav.emottak.cpa.config.DatabaseConfig
import no.nav.emottak.cpa.config.mapHikariConfig
import no.nav.emottak.melding.model.Header
import no.nav.emottak.melding.model.ValidationResult

fun main() {
val database = Database(mapHikariConfig(DatabaseConfig()))
Expand All @@ -33,6 +35,7 @@ fun Application.myApplicationModule() {
post("cpa/validate") {
val validateRequest = call.receive(Header::class)
getCpa(validateRequest.cpaId)!!.validate(validateRequest)
call.respond(HttpStatusCode.OK,ValidationResult(true))
}

get("/cpa/{$CPA_ID}/her/{$HER_ID}/encryption/certificate") {
Expand Down
6 changes: 3 additions & 3 deletions cpa-repo/src/main/kotlin/no/nav/emottak/cpa/CPAUtil.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package no.nav.emottak.cpa

import io.ktor.server.plugins.BadRequestException
import io.ktor.server.plugins.NotFoundException
import no.nav.emottak.melding.model.SignatureDetailsResponse
import no.nav.emottak.melding.model.SignatureDetails
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 Down Expand Up @@ -35,9 +35,9 @@ fun PartyInfo.getCertificateForSignatureValidation(
role: String,
service: String,
action: String
): SignatureDetailsResponse {
): SignatureDetails {
val deliveryChannel = this.getSendDeliveryChannel(role, service, action)
return SignatureDetailsResponse(
return SignatureDetails(
certificate = deliveryChannel.getSigningCertificate().getX509Certificate(),
signatureAlgorithm = deliveryChannel.getSignatureAlgorithm(),
hashFunction = deliveryChannel.getHashFunction()
Expand Down
2 changes: 1 addition & 1 deletion ebms-provider/src/main/kotlin/no/nav/emottak/ebms/App.kt
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ fun Application.myApplicationModule() {
try {
DokumentValidator().validate(ebMSDocument)
}catch(ex:Exception) {
// parse fail
call.respond(HttpStatusCode.InternalServerError,"Validation feilet")
}

val message = ebMSDocument.buildEbmMessage()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,14 @@ import io.ktor.client.request.post
import io.ktor.client.request.request
import io.ktor.client.request.setBody
import io.ktor.client.statement.HttpResponse
import io.ktor.http.*
import io.ktor.http.ContentType.Application.Json
import io.ktor.http.HttpMethod
import io.ktor.http.contentType
import kotlinx.coroutines.runBlocking
import no.nav.emottak.melding.model.Header
import no.nav.emottak.melding.model.PayloadRequest
import no.nav.emottak.melding.model.PayloadResponse
import no.nav.emottak.melding.model.SignatureDetailsResponse
import no.nav.emottak.melding.model.SignatureDetails
import no.nav.emottak.melding.model.ValidationResult
import no.nav.emottak.util.createX509Certificate
import no.nav.emottak.util.decodeBase64
import org.apache.xml.security.algorithms.MessageDigestAlgorithm
Expand All @@ -24,21 +25,23 @@ import java.security.cert.X509Certificate

private val httpClientUtil = HttpClientUtil()
private const val payloadProcessorEndpoint = "http://payload-processor/payload"
private const val validatorEndpoint = "https://cpa-repo.intern.dev.nav.no/validate"

fun postPayloadRequest(payloadRequest: PayloadRequest): PayloadResponse = runBlocking {
httpClientUtil.postPayloadRequest(payloadRequest)
}

fun MessageHeader.getPublicSigningCertificate(): X509Certificate {
return createX509Certificate(this.getPublicSigningDetails().certificate)

fun SignatureDetails.getPublicSigningCertificate(): X509Certificate {
return createX509Certificate(this.certificate)
}

fun MessageHeader.getPublicSigningDetails(): SignatureDetailsResponse {
fun MessageHeader.getPublicSigningDetails(): SignatureDetails {
//TODO hent og valider sertifikat
val cert = decodeBase64("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".toByteArray())
//val timestamp = messageHeader.messageData.timestamp
//SecurityUtils.validateCertificate(trustStore, certificate, timestamp)
return SignatureDetailsResponse(
return SignatureDetails(
certificate = cert,
signatureAlgorithm = XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA256,
hashFunction = MessageDigestAlgorithm.ALGO_ID_DIGEST_SHA256
Expand All @@ -57,6 +60,14 @@ class HttpClientUtil {
contentType(Json)
}.body()
}
suspend fun postValidate(header: Header) : ValidationResult {
return client.post(validatorEndpoint) {
this.url {
this.path("/cpa/validate")
}
setBody(header)
}.body()
}

suspend fun makeHttpRequest(urlString: String): HttpResponse {
val response: HttpResponse = client.request(urlString) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@
*/
package no.nav.emottak.ebms.model

import no.nav.emottak.ebms.xml.unmarshal
import no.nav.emottak.ebms.processing.SignatursjekkProcessor
import no.nav.emottak.ebms.xml.xmlMarshaller
import no.nav.emottak.util.getFirstChildElement
import no.nav.emottak.melding.model.SignatureDetails
import no.nav.emottak.util.marker
import org.oasis_open.committees.ebxml_msg.schema.msg_header_2_0.MessageHeader
import org.slf4j.LoggerFactory
Expand All @@ -27,20 +27,29 @@ import java.lang.RuntimeException
import java.time.LocalDateTime

val log = LoggerFactory.getLogger("no.nav.emottak.ebms.model")
data class EbMSDocument(val conversationId: String, val dokument: Document, val attachments: List<EbMSAttachment>){
fun dokumentType(): DokumentType {
if (attachments.size>0) return DokumentType.PAYLOAD
if (dokument.getElementsByTagName("Acknowledgment").item(0)!=null) return DokumentType.ACKNOWLEDGMENT
if (dokument.getElementsByTagName("ErrorList").item(0)) return DokumentType.FAIL
throw RuntimeException("Unrecognized dokument type")
data class EbMSDocument(val messageId: String, val dokument: Document, val attachments: List<EbMSAttachment>) {
fun dokumentType(): DokumentType {
if (attachments.size > 0) return DokumentType.PAYLOAD
if (dokument.getElementsByTagName("Acknowledgment").item(0) != null) return DokumentType.ACKNOWLEDGMENT
if (dokument.getElementsByTagName("ErrorList").item(0)) return DokumentType.FAIL
throw RuntimeException("Unrecognized dokument type")

}
fun messageHeader():MessageHeader {
val node =this.dokument.getElementsByTagName("MessageHeader").item(0)
return xmlMarshaller.unmarshal(node)
}

}
}

enum class DokumentType {
PAYLOAD, ACKNOWLEDGMENT,FAIL,STATUS,PING
}

fun EbMSDocument.sjekkSignature(signatureDetails: SignatureDetails) {
SignatursjekkProcessor().validate(signatureDetails, this.dokument, this.attachments)
}


fun EbMSDocument.buildEbmMessage(): EbMSBaseMessage {
val envelope: Envelope = xmlMarshaller.unmarshal( this.dokument)
Expand All @@ -57,6 +66,10 @@ fun EbMSDocument.buildEbmMessage(): EbMSBaseMessage {
}
}

fun EbMSDocument.checkSignature(signatureDetails: SignatureDetails, dokument: Document, attachments: List<EbMSAttachment>) {
SignatursjekkProcessor().validate(signatureDetails, dokument, attachments)
}

fun EbMSDocument.sendResponse(messageHeader: MessageHeader) {
log.info(messageHeader.marker(), "TODO return response message")
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import no.nav.emottak.ebms.model.EbMSDocument
import no.nav.emottak.ebms.model.EbMSPayloadMessage
import no.nav.emottak.ebms.validation.CID_PREFIX
import no.nav.emottak.ebms.validation.EbMSAttachmentResolver
import no.nav.emottak.melding.model.SignatureDetails
import no.nav.emottak.util.retrievePublicX509Certificate
import no.nav.emottak.util.retrieveSignatureElement
import no.nav.emottak.util.signatur.SignatureException
Expand All @@ -30,22 +31,17 @@ import java.security.cert.X509Certificate
* Mangler: 104 (sertifikatsjekk), 105 (sertifikatsjekk) //TODO
*
*/
class SignatursjekkProcessor(val dokument: Document, ebMSMessage: EbMSBaseMessage): Processor(ebMSMessage) {

override fun process() {
val attachments = if (ebMSMessage is EbMSPayloadMessage) ebMSMessage.attachments else emptyList()
validate(ebMSMessage.messageHeader, dokument, attachments)
}
class SignatursjekkProcessor() {

init {
org.apache.xml.security.Init.init()
}

@Throws(SignatureException::class)
private fun validate(messageHeader: MessageHeader, dokument: Document, attachments: List<EbMSAttachment>) {
public fun validate(signatureDetails: SignatureDetails, dokument: Document, attachments: List<EbMSAttachment>) {
//TODO Sjekk isNonRepudiation?
val xmlSignature = retrieveSignatureElement(dokument)
val certificateFraCPA = messageHeader.getPublicSigningCertificate()
val certificateFraCPA = signatureDetails.getPublicSigningCertificate()
val certificateFraSignatur = xmlSignature.retrievePublicX509Certificate()
if (certificateFraSignatur != certificateFraCPA) throw SignatureException("Signert med annet sertifikat enn definert i CPA")
try {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,38 @@
package no.nav.emottak.ebms.validation

import kotlinx.coroutines.runBlocking
import no.nav.emottak.ebms.HttpClientUtil
import no.nav.emottak.ebms.getPublicSigningDetails
import no.nav.emottak.ebms.model.EbMSDocument
import no.nav.emottak.ebms.model.sjekkSignature
import no.nav.emottak.melding.model.Header
import no.nav.emottak.melding.model.Party
import no.nav.emottak.melding.model.SignatureDetails

class DokumentValidator {

var httpClient = HttpClientUtil()


fun validate(dokument: EbMSDocument) {

val messageHeader = dokument.messageHeader()
val signaturedetails: SignatureDetails = messageHeader.getPublicSigningDetails()
val header = Header(messageHeader.messageData.messageId,
messageHeader.conversationId,
messageHeader.cpaId,
Party(messageHeader.to.partyId.first().value!!,messageHeader.to.role!!),
Party(messageHeader.from.partyId.first().value!!,messageHeader.from.role!!),
messageHeader.service.value!!,
messageHeader.action)
runBlocking {
httpClient.postValidate(header)
}
dokument.sjekkSignature(signaturedetails)





}
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,8 @@ data class Party(
val herID: String,
val role: String
)

@Serializable
data class ValidationResult(
val valid: Boolean
)
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package no.nav.emottak.melding.model

data class SignatureDetailsResponse(
data class SignatureDetails(
val certificate: ByteArray,
val signatureAlgorithm: String,
val hashFunction: String
Expand Down

0 comments on commit 487760e

Please sign in to comment.