Added ZweiSchrittTanEinreichung. Authenticating with it works, but is not really configurable / usable.
This commit is contained in:
parent
b9733189e6
commit
9ac4af58ff
|
@ -2,6 +2,7 @@ package net.dankito.fints.messages
|
|||
|
||||
import net.dankito.fints.messages.datenelemente.implementierte.*
|
||||
import net.dankito.fints.messages.datenelemente.implementierte.signatur.Sicherheitsfunktion
|
||||
import net.dankito.fints.messages.datenelemente.implementierte.tan.TanProcess
|
||||
import net.dankito.fints.messages.nachrichten.Nachricht
|
||||
import net.dankito.fints.messages.segmente.ISegmentNumberGenerator
|
||||
import net.dankito.fints.messages.segmente.Segment
|
||||
|
@ -39,8 +40,12 @@ open class MessageBuilder(protected val generator: ISegmentNumberGenerator = Seg
|
|||
productVersion: String
|
||||
): String {
|
||||
|
||||
return createDialogInitMessage(bankCountryCode, bankCode, KundenID.Anonymous, KundensystemID.Anonymous, KundensystemStatusWerte.NichtBenoetigt,
|
||||
BPDVersion.VersionNotReceivedYet, UPDVersion.VersionNotReceivedYet, Dialogsprache.Default, productName, productVersion, false, false)
|
||||
val customerId = KundenID.Anonymous
|
||||
|
||||
return createMessage(false, false, bankCountryCode, bankCode, customerId, listOf(
|
||||
IdentifikationsSegment(generator.resetSegmentNumber(1), bankCountryCode, bankCode, customerId, KundensystemID.Anonymous, KundensystemStatusWerte.NichtBenoetigt),
|
||||
Verarbeitungsvorbereitung(generator.getNextSegmentNumber(), BPDVersion.VersionNotReceivedYet, UPDVersion.VersionNotReceivedYet, Dialogsprache.Default, productName, productVersion)
|
||||
))
|
||||
}
|
||||
|
||||
open fun createDialogInitMessage(
|
||||
|
@ -53,14 +58,13 @@ open class MessageBuilder(protected val generator: ISegmentNumberGenerator = Seg
|
|||
updVersion: Int,
|
||||
language: Dialogsprache,
|
||||
productName: String,
|
||||
productVersion: String,
|
||||
signMessage: Boolean = true,
|
||||
encryptMessage: Boolean = true
|
||||
productVersion: String
|
||||
): String {
|
||||
|
||||
return createMessage(signMessage, encryptMessage, bankCountryCode, bankCode, customerId, listOf(
|
||||
IdentifikationsSegment(generator.resetSegmentNumber(if (signMessage) 2 else 1), bankCountryCode, bankCode, customerId, customerSystemId, status),
|
||||
Verarbeitungsvorbereitung(generator.getNextSegmentNumber(), bpdVersion, updVersion, language, productName, productVersion)
|
||||
return createMessage(true, true, bankCountryCode, bankCode, customerId, listOf(
|
||||
IdentifikationsSegment(generator.resetSegmentNumber(2), bankCountryCode, bankCode, customerId, customerSystemId, status),
|
||||
Verarbeitungsvorbereitung(generator.getNextSegmentNumber(), bpdVersion, updVersion, language, productName, productVersion),
|
||||
ZweiSchrittTanEinreichung(generator.getNextSegmentNumber(), TanProcess.TanProcess4, "HKIDN")
|
||||
))
|
||||
}
|
||||
|
||||
|
|
|
@ -25,7 +25,11 @@ open class BinaerDatenelement @JvmOverloads constructor(val data: ByteArray, exi
|
|||
* Spezifikation vorzusehen.
|
||||
*/
|
||||
override fun format(): String {
|
||||
return "@${data.size}@" + String(data)
|
||||
if (data.size > 0) {
|
||||
return "@${data.size}@" + String(data)
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
override fun validate() {
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
package net.dankito.fints.messages.datenelemente.implementierte.signatur
|
||||
|
||||
|
||||
/**
|
||||
* Ab FinTS 3.0 existieren beim RAH-Verfahren drei Schlüssel (DS-Schlüssel für Non-Repudiation,
|
||||
* Signierschlüssel für Authentication und Chiffrierschlüssel für Verschlüsselung) und somit
|
||||
* auch drei Sicherheitsfunktionen (Sicherheitsfunktion 1 bei Verwendung des DS-Schlüssels,
|
||||
* Sicherheitsfunktion 2 bei Verwendung des Signierschlüssels und Sicherheitsfunktion 4 bei
|
||||
* Verwendung des Chiffrierschlüssels) beim RAH-Verfahren.
|
||||
*
|
||||
* Die Sicherheitsfunktion hat ab FinTS 3.0 lediglich informatorischen Wert, da die eigentliche
|
||||
* Steuerung über die Sicherheitsprofile und –Klassen erfolgt.
|
||||
*
|
||||
* Kodierte Information über die Sicherheitsfunktion, die auf die Nachricht angewendet wird.
|
||||
*
|
||||
* Codierung:
|
||||
* - 1: Non-Repudiation of Origin (NRO)
|
||||
* - 2: Message Origin Authentication (AUT)
|
||||
* - 4: Encryption, Verschlüsselung und evtl. Komprimierung (ENC)
|
||||
*/
|
||||
enum class SicherheitsfunktionWhatIsThisShit(val code: String) {
|
||||
|
||||
NonRepudiationOfOrigin("1"),
|
||||
|
||||
MessageOriginAuthentication("2"),
|
||||
|
||||
Encryption("4")
|
||||
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
package net.dankito.fints.messages.datenelemente.implementierte.tan
|
||||
|
||||
import net.dankito.fints.messages.Existenzstatus
|
||||
import net.dankito.fints.messages.datenelemente.basisformate.BinaerDatenelement
|
||||
|
||||
|
||||
/**
|
||||
* Er enthält im Falle des Zwei-Schritt-TAN-Verfahrens bei TAN-Prozess=1 den Hashwert über die
|
||||
* Daten eines Kundenauftrags (z. B. „HKCCS“). Dieser wird z. B. im Rahmen des Geschäftsvorfalls
|
||||
* HKTAN vom Kunden übermittelt und vom Kreditinstitut in der Antwortnachricht HITAN gespiegelt.
|
||||
*
|
||||
* Das vom Institut verwendete Auftrags-Hashwertverfahren wird in der BPD übermittelt. In der
|
||||
* vorliegenden Version wird RIPEMD-160 verwendet.
|
||||
*
|
||||
* In die Berechnung des Auftrags-Hashwerts geht der Bereich vom ersten bit des Segmentkopfes
|
||||
* bis zum letzten bit des Trennzeichens ein.
|
||||
*
|
||||
* RIPEMD-160
|
||||
*
|
||||
* Der Hash-Algorithmus RIPEMD-160 bildet Eingabe-Bitfolgen beliebiger Länge auf einen als
|
||||
* Bytefolge dargestellten Hash-Wert von 20 Byte (160 Bit) Länge ab. Teil des Hash-Algorithmus
|
||||
* ist das Padding von Eingabe-Bitfolgen auf ein Vielfaches von 64 Byte. Das Padding erfolgt
|
||||
* auch dann, wenn die Eingabe-Bitfolge bereits eine Länge hat, die ein Vielfaches von 64 Byte ist.
|
||||
* RIPEMD-160 verarbeitet die Eingabe-Bitfolgen in Blöcken von 64 Byte Länge.
|
||||
*
|
||||
* Als Initialisierungsvektor dient die binäre Zeichenfolge
|
||||
* X’01 23 45 67 89 AB CD EF FE DC BA 98 76 54 32 10 F0 E1 D2 C3’.
|
||||
*/
|
||||
open class AuftragsHashwert(hash: ByteArray, existenzstatus: Existenzstatus)
|
||||
: BinaerDatenelement(hash, existenzstatus, 256)
|
|
@ -0,0 +1,17 @@
|
|||
package net.dankito.fints.messages.datenelemente.implementierte.tan
|
||||
|
||||
import net.dankito.fints.messages.Existenzstatus
|
||||
import net.dankito.fints.messages.datenelemente.basisformate.AlphanumerischesDatenelement
|
||||
|
||||
|
||||
/**
|
||||
* Enthält im Falle des Zwei-Schritt-TAN-Verfahrens die Referenz auf einen eingereichten Auftrag.
|
||||
* Die Auftragsreferenz wird bei der späteren Einreichung der zugehörigen TANs (mittels HKTAN bei
|
||||
* TAN-Prozess=2 bzw. 3) zur Referenzierung des Auftrags verwendet.
|
||||
*
|
||||
* Da die Auftragsreferenz immer eindeutig ist, sollten Kundenprodukte diese als zentrale
|
||||
* Referenzierung verwenden und dem Kunden auch zusammen mit den Auftragsdaten präsentieren bzw.
|
||||
* für die Problemverfolgung leicht zugänglich machen.
|
||||
*/
|
||||
open class Auftragsreferenz(reference: String, existenzstatus: Existenzstatus)
|
||||
: AlphanumerischesDatenelement(reference, existenzstatus, 35)
|
|
@ -0,0 +1,13 @@
|
|||
package net.dankito.fints.messages.datenelemente.implementierte.tan
|
||||
|
||||
import net.dankito.fints.messages.Existenzstatus
|
||||
import net.dankito.fints.messages.datenelemente.basisformate.AlphanumerischesDatenelement
|
||||
|
||||
|
||||
/**
|
||||
* Symbolischer Name für ein TAN-Medium wie z. B. TAN-Generator oder Mobiltelefon. Diese Bezeichnung
|
||||
* kann in Verwaltungs-Geschäftsvorfällen benutzt werden, wenn z. B. die Angabe der echten Handynummer
|
||||
* aus Datenschutzgründen nicht möglich ist oder auch um die Benutzerfreundlichkeit zu erhöhen.
|
||||
*/
|
||||
open class BezeichnungDesTANMediums(identifier: String, existenzstatus: Existenzstatus)
|
||||
: AlphanumerischesDatenelement(identifier, existenzstatus, 32)
|
|
@ -0,0 +1,16 @@
|
|||
package net.dankito.fints.messages.datenelemente.implementierte.tan
|
||||
|
||||
import net.dankito.fints.messages.Existenzstatus
|
||||
import net.dankito.fints.messages.datenelemente.basisformate.BinaerDatenelement
|
||||
|
||||
|
||||
/**
|
||||
* Bei Verwendung von Zwei-Schritt-Verfahren mit unidirektionaler Kopplung (vgl. hierzu [HHD_UC])
|
||||
* müssen zusätzlich zum Datenelement „Challenge“ die Daten für die Übertragung z. B. über eine
|
||||
* optische Schnittstelle bereitgestellt werden. Die einzelnen Datenelemente der „Challenge HHD_UC“
|
||||
* sind in [HHD_UC] beschrieben und werden hier im FinTS Data Dictionary nicht näher erläutert.
|
||||
* Da HHD_UC einen anderen Basiszeichensatz verwendet (ISO 646) wird die HHD_UC-Struktur als binär
|
||||
* definiert. Als maximale Länge kann ein Wert von 128 angenommen werden.
|
||||
*/
|
||||
open class ChallengeHHD_UC(challenge: ByteArray, existenzstatus: Existenzstatus)
|
||||
: BinaerDatenelement(challenge, existenzstatus, 128)
|
|
@ -0,0 +1,27 @@
|
|||
package net.dankito.fints.messages.datenelemente.implementierte.tan
|
||||
|
||||
import net.dankito.fints.messages.Existenzstatus
|
||||
import net.dankito.fints.messages.datenelemente.basisformate.AlphanumerischesDatenelement
|
||||
|
||||
|
||||
/**
|
||||
* Dieses Datenelement enthält im Falle des Zwei-Schritt-TAN-Verfahrens die Challenge zu einem
|
||||
* eingereichten Auftrag. Aus der Challenge wird vom Kunden die eigentliche TAN ermittelt.
|
||||
* Die Challenge wird unabhängig vom Prozessvariante 1 oder 2 in der Kreditinstitutsantwort im
|
||||
* Segment HITAN übermittelt.
|
||||
*
|
||||
* Ist der BPD-Parameter „Challenge strukturiert“ mit „J“ belegt, so können im Text folgende
|
||||
* Formatsteuerzeichen enthalten sein, die kundenseitig entsprechend zu interpretieren sind.
|
||||
* Eine Kaskadierung von Steuerzeichen ist nicht erlaubt.
|
||||
*
|
||||
* <br> Zeilenumbruch
|
||||
* <p> Neuer Absatz
|
||||
* <b> ... </b> Fettdruck
|
||||
* <i> ... </i> Kursivdruck
|
||||
* <u> ... </u> Unterstreichen
|
||||
* <ul> ... </ul> Beginn / Ende Aufzählung
|
||||
* <ol> ... </ol> Beginn / Ende Nummerierte Liste
|
||||
* <li> ... </li> Listenelement einer Aufzählung / Nummerierten Liste
|
||||
*/
|
||||
open class ChallengeVersion3(challenge: String, existenzstatus: Existenzstatus)
|
||||
: AlphanumerischesDatenelement(challenge, existenzstatus, 2048)
|
|
@ -0,0 +1,57 @@
|
|||
package net.dankito.fints.messages.datenelemente.implementierte.tan
|
||||
|
||||
import net.dankito.fints.messages.Existenzstatus
|
||||
import net.dankito.fints.messages.datenelemente.abgeleiteteformate.Code
|
||||
import net.dankito.fints.messages.datenelemente.implementierte.allCodes
|
||||
|
||||
|
||||
/**
|
||||
* Beim Zwei-Schritt-Verfahren werden die notwendigen Prozess-Schritte mittels des Geschäftsvorfalls
|
||||
* HKTAN durchgeführt. Dieser unterstützt flexibel vier unterschiedliche Ausprägungen für die beiden
|
||||
* Prozessvarianten für Zwei-Schritt-Verfahren, wobei die TAN-Prozesse 3 und 4 nicht isoliert und nur
|
||||
* in Verbindung mit TAN-Prozess=2 auftreten können. Der TAN-Prozess wird wie folgt kodiert:
|
||||
*
|
||||
* Codierung:
|
||||
*
|
||||
* Prozessvariante 1:
|
||||
*
|
||||
* TAN-Prozess=1:
|
||||
* Im ersten Schritt wird der Auftrags-Hashwert über den Geschäftsvorfall HKTAN mitgeteilt, im
|
||||
* zweiten Schritt erfolgt nach Ermittlung der TAN aus der zurückgemeldeten Challenge die
|
||||
* Einreichung des eigentlichen Auftrags inklusive der TAN über das normale Auftragssegment.
|
||||
* Abfolge der Segmente am Beispiel HKCCS:
|
||||
* 1. Schritt: HKTAN <-> HITAN
|
||||
* 2. Schritt: HKCCS <-> HIRMS zu HKCCS
|
||||
*
|
||||
* Prozessvariante 2:
|
||||
* Im ersten Schritt wird der Auftrag komplett über das normale Auftragssegment eingereicht,
|
||||
* jedoch ohne Übermittlung der TAN. Im zweiten Schritt erfolgt nach Ermittlung der TAN aus
|
||||
* der zurückgemeldeten Challenge die Einreichung der TAN über den Geschäftsvorfall HKTAN.
|
||||
* Abfolge der Segmente am Beispiel HKCCS:
|
||||
* Schritt 1: HKCCS und HKTAN HITAN
|
||||
* Schritt 2: HKTAN HITAN und HIRMS zu HICCS
|
||||
*
|
||||
* TAN-Prozess=2:
|
||||
* kann nur im zweiten Schritt auftreten. Er dient zur Übermittlung der TAN mittels HKTAN,
|
||||
* nachdem der Auftrag selbst zuvor bereits mit TAN-Prozess=3 oder 4 eingereicht wurde.
|
||||
* Dieser Geschäftsvorfall wird mit HITAN, TAN-Prozess=2 beantwortet.
|
||||
*
|
||||
* TAN-Prozess=3:
|
||||
* kann nur im ersten Schritt bei Mehrfach-TANs für die zweite und ggf. dritte TAN auftreten.
|
||||
* Hierdurch wird die Einreichung eingeleitet, wenn zeitversetzte Einreichung von
|
||||
* Mehrfach-TANs erlaubt ist.
|
||||
*
|
||||
* TAN-Prozess=4:
|
||||
* kann nur im ersten Schritt auftreten. Hiermit wird das Zwei-Schritt-Verfahren nach
|
||||
* Prozessvariante 2 für die erste TAN eingeleitet. HKTAN wird zusammen mit dem Auftragssegment
|
||||
* übertragen und durch HITAN mit TAN-Prozess=4 beantwortet. TAN-Prozess=4 wird auch beim
|
||||
* Geschäftsvorfall „Prüfen / Verbrennen von TANs“ eingesetzt.
|
||||
*/
|
||||
open class TANProzessDatenelement(process: TanProcess) : Code(process.code,
|
||||
AllowedValues, Existenzstatus.Mandatory) {
|
||||
|
||||
companion object {
|
||||
val AllowedValues = allCodes<TanProcess>()
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
package net.dankito.fints.messages.datenelemente.implementierte.tan
|
||||
|
||||
import net.dankito.fints.messages.datenelemente.implementierte.ICodeEnum
|
||||
|
||||
|
||||
enum class TanProcess(override val code: String) : ICodeEnum {
|
||||
|
||||
TanProcess1("1"),
|
||||
|
||||
TanProcess2("2"),
|
||||
|
||||
TanProcess3("3"),
|
||||
|
||||
TanProcess4("4"),
|
||||
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
package net.dankito.fints.messages.datenelementgruppen.implementierte.tan
|
||||
|
||||
import net.dankito.fints.messages.Existenzstatus
|
||||
import net.dankito.fints.messages.datenelemente.abgeleiteteformate.Datum
|
||||
import net.dankito.fints.messages.datenelemente.abgeleiteteformate.Uhrzeit
|
||||
import net.dankito.fints.messages.datenelementgruppen.Datenelementgruppe
|
||||
|
||||
|
||||
/**
|
||||
* Datum und Uhrzeit, bis zu welchem Zeitpunkt eine TAN auf Basis der gesendeten Challenge
|
||||
* gültig ist. Nach Ablauf der Gültigkeitsdauer wird die entsprechende TAN entwertet.
|
||||
*/
|
||||
open class GueltigkeitsdatumUndUhrzeitFuerChallenge(date: Int, time: Int)
|
||||
: Datenelementgruppe(listOf(
|
||||
Datum(date, Existenzstatus.Mandatory),
|
||||
Uhrzeit(time, Existenzstatus.Mandatory)
|
||||
), Existenzstatus.Optional)
|
|
@ -0,0 +1,29 @@
|
|||
package net.dankito.fints.messages.segmente.implementierte
|
||||
|
||||
import net.dankito.fints.messages.Existenzstatus
|
||||
import net.dankito.fints.messages.datenelemente.implementierte.NotAllowedDatenelement
|
||||
import net.dankito.fints.messages.datenelemente.implementierte.tan.*
|
||||
import net.dankito.fints.messages.datenelementgruppen.implementierte.Segmentkopf
|
||||
import net.dankito.fints.messages.segmente.Segment
|
||||
|
||||
|
||||
open class ZweiSchrittTanEinreichung(
|
||||
segmentNumber: Int,
|
||||
process: TanProcess,
|
||||
jobReference: String,
|
||||
challenge: String = "",
|
||||
challgendHHD_UC: ByteArray = byteArrayOf(),
|
||||
date: Int? = null,
|
||||
time: Int? = null,
|
||||
tanMediaIdentifier: String? = "N" // TODO: why 'N'?
|
||||
|
||||
) : Segment(listOf(
|
||||
Segmentkopf("HKTAN", 6, segmentNumber),
|
||||
TANProzessDatenelement(process),
|
||||
// AuftragsHashwert(), // M: bei AuftragsHashwertverfahren<>0 und TAN-Prozess=1. N: sonst
|
||||
Auftragsreferenz(jobReference, Existenzstatus.Mandatory), // M: bei TAN-Prozess=2, 3, 4. O: bei TAN-Prozess=1
|
||||
ChallengeVersion3(challenge, Existenzstatus.Mandatory), // M: bei TAN-Prozess=1, 3, 4. O: bei TAN-Prozess=2
|
||||
ChallengeHHD_UC(challgendHHD_UC, Existenzstatus.Optional),
|
||||
NotAllowedDatenelement(), // GueltigkeitsdatumUndUhrzeitFuerChallenge // TODO: how to not write an element if it's optional and its paramters (date and time) are not set?
|
||||
BezeichnungDesTANMediums(tanMediaIdentifier ?: "", Existenzstatus.Optional)// M: bei TAN-Prozess=1, 3, 4 und „Anzahl unterstützter aktiver TAN-Medien“ nicht vorhanden. O: sonst
|
||||
), Existenzstatus.Mandatory)
|
|
@ -78,13 +78,14 @@ class MessageBuilderTest {
|
|||
|
||||
// then
|
||||
assertThat(normalizeBinaryData(result)).isEqualTo(normalizeBinaryData(
|
||||
"HNHBK:1:3+000000000363+300+0+1'" +
|
||||
"HNHBK:1:3+000000000386+300+0+1'" +
|
||||
"HNVSK:998:3+PIN:2+998+1+1::0+1:$Date:$Time+2:16:14:@8@ :5:1+280:$BankCode:$CustomerId:V:0:0+0+'" +
|
||||
"HNVSD:999:1+@198@" + "HNSHK:2:4+PIN:2+${SecurityFunction.code}+$ControlReference+1+1+1::0+1+1:$Date:$Time+1:999:1+6:10:16+280:$BankCode:$CustomerId:S:0:0'" +
|
||||
"HNVSD:999:1+@221@" + "HNSHK:2:4+PIN:2+${SecurityFunction.code}+$ControlReference+1+1+1::0+1+1:$Date:$Time+1:999:1+6:10:16+280:$BankCode:$CustomerId:S:0:0'" +
|
||||
"HKIDN:3:2+280:$BankCode+$CustomerId+0+1'" +
|
||||
"HKVVB:4:3+0+0+${Language.code}+$ProductName+$ProductVersion'" +
|
||||
"HNSHA:5:2+$ControlReference++$Pin''" +
|
||||
"HNHBS:6:1+1'"
|
||||
"HKTAN:5:6+4+HKIDN++++N'" +
|
||||
"HNSHA:6:2+$ControlReference++$Pin''" +
|
||||
"HNHBS:7:1+1'"
|
||||
))
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue