From b9c5883942e22ed1110f05cc0e52ea640461f7bd Mon Sep 17 00:00:00 2001 From: dankl Date: Sat, 5 Oct 2019 22:25:35 +0200 Subject: [PATCH] Implemented parsing SecurityMethods --- .../signatur/Sicherheitsverfahren.kt | 6 ++- .../signatur/Sicherheitsprofil.kt | 30 ++++++++++-- .../fints/response/InstituteSegmentId.kt | 4 +- .../dankito/fints/response/ResponseParser.kt | 46 +++++++++++++++++-- .../response/segments/SecurityMethods.kt | 34 ++++++++++++++ .../fints/response/ResponseParserTest.kt | 28 +++++++++++ 6 files changed, 139 insertions(+), 9 deletions(-) create mode 100644 fints4javaLib/src/main/kotlin/net/dankito/fints/response/segments/SecurityMethods.kt diff --git a/fints4javaLib/src/main/kotlin/net/dankito/fints/messages/datenelemente/implementierte/signatur/Sicherheitsverfahren.kt b/fints4javaLib/src/main/kotlin/net/dankito/fints/messages/datenelemente/implementierte/signatur/Sicherheitsverfahren.kt index 8993015a..411499ab 100644 --- a/fints4javaLib/src/main/kotlin/net/dankito/fints/messages/datenelemente/implementierte/signatur/Sicherheitsverfahren.kt +++ b/fints4javaLib/src/main/kotlin/net/dankito/fints/messages/datenelemente/implementierte/signatur/Sicherheitsverfahren.kt @@ -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") } \ No newline at end of file diff --git a/fints4javaLib/src/main/kotlin/net/dankito/fints/messages/datenelementgruppen/implementierte/signatur/Sicherheitsprofil.kt b/fints4javaLib/src/main/kotlin/net/dankito/fints/messages/datenelementgruppen/implementierte/signatur/Sicherheitsprofil.kt index 55167492..355fd292 100644 --- a/fints4javaLib/src/main/kotlin/net/dankito/fints/messages/datenelementgruppen/implementierte/signatur/Sicherheitsprofil.kt +++ b/fints4javaLib/src/main/kotlin/net/dankito/fints/messages/datenelementgruppen/implementierte/signatur/Sicherheitsprofil.kt @@ -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) \ No newline at end of file +), 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}" + } + +} \ No newline at end of file diff --git a/fints4javaLib/src/main/kotlin/net/dankito/fints/response/InstituteSegmentId.kt b/fints4javaLib/src/main/kotlin/net/dankito/fints/response/InstituteSegmentId.kt index 1c2d23f3..9dbf27d1 100644 --- a/fints4javaLib/src/main/kotlin/net/dankito/fints/response/InstituteSegmentId.kt +++ b/fints4javaLib/src/main/kotlin/net/dankito/fints/response/InstituteSegmentId.kt @@ -7,6 +7,8 @@ enum class InstituteSegmentId(override val id: String) : ISegmentId { Synchronization("HISYN"), - BankParameters("HIBPA") + BankParameters("HIBPA"), + + SecurityMethods("HISHV") } \ No newline at end of file diff --git a/fints4javaLib/src/main/kotlin/net/dankito/fints/response/ResponseParser.kt b/fints4javaLib/src/main/kotlin/net/dankito/fints/response/ResponseParser.kt index f06cd4b1..f8a2177b 100644 --- a/fints4javaLib/src/main/kotlin/net/dankito/fints/response/ResponseParser.kt +++ b/fints4javaLib/src/main/kotlin/net/dankito/fints/response/ResponseParser.kt @@ -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): 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): List { + 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 parseFromCode(codeValues: List, allValues: Array): List { // 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 + } + } \ No newline at end of file diff --git a/fints4javaLib/src/main/kotlin/net/dankito/fints/response/segments/SecurityMethods.kt b/fints4javaLib/src/main/kotlin/net/dankito/fints/response/segments/SecurityMethods.kt new file mode 100644 index 00000000..479492df --- /dev/null +++ b/fints4javaLib/src/main/kotlin/net/dankito/fints/response/segments/SecurityMethods.kt @@ -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, + + segmentString: String +) + : ReceivedSegment(segmentString) \ No newline at end of file diff --git a/fints4javaLib/src/test/kotlin/net/dankito/fints/response/ResponseParserTest.kt b/fints4javaLib/src/test/kotlin/net/dankito/fints/response/ResponseParserTest.kt index 93b7e018..f301b42e 100644 --- a/fints4javaLib/src/test/kotlin/net/dankito/fints/response/ResponseParserTest.kt +++ b/fints4javaLib/src/test/kotlin/net/dankito/fints/response/ResponseParserTest.kt @@ -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(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) {