Implemented parsing SecurityMethods
This commit is contained in:
parent
af35f35ba0
commit
b9c5883942
|
@ -5,8 +5,12 @@ import net.dankito.fints.messages.datenelemente.implementierte.ICodeEnum
|
||||||
|
|
||||||
enum class Sicherheitsverfahren(override val code: String) : ICodeEnum {
|
enum class Sicherheitsverfahren(override val code: String) : ICodeEnum {
|
||||||
|
|
||||||
|
PIN_TAN_Verfahren("PIN"),
|
||||||
|
|
||||||
RSA_AES_Hybridverfahren("RAH"),
|
RSA_AES_Hybridverfahren("RAH"),
|
||||||
|
|
||||||
PIN_TAN_Verfahren("PIN")
|
RDH("RDH"),
|
||||||
|
|
||||||
|
DDV("DDV")
|
||||||
|
|
||||||
}
|
}
|
|
@ -25,9 +25,33 @@ import net.dankito.fints.messages.datenelementgruppen.Datenelementgruppe
|
||||||
* - „2“ : bei allen Nachrichten, wenn Dialog im Zwei-Schritt-Verfahren
|
* - „2“ : bei allen Nachrichten, wenn Dialog im Zwei-Schritt-Verfahren
|
||||||
*/
|
*/
|
||||||
open class Sicherheitsprofil(
|
open class Sicherheitsprofil(
|
||||||
method: Sicherheitsverfahren,
|
val method: Sicherheitsverfahren,
|
||||||
version: VersionDesSicherheitsverfahrens
|
val version: VersionDesSicherheitsverfahrens
|
||||||
) : Datenelementgruppe(listOf(
|
) : Datenelementgruppe(listOf(
|
||||||
SicherheitsverfahrenCode(method),
|
SicherheitsverfahrenCode(method),
|
||||||
VersionDesSicherheitsverfahrensDatenelement(version)
|
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}"
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -7,6 +7,8 @@ enum class InstituteSegmentId(override val id: String) : ISegmentId {
|
||||||
|
|
||||||
Synchronization("HISYN"),
|
Synchronization("HISYN"),
|
||||||
|
|
||||||
BankParameters("HIBPA")
|
BankParameters("HIBPA"),
|
||||||
|
|
||||||
|
SecurityMethods("HISHV")
|
||||||
|
|
||||||
}
|
}
|
|
@ -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.Dialogsprache
|
||||||
import net.dankito.fints.messages.datenelemente.implementierte.HbciVersion
|
import net.dankito.fints.messages.datenelemente.implementierte.HbciVersion
|
||||||
import net.dankito.fints.messages.datenelemente.implementierte.ICodeEnum
|
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.Kreditinstitutskennung
|
||||||
|
import net.dankito.fints.messages.datenelementgruppen.implementierte.signatur.Sicherheitsprofil
|
||||||
import net.dankito.fints.messages.segmente.id.MessageSegmentId
|
import net.dankito.fints.messages.segmente.id.MessageSegmentId
|
||||||
import net.dankito.fints.response.segments.BankParameters
|
import net.dankito.fints.response.segments.*
|
||||||
import net.dankito.fints.response.segments.ReceivedMessageHeader
|
|
||||||
import net.dankito.fints.response.segments.ReceivedSegment
|
|
||||||
import net.dankito.fints.response.segments.ReceivedSynchronization
|
|
||||||
import org.slf4j.LoggerFactory
|
import org.slf4j.LoggerFactory
|
||||||
|
|
||||||
|
|
||||||
|
@ -60,6 +60,7 @@ open class ResponseParser {
|
||||||
MessageSegmentId.MessageHeader.id -> parseMessageHeaderSegment(segment, dataElementGroups)
|
MessageSegmentId.MessageHeader.id -> parseMessageHeaderSegment(segment, dataElementGroups)
|
||||||
InstituteSegmentId.Synchronization.id -> parseSynchronization(segment, dataElementGroups)
|
InstituteSegmentId.Synchronization.id -> parseSynchronization(segment, dataElementGroups)
|
||||||
InstituteSegmentId.BankParameters.id -> parseBankParameters(segment, dataElementGroups)
|
InstituteSegmentId.BankParameters.id -> parseBankParameters(segment, dataElementGroups)
|
||||||
|
InstituteSegmentId.SecurityMethods.id -> parseSecurityMethods(segment, dataElementGroups)
|
||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -101,6 +102,13 @@ open class ResponseParser {
|
||||||
countMaxJobsPerMessage, supportedLanguages, supportedHbciVersions, maxMessageSize, minTimeout, maxTimeout, segment)
|
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 {
|
protected open fun parseBankDetails(dataElementsGroup: String): Kreditinstitutskennung {
|
||||||
val detailsStrings = getDataElements(dataElementsGroup)
|
val detailsStrings = getDataElements(dataElementsGroup)
|
||||||
|
@ -120,6 +128,28 @@ open class ResponseParser {
|
||||||
return parseFromCode(versionStrings, HbciVersion.values())
|
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> {
|
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
|
// 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 } }
|
return codeValues.mapNotNull { code -> allValues.first { it.code == code } }
|
||||||
|
@ -130,4 +160,12 @@ open class ResponseParser {
|
||||||
return dataElementGroup.split(Separators.DataElementsSeparator)
|
return dataElementGroup.split(Separators.DataElementsSeparator)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected open fun parseBoolean(dataElement: String): Boolean {
|
||||||
|
if ("J" == dataElement) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -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)
|
|
@ -2,11 +2,15 @@ package net.dankito.fints.response
|
||||||
|
|
||||||
import net.dankito.fints.messages.datenelemente.implementierte.Dialogsprache
|
import net.dankito.fints.messages.datenelemente.implementierte.Dialogsprache
|
||||||
import net.dankito.fints.messages.datenelemente.implementierte.HbciVersion
|
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.ISegmentId
|
||||||
import net.dankito.fints.messages.segmente.id.MessageSegmentId
|
import net.dankito.fints.messages.segmente.id.MessageSegmentId
|
||||||
import net.dankito.fints.response.segments.BankParameters
|
import net.dankito.fints.response.segments.BankParameters
|
||||||
import net.dankito.fints.response.segments.ReceivedMessageHeader
|
import net.dankito.fints.response.segments.ReceivedMessageHeader
|
||||||
import net.dankito.fints.response.segments.ReceivedSynchronization
|
import net.dankito.fints.response.segments.ReceivedSynchronization
|
||||||
|
import net.dankito.fints.response.segments.SecurityMethods
|
||||||
import org.assertj.core.api.Assertions.assertThat
|
import org.assertj.core.api.Assertions.assertThat
|
||||||
import org.junit.Assert
|
import org.junit.Assert
|
||||||
import org.junit.Test
|
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,
|
private fun assertSuccessfullyParsedSegment(result: Response, segmentId: ISegmentId, segmentNumber: Int,
|
||||||
segmentVersion: Int, referenceSegmentNumber: Int? = null) {
|
segmentVersion: Int, referenceSegmentNumber: Int? = null) {
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue