de.adorsys.multibanking.hbci.job.TransactionAuthorisationJob Maven / Gradle / Ivy
The newest version!
/*
* Copyright 2018-2019 adorsys GmbH & Co KG
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.adorsys.multibanking.hbci.job;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import de.adorsys.multibanking.domain.ScaStatus;
import de.adorsys.multibanking.domain.exception.MultibankingException;
import de.adorsys.multibanking.domain.response.AbstractResponse;
import de.adorsys.multibanking.domain.response.TransactionAuthorisationResponse;
import de.adorsys.multibanking.domain.transaction.AbstractPayment;
import de.adorsys.multibanking.domain.transaction.AbstractTransaction;
import de.adorsys.multibanking.domain.transaction.TransactionAuthorisation;
import de.adorsys.multibanking.hbci.model.HbciConsent;
import de.adorsys.multibanking.hbci.model.HbciDialogFactory;
import de.adorsys.multibanking.hbci.model.HbciPassport;
import de.adorsys.multibanking.hbci.model.HbciTanSubmit;
import de.adorsys.multibanking.hbci.util.HbciErrorUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.kapott.hbci.GV.AbstractHBCIJob;
import org.kapott.hbci.GV.GVTAN2Step;
import org.kapott.hbci.callback.AbstractHBCICallback;
import org.kapott.hbci.dialog.HBCIJobsDialog;
import org.kapott.hbci.manager.KnownTANProcess;
import org.kapott.hbci.status.HBCIExecStatus;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import static de.adorsys.multibanking.domain.ScaStatus.FINALISED;
import static de.adorsys.multibanking.domain.ScaStatus.SCAMETHODSELECTED;
import static de.adorsys.multibanking.domain.exception.MultibankingError.INTERNAL_ERROR;
@Slf4j
public class TransactionAuthorisationJob {
private static final ObjectMapper objectMapper = new ObjectMapper()
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
.findAndRegisterModules();
private final ScaAwareJob scaJob;
private final TransactionAuthorisation transactionAuthorisation;
private final HbciConsent consent;
private final HBCIJobsDialog hbciDialog;
public TransactionAuthorisationJob(ScaAwareJob scaJob, TransactionAuthorisation transactionAuthorisation) {
this.scaJob = scaJob;
this.transactionAuthorisation = transactionAuthorisation;
consent = (HbciConsent) transactionAuthorisation.getOriginTransactionRequest().getBankApiConsentData();
scaJob.hbciTanSubmit = evaluateTanSubmit();
hbciDialog = new HBCIJobsDialog(createPassport(), scaJob.hbciTanSubmit.getDialogId(),
scaJob.hbciTanSubmit.getMsgNum());
scaJob.dialog = hbciDialog;
}
public TransactionAuthorisationResponse execute() {
if (scaJob.hbciTanSubmit.getTwoStepMechanism().getProcess() == 1)
submitProcess1();
else
submitProcess2();
HBCIExecStatus hbciExecStatus = hbciDialog.execute(false);
if (!hbciExecStatus.isOK()) {
if (consent.isCloseDialog()) {
hbciDialog.dialogEnd();
}
throw HbciErrorUtils.toMultibankingException(hbciExecStatus.getMsgStatusList());
}
if (StringUtils.equals("HKIDN", scaJob.hbciTanSubmit.getHbciJobName())) {
if (!hbciExecStatus.getMsgStatusList().isEmpty()) {
hbciDialog.getPassport().updateUPD(hbciExecStatus.getMsgStatusList().get(0).getData());
}
//sca for dialoginit was needed -> fints consent active, expecting response with exempted sca
TransactionAuthorisationResponse response = new TransactionAuthorisationResponse<>(scaJob.execute(null));
response.setScaStatus(FINALISED);
return response;
} else if (consent.isCloseDialog()) {
hbciDialog.dialogEnd();
}
scaJob.hbciTanSubmit.setMsgNum(scaJob.hbciTanSubmit.getMsgNum() + 1);
return createResponse(hbciExecStatus);
}
private void submitProcess1() {
//1. Schritt: HKTAN <-> HITAN
//2. Schritt: HKUEB <-> HIRMS zu HKUEB
AbstractHBCIJob hbciJob = scaJob.getOrCreateHbciJob();
if (scaJob.hbciTanSubmit.getSepaPain() != null) {
hbciJob.getConstraints().remove("_sepapain"); //prevent pain generation
hbciJob.setLowlevelParam(hbciJob.getName() + ".sepapain", scaJob.hbciTanSubmit.getSepaPain());
}
hbciDialog.addTask(hbciJob);
}
@SuppressWarnings("unchecked")
private void submitProcess2() {
//Schritt 1: HKUEB und HKTAN <-> HITAN
//Schritt 2: HKTAN <-> HITAN und HIRMS zu HIUEB
AbstractHBCIJob originJob = Optional.ofNullable(scaJob.hbciTanSubmit.getOriginJobName())
.map(originJobName -> {
AbstractHBCIJob hbciJob = scaJob.getOrCreateHbciJob();
try {
hbciJob.setLlParams(objectMapper.readValue(scaJob.hbciTanSubmit.getLowLevelParams(), HashMap.class));
} catch (Exception e) {
log.error(e.getMessage(), e);
throw new MultibankingException(INTERNAL_ERROR, 500, e.getMessage());
}
hbciJob.setSegVersion(scaJob.hbciTanSubmit.getOriginSegVersion());
return hbciJob;
}).orElse(null);
GVTAN2Step hktan = new GVTAN2Step(hbciDialog.getPassport(), originJob);
hktan.setSegVersion(scaJob.hbciTanSubmit.getTwoStepMechanism().getSegversion());
hktan.setProcess(KnownTANProcess.PROCESS2_STEP2);
Optional.ofNullable(scaJob.hbciTanSubmit.getHbciJobName())
.ifPresent(hbciSegCode -> hktan.setParam("ordersegcode", hbciSegCode));
hktan.setVeu(scaJob.hbciTanSubmit.isVeu());
hktan.setParam("orderref", scaJob.hbciTanSubmit.getOrderRef());
hktan.setParam("process", scaJob.hbciTanSubmit.getHktanProcess() != null ? scaJob.hbciTanSubmit.getHktanProcess() : "2");
hktan.setParam("notlasttan", "N");
hbciDialog.addTask(hktan, false);
}
private TransactionAuthorisationResponse createResponse(HBCIExecStatus hbciExecStatus) {
R jobResponse = scaJob.createJobResponse();
jobResponse.setMessages(HbciErrorUtils.msgStatusListToMessages(hbciExecStatus.getMsgStatusList()));
TransactionAuthorisationResponse response = new TransactionAuthorisationResponse<>(jobResponse);
//HKIDN -> FINALISED -> further request like HKCAZ already executed
ScaStatus scaStatus = Optional.ofNullable(scaJob.hbciTanSubmit.getHbciJobName())
.map(hbciJobName -> hbciJobName.equals("HKIDN") || scaJob.transactionRequest.getTransaction() instanceof AbstractPayment)
.map(finalised -> Boolean.TRUE.equals(finalised) ? FINALISED : SCAMETHODSELECTED)
.orElse(FINALISED);
response.setScaStatus(scaStatus);
return response;
}
private HbciTanSubmit evaluateTanSubmit() {
if (consent.getHbciTanSubmit() instanceof HbciTanSubmit) {
return (HbciTanSubmit) consent.getHbciTanSubmit();
} else {
return deserializeTanSubmit((byte[]) consent.getHbciTanSubmit());
}
}
private HbciTanSubmit deserializeTanSubmit(byte[] data) {
try {
return objectMapper.readValue(data, HbciTanSubmit.class);
} catch (Exception e) {
throw new IllegalStateException("Could not deserialize HbciTanSubmit", e);
}
}
private HbciPassport createPassport() {
Map bpd =
Optional.ofNullable(scaJob.getHbciBpdCacheHolder().getBpd(transactionAuthorisation.getOriginTransactionRequest()))
.orElseGet(() -> scaJob.fetchBpd(null).getBPD());
HbciPassport.State state = HbciPassport.State.fromJson(scaJob.hbciTanSubmit.getPassportState());
HbciPassport passport = HbciDialogFactory.createPassport(state,
new AbstractHBCICallback() {
@Override
public String needTAN() {
return ((HbciConsent) transactionAuthorisation.getOriginTransactionRequest().getBankApiConsentData()).getScaAuthenticationData();
}
});
state.apply(passport);
HbciConsent hbciConsent =
(HbciConsent) transactionAuthorisation.getOriginTransactionRequest().getBankApiConsentData();
passport.setPIN(hbciConsent.getCredentials().getPin());
passport.setCurrentSecMechInfo(scaJob.hbciTanSubmit.getTwoStepMechanism());
passport.setBPD(bpd);
return passport;
}
}