Skip to content

Commit

Permalink
OBG-1234 Allow fintech pass consent
Browse files Browse the repository at this point in the history
  • Loading branch information
max402 committed Jun 15, 2021
1 parent 06f90e9 commit 31b2f7b
Show file tree
Hide file tree
Showing 25 changed files with 462 additions and 88 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,7 @@ paths:
- $ref: "#/components/parameters/Fintech-Redirect-URL-OK"
- $ref: "#/components/parameters/Fintech-Redirect-URL-NOK"
- $ref: "#/components/parameters/LoARetrievalInformation"
- $ref: "#/components/parameters/X-Create-Consent-If-None"
#query
- $ref: "#/components/parameters/withBalance"
- $ref: "#/components/parameters/online"
Expand Down Expand Up @@ -287,21 +288,21 @@ paths:
#path
- $ref: "#/components/parameters/bank-id"
- $ref: "#/components/parameters/account-id"
#query
- $ref: "#/components/parameters/dateFrom"
- $ref: "#/components/parameters/dateTo"
- $ref: "#/components/parameters/entryReferenceFrom"
- $ref: "#/components/parameters/bookingStatus"
- $ref: "#/components/parameters/deltaList"
- $ref: "#/components/parameters/online"

#header
- $ref: "#/components/parameters/X-Request-ID"
- $ref: "#/components/parameters/X-XSRF-TOKEN"
- $ref: "#/components/parameters/X-Psu-Authentication-Required"
- $ref: "#/components/parameters/Fintech-Redirect-URL-OK"
- $ref: "#/components/parameters/Fintech-Redirect-URL-NOK"
- $ref: "#/components/parameters/LoTRetrievalInformation"
- $ref: "#/components/parameters/X-Create-Consent-If-None"
#query
- $ref: "#/components/parameters/dateFrom"
- $ref: "#/components/parameters/dateTo"
- $ref: "#/components/parameters/entryReferenceFrom"
- $ref: "#/components/parameters/bookingStatus"
- $ref: "#/components/parameters/deltaList"
- $ref: "#/components/parameters/online"

security:
- sessionCookie: []
Expand Down Expand Up @@ -606,6 +607,13 @@ components:
- "FROM_TPP_WITH_AVAILABLE_CONSENT"
- "FROM_TPP_WITH_NEW_CONSENT"

X-Create-Consent-If-None:
name: X-Create-Consent-If-None
required: false
in: header
schema:
$ref: "#/components/schemas/aisConsentRequest"

X-Request-ID:
name: X-Request-ID
in: header
Expand Down Expand Up @@ -2007,3 +2015,77 @@ components:
referenceDate:
type: string
format: date

aisAccountAccessInfo:
title: AisAccountAccessInfo
type: object
properties:
accounts:
type: array
description: Access to accounts
items:
$ref: "#/components/schemas/accountReference"
allPsd2:
type: string
description: Consent on all accounts, balances and transactions of psu
example: ALL_ACCOUNTS
enum:
- ALL_ACCOUNTS
- ALL_ACCOUNTS_WITH_BALANCES
availableAccounts:
type: string
description: Consent on all available accounts of psu
example: ALL_ACCOUNTS
enum:
- ALL_ACCOUNTS
- ALL_ACCOUNTS_WITH_BALANCES
balances:
type: array
description: Access to balances
items:
$ref: "#/components/schemas/accountReference"
transactions:
type: array
description: Access to transactions
items:
$ref: "#/components/schemas/accountReference"
description: Ais account access information

aisConsentRequest:
title: AisConsentRequest
required:
- access
- frequencyPerDay
- recurringIndicator
- validUntil
type: object
properties:
access:
$ref: "#/components/schemas/aisAccountAccessInfo"
frequencyPerDay:
type: integer
description:
Maximum frequency for an access per day. For a once-off access,
this attribute is set to 1
format: int32
example: 4
recurringIndicator:
type: boolean
description:
"'true', if the consent is for recurring access to the account
data , 'false', if the consent is for one access to the account data"
example: false
validUntil:
type: string
description:
Consent`s expiration date. The content is the local ASPSP date
in ISODate Format
format: date
example: 2020-10-10
combinedServiceIndicator:
type: boolean
description:
"'true', if the consent is i.e. account list and then payment
'false', if the consent is for one access to the account data"
default: false
description: Ais consent request
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package de.adorsys.opba.fintech.impl.controller;

import de.adorsys.opba.fintech.api.model.generated.AccountList;
import de.adorsys.opba.fintech.api.model.generated.AisConsentRequest;
import de.adorsys.opba.fintech.api.model.generated.TransactionsResponse;
import de.adorsys.opba.fintech.api.resource.generated.FinTechAccountInformationApi;
import de.adorsys.opba.fintech.impl.controller.utils.LoARetrievalInformation;
Expand All @@ -12,6 +13,7 @@
import de.adorsys.opba.fintech.impl.service.TransactionService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.mapstruct.Mapper;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RestController;
Expand All @@ -29,38 +31,42 @@ public class FinTechAccountInformationImpl implements FinTechAccountInformationA
private final AccountService accountService;
private final TransactionService transactionService;
private final ConsentService consentService;
private final AisConsentRequestMapper consenRequestMapper;

@Override
public ResponseEntity<AccountList> aisAccountsGET(String bankId, UUID xRequestID, String xsrfToken,
String fintechRedirectURLOK, String fintechRedirectURLNOK,
String loARetrievalInformation,
Boolean xPsuAuthenticationRequired, Boolean withBalance,
Boolean online) {
String loARetrievalInformation, Boolean xPsuAuthenticationRequired,
AisConsentRequest createConsentIfNone, Boolean withBalance, Boolean online) {
if (!sessionLogicService.isSessionAuthorized()) {
log.warn("aisAccountsGET failed: user is not authorized!");
return new ResponseEntity<>(HttpStatus.UNAUTHORIZED);
}

SessionEntity sessionEntity = sessionLogicService.getSession();
return sessionLogicService.addSessionMaxAgeToHeader(accountService.listAccounts(sessionEntity,
fintechRedirectURLOK, fintechRedirectURLNOK, bankId, LoARetrievalInformation.valueOf(loARetrievalInformation), withBalance, xPsuAuthenticationRequired, online));
return sessionLogicService.addSessionMaxAgeToHeader(
accountService.listAccounts(sessionEntity, fintechRedirectURLOK, fintechRedirectURLNOK,
bankId, LoARetrievalInformation.valueOf(loARetrievalInformation),
consenRequestMapper.map(createConsentIfNone), withBalance, xPsuAuthenticationRequired, online));
}

@Override
public ResponseEntity<TransactionsResponse> aisTransactionsGET(String bankId, String accountId, UUID xRequestID,
String xsrfToken, String fintechRedirectURLOK, String fintechRedirectURLNOK,
String loTRetrievalInformation,
LocalDate dateFrom, LocalDate dateTo,
String entryReferenceFrom, String bookingStatus, Boolean deltaList,
Boolean online, Boolean xPsuAuthenticationRequired) {
Boolean xPsuAuthenticationRequired, AisConsentRequest createConsentIfNone,
LocalDate dateFrom, LocalDate dateTo, String entryReferenceFrom, String bookingStatus,
Boolean deltaList, Boolean online) {
if (!sessionLogicService.isSessionAuthorized()) {
log.warn("aisTransactionsGET failed: user is not authorized!");
return new ResponseEntity<>(HttpStatus.UNAUTHORIZED);
}
SessionEntity sessionEntity = sessionLogicService.getSession();
return sessionLogicService.addSessionMaxAgeToHeader(
transactionService.listTransactions(sessionEntity, fintechRedirectURLOK, fintechRedirectURLNOK,
bankId, accountId, dateFrom, dateTo, entryReferenceFrom, bookingStatus, deltaList, LoTRetrievalInformation.valueOf(loTRetrievalInformation), xPsuAuthenticationRequired, online));
transactionService.listTransactions(sessionEntity, fintechRedirectURLOK, fintechRedirectURLNOK,
bankId, accountId, consenRequestMapper.map(createConsentIfNone), dateFrom, dateTo,
entryReferenceFrom, bookingStatus, deltaList,
LoTRetrievalInformation.valueOf(loTRetrievalInformation), xPsuAuthenticationRequired, online));
}

@Override
Expand All @@ -69,4 +75,9 @@ public ResponseEntity<Object> aisConsentsDELETE(String bankId, UUID xRequestID,
consentService.deleteAllConsentsOfBank(sessionEntity, bankId);
return ResponseEntity.ok().body(Map.of());
}

@Mapper(componentModel = "spring", implementationPackage = "de.adorsys.opba.fintech.impl.mapper.generated")
public interface AisConsentRequestMapper {
de.adorsys.opba.tpp.ais.api.model.generated.AisConsentRequest map(AisConsentRequest aisConsentRequest);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,15 @@
import de.adorsys.opba.fintech.impl.tppclients.AisErrorDecoder;
import de.adorsys.opba.fintech.impl.tppclients.ConsentType;
import de.adorsys.opba.fintech.impl.tppclients.TppAisClient;
import de.adorsys.opba.tpp.banksearch.api.model.generated.BankProfileResponse;
import de.adorsys.opba.tpp.ais.api.model.generated.AisConsentRequest;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;

import java.util.Map;
import java.util.Optional;
import java.util.UUID;

Expand All @@ -45,13 +46,14 @@ public class AccountService {

public ResponseEntity listAccounts(SessionEntity sessionEntity,
String fintechOkUrl, String fintechNOKUrl,
String bankId, LoARetrievalInformation loARetrievalInformation, boolean withBalance, Boolean psuAuthenticationRequired, Boolean online) {
String bankId, LoARetrievalInformation loARetrievalInformation, AisConsentRequest createConsentIfNone,
boolean withBalance, Boolean psuAuthenticationRequired, Boolean online) {

log.info("List of accounts {} with balance {}", loARetrievalInformation, withBalance);
final String fintechRedirectCode = UUID.randomUUID().toString();

try {
ResponseEntity accounts = readOpbaResponse(bankId, sessionEntity, fintechRedirectCode, loARetrievalInformation, withBalance, psuAuthenticationRequired, online);
ResponseEntity accounts = readOpbaResponse(bankId, sessionEntity, fintechRedirectCode, loARetrievalInformation, createConsentIfNone, withBalance, psuAuthenticationRequired, online);

switch (accounts.getStatusCode()) {
case OK:
Expand All @@ -68,14 +70,14 @@ public ResponseEntity listAccounts(SessionEntity sessionEntity,
} catch (ConsentException consentException) {
HttpHeaders headers = new HttpHeaders();
headers.add(AisErrorDecoder.X_ERROR_CODE, consentException.getXErrorCode());
return new ResponseEntity(headers, HttpStatus.valueOf(consentException.getHttpResponseCode()));
return new ResponseEntity<>(headers, HttpStatus.valueOf(consentException.getHttpResponseCode()));
}
}


private ResponseEntity readOpbaResponse(String bankID, SessionEntity sessionEntity, String redirectCode,
LoARetrievalInformation loARetrievalInformation, boolean withBalance,
Boolean psuAuthenticationRequired, Boolean online) {
LoARetrievalInformation loARetrievalInformation, AisConsentRequest createConsentIfNone,
boolean withBalance, Boolean psuAuthenticationRequired, Boolean online) {
UUID xRequestId = UUID.fromString(restRequestContext.getRequestId());
Optional<ConsentEntity> optionalConsent = Optional.empty();
if (loARetrievalInformation.equals(LoARetrievalInformation.FROM_TPP_WITH_AVAILABLE_CONSENT)) {
Expand All @@ -88,21 +90,20 @@ private ResponseEntity readOpbaResponse(String bankID, SessionEntity sessionEnti
optionalConsent.get().getUserEntity().getLoginUserName(),
optionalConsent.get().getBankId(),
optionalConsent.get().getCreationTime());
return consentAvailable(bankID, sessionEntity, redirectCode, xRequestId, optionalConsent, withBalance, psuAuthenticationRequired, online);
return consentAvailable(bankID, sessionEntity, redirectCode, xRequestId, optionalConsent, createConsentIfNone, withBalance, psuAuthenticationRequired, online);
}

BankProfileResponse bankProfile = searchService.getBankProfileById(bankID).getBody();
if (null != bankProfile.getBankProfileDescriptor().getConsentSupportByService()
&& "true".equals(bankProfile.getBankProfileDescriptor().getConsentSupportByService().get(Actions.LIST_ACCOUNTS.name()))) {
Map<String, String> consentSupportByService = searchService.getBankProfileById(bankID).getBody().getBankProfileDescriptor().getConsentSupportByService();
if (null != consentSupportByService && "true".equals(consentSupportByService.get(Actions.LIST_ACCOUNTS.name()))) {
log.info("LoA no valid ais consent for user {} bank {} available", sessionEntity.getUserEntity().getLoginUserName(), bankID);
return consentNotYetAvailable(bankID, sessionEntity, redirectCode, xRequestId, psuAuthenticationRequired, optionalConsent, withBalance, online);
return consentNotYetAvailable(bankID, sessionEntity, redirectCode, xRequestId, psuAuthenticationRequired, optionalConsent, withBalance, online, createConsentIfNone);
}

return consentAvailable(bankID, sessionEntity, redirectCode, xRequestId, optionalConsent, withBalance, psuAuthenticationRequired, online);
return consentAvailable(bankID, sessionEntity, redirectCode, xRequestId, optionalConsent, createConsentIfNone, withBalance, psuAuthenticationRequired, online);
}

private ResponseEntity consentAvailable(String bankID, SessionEntity sessionEntity, String redirectCode,
UUID xRequestId, Optional<ConsentEntity> optionalConsent, boolean withBalance,
UUID xRequestId, Optional<ConsentEntity> optionalConsent, AisConsentRequest createConsentIfNone, boolean withBalance,
Boolean psuAuthenticationRequired, Boolean online) {
log.info("do LOA for bank {} {} consent", bankID, optionalConsent.isPresent() ? "with" : "without");
UUID serviceSessionID = optionalConsent.map(ConsentEntity::getTppServiceSessionId).orElse(null);
Expand All @@ -118,13 +119,14 @@ private ResponseEntity consentAvailable(String bankID, SessionEntity sessionEnti
bankID,
psuAuthenticationRequired,
serviceSessionID,
createConsentIfNone,
withBalance,
online);
}

private ResponseEntity consentNotYetAvailable(String bankID, SessionEntity sessionEntity, String redirectCode, UUID xRequestId,
Boolean psuAuthenticationRequired, Optional<ConsentEntity> optionalConsent,
boolean withBalance, Boolean online) {
boolean withBalance, Boolean online, AisConsentRequest createConsentIfNone) {
log.info("do LOT (instead of loa) for bank {} {} consent", bankID, optionalConsent.isPresent() ? "with" : "without");
UUID serviceSessionID = optionalConsent.map(ConsentEntity::getTppServiceSessionId).orElse(null);
var response = tppAisClient.getTransactionsWithoutAccountId(
Expand All @@ -139,6 +141,7 @@ private ResponseEntity consentNotYetAvailable(String bankID, SessionEntity sessi
bankID,
psuAuthenticationRequired,
serviceSessionID,
createConsentIfNone,
null,
null,
null,
Expand All @@ -157,6 +160,7 @@ private ResponseEntity consentNotYetAvailable(String bankID, SessionEntity sessi
redirectCode,
UUID.randomUUID(),
optionalConsent,
createConsentIfNone,
withBalance,
psuAuthenticationRequired,
online
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import de.adorsys.opba.fintech.impl.properties.TppProperties;
import de.adorsys.opba.fintech.impl.tppclients.ConsentType;
import de.adorsys.opba.fintech.impl.tppclients.TppAisClient;
import de.adorsys.opba.tpp.ais.api.model.generated.AisConsentRequest;
import de.adorsys.opba.tpp.ais.api.model.generated.TransactionsResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
Expand Down Expand Up @@ -42,7 +43,7 @@ public class TransactionService {

@SuppressWarnings("checkstyle:MethodLength") // FIXME - It is just too many lines of text
public ResponseEntity listTransactions(SessionEntity sessionEntity, String fintechOkUrl, String fintechNOkUrl, String bankId,
String accountId, LocalDate dateFrom, LocalDate dateTo, String entryReferenceFrom,
String accountId, AisConsentRequest createConsentIfNone, LocalDate dateFrom, LocalDate dateTo, String entryReferenceFrom,
String bookingStatus, Boolean deltaList, LoTRetrievalInformation loTRetrievalInformation,
Boolean psuAuthenticationRequired, Boolean online) {
log.info("LoT {}", loTRetrievalInformation);
Expand Down Expand Up @@ -71,6 +72,7 @@ public ResponseEntity listTransactions(SessionEntity sessionEntity, String finte
bankId,
psuAuthenticationRequired,
optionalConsent.map(ConsentEntity::getTppServiceSessionId).orElse(null),
createConsentIfNone,
dateFrom,
dateTo,
entryReferenceFrom,
Expand Down
Loading

0 comments on commit 31b2f7b

Please sign in to comment.