Skip to content

Commit

Permalink
Bugfix/redirect before start (#1233)
Browse files Browse the repository at this point in the history
* Fixed redirects before consent auth start

* Set approach from init call

* Use special redirection handler

* Use special redirection handler

* Fixes for payment redirection

* Fixed typo

* Refactored consent handling

* Refactored consent handling

* Remove object mapper

* Remove object mapper

* Remove unnecessary classes

* Fixed wrong transaction listing bean

* Separate support for skipping start consent authorization

* Disable test profiles
  • Loading branch information
valb3r committed May 13, 2021
1 parent abcba51 commit 748c8e4
Show file tree
Hide file tree
Showing 22 changed files with 28,673 additions and 28,499 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -71,3 +71,6 @@ docs_for_site
jgiven-reports
logs
site/

# Disable test profiles
opba-embedded-starter/src/main/resources/test-profiles/
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ public class BankProfile implements Serializable, CurrentBankProfile {
private Approach preferredApproach;
private boolean tryToUsePreferredApproach;
private boolean uniquePaymentPurpose;
private boolean xs2aSkipConsentAuthorization;

@OneToMany(mappedBy = "bankProfile", cascade = CascadeType.ALL, orphanRemoval = true)
@MapKey(name = "protocolAction")
Expand Down
1 change: 1 addition & 0 deletions opba-db/src/main/resources/migration/master.xml
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,5 @@
<include relativeToChangelogFile="true" file="migrations/0001-init-protocol-facade.xml"/>
<include relativeToChangelogFile="true" file="migrations/0002-mock-data.xml"/>
<include relativeToChangelogFile="true" file="migrations/0003-add-staging-bank-configuration.xml"/>
<include relativeToChangelogFile="true" file="migrations/0004-add-skip-auth-for-deutsche-bank.xml"/>
</databaseChangeLog>
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@
<column name="try_to_use_preferred_approach" type="BOOLEAN" defaultValue="false">
<constraints nullable="false"/>
</column>
<column name="xs2a_skip_consent_authorization" type="BOOLEAN" defaultValue="false">
<constraints nullable="false"/>
</column>
<column name="unique_payment_purpose" type="BOOLEAN" defaultValue="false">
<constraints nullable="false"/>
</column>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<databaseChangeLog logicalFilePath="db.changelog-1.0.xml" xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.8.xsd">

<changeSet author="vbeex@adorsys.com.ua" id="2021-05-12-23">
<comment>Updates xs2a_skip_consent_authorization for DeutscheBank</comment>
<update tableName="${table-prefix}bank_profile">
<column name="xs2a_skip_consent_authorization" value="true"/>
<where>
adapter_id = 'deutsche-bank-adapter'
</where>
</update>
</changeSet>

</databaseChangeLog>
49,742 changes: 24,871 additions & 24,871 deletions opba-db/src/main/resources/migration/migrations/bank_action_data.csv

Large diffs are not rendered by default.

7,106 changes: 3,553 additions & 3,553 deletions opba-db/src/main/resources/migration/migrations/bank_profile_data.csv

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ private void writeXs2aBankActionData(String bankRecord) {
int authorizationId;

writelnToFile(BANK_ACTION_DESTINATION_PATH, String.format("%d,%s,LIST_ACCOUNTS,xs2aListAccounts,true", bankActionId++, bankUUID));
writelnToFile(BANK_ACTION_DESTINATION_PATH, String.format("%d,%s,LIST_TRANSACTIONS,xs2aSandboxListTransactions,true", bankActionId++, bankUUID));
writelnToFile(BANK_ACTION_DESTINATION_PATH, String.format("%d,%s,LIST_TRANSACTIONS,xs2aListTransactions,true", bankActionId++, bankUUID));
writelnToFile(BANK_ACTION_DESTINATION_PATH, String.format("%d,%s,AUTHORIZATION,,true", authorizationId = bankActionId++, bankUUID));
writelnToFile(BANK_ACTION_DESTINATION_PATH, String.format("%d,%s,SINGLE_PAYMENT,xs2aInitiateSinglePayment,true", bankActionId++, bankUUID));
writelnToFile(BANK_ACTION_DESTINATION_PATH, String.format("%d,%s,GET_PAYMENT_INFORMATION,xs2aGetPaymentInfoState,true", bankActionId++, bankUUID));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,11 @@ public interface CurrentBankProfile {
*/
boolean isUniquePaymentPurpose();

/**
* Whether to try to skip call to ConsentAuthorization action (startAuthorization)
*/
boolean isXs2aSkipConsentAuthorization();

/**
* Bank identification code.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,16 @@

import com.google.common.collect.ImmutableSet;
import de.adorsys.opba.protocol.bpmnshared.dto.messages.ProcessError;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.flowable.common.engine.api.delegate.event.FlowableEngineEntityEvent;
import org.flowable.common.engine.api.delegate.event.FlowableExceptionEvent;
import org.flowable.engine.delegate.event.AbstractFlowableEngineEventListener;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.ReflectionUtils;

import java.lang.reflect.InvocationTargetException;

import static org.flowable.common.engine.api.delegate.event.FlowableEngineEventType.JOB_EXECUTION_FAILURE;
import static org.flowable.common.engine.api.delegate.event.FlowableEngineEventType.PROCESS_COMPLETED_WITH_ERROR_END_EVENT;
Expand All @@ -33,9 +37,12 @@ protected void processCompletedWithErrorEnd(FlowableEngineEntityEvent event) {
handleError(event);
}

@SneakyThrows
private void handleError(FlowableEngineEntityEvent event) {
if (event instanceof FlowableExceptionEvent) {
log.error("Exception occurred for execution {} of process {}", event.getExecutionId(), event.getProcessInstanceId(), ((FlowableExceptionEvent) event).getCause());
var cause = ((FlowableExceptionEvent) event).getCause();
log.error("Exception occurred for execution {} of process {}", event.getExecutionId(), event.getProcessInstanceId(), cause);
handleXs2aAdapterError(cause);
}

ProcessError result = ProcessError.builder()
Expand All @@ -47,6 +54,15 @@ private void handleError(FlowableEngineEntityEvent event) {
applicationEventPublisher.publishEvent(result);
}

private void handleXs2aAdapterError(Throwable cause) throws IllegalAccessException, InvocationTargetException {
if (null != cause) {
var method = ReflectionUtils.findMethod(cause.getClass(), "getStatusCode");
if (null != method) {
log.error("Response status code: {}", method.invoke(cause));
}
}
}

private String exceptionMessage(FlowableEngineEntityEvent event) {
if (event instanceof FlowableExceptionEvent) {
return "An exception occurred";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,14 @@

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.google.common.collect.ImmutableMap;
import de.adorsys.opba.protocol.api.common.Approach;
import de.adorsys.opba.protocol.api.common.ProtocolAction;
import de.adorsys.opba.protocol.bpmnshared.dto.context.BaseContext;
import de.adorsys.opba.protocol.api.common.Approach;
import de.adorsys.opba.protocol.xs2a.domain.dto.forms.ScaMethod;
import de.adorsys.opba.protocol.xs2a.service.storage.TransientDataEntry;
import de.adorsys.xs2a.adapter.api.model.AuthenticationObject;
import de.adorsys.xs2a.adapter.api.model.ChallengeData;
import de.adorsys.xs2a.adapter.api.model.HrefType;
import de.adorsys.xs2a.adapter.api.model.StartScaprocessResponse;
import de.adorsys.xs2a.adapter.api.model.TokenResponse;
import lombok.Data;
Expand Down Expand Up @@ -57,6 +58,11 @@ public class Xs2aContext extends BaseContext {
*/
private String aspspScaApproach;

/**
* Consent/Payment create links response from ASPSP.
*/
private Map<String, HrefType> consentOrPaymentCreateLinks;

/**
* ASPSP response after consent authorization was initiated. Used to retrieve ASPSP redirection link for
* consent authorization for REDIRECT consent authorization.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
@RequiredArgsConstructor
public class Xs2aDoScaRedirectToAspspForScaChallenge extends ValidatedExecution<Xs2aContext> {

public static final String SCA_REDIRECT = "scaRedirect";

private final ProtocolUrlsConfiguration urlsConfiguration;
private final RuntimeService runtimeService;
private final Xs2aRedirectExecutor redirectExecutor;
Expand All @@ -33,7 +35,7 @@ protected void doRealExecution(DelegateExecution execution, Xs2aContext context)
execution,
context,
urlSet.getToAspsp(),
context.getStartScaProcessResponse().getLinks().get("scaRedirect").getHref(),
getRedirectToAspspUrl(context),
redirect -> new RedirectToAspsp(redirect.build())
);
}
Expand All @@ -44,4 +46,8 @@ protected void doMockedExecution(DelegateExecution execution, Xs2aContext contex

runtimeService.trigger(execution.getId());
}

protected String getRedirectToAspspUrl(Xs2aContext context) {
return context.getStartScaProcessResponse().getLinks().get(SCA_REDIRECT).getHref();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package de.adorsys.opba.protocol.xs2a.service.xs2a.authenticate.redirect;

import de.adorsys.opba.protocol.xs2a.config.protocol.ProtocolUrlsConfiguration;
import de.adorsys.opba.protocol.xs2a.context.Xs2aContext;
import de.adorsys.opba.protocol.xs2a.service.xs2a.Xs2aRedirectExecutor;
import org.flowable.engine.RuntimeService;
import org.springframework.stereotype.Service;

/**
* Performs redirection to the ASPSP by sending him to the page with redirection button (to ASPSP) for the redirect approach.
* But is specific as happens just after consent was created.
*/
@Service("xs2aDoScaRedirectToAspspForScaChallengeAfterCreate")
public class Xs2aDoScaRedirectToAspspForScaChallengeAfterCreate extends Xs2aDoScaRedirectToAspspForScaChallenge {

public Xs2aDoScaRedirectToAspspForScaChallengeAfterCreate(ProtocolUrlsConfiguration urlsConfiguration, RuntimeService runtimeService, Xs2aRedirectExecutor redirectExecutor) {
super(urlsConfiguration, runtimeService, redirectExecutor);
}

@Override
protected String getRedirectToAspspUrl(Xs2aContext context) {
return context.getConsentOrPaymentCreateLinks().get(SCA_REDIRECT).getHref();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package de.adorsys.opba.protocol.xs2a.service.xs2a.consent;

import de.adorsys.opba.protocol.bpmnshared.service.exec.ValidatedExecution;
import de.adorsys.opba.protocol.xs2a.context.Xs2aContext;
import de.adorsys.opba.protocol.xs2a.util.logresolver.Xs2aLogResolver;
import de.adorsys.xs2a.adapter.api.Response;
import de.adorsys.xs2a.adapter.api.model.ConsentsResponse201;
import org.apache.logging.log4j.util.Strings;
import org.flowable.engine.delegate.DelegateExecution;

import java.util.UUID;

import static de.adorsys.opba.protocol.bpmnshared.GlobalConst.CONTEXT;
import static de.adorsys.xs2a.adapter.api.ResponseHeaders.ASPSP_SCA_APPROACH;
import static de.adorsys.xs2a.adapter.impl.link.bg.template.LinksTemplate.SCA_OAUTH;

public abstract class BaseCreateAisConsentService<T extends Xs2aContext> extends ValidatedExecution<T> {

protected final Xs2aLogResolver logResolver = new Xs2aLogResolver(getClass());

@Override
protected void doMockedExecution(DelegateExecution execution, T context) {
logResolver.log("doMockedExecution: execution ({}) with context ({})", execution, context);

context.setConsentId("MOCK-" + UUID.randomUUID().toString());
execution.setVariable(CONTEXT, context);
}

protected void postHandleCreatedConsent(Response<ConsentsResponse201> consentInit, DelegateExecution execution, Xs2aContext context) {
context.setWrongAuthCredentials(false);
context.setConsentId(consentInit.getBody().getConsentId());
if (null != consentInit.getBody().getLinks() && consentInit.getBody().getLinks().containsKey(SCA_OAUTH)) {
context.setOauth2IntegratedNeeded(true);
context.setScaOauth2Link(consentInit.getBody().getLinks().get(SCA_OAUTH).getHref());
}

if (null != consentInit.getHeaders() && Strings.isNotBlank(consentInit.getHeaders().getHeader(ASPSP_SCA_APPROACH))) {
context.setAspspScaApproach(consentInit.getHeaders().getHeader(ASPSP_SCA_APPROACH));
if (null != consentInit.getBody()) {
context.setConsentOrPaymentCreateLinks(consentInit.getBody().getLinks());
}
}

execution.setVariable(CONTEXT, context);
}
}
Original file line number Diff line number Diff line change
@@ -1,23 +1,19 @@
package de.adorsys.opba.protocol.xs2a.service.xs2a.consent;

import de.adorsys.opba.protocol.bpmnshared.service.context.ContextUtil;
import de.adorsys.opba.protocol.bpmnshared.service.exec.ValidatedExecution;
import de.adorsys.opba.protocol.xs2a.config.protocol.ProtocolUrlsConfiguration;
import de.adorsys.opba.protocol.xs2a.context.ais.AccountListXs2aContext;
import de.adorsys.opba.protocol.xs2a.service.dto.ValidatedPathHeadersBody;
import de.adorsys.opba.protocol.xs2a.service.xs2a.dto.consent.ConsentInitiateHeaders;
import de.adorsys.opba.protocol.xs2a.service.xs2a.dto.consent.ConsentInitiateParameters;
import de.adorsys.opba.protocol.xs2a.service.xs2a.validation.Xs2aValidator;
import de.adorsys.opba.protocol.xs2a.util.logresolver.Xs2aLogResolver;
import de.adorsys.xs2a.adapter.api.AccountInformationService;
import de.adorsys.xs2a.adapter.api.model.Consents;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.flowable.engine.delegate.DelegateExecution;
import org.springframework.stereotype.Service;

import java.util.UUID;

import static de.adorsys.opba.protocol.xs2a.constant.GlobalConst.CONTEXT;

/**
Expand All @@ -27,15 +23,14 @@
@Slf4j
@Service("xs2aAccountListConsentInitiate")
@RequiredArgsConstructor
public class CreateAisAccountListConsentService extends ValidatedExecution<AccountListXs2aContext> {
public class CreateAisAccountListConsentService extends BaseCreateAisConsentService<AccountListXs2aContext> {

private final AisConsentInitiateExtractor extractor;
private final AccountInformationService ais;
private final Xs2aValidator validator;
private final ProtocolUrlsConfiguration urlsConfiguration;
private final CreateConsentOrPaymentPossibleErrorHandler handler;
private final CreateAisConsentService createAisConsentService;
private final Xs2aLogResolver logResolver = new Xs2aLogResolver(getClass());

@Override
protected void doPrepareContext(DelegateExecution execution, AccountListXs2aContext context) {
Expand All @@ -59,14 +54,13 @@ protected void doRealExecution(DelegateExecution execution, AccountListXs2aConte
logResolver.log("doRealExecution: execution ({}) with context ({})", execution, context);

ValidatedPathHeadersBody<ConsentInitiateParameters, ConsentInitiateHeaders, Consents> params = extractor.forExecution(context);
handler.tryCreateAndHandleErrors(execution, () -> createAisConsentService.createConsent(ais, execution, context, params));
}

@Override
protected void doMockedExecution(DelegateExecution execution, AccountListXs2aContext context) {
logResolver.log("doMockedExecution: execution ({}) with context ({})", execution, context);
var result = handler.tryCreateAndHandleErrors(execution, () -> createAisConsentService.createConsent(ais, context, params));
if (null == result) {
execution.setVariable(CONTEXT, context);
log.warn("Consent creation failed");
return;
}

context.setConsentId("MOCK-" + UUID.randomUUID().toString());
execution.setVariable(CONTEXT, context);
postHandleCreatedConsent(result, execution, context);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,8 @@
import de.adorsys.xs2a.adapter.api.Response;
import de.adorsys.xs2a.adapter.api.model.Consents;
import de.adorsys.xs2a.adapter.api.model.ConsentsResponse201;
import org.flowable.engine.delegate.DelegateExecution;
import org.springframework.stereotype.Service;

import static de.adorsys.opba.protocol.xs2a.constant.GlobalConst.CONTEXT;
import static de.adorsys.xs2a.adapter.impl.link.bg.template.LinksTemplate.SCA_OAUTH;

/**
* Calls Xs2a API to initiate AIS consent.
*/
Expand All @@ -24,9 +20,8 @@ public class CreateAisConsentService {

private final Xs2aLogResolver logResolver = new Xs2aLogResolver(getClass());

void createConsent(
Response<ConsentsResponse201> createConsent(
AccountInformationService ais,
DelegateExecution execution,
Xs2aAisContext context,
ValidatedPathHeadersBody<ConsentInitiateParameters, ConsentInitiateHeaders, Consents> params) {
logResolver.log("createConsent with parameters: {}", params.getPath(), params.getHeaders(), params.getBody());
Expand All @@ -36,13 +31,6 @@ void createConsent(
params.getBody()
);
logResolver.log("createConsent response: {}", consentInit);

context.setWrongAuthCredentials(false);
context.setConsentId(consentInit.getBody().getConsentId());
if (null != consentInit.getBody().getLinks() && consentInit.getBody().getLinks().containsKey(SCA_OAUTH)) {
context.setOauth2IntegratedNeeded(true);
context.setScaOauth2Link(consentInit.getBody().getLinks().get(SCA_OAUTH).getHref());
}
execution.setVariable(CONTEXT, context);
return consentInit;
}
}

0 comments on commit 748c8e4

Please sign in to comment.