Implemented parsing SecurityMethods

This commit is contained in:
dankl 2019-10-05 22:25:35 +02:00 committed by dankito
parent af35f35ba0
commit b9c5883942
6 changed files with 139 additions and 9 deletions

View File

@ -5,8 +5,12 @@ import net.dankito.fints.messages.datenelemente.implementierte.ICodeEnum
enum class Sicherheitsverfahren(override val code: String) : ICodeEnum {
PIN_TAN_Verfahren("PIN"),
RSA_AES_Hybridverfahren("RAH"),
PIN_TAN_Verfahren("PIN")
RDH("RDH"),
DDV("DDV")
}

View File

@ -25,9 +25,33 @@ import net.dankito.fints.messages.datenelementgruppen.Datenelementgruppe
* - 2 : bei allen Nachrichten, wenn Dialog im Zwei-Schritt-Verfahren
*/
open class Sicherheitsprofil(
method: Sicherheitsverfahren,
version: VersionDesSicherheitsverfahrens
val method: Sicherheitsverfahren,
val version: VersionDesSicherheitsverfahrens
) : Datenelementgruppe(listOf(
SicherheitsverfahrenCode(method),
VersionDesSicherheitsverfahrensDatenelement(version)
), Existenzstatus.Mandatory)
), Existenzstatus.Mandatory) {
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other !is Sicherheitsprofil) return false
if (method != other.method) return false
if (version != other.version) return false
return true
}
override fun hashCode(): Int {
var result = method.hashCode()
result = 31 * result + version.hashCode()
return result
}
override fun toString(): String {
return "$method ${version.methodNumber}"
}
}

View File

@ -7,6 +7,8 @@ enum class InstituteSegmentId(override val id: String) : ISegmentId {
Synchronization("HISYN"),
BankParameters("HIBPA")
BankParameters("HIBPA"),
SecurityMethods("HISHV")
}

View File

@ -4,12 +4,12 @@ import net.dankito.fints.messages.Separators
import net.dankito.fints.messages.datenelemente.implementierte.Dialogsprache
import net.dankito.fints.messages.datenelemente.implementierte.HbciVersion
import net.dankito.fints.messages.datenelemente.implementierte.ICodeEnum
import net.dankito.fints.messages.datenelemente.implementierte.signatur.Sicherheitsverfahren
import net.dankito.fints.messages.datenelemente.implementierte.signatur.VersionDesSicherheitsverfahrens
import net.dankito.fints.messages.datenelementgruppen.implementierte.Kreditinstitutskennung
import net.dankito.fints.messages.datenelementgruppen.implementierte.signatur.Sicherheitsprofil
import net.dankito.fints.messages.segmente.id.MessageSegmentId
import net.dankito.fints.response.segments.BankParameters
import net.dankito.fints.response.segments.ReceivedMessageHeader
import net.dankito.fints.response.segments.ReceivedSegment
import net.dankito.fints.response.segments.ReceivedSynchronization
import net.dankito.fints.response.segments.*
import org.slf4j.LoggerFactory
@ -60,6 +60,7 @@ open class ResponseParser {
MessageSegmentId.MessageHeader.id -> parseMessageHeaderSegment(segment, dataElementGroups)
InstituteSegmentId.Synchronization.id -> parseSynchronization(segment, dataElementGroups)
InstituteSegmentId.BankParameters.id -> parseBankParameters(segment, dataElementGroups)
InstituteSegmentId.SecurityMethods.id -> parseSecurityMethods(segment, dataElementGroups)
else -> null
}
}
@ -101,6 +102,13 @@ open class ResponseParser {
countMaxJobsPerMessage, supportedLanguages, supportedHbciVersions, maxMessageSize, minTimeout, maxTimeout, segment)
}
protected open fun parseSecurityMethods(segment: String, dataElementGroups: List<String>): SecurityMethods {
val mixingAllowed = parseBoolean(dataElementGroups[1])
val profiles = parseSecurityProfiles(dataElementGroups.subList(2, dataElementGroups.size))
return SecurityMethods(mixingAllowed, profiles, segment)
}
protected open fun parseBankDetails(dataElementsGroup: String): Kreditinstitutskennung {
val detailsStrings = getDataElements(dataElementsGroup)
@ -120,6 +128,28 @@ open class ResponseParser {
return parseFromCode(versionStrings, HbciVersion.values())
}
protected open fun parseSecurityProfiles(dataElementsGroups: List<String>): List<Sicherheitsprofil> {
return dataElementsGroups.flatMap { dataElementGroup ->
val parts = getDataElements(dataElementGroup)
val method = parseSecurityMethod(parts[0])
parts.subList(1, parts.size).map {
Sicherheitsprofil(method, parseSecurityMethodVersion(it))
}
}
}
protected open fun parseSecurityMethod(methodString: String): Sicherheitsverfahren {
return parseFromCode(listOf(methodString), Sicherheitsverfahren.values()).first()
}
protected open fun parseSecurityMethodVersion(versionString: String): VersionDesSicherheitsverfahrens {
val versionInt = versionString.toInt()
return VersionDesSicherheitsverfahrens.values().first { it.methodNumber == versionInt }
}
protected open fun <T : ICodeEnum> parseFromCode(codeValues: List<String>, allValues: Array<T>): List<T> {
// mapNotNull: don't crash if new, at time of implementation unknown values get introduced / returned by bank
return codeValues.mapNotNull { code -> allValues.first { it.code == code } }
@ -130,4 +160,12 @@ open class ResponseParser {
return dataElementGroup.split(Separators.DataElementsSeparator)
}
protected open fun parseBoolean(dataElement: String): Boolean {
if ("J" == dataElement) {
return true
}
return false
}
}

View File

@ -0,0 +1,34 @@
package net.dankito.fints.response.segments
import net.dankito.fints.messages.datenelementgruppen.implementierte.signatur.Sicherheitsprofil
open class SecurityMethods(
/**
* Kennzeichen dafür, ob das Kreditinstitut die Mischung von Sicherheitsverfahren zulässt, sofern es mehrere
* Sicherheitsverfahren anbietet. Hierunter ist zu verstehen,
* - dass eine Nachricht von mehreren Benutzern mit unterschiedlichen Verfahren signiert wird.
* - dass ein Benutzer die Nachrichten eines Dialoges mit verschiedenen Verfahren signiert.
* - dass Signatur und Verschlüsselung einer Nachricht mit verschiedenen Verfahren durchgeführt werden.
* - dass zwischen den folgenden Gruppen gemischt werden soll:
* + RAH-7, RAH-9, RDH-3, RDH-5, RDH-6, RDH-7, RDH-8 und RDH-9
* + RAH-10, RDH-2 und RDH-10
* + DDV
* + PIN
*
* Eine Verwendung von Sicherheitsverfahren innerhalb dieser Gruppen gilt nicht als Mischung.
*
* Ist hier N eingestellt, so sind die genannten Fälle nicht zulässig, d. h. alle Signaturen und
* Verschlüsselungen eines Dialoges müssen mit demselben Sicherheitsverfahren bzw. mit Verfahren aus der gleichen
* Gruppe vorgenommen werden. Ist J eingestellt, so müssen kreditinstitutsseitig alle vorgenannten Fälle unterstützt werden.
*
* Falls das Kreditinstitut nur ein Sicherheitsverfahren anbietet, ist N einzustellen.
*/
val mixingAllowed: Boolean,
val securityProfiles: List<Sicherheitsprofil>,
segmentString: String
)
: ReceivedSegment(segmentString)

View File

@ -2,11 +2,15 @@ package net.dankito.fints.response
import net.dankito.fints.messages.datenelemente.implementierte.Dialogsprache
import net.dankito.fints.messages.datenelemente.implementierte.HbciVersion
import net.dankito.fints.messages.datenelemente.implementierte.signatur.Sicherheitsverfahren
import net.dankito.fints.messages.datenelemente.implementierte.signatur.VersionDesSicherheitsverfahrens
import net.dankito.fints.messages.datenelementgruppen.implementierte.signatur.Sicherheitsprofil
import net.dankito.fints.messages.segmente.id.ISegmentId
import net.dankito.fints.messages.segmente.id.MessageSegmentId
import net.dankito.fints.response.segments.BankParameters
import net.dankito.fints.response.segments.ReceivedMessageHeader
import net.dankito.fints.response.segments.ReceivedSynchronization
import net.dankito.fints.response.segments.SecurityMethods
import org.assertj.core.api.Assertions.assertThat
import org.junit.Assert
import org.junit.Test
@ -79,6 +83,30 @@ class ResponseParserTest {
}
@Test
fun parseSecurityMethods() {
// when
val result = underTest.parse("HISHV:7:3:3+N+RDH:1:9:10+DDV:1+PIN:1'")
// then
assertSuccessfullyParsedSegment(result, InstituteSegmentId.SecurityMethods, 7, 3, 3)
result.getFirstSegmentById<SecurityMethods>(InstituteSegmentId.SecurityMethods)?.let { segment ->
assertThat(segment.mixingAllowed).isFalse()
assertThat(segment.securityProfiles).contains(
Sicherheitsprofil(Sicherheitsverfahren.RDH, VersionDesSicherheitsverfahrens.PIN_Ein_Schritt),
Sicherheitsprofil(Sicherheitsverfahren.RDH, VersionDesSicherheitsverfahrens.RAH_9),
Sicherheitsprofil(Sicherheitsverfahren.RDH, VersionDesSicherheitsverfahrens.RAH_10),
Sicherheitsprofil(Sicherheitsverfahren.DDV, VersionDesSicherheitsverfahrens.PIN_Ein_Schritt),
Sicherheitsprofil(Sicherheitsverfahren.PIN_TAN_Verfahren, VersionDesSicherheitsverfahrens.PIN_Ein_Schritt)
)
}
?: run { Assert.fail("No segment of type SecurityMethods found in ${result.receivedSegments}") }
}
private fun assertSuccessfullyParsedSegment(result: Response, segmentId: ISegmentId, segmentNumber: Int,
segmentVersion: Int, referenceSegmentNumber: Int? = null) {