Implemented initializing dialog without strong customer authentication (but HKTAN is sent anyway) which is required that is essential for authenticated dialogs, e.g. TAN media which require some banks to be able to initialize an authenticated dialog

This commit is contained in:
dankito 2020-08-12 14:48:42 +02:00
parent 7146ec3a3c
commit 4cbbbfbe48
2 changed files with 101 additions and 22 deletions

View File

@ -10,6 +10,7 @@ import net.dankito.banking.fints.messages.datenelemente.implementierte.Kundensys
import net.dankito.banking.fints.messages.datenelemente.implementierte.signatur.Sicherheitsfunktion
import net.dankito.banking.fints.messages.datenelemente.implementierte.signatur.VersionDesSicherheitsverfahrens
import net.dankito.banking.fints.messages.datenelemente.implementierte.tan.*
import net.dankito.banking.fints.messages.segmente.id.CustomerSegmentId
import net.dankito.banking.fints.model.*
import net.dankito.banking.fints.response.GetUserTanProceduresResponse
import net.dankito.banking.fints.response.InstituteSegmentId
@ -446,9 +447,14 @@ open class FinTsClient(
open fun getTanMediaList(bank: BankData, customer: CustomerData, tanMediaKind: TanMedienArtVersion = TanMedienArtVersion.Alle,
tanMediumClass: TanMediumKlasse = TanMediumKlasse.AlleMedien, callback: (GetTanMediaListResponse) -> Unit) {
sendMessageAndHandleResponse(bank, customer, true, { dialogContext ->
sendMessageAndHandleResponse(bank, customer, true, CustomerSegmentId.TanMediaList, { dialogContext ->
messageBuilder.createGetTanMediaListMessage(dialogContext, tanMediaKind, tanMediumClass)
}) { response ->
handleGetTanMediaListResponse(response, customer, callback)
}
}
private fun handleGetTanMediaListResponse(response: Response, customer: CustomerData, callback: (GetTanMediaListResponse) -> Unit) {
// TAN media list (= TAN generator list) is only returned for users with chipTAN TAN procedures
val tanMediaList = if (response.successful == false) null
else response.getFirstSegmentById<TanMediaList>(InstituteSegmentId.TanMediaList)
@ -459,7 +465,6 @@ open class FinTsClient(
callback(GetTanMediaListResponse(response, tanMediaList))
}
}
open fun changeTanMedium(newActiveTanMedium: TanGeneratorTanMedium, bank: BankData, customer: CustomerData, callback: (FinTsClientResponse) -> Unit) {
@ -483,7 +488,7 @@ open class FinTsClient(
protected open fun sendChangeTanMediumMessage(bank: BankData, customer: CustomerData, newActiveTanMedium: TanGeneratorTanMedium,
enteredAtc: EnterTanGeneratorAtcResult?, callback: (FinTsClientResponse) -> Unit) {
sendMessageAndHandleResponse(bank, customer, false, { dialogContext ->
sendMessageAndHandleResponse(bank, customer, false, null, { dialogContext ->
messageBuilder.createChangeTanMediumMessage(newActiveTanMedium, dialogContext, enteredAtc?.tan, enteredAtc?.atc)
}) { response ->
callback(FinTsClientResponse(response))
@ -494,7 +499,7 @@ open class FinTsClient(
open fun doBankTransferAsync(bankTransferData: BankTransferData, bank: BankData,
customer: CustomerData, account: AccountData, callback: (FinTsClientResponse) -> Unit) {
sendMessageAndHandleResponse(bank, customer, true, { dialogContext ->
sendMessageAndHandleResponse(bank, customer, true, null, { dialogContext ->
messageBuilder.createBankTransferMessage(bankTransferData, account, dialogContext)
}) { response ->
callback(FinTsClientResponse(response))
@ -503,11 +508,25 @@ open class FinTsClient(
protected open fun sendMessageAndHandleResponse(bank: BankData, customer: CustomerData, messageMayRequiresTan: Boolean = true,
segmentForNonStrongCustomerAuthenticationTwoStepTanProcess: CustomerSegmentId? = null,
createMessage: (DialogContext) -> MessageBuilderResult, callback: (Response) -> Unit) {
val dialogContext = DialogContext(bank, customer, product)
if (segmentForNonStrongCustomerAuthenticationTwoStepTanProcess == null) {
initDialog(dialogContext) { initDialogResponse ->
sendMessageAndHandleResponseAfterDialogInitialization(dialogContext, initDialogResponse, createMessage, callback)
}
}
else {
initInitDialogMessageWithoutStrongCustomerAuthenticationAfterSuccessfulChecks(dialogContext, segmentForNonStrongCustomerAuthenticationTwoStepTanProcess) { initDialogResponse ->
sendMessageAndHandleResponseAfterDialogInitialization(dialogContext, initDialogResponse, createMessage, callback)
}
}
}
private fun sendMessageAndHandleResponseAfterDialogInitialization(dialogContext: DialogContext, initDialogResponse: Response, createMessage: (DialogContext) -> MessageBuilderResult, callback: (Response) -> Unit) {
if (initDialogResponse.successful == false) {
callback(initDialogResponse)
}
@ -521,7 +540,6 @@ open class FinTsClient(
}
}
}
}
protected open fun initDialog(dialogContext: DialogContext, callback: (Response) -> Unit) {
@ -561,6 +579,21 @@ open class FinTsClient(
}
}
protected open fun initInitDialogMessageWithoutStrongCustomerAuthenticationAfterSuccessfulChecks(dialogContext: DialogContext, segmentIdForTwoStepTanProcess: CustomerSegmentId?,
callback: (Response) -> Unit) {
val message = messageBuilder.createInitDialogMessageWithoutStrongCustomerAuthentication(dialogContext, segmentIdForTwoStepTanProcess)
getAndHandleResponseForMessage(message, dialogContext) { response ->
if (response.successful) {
updateBankData(dialogContext.bank, response)
updateCustomerData(dialogContext.customer, dialogContext.bank, response)
}
callback(response)
}
}
protected open fun closeDialog(dialogContext: DialogContext) {
// bank already closed dialog -> there's no need to send dialog end message

View File

@ -66,13 +66,58 @@ open class MessageBuilder(protected val generator: ISegmentNumberGenerator = Seg
open fun createInitDialogMessage(dialogContext: DialogContext): MessageBuilderResult {
return createInitDialogMessage(dialogContext, null)
}
/**
* Im Rahmen der PIN/TAN-Management-Geschäftsvorfälle (vgl. Kapitel C.3) ist in be-
stimmten Situationen eine Einreichung ohne starke Kundenauthentifizierung erfor-
derlich (Authentifizierungsklasse 4, vgl. Kapitel B.3). Daher wird in einem solchen
Fall das Element Segmentkennung in HKTAN ab #6 mit der Segmentkennung des
jeweiligen Geschäftsvorfalls belegt, der dann isoliert in diesem Dialog eingereicht
wird.
(PinTan S. 35)
* Beim Erstzugang mit einem neuen TAN-Verfahren liegt einem Kundenprodukt
ggf. noch keine TAN-Medien-Bezeichnung für dieses Verfahren vor. In diesem
Fall muss der Geschäftsvorfall Anzeige der verfügbaren TAN-Medien
(HKTAB) ohne starke Kundenauthentifizierung durchführbar sein. (..)
In das DE Segmentkennung in HKTAN wird der Wert HKTAB eingestellt.
Der vom Kundenprodukt hier als Füllwert gelieferte Inhalt des
Elementes Bezeichnung des TAN-Mediums in HKTAN ist vom
Kreditinstitut in dieser Situation zu ignorieren. (..)
Anschließend hat das Kundensystem den Dialog durch Senden einer
Dialogendenachricht (HKEND) zu beenden.
Zweiter Dialog Starke Kundenauthentifizierung
o Nun wird unter Verwendung eines zugelassenen TAN-Verfahrens
und TAN-Mediums ein zweiter Dialog zum Durchführen einer starken
Kundenauthentifizierung eröffnet. Die SCA ist obligatorisch, da es
sich um die erste Nutzung dieses TAN-Verfahrens inkl. des gewähl-
ten TAN-Mediums handelt.
o Im Rahmen dieses Dialoges können nach erfolgreicher Durchführung
der starken Kundenauthentifizierung beliebige Geschäftsvorfälle
durchgeführt werden.
(PinTan S. 37/38)
*/
open fun createInitDialogMessageWithoutStrongCustomerAuthentication(dialogContext: DialogContext, segmentIdForTwoStepTanProcess: CustomerSegmentId?): MessageBuilderResult {
return createInitDialogMessage(dialogContext, segmentIdForTwoStepTanProcess)
}
protected open fun createInitDialogMessage(dialogContext: DialogContext, segmentIdForTwoStepTanProcess: CustomerSegmentId?): MessageBuilderResult {
val segments = mutableListOf(
IdentifikationsSegment(generator.resetSegmentNumber(2), dialogContext),
Verarbeitungsvorbereitung(generator.getNextSegmentNumber(), dialogContext)
)
if (dialogContext.customer.isTanProcedureSelected) {
if (segmentIdForTwoStepTanProcess != null) {
segments.add(ZweiSchrittTanEinreichung(generator.getNextSegmentNumber(), TanProcess.TanProcess4, segmentIdForTwoStepTanProcess))
}
else if (dialogContext.customer.isTanProcedureSelected) {
segments.add(ZweiSchrittTanEinreichung(generator.getNextSegmentNumber(), TanProcess.TanProcess4, CustomerSegmentId.Identification))
}
@ -175,6 +220,7 @@ open class MessageBuilder(protected val generator: ISegmentNumberGenerator = Seg
return result
}
// TODO: no HKTAN needed?
open fun createChangeTanMediumMessage(newActiveTanMedium: TanGeneratorTanMedium, dialogContext: DialogContext,
tan: String? = null, atc: Int? = null): MessageBuilderResult {