mirror of
https://github.com/OpenBankProject/OBP-API.git
synced 2026-02-06 16:56:56 +00:00
commit
3dcb585bad
@ -80,8 +80,13 @@
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.bouncycastle</groupId>
|
||||
<artifactId>bcpg-jdk16</artifactId>
|
||||
<version>1.46</version>
|
||||
<artifactId>bcpg-jdk15on</artifactId>
|
||||
<version>1.47</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.bouncycastle</groupId>
|
||||
<artifactId>bcpkix-jdk15on</artifactId>
|
||||
<version>1.62</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.postgresql</groupId>
|
||||
|
||||
@ -313,6 +313,10 @@ webui_api_documentation_url = https://github.com/OpenBankProject/OBP-API/wiki
|
||||
# We currently use this to display example customer login in sandbox etc.
|
||||
webui_login_page_special_instructions=
|
||||
|
||||
# To display the introduction page for sandbox.It supports the markdown format.It will show the introduction OBP-API home
|
||||
# page `INTRODUCTION` page and also for Glossary `Sandbox Introduction`.
|
||||
webui_sandbox_introduction=
|
||||
|
||||
# Link for SDKs
|
||||
webui_sdks_url = https://github.com/OpenBankProject/OBP-API/wiki/OAuth-Client-SDKS
|
||||
|
||||
|
||||
@ -691,7 +691,7 @@ where the consent was directly managed between ASPSP and PSU e.g. in a re-direct
|
||||
(Full(u), callContext) <- authorizedAccess(cc)
|
||||
_ <- passesPsd2Aisp(callContext)
|
||||
consent <- Future(Consents.consentProvider.vend.getConsentByConsentId(consentId)) map {
|
||||
i => connectorEmptyResponse(i, callContext)
|
||||
unboxFullOrFail(_, callContext, s"$ConsentNotFound ($consentId)")
|
||||
}
|
||||
} yield {
|
||||
(createGetConsentResponseJson(consent), HttpCode.`200`(callContext))
|
||||
@ -735,7 +735,7 @@ This method returns the SCA status of a consent initiation's authorisation sub-r
|
||||
(_, callContext) <- authorizedAccess(cc)
|
||||
_ <- passesPsd2Aisp(callContext)
|
||||
_ <- Future(Consents.consentProvider.vend.getConsentByConsentId(consentId)) map {
|
||||
unboxFullOrFail(_, callContext, ConsentNotFound)
|
||||
unboxFullOrFail(_, callContext, s"$ConsentNotFound ($consentId)")
|
||||
}
|
||||
authorisation <- Future(Authorisations.authorisationProvider.vend.getAuthorizationByAuthorizationId(
|
||||
authorisationId
|
||||
@ -788,16 +788,17 @@ This method returns the SCA status of a consent initiation's authorisation sub-r
|
||||
getTransactionDetails,
|
||||
apiVersion,
|
||||
nameOf(getTransactionDetails),
|
||||
"GET",
|
||||
"/accounts/ACCOUNT_ID/transactions/RESOURCEID",
|
||||
"GET",
|
||||
"/accounts/ACCOUNT_ID/transactions/TRANSACTIONID",
|
||||
"Read Transaction Details",
|
||||
s"""${mockedDataText(true)}
|
||||
Reads transaction details from a given transaction addressed by "resourceId" on a given account addressed by "account-id".
|
||||
This call is only available on transactions as reported in a JSON format.
|
||||
Reads transaction details from a given transaction addressed by "transactionId" on a given account addressed
|
||||
by "account-id". This call is only available on transactions as reported in a JSON format.
|
||||
|
||||
**Remark:** Please note that the PATH might be already given in detail by the corresponding entry of the response
|
||||
of the "Read Transaction List" call within the _links subfield.
|
||||
|
||||
**Remark:** Please note that the PATH might be already given in detail by the corresponding entry of the response of the
|
||||
"Read Transaction List" call within the _links subfield.
|
||||
""",
|
||||
""",
|
||||
json.parse(""""""),
|
||||
json.parse("""{
|
||||
"debtorAccount" : {
|
||||
@ -819,8 +820,8 @@ This call is only available on transactions as reported in a JSON format.
|
||||
"valueDate" : "2000-01-23",
|
||||
"endToEndId" : "endToEndId",
|
||||
"transactionId" : "transactionId",
|
||||
"currencyExchange" : "",
|
||||
"ultimateDebtor" : "Ultimate Debtor",
|
||||
"exchangeRate" : "",
|
||||
"creditorAccount" : {
|
||||
"bban" : "BARC12345612345678",
|
||||
"maskedPan" : "123456xxxxxx1234",
|
||||
@ -837,7 +838,7 @@ This call is only available on transactions as reported in a JSON format.
|
||||
},
|
||||
"proprietaryBankTransactionCode" : { },
|
||||
"bookingDate" : { },
|
||||
"remittanceInformationUnstructured" : "remittanceInformationUnstructured",
|
||||
"remittanceInformationUnstructured" : "Ref Number Merchant",
|
||||
"checkId" : "checkId",
|
||||
"creditorId" : "creditorId",
|
||||
"entryReference" : "entryReference"
|
||||
@ -848,7 +849,7 @@ This call is only available on transactions as reported in a JSON format.
|
||||
)
|
||||
|
||||
lazy val getTransactionDetails : OBPEndpoint = {
|
||||
case "accounts" :: account_id:: "transactions" :: resourceid :: Nil JsonGet _ => {
|
||||
case "accounts" :: account_id:: "transactions" :: transactionid :: Nil JsonGet _ => {
|
||||
cc =>
|
||||
for {
|
||||
(Full(u), callContext) <- authorizedAccess(cc)
|
||||
@ -873,8 +874,8 @@ This call is only available on transactions as reported in a JSON format.
|
||||
"valueDate" : "2000-01-23",
|
||||
"endToEndId" : "endToEndId",
|
||||
"transactionId" : "transactionId",
|
||||
"currencyExchange" : "",
|
||||
"ultimateDebtor" : "Ultimate Debtor",
|
||||
"exchangeRate" : "",
|
||||
"creditorAccount" : {
|
||||
"bban" : "BARC12345612345678",
|
||||
"maskedPan" : "123456xxxxxx1234",
|
||||
@ -891,7 +892,7 @@ This call is only available on transactions as reported in a JSON format.
|
||||
},
|
||||
"proprietaryBankTransactionCode" : { },
|
||||
"bookingDate" : { },
|
||||
"remittanceInformationUnstructured" : "remittanceInformationUnstructured",
|
||||
"remittanceInformationUnstructured" : "Ref Number Merchant",
|
||||
"checkId" : "checkId",
|
||||
"creditorId" : "creditorId",
|
||||
"entryReference" : "entryReference"
|
||||
@ -899,7 +900,7 @@ This call is only available on transactions as reported in a JSON format.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
resourceDocs += ResourceDoc(
|
||||
getTransactionList,
|
||||
apiVersion,
|
||||
@ -908,11 +909,12 @@ This call is only available on transactions as reported in a JSON format.
|
||||
"/accounts/ACCOUNT_ID/transactions",
|
||||
"Read transaction list of an account",
|
||||
s"""${mockedDataText(false)}
|
||||
Read transaction reports or transaction lists of a given account ddressed by "account-id", depending on the steering parameter "bookingStatus" together with balances.
|
||||
Read transaction reports or transaction lists of a given account ddressed by "account-id",
|
||||
depending on the steering parameter "bookingStatus" together with balances.
|
||||
For a given account, additional parameters are e.g. the attributes "dateFrom" and "dateTo".
|
||||
The ASPSP might add balance information, if transaction lists without balances are not supported.
|
||||
|
||||
For a given account, additional parameters are e.g. the attributes "dateFrom" and "dateTo".
|
||||
The ASPSP might add balance information, if transaction lists without balances are not supported.
|
||||
""",
|
||||
""",
|
||||
json.parse(""""""),
|
||||
json.parse("""{
|
||||
"account": {
|
||||
@ -966,7 +968,7 @@ The ASPSP might add balance information, if transaction lists without balances a
|
||||
],
|
||||
"_links": {
|
||||
"account": {
|
||||
"href": "/v1.3/accounts/3dc3d5b3-7023-4848-9853- f5400a64e80f"
|
||||
"href": "/v1.3/accounts/3dc3d5b3-7023-4848-9853-f5400a64e80f"
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1020,19 +1022,14 @@ The ASPSP might add balance information, if transaction lists without balances a
|
||||
"/accounts/ACCOUNT_ID",
|
||||
"Read Account Details",
|
||||
s"""${mockedDataText(true)}
|
||||
Reads details about an account, with balances where required.
|
||||
It is assumed that a consent of the PSU to
|
||||
this access is already given and stored on the ASPSP system.
|
||||
The addressed details of this account depends then on the stored consent addressed by consentId,
|
||||
respectively the OAuth2 access token.
|
||||
Reads details about an account, with balances where required.
|
||||
It is assumed that a consent of the PSU to this access is already given and stored on the ASPSP system.
|
||||
The addressed details of this account depends then on the stored consent addressed by consentId,
|
||||
respectively the OAuth2 access token. **NOTE:** The account-id can represent a multicurrency account.
|
||||
In this case the currency code is set to "XXX". Give detailed information about the addressed account.
|
||||
Give detailed information about the addressed account together with balance information
|
||||
|
||||
**NOTE:** The account-id can represent a multicurrency account.
|
||||
In this case the currency code is set to "XXX".
|
||||
|
||||
Give detailed information about the addressed account.
|
||||
|
||||
Give detailed information about the addressed account together with balance information
|
||||
""",
|
||||
""",
|
||||
json.parse(""""""),
|
||||
json.parse("""{
|
||||
"cashAccountType" : { },
|
||||
@ -1097,12 +1094,12 @@ Give detailed information about the addressed account together with balance info
|
||||
"/card-accounts/ACCOUNT_ID",
|
||||
"Reads details about a card account",
|
||||
s"""${mockedDataText(true)}
|
||||
Reads details about a card account.
|
||||
It is assumed that a consent of the PSU to this access is already given
|
||||
and stored on the ASPSP system. The addressed details of this account depends
|
||||
then on the stored consent addressed by consentId, respectively the OAuth2
|
||||
access token.
|
||||
""",
|
||||
Reads details about a card account.
|
||||
It is assumed that a consent of the PSU to this access is already given and stored on the ASPSP system.
|
||||
The addressed details of this account depends then on the stored consent addressed by consentId,
|
||||
respectively the OAuth2 access token.
|
||||
|
||||
""",
|
||||
json.parse(""""""),
|
||||
json.parse("""{
|
||||
"balances" : "",
|
||||
@ -1156,7 +1153,7 @@ access token.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
resourceDocs += ResourceDoc(
|
||||
startConsentAuthorisation,
|
||||
apiVersion,
|
||||
@ -1165,38 +1162,33 @@ access token.
|
||||
"/consents/CONSENTID/authorisations",
|
||||
"Start the authorisation process for a consent",
|
||||
s"""${mockedDataText(false)}
|
||||
Create an authorisation sub-resource and start the authorisation process of a consent.
|
||||
The message might in addition transmit authentication and authorisation related data.
|
||||
Create an authorisation sub-resource and start the authorisation process of a consent.
|
||||
The message might in addition transmit authentication and authorisation related data.
|
||||
his method is iterated n times for a n times SCA authorisation in a corporate context,
|
||||
each creating an own authorisation sub-endpoint for the corresponding PSU authorising the consent.
|
||||
The ASPSP might make the usage of this access method unnecessary, since the related authorisation
|
||||
resource will be automatically created by the ASPSP after the submission of the consent data with the
|
||||
first POST consents call. The start authorisation process is a process which is needed for creating
|
||||
a new authorisation or cancellation sub-resource.
|
||||
|
||||
This applies in the following scenarios: * The ASPSP has indicated with an 'startAuthorisation' hyperlink
|
||||
in the preceding Payment Initiation Response that an explicit start of the authorisation process is needed by the TPP.
|
||||
The 'startAuthorisation' hyperlink can transport more information about data which needs to be uploaded by using
|
||||
the extended forms.
|
||||
* 'startAuthorisationWithPsuIdentfication',
|
||||
* 'startAuthorisationWithPsuAuthentication'
|
||||
* 'startAuthorisationWithEncryptedPsuAuthentication'
|
||||
* 'startAuthorisationWithAuthentciationMethodSelection'
|
||||
* The related payment initiation cannot yet be executed since a multilevel SCA is mandated.
|
||||
* The ASPSP has indicated with an 'startAuthorisation' hyperlink in the preceding Payment Cancellation
|
||||
Response that an explicit start of the authorisation process is needed by the TPP.
|
||||
|
||||
The 'startAuthorisation' hyperlink can transport more information about data which needs to be uploaded by
|
||||
using the extended forms as indicated above.
|
||||
* The related payment cancellation request cannot be applied yet since a multilevel SCA is mandate for executing the cancellation.
|
||||
* The signing basket needs to be authorised yet.
|
||||
|
||||
his method is iterated n times for a n times SCA authorisation in a
|
||||
corporate context, each creating an own authorisation sub-endpoint for
|
||||
the corresponding PSU authorising the consent.
|
||||
|
||||
The ASPSP might make the usage of this access method unnecessary,
|
||||
since the related authorisation resource will be automatically created by
|
||||
the ASPSP after the submission of the consent data with the first POST consents call.
|
||||
|
||||
The start authorisation process is a process which is needed for creating a new authorisation
|
||||
or cancellation sub-resource.
|
||||
|
||||
This applies in the following scenarios:
|
||||
|
||||
* The ASPSP has indicated with an 'startAuthorisation' hyperlink in the preceeding Payment
|
||||
Initiation Response that an explicit start of the authorisation process is needed by the TPP.
|
||||
The 'startAuthorisation' hyperlink can transport more information about data which needs to be
|
||||
uploaded by using the extended forms.
|
||||
* 'startAuthorisationWithPsuIdentfication',
|
||||
* 'startAuthorisationWithPsuAuthentication' #TODO
|
||||
* 'startAuthorisationWithAuthentciationMethodSelection'
|
||||
* The related payment initiation cannot yet be executed since a multilevel SCA is mandated.
|
||||
* The ASPSP has indicated with an 'startAuthorisation' hyperlink in the preceeding
|
||||
Payment Cancellation Response that an explicit start of the authorisation process is needed by the TPP.
|
||||
The 'startAuthorisation' hyperlink can transport more information about data which needs to be uploaded
|
||||
by using the extended forms as indicated above.
|
||||
* The related payment cancellation request cannot be applied yet since a multilevel SCA is mandate for
|
||||
executing the cancellation.
|
||||
* The signing basket needs to be authorised yet.
|
||||
""",
|
||||
""",
|
||||
json.parse(""""""),
|
||||
json.parse("""{
|
||||
"scaStatus": "received",
|
||||
@ -1244,47 +1236,32 @@ This applies in the following scenarios:
|
||||
"/consents/CONSENTID/authorisations/AUTHORISATIONID",
|
||||
"Update PSU Data for consents",
|
||||
s"""${mockedDataText(false)}
|
||||
This method update PSU data on the consents resource if needed.
|
||||
It may authorise a consent within the Embedded SCA Approach where needed.
|
||||
This method update PSU data on the consents resource if needed. It may authorise a consent within the Embedded
|
||||
SCA Approach where needed. Independently from the SCA Approach it supports
|
||||
e.g. the selection of the authentication method and a non-SCA PSU authentication.
|
||||
This methods updates PSU data on the cancellation authorisation resource if needed.
|
||||
There are several possible Update PSU Data requests in the context of a consent request if needed,
|
||||
which depends on the SCA approach: * Redirect SCA Approach: A specific Update PSU Data Request is applicable
|
||||
for
|
||||
* the selection of authentication methods, before choosing the actual SCA approach.
|
||||
* Decoupled SCA Approach: A specific Update PSU Data Request is only applicable for
|
||||
* adding the PSU Identification, if not provided yet in the Payment Initiation Request or the Account Information Consent Request,
|
||||
or if no OAuth2 access token is used, or
|
||||
* the selection of authentication methods.
|
||||
* Embedded SCA Approach: The Update PSU Data Request might be used
|
||||
* to add credentials as a first factor authentication data of the PSU and
|
||||
* to select the authentication method and
|
||||
* transaction authorisation.
|
||||
The SCA Approach might depend on the chosen SCA method. For that reason,
|
||||
the following possible Update PSU Data request can apply to all SCA approaches:
|
||||
* Select an SCA method in case of several SCA methods are available for the customer. There are the following request types on this access path:
|
||||
* Update PSU Identification * Update PSU Authentication
|
||||
* Select PSU Autorization Method WARNING: This method need a reduced header, therefore many optional elements are not present.
|
||||
Maybe in a later version the access path will change.
|
||||
* Transaction Authorisation WARNING: This method need a reduced header, therefore many optional elements are not present.
|
||||
Maybe in a later version the access path will change.
|
||||
|
||||
Independently from the SCA Approach it supports e.g. the selection of
|
||||
the authentication method and a non-SCA PSU authentication.
|
||||
|
||||
This methods updates PSU data on the cancellation authorisation resource if needed.
|
||||
|
||||
There are several possible Update PSU Data requests in the context of a consent request if needed,
|
||||
which depends on the SCA approach:
|
||||
|
||||
* Redirect SCA Approach:
|
||||
A specific Update PSU Data Request is applicable for
|
||||
* the selection of authentication methods, before choosing the actual SCA approach.
|
||||
* Decoupled SCA Approach:
|
||||
A specific Update PSU Data Request is only applicable for
|
||||
* adding the PSU Identification, if not provided yet in the Payment Initiation Request or the Account Information Consent Request, or if no OAuth2 access token is used, or
|
||||
* the selection of authentication methods.
|
||||
* Embedded SCA Approach:
|
||||
The Update PSU Data Request might be used
|
||||
* to add credentials as a first factor authentication data of the PSU and
|
||||
* to select the authentication method and
|
||||
* transaction authorisation.
|
||||
|
||||
The SCA Approach might depend on the chosen SCA method.
|
||||
For that reason, the following possible Update PSU Data request can apply to all SCA approaches:
|
||||
|
||||
* Select an SCA method in case of several SCA methods are available for the customer.
|
||||
|
||||
There are the following request types on this access path:
|
||||
* Update PSU Identification
|
||||
* Update PSU Authentication
|
||||
* Select PSU Autorization Method
|
||||
WARNING: This method need a reduced header,
|
||||
therefore many optional elements are not present.
|
||||
Maybe in a later version the access path will change.
|
||||
* Transaction Authorisation
|
||||
WARNING: This method need a reduced header,
|
||||
therefore many optional elements are not present.
|
||||
Maybe in a later version the access path will change.
|
||||
""",
|
||||
""",
|
||||
json.parse("""{
|
||||
"access": {"accounts": []},
|
||||
"recurringIndicator": false,
|
||||
@ -1292,7 +1269,7 @@ There are the following request types on this access path:
|
||||
"frequencyPerDay": 4,
|
||||
"combinedServiceIndicator": false
|
||||
}"""),
|
||||
json.parse(""""""""),
|
||||
json.parse(""""""),
|
||||
List(UserNotLoggedIn, UnknownError),
|
||||
Catalogs(notCore, notPSD2, notOBWG),
|
||||
ApiTag("Account Information Service (AIS)") :: apiTagBerlinGroupM :: Nil
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -42,9 +42,11 @@ object APIMethods_ConfirmationOfFundsServicePIISApi extends RestHelper {
|
||||
"POST",
|
||||
"/funds-confirmations",
|
||||
"Confirmation of Funds Request",
|
||||
s"""
|
||||
Creates a confirmation of funds request at the ASPSP. Checks whether a specific amount is available at point of
|
||||
time of the request on an account linked to a given tuple card issuer(TPP)/card number, or addressed by IBAN and TPP respectively""",
|
||||
s""" ${mockedDataText(false)}
|
||||
Creates a confirmation of funds request at the ASPSP. Checks whether a specific amount is available at point
|
||||
of time of the request on an account linked to a given tuple card issuer(TPP)/card number, or addressed by
|
||||
IBAN and TPP respectively. If the related extended services are used a conditional Consent-ID is contained
|
||||
in the header. This field is contained but commented out in this specification. """,
|
||||
json.parse(
|
||||
"""{
|
||||
"instructedAmount" : {
|
||||
|
||||
@ -20,13 +20,15 @@ case class JvalueCaseClass(jvalueToCaseclass: JValue)
|
||||
|
||||
object JSONFactory_BERLIN_GROUP_1_3 extends CustomJsonFormats {
|
||||
|
||||
trait links
|
||||
case class Balances(balances: String) extends links
|
||||
case class Transactions(trasactions: String) extends links
|
||||
case class ViewAccount(viewAccount: String) extends links
|
||||
case class AdditionalProp1(additionalProp1: String) extends links
|
||||
case class AdditionalProp2(additionalProp2: String) extends links
|
||||
case class AdditionalProp3(additionalProp3: String) extends links
|
||||
|
||||
case class LinkHrefJson(
|
||||
href: String
|
||||
)
|
||||
|
||||
case class CoreAccountLinksJsonV13(
|
||||
balances: LinkHrefJson //,
|
||||
// trasactions: LinkHrefJson // These links are only supported, when the corresponding consent has been already granted.
|
||||
)
|
||||
|
||||
case class CoreAccountBalancesJson(
|
||||
balanceAmount:AmountOfMoneyV13 = AmountOfMoneyV13("EUR","123"),
|
||||
@ -49,7 +51,7 @@ object JSONFactory_BERLIN_GROUP_1_3 extends CustomJsonFormats {
|
||||
// usage: String ="PRIV",
|
||||
// details: String ="",
|
||||
balances: CoreAccountBalancesJson,
|
||||
_links: List[links],
|
||||
_links: CoreAccountLinksJsonV13,
|
||||
)
|
||||
|
||||
case class CoreAccountsJsonV13(accounts: List[CoreAccountJsonV13])
|
||||
@ -67,14 +69,14 @@ object JSONFactory_BERLIN_GROUP_1_3 extends CustomJsonFormats {
|
||||
|
||||
)
|
||||
case class FromAccount(
|
||||
iban : String = "FR7612345987650123456789014"
|
||||
iban : String
|
||||
)
|
||||
case class CardBalanceAccount(
|
||||
maskedPan: String,
|
||||
)
|
||||
case class AccountBalancesV13(
|
||||
account:FromAccount= FromAccount(),
|
||||
`balances`: List[AccountBalance] = AccountBalance() :: Nil
|
||||
account:FromAccount,
|
||||
`balances`: List[AccountBalance]
|
||||
)
|
||||
case class TransactionsLinksV13(
|
||||
account: String
|
||||
@ -86,18 +88,9 @@ object JSONFactory_BERLIN_GROUP_1_3 extends CustomJsonFormats {
|
||||
account: LinkHrefJson ,
|
||||
|
||||
)
|
||||
case class ExchangeRateJson(
|
||||
sourceCurrency: String = "EUR",
|
||||
rate: String = "string",
|
||||
unitCurrency: String = "string",
|
||||
targetCurrency: String = "EUR",
|
||||
rateDate: String = "string",
|
||||
rateContract: String = "string"
|
||||
)
|
||||
case class CreditorAccountJson(
|
||||
iban: String,
|
||||
)
|
||||
|
||||
case class TransactionJsonV13(
|
||||
transactionId: String,
|
||||
creditorName: String,
|
||||
@ -200,9 +193,6 @@ object JSONFactory_BERLIN_GROUP_1_3 extends CustomJsonFormats {
|
||||
_links: ScaStatusJsonV13
|
||||
)
|
||||
|
||||
case class LinkHrefJson(
|
||||
href: String
|
||||
)
|
||||
case class InitiatePaymentResponseLinks(
|
||||
scaRedirect: LinkHrefJson,
|
||||
self: LinkHrefJson,
|
||||
@ -253,14 +243,13 @@ object JSONFactory_BERLIN_GROUP_1_3 extends CustomJsonFormats {
|
||||
bban = bBan,
|
||||
currency = x.currency,
|
||||
name = x.label,
|
||||
bic = getBicFromBankId(x.bankId.value),
|
||||
cashAccountType = x.accountType,
|
||||
product = x.accountType,
|
||||
balances = balance,
|
||||
bic = getBicFromBankId(x.bankId.value),
|
||||
_links = Balances(s"/${OBP_BERLIN_GROUP_1_3.version}/accounts/${x.accountId.value}/balances")
|
||||
:: Nil
|
||||
_links = CoreAccountLinksJsonV13(LinkHrefJson(s"/${OBP_BERLIN_GROUP_1_3.version}/accounts/${x.accountId.value}/balances"))
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@ -476,10 +465,10 @@ object JSONFactory_BERLIN_GROUP_1_3 extends CustomJsonFormats {
|
||||
},
|
||||
paymentId = paymentId,
|
||||
_links = InitiatePaymentResponseLinks(
|
||||
scaRedirect = LinkHrefJson("answer transaction request url"),
|
||||
scaRedirect = LinkHrefJson(s"$getServerUrl/otp?flow=payment&paymentService=payments&paymentProduct=sepa_credit_transfers&paymentId=$paymentId"),
|
||||
self = LinkHrefJson(s"/v1.3/payments/sepa-credit-transfers/$paymentId"),
|
||||
status = LinkHrefJson(s"/v1.3/payments/$paymentId/status"),
|
||||
scaStatus = LinkHrefJson(s"/v1.3/payments/$paymentId/authorisations/${paymentId}xx")
|
||||
scaStatus = LinkHrefJson(s"/v1.3/payments/$paymentId/authorisations/${paymentId}")
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@ -63,10 +63,10 @@ object OBP_BERLIN_GROUP_1_3 extends OBPRestHelper with MdcLoggable with ScannedA
|
||||
|
||||
override val allResourceDocs: ArrayBuffer[ResourceDoc] =
|
||||
APIMethods_AccountInformationServiceAISApi.resourceDocs ++
|
||||
APIMethods_ConfirmationOfFundsServicePIISApi.resourceDocs ++
|
||||
APIMethods_PaymentInitiationServicePISApi.resourceDocs ++
|
||||
APIMethods_SigningBasketsApi.resourceDocs ++
|
||||
APIMethods_CommonServicesApi.resourceDocs
|
||||
APIMethods_ConfirmationOfFundsServicePIISApi.resourceDocs ++
|
||||
APIMethods_PaymentInitiationServicePISApi.resourceDocs ++
|
||||
APIMethods_SigningBasketsApi.resourceDocs ++
|
||||
APIMethods_CommonServicesApi.resourceDocs
|
||||
|
||||
private[this] def findResourceDoc(pf: OBPEndpoint): Option[ResourceDoc] = {
|
||||
allResourceDocs.find(_.partialFunction==pf)
|
||||
|
||||
@ -12,6 +12,7 @@ import code.consent.ConsentStatus
|
||||
import code.database.authorisation.Authorisations
|
||||
import code.fx.fx
|
||||
import code.model._
|
||||
import code.transactionrequests.TransactionRequests.TransactionRequestTypes.{TRANSFER_TO_ACCOUNT, TRANSFER_TO_ATM, TRANSFER_TO_PHONE}
|
||||
import code.transactionrequests.TransactionRequests.{PaymentServiceTypes, TransactionRequestTypes}
|
||||
import code.util.Helper
|
||||
import com.github.dwickern.macros.NameOf.nameOf
|
||||
@ -61,19 +62,16 @@ object APIMethods_PaymentInitiationServicePISApi extends RestHelper {
|
||||
"/PAYMENT_SERVICE/PAYMENT_PRODUCT/PAYMENTID",
|
||||
"Payment Cancellation Request",
|
||||
s"""${mockedDataText(true)}
|
||||
This method initiates the cancellation of a payment.
|
||||
Depending on the payment-service, the payment-product and the ASPSP's implementation,
|
||||
this TPP call might be sufficient to cancel a payment.
|
||||
If an authorisation of the payment cancellation is mandated by the ASPSP,
|
||||
a corresponding hyperlink will be contained in the response message.
|
||||
This method initiates the cancellation of a payment. Depending on the payment-service, the payment-product
|
||||
and the ASPSP's implementation, this TPP call might be sufficient to cancel a payment. If an authorisation
|
||||
of the payment cancellation is mandated by the ASPSP, a corresponding hyperlink will be contained in the
|
||||
response message. Cancels the addressed payment with resource identification paymentId if applicable to the
|
||||
payment-service, payment-product and received in product related timelines (e.g. before end of business day
|
||||
for scheduled payments of the last business day before the scheduled execution day). The response to this
|
||||
DELETE command will tell the TPP whether the * access method was rejected * access method was successful,
|
||||
or * access method is generally applicable, but further authorisation processes are needed.
|
||||
|
||||
Cancels the addressed payment with resource identification paymentId if applicable to the payment-service, payment-product and received in product related timelines (e.g. before end of business day for scheduled payments of the last business day before the scheduled execution day).
|
||||
|
||||
The response to this DELETE command will tell the TPP whether the
|
||||
* access method was rejected
|
||||
* access method was successful, or
|
||||
* access method is generally applicable, but further authorisation processes are needed.
|
||||
""",
|
||||
""",
|
||||
json.parse(""""""),
|
||||
json.parse("""{
|
||||
"challengeData" : {
|
||||
@ -82,7 +80,7 @@ The response to this DELETE command will tell the TPP whether the
|
||||
"image" : "image",
|
||||
"imageLink" : "http://example.com/aeiou",
|
||||
"otpFormat" : "characters",
|
||||
"data" : "data"
|
||||
"data" : [ "data", "data" ]
|
||||
},
|
||||
"scaMethods" : "",
|
||||
"_links" : {
|
||||
@ -523,12 +521,12 @@ $additionalInstructions
|
||||
},
|
||||
"creditorName": "70charname"
|
||||
}"""),
|
||||
json.parse("""{
|
||||
json.parse(s"""{
|
||||
"transactionStatus": "RCVD",
|
||||
"paymentId": "1234-wertiq-983",
|
||||
"_links":
|
||||
{
|
||||
"scaRedirect": {"href": "answer transaction request url"},
|
||||
"scaRedirect": {"href": "$getServerUrl/otp?flow=payment&paymentService=payments&paymentProduct=sepa_credit_transfers&paymentId=b0472c21-6cea-4ee0-b036-3e253adb3b0b"},
|
||||
"self": {"href": "/v1.3/payments/sepa-credit-transfers/1234-wertiq-983"},
|
||||
"status": {"href": "/v1.3/payments/1234-wertiq-983/status"},
|
||||
"scaStatus": {"href": "/v1.3/payments/1234-wertiq-983/authorisations/123auth456"}
|
||||
@ -939,7 +937,7 @@ There are the following request types on this access path:
|
||||
""",
|
||||
json.parse("""{"scaAuthenticationData":"12345"}"""),
|
||||
json.parse("""{
|
||||
"scaStatus": "received",
|
||||
"scaStatus": "finalised",
|
||||
"authorisationId": "88695566-6642-46d5-9985-0d824624f507",
|
||||
"psuMessage": "Please check your SMS at a mobile device.",
|
||||
"_links": {
|
||||
@ -955,7 +953,7 @@ There are the following request types on this access path:
|
||||
case paymentService :: paymentProduct :: paymentid:: "authorisations" :: authorisationid :: Nil JsonPut json -> _ => {
|
||||
cc =>
|
||||
for {
|
||||
(_, callContext) <- authorizedAccess(cc)
|
||||
(Full(u), callContext) <- authorizedAccess(cc)
|
||||
_ <- passesPsd2Pisp(callContext)
|
||||
failMsg = s"$InvalidJsonFormat The Json body should be the $UpdatePaymentPsuDataJson "
|
||||
updatePaymentPsuDataJson <- NewStyle.function.tryons(failMsg, 400, callContext) {
|
||||
@ -971,6 +969,22 @@ There are the following request types on this access path:
|
||||
authorisation <- Future(Authorisations.authorisationProvider.vend.checkAnswer(paymentid,authorisationid, updatePaymentPsuDataJson.scaAuthenticationData))map {
|
||||
i => connectorEmptyResponse(i, callContext)
|
||||
}
|
||||
|
||||
//Map obp transacition request id with BerlinGroup PaymentId
|
||||
transactionRequestId = TransactionRequestId(paymentid)
|
||||
|
||||
(existingTransactionRequest, callContext) <- NewStyle.function.getTransactionRequestImpl(transactionRequestId, callContext)
|
||||
|
||||
(fromAccount, callContext) <- NewStyle.function.checkBankAccountExists(
|
||||
BankId(existingTransactionRequest.from.bank_id),
|
||||
AccountId(existingTransactionRequest.from.account_id),
|
||||
callContext
|
||||
)
|
||||
_ <- if(authorisation.scaStatus =="finalised")
|
||||
NewStyle.function.createTransactionAfterChallengeV210(fromAccount, existingTransactionRequest, callContext)
|
||||
else //If it is not `finalised`, just return the `authorisation` back, without any payments
|
||||
Future{true}
|
||||
|
||||
} yield {
|
||||
(JSONFactory_BERLIN_GROUP_1_3.createStartPaymentAuthorisationJson(authorisation), callContext)
|
||||
}
|
||||
|
||||
@ -63,7 +63,7 @@ The resource identifications of these transactions are contained in the payload
|
||||
"image" : "image",
|
||||
"imageLink" : "http://example.com/aeiou",
|
||||
"otpFormat" : "characters",
|
||||
"data" : "data"
|
||||
"data" : [ "data", "data" ]
|
||||
},
|
||||
"scaMethods" : "",
|
||||
"tppMessages" : [ {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,76 +0,0 @@
|
||||
package code.api.berlin.group.v1_3_1
|
||||
|
||||
import code.api.APIFailureNewStyle
|
||||
import code.api.berlin.group.v1_3.JvalueCaseClass
|
||||
import net.liftweb.json
|
||||
import net.liftweb.json._
|
||||
import code.api.util.APIUtil.{defaultBankId, _}
|
||||
import code.api.util.{ApiVersion, NewStyle}
|
||||
import code.api.util.ErrorMessages._
|
||||
import code.api.util.ApiTag._
|
||||
import code.api.util.NewStyle.HttpCode
|
||||
import code.bankconnectors.Connector
|
||||
import code.model._
|
||||
import code.util.Helper
|
||||
import code.views.Views
|
||||
import net.liftweb.common.Full
|
||||
import net.liftweb.http.rest.RestHelper
|
||||
import com.github.dwickern.macros.NameOf.nameOf
|
||||
import scala.collection.immutable.Nil
|
||||
import scala.collection.mutable.ArrayBuffer
|
||||
import scala.concurrent.ExecutionContext.Implicits.global
|
||||
import scala.concurrent.Future
|
||||
import code.api.berlin.group.v1_3_1.JSONFactory_BERLIN_GROUP_1_3_3
|
||||
import code.api.util.ApiTag
|
||||
|
||||
object APIMethods_ConfirmationOfFundsServicePIISApi extends RestHelper {
|
||||
val apiVersion = JSONFactory_BERLIN_GROUP_1_3_3.apiVersion
|
||||
val resourceDocs = ArrayBuffer[ResourceDoc]()
|
||||
val apiRelations = ArrayBuffer[ApiRelation]()
|
||||
protected implicit def JvalueToSuper(what: JValue): JvalueCaseClass = JvalueCaseClass(what)
|
||||
|
||||
val endpoints =
|
||||
checkAvailabilityOfFunds ::
|
||||
Nil
|
||||
|
||||
|
||||
resourceDocs += ResourceDoc(
|
||||
checkAvailabilityOfFunds,
|
||||
apiVersion,
|
||||
nameOf(checkAvailabilityOfFunds),
|
||||
"POST",
|
||||
"/funds-confirmations",
|
||||
"Confirmation of Funds Request",
|
||||
s"""${mockedDataText(true)}
|
||||
Creates a confirmation of funds request at the ASPSP. Checks whether a specific amount is available at point
|
||||
of time of the request on an account linked to a given tuple card issuer(TPP)/card number, or addressed by
|
||||
IBAN and TPP respectively. If the related extended services are used a conditional Consent-ID is contained
|
||||
in the header. This field is contained but commented out in this specification.
|
||||
|
||||
""",
|
||||
json.parse(""""""),
|
||||
json.parse("""{
|
||||
"fundsAvailable" : { }
|
||||
}"""),
|
||||
List(UserNotLoggedIn, UnknownError),
|
||||
Catalogs(notCore, notPSD2, notOBWG),
|
||||
ApiTag("Confirmation of Funds Service (PIIS)") :: apiTagMockedData :: Nil
|
||||
)
|
||||
|
||||
lazy val checkAvailabilityOfFunds : OBPEndpoint = {
|
||||
case "funds-confirmations" :: Nil JsonPost _ => {
|
||||
cc =>
|
||||
for {
|
||||
(Full(u), callContext) <- authorizedAccess(cc, UserNotLoggedIn)
|
||||
} yield {
|
||||
(json.parse("""{
|
||||
"fundsAvailable" : { }
|
||||
}"""), callContext)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -1,85 +0,0 @@
|
||||
/**
|
||||
* Open Bank Project - API
|
||||
* Copyright (C) 2011-2018, TESOBE Ltd
|
||||
**
|
||||
*This program is free software: you can redistribute it and/or modify
|
||||
*it under the terms of the GNU Affero General Public License as published by
|
||||
*the Free Software Foundation, either version 3 of the License, or
|
||||
*(at your option) any later version.
|
||||
**
|
||||
*This program is distributed in the hope that it will be useful,
|
||||
*but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
*MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
*GNU Affero General Public License for more details.
|
||||
**
|
||||
*You should have received a copy of the GNU Affero General Public License
|
||||
*along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
**
|
||||
*Email: contact@tesobe.com
|
||||
*TESOBE Ltd
|
||||
*Osloerstrasse 16/17
|
||||
*Berlin 13359, Germany
|
||||
**
|
||||
*This product includes software developed at
|
||||
*TESOBE (http://www.tesobe.com/)
|
||||
* by
|
||||
*Simon Redfern : simon AT tesobe DOT com
|
||||
*Stefan Bethge : stefan AT tesobe DOT com
|
||||
*Everett Sochowski : everett AT tesobe DOT com
|
||||
*Ayoub Benali: ayoub AT tesobe DOT com
|
||||
*
|
||||
*/
|
||||
package code.api.berlin.group.v1_3_1
|
||||
|
||||
import code.api.OBPRestHelper
|
||||
import code.api.util.APIUtil.{OBPEndpoint, ResourceDoc, getAllowedEndpoints}
|
||||
import code.api.util.{ScannedApiVersion, ScannedApis}
|
||||
import code.util.Helper.MdcLoggable
|
||||
|
||||
//import code.api.berlin.group.v1_3_1.APIMethods_AccountInformationServiceAISApi
|
||||
//import code.api.berlin.group.v1_3_1.APIMethods_CommonServicesApi
|
||||
import code.api.berlin.group.v1_3_1.APIMethods_ConfirmationOfFundsServicePIISApi
|
||||
//import code.api.berlin.group.v1_3_1.APIMethods_PaymentInitiationServicePISApi
|
||||
//import code.api.berlin.group.v1_3_1.APIMethods_SigningBasketsSBSApi
|
||||
|
||||
import scala.collection.mutable.ArrayBuffer
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
This file defines which endpoints from all the versions are available in v1
|
||||
*/
|
||||
object JSONFactory_BERLIN_GROUP_1_3_3 extends OBPRestHelper with MdcLoggable with ScannedApis {
|
||||
//please modify these three parameter if it is not correct.
|
||||
override val apiVersion = ScannedApiVersion("berlin-group", "BG", "v1.3.1")
|
||||
val versionStatus = "DRAFT"
|
||||
|
||||
private[this] val endpoints =
|
||||
APIMethods_AccountInformationServiceAISApi.endpoints ++
|
||||
APIMethods_CommonServicesApi.endpoints ++
|
||||
APIMethods_ConfirmationOfFundsServicePIISApi.endpoints ++
|
||||
APIMethods_PaymentInitiationServicePISApi.endpoints ++
|
||||
APIMethods_SigningBasketsSBSApi.endpoints
|
||||
|
||||
override val allResourceDocs: ArrayBuffer[ResourceDoc] =
|
||||
APIMethods_AccountInformationServiceAISApi.resourceDocs ++
|
||||
APIMethods_CommonServicesApi.resourceDocs ++
|
||||
APIMethods_ConfirmationOfFundsServicePIISApi.resourceDocs ++
|
||||
APIMethods_PaymentInitiationServicePISApi.resourceDocs ++
|
||||
APIMethods_SigningBasketsSBSApi.resourceDocs
|
||||
|
||||
private[this] def findResourceDoc(pf: OBPEndpoint): Option[ResourceDoc] = {
|
||||
allResourceDocs.find(_.partialFunction==pf)
|
||||
}
|
||||
|
||||
// Filter the possible endpoints by the disabled / enabled Props settings and add them together
|
||||
override val routes : List[OBPEndpoint] = getAllowedEndpoints(endpoints, allResourceDocs)
|
||||
|
||||
// Make them available for use!
|
||||
routes.foreach(route => {
|
||||
oauthServe((apiVersion.urlPrefix / version.vDottedApiVersion()).oPrefix{route}, findResourceDoc(route))
|
||||
})
|
||||
|
||||
logger.info(s"version $version has been run! There are ${routes.length} routes.")
|
||||
}
|
||||
@ -1,828 +0,0 @@
|
||||
package code.api.berlin.group.v1_3_1
|
||||
|
||||
import code.api.APIFailureNewStyle
|
||||
import code.api.berlin.group.v1_3.JvalueCaseClass
|
||||
import net.liftweb.json
|
||||
import net.liftweb.json._
|
||||
import code.api.util.APIUtil.{defaultBankId, _}
|
||||
import code.api.util.{ApiVersion, NewStyle}
|
||||
import code.api.util.ErrorMessages._
|
||||
import code.api.util.ApiTag._
|
||||
import code.api.util.NewStyle.HttpCode
|
||||
import code.bankconnectors.Connector
|
||||
import code.model._
|
||||
import code.util.Helper
|
||||
import code.views.Views
|
||||
import net.liftweb.common.Full
|
||||
import net.liftweb.http.rest.RestHelper
|
||||
import com.github.dwickern.macros.NameOf.nameOf
|
||||
import scala.collection.immutable.Nil
|
||||
import scala.collection.mutable.ArrayBuffer
|
||||
import scala.concurrent.ExecutionContext.Implicits.global
|
||||
import scala.concurrent.Future
|
||||
import code.api.berlin.group.v1_3_1.JSONFactory_BERLIN_GROUP_1_3_3
|
||||
import code.api.util.ApiTag
|
||||
|
||||
object APIMethods_PaymentInitiationServicePISApi extends RestHelper {
|
||||
val apiVersion = JSONFactory_BERLIN_GROUP_1_3_3.apiVersion
|
||||
val resourceDocs = ArrayBuffer[ResourceDoc]()
|
||||
val apiRelations = ArrayBuffer[ApiRelation]()
|
||||
protected implicit def JvalueToSuper(what: JValue): JvalueCaseClass = JvalueCaseClass(what)
|
||||
|
||||
val endpoints =
|
||||
cancelPayment ::
|
||||
getPaymentCancellationScaStatus ::
|
||||
getPaymentInformation ::
|
||||
getPaymentInitiationAuthorisation ::
|
||||
getPaymentInitiationCancellationAuthorisationInformation ::
|
||||
getPaymentInitiationScaStatus ::
|
||||
getPaymentInitiationStatus ::
|
||||
initiatePayment ::
|
||||
startPaymentAuthorisation ::
|
||||
startPaymentInitiationCancellationAuthorisation ::
|
||||
updatePaymentCancellationPsuData ::
|
||||
updatePaymentPsuData ::
|
||||
Nil
|
||||
|
||||
|
||||
resourceDocs += ResourceDoc(
|
||||
cancelPayment,
|
||||
apiVersion,
|
||||
nameOf(cancelPayment),
|
||||
"DELETE",
|
||||
"/PAYMENT_SERVICE/PAYMENT_PRODUCT/PAYMENTID",
|
||||
"Payment Cancellation Request",
|
||||
s"""${mockedDataText(true)}
|
||||
This method initiates the cancellation of a payment. Depending on the payment-service, the payment-product
|
||||
and the ASPSP's implementation, this TPP call might be sufficient to cancel a payment. If an authorisation
|
||||
of the payment cancellation is mandated by the ASPSP, a corresponding hyperlink will be contained in the
|
||||
response message. Cancels the addressed payment with resource identification paymentId if applicable to the
|
||||
payment-service, payment-product and received in product related timelines (e.g. before end of business day
|
||||
for scheduled payments of the last business day before the scheduled execution day). The response to this
|
||||
DELETE command will tell the TPP whether the * access method was rejected * access method was successful,
|
||||
or * access method is generally applicable, but further authorisation processes are needed.
|
||||
|
||||
""",
|
||||
json.parse(""""""),
|
||||
json.parse("""{
|
||||
"challengeData" : {
|
||||
"otpMaxLength" : 0,
|
||||
"additionalInformation" : "additionalInformation",
|
||||
"image" : "image",
|
||||
"imageLink" : "http://example.com/aeiou",
|
||||
"otpFormat" : "characters",
|
||||
"data" : [ "data", "data" ]
|
||||
},
|
||||
"scaMethods" : "",
|
||||
"_links" : {
|
||||
"startAuthorisationWithEncryptedPsuAuthentication" : {
|
||||
"href" : "/v1/payments/sepa-credit-transfers/1234-wertiq-983"
|
||||
},
|
||||
"startAuthorisationWithAuthenticationMethodSelection" : {
|
||||
"href" : "/v1/payments/sepa-credit-transfers/1234-wertiq-983"
|
||||
},
|
||||
"startAuthorisationWithPsuAuthentication" : {
|
||||
"href" : "/v1/payments/sepa-credit-transfers/1234-wertiq-983"
|
||||
},
|
||||
"startAuthorisationWithPsuIdentification" : {
|
||||
"href" : "/v1/payments/sepa-credit-transfers/1234-wertiq-983"
|
||||
},
|
||||
"startAuthorisation" : {
|
||||
"href" : "/v1/payments/sepa-credit-transfers/1234-wertiq-983"
|
||||
}
|
||||
},
|
||||
"chosenScaMethod" : "",
|
||||
"transactionStatus" : "ACCP"
|
||||
}"""),
|
||||
List(UserNotLoggedIn, UnknownError),
|
||||
Catalogs(notCore, notPSD2, notOBWG),
|
||||
ApiTag("Payment Initiation Service (PIS)") :: apiTagMockedData :: Nil
|
||||
)
|
||||
|
||||
lazy val cancelPayment : OBPEndpoint = {
|
||||
case payment_service :: payment_product :: paymentid :: Nil JsonDelete _ => {
|
||||
cc =>
|
||||
for {
|
||||
(Full(u), callContext) <- authorizedAccess(cc, UserNotLoggedIn)
|
||||
} yield {
|
||||
(json.parse("""{
|
||||
"challengeData" : {
|
||||
"otpMaxLength" : 0,
|
||||
"additionalInformation" : "additionalInformation",
|
||||
"image" : "image",
|
||||
"imageLink" : "http://example.com/aeiou",
|
||||
"otpFormat" : "characters",
|
||||
"data" : [ "data", "data" ]
|
||||
},
|
||||
"scaMethods" : "",
|
||||
"_links" : {
|
||||
"startAuthorisationWithEncryptedPsuAuthentication" : {
|
||||
"href" : "/v1/payments/sepa-credit-transfers/1234-wertiq-983"
|
||||
},
|
||||
"startAuthorisationWithAuthenticationMethodSelection" : {
|
||||
"href" : "/v1/payments/sepa-credit-transfers/1234-wertiq-983"
|
||||
},
|
||||
"startAuthorisationWithPsuAuthentication" : {
|
||||
"href" : "/v1/payments/sepa-credit-transfers/1234-wertiq-983"
|
||||
},
|
||||
"startAuthorisationWithPsuIdentification" : {
|
||||
"href" : "/v1/payments/sepa-credit-transfers/1234-wertiq-983"
|
||||
},
|
||||
"startAuthorisation" : {
|
||||
"href" : "/v1/payments/sepa-credit-transfers/1234-wertiq-983"
|
||||
}
|
||||
},
|
||||
"chosenScaMethod" : "",
|
||||
"transactionStatus" : "ACCP"
|
||||
}"""), callContext)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resourceDocs += ResourceDoc(
|
||||
getPaymentCancellationScaStatus,
|
||||
apiVersion,
|
||||
nameOf(getPaymentCancellationScaStatus),
|
||||
"GET",
|
||||
"/PAYMENT_SERVICE/PAYMENT_PRODUCT/PAYMENTID/cancellation-authorisations/CANCELLATIONID",
|
||||
"Read the SCA status of the payment cancellation's authorisation.",
|
||||
s"""${mockedDataText(true)}
|
||||
This method returns the SCA status of a payment initiation's authorisation sub-resource.
|
||||
|
||||
""",
|
||||
json.parse(""""""),
|
||||
json.parse("""{
|
||||
"scaStatus" : "psuAuthenticated"
|
||||
}"""),
|
||||
List(UserNotLoggedIn, UnknownError),
|
||||
Catalogs(notCore, notPSD2, notOBWG),
|
||||
ApiTag("Payment Initiation Service (PIS)") ::ApiTag("Common Services") :: apiTagMockedData :: Nil
|
||||
)
|
||||
|
||||
lazy val getPaymentCancellationScaStatus : OBPEndpoint = {
|
||||
case payment_service :: payment_product :: paymentid:: "cancellation-authorisations" :: cancellationid :: Nil JsonGet _ => {
|
||||
cc =>
|
||||
for {
|
||||
(Full(u), callContext) <- authorizedAccess(cc, UserNotLoggedIn)
|
||||
} yield {
|
||||
(json.parse("""{
|
||||
"scaStatus" : "psuAuthenticated"
|
||||
}"""), callContext)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resourceDocs += ResourceDoc(
|
||||
getPaymentInformation,
|
||||
apiVersion,
|
||||
nameOf(getPaymentInformation),
|
||||
"GET",
|
||||
"/PAYMENT_SERVICE/PAYMENT_PRODUCT/PAYMENTID",
|
||||
"Get Payment Information",
|
||||
s"""${mockedDataText(true)}
|
||||
Returns the content of a payment object
|
||||
|
||||
""",
|
||||
json.parse(""""""),
|
||||
json.parse(""""""""),
|
||||
List(UserNotLoggedIn, UnknownError),
|
||||
Catalogs(notCore, notPSD2, notOBWG),
|
||||
ApiTag("Payment Initiation Service (PIS)") :: apiTagMockedData :: Nil
|
||||
)
|
||||
|
||||
lazy val getPaymentInformation : OBPEndpoint = {
|
||||
case payment_service :: payment_product :: paymentid :: Nil JsonGet _ => {
|
||||
cc =>
|
||||
for {
|
||||
(Full(u), callContext) <- authorizedAccess(cc, UserNotLoggedIn)
|
||||
} yield {
|
||||
(json.parse(""""""""), callContext)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resourceDocs += ResourceDoc(
|
||||
getPaymentInitiationAuthorisation,
|
||||
apiVersion,
|
||||
nameOf(getPaymentInitiationAuthorisation),
|
||||
"GET",
|
||||
"/PAYMENT_SERVICE/PAYMENT_PRODUCT/PAYMENTID/authorisations",
|
||||
"Get Payment Initiation Authorisation Sub-Resources Request",
|
||||
s"""${mockedDataText(true)}
|
||||
Read a list of all authorisation subresources IDs which have been created. This function returns an array
|
||||
of hyperlinks to all generated authorisation sub-resources.
|
||||
|
||||
""",
|
||||
json.parse(""""""),
|
||||
json.parse("""{
|
||||
"authorisationIds" : ""
|
||||
}"""),
|
||||
List(UserNotLoggedIn, UnknownError),
|
||||
Catalogs(notCore, notPSD2, notOBWG),
|
||||
ApiTag("Payment Initiation Service (PIS)") ::ApiTag("Common Services") :: apiTagMockedData :: Nil
|
||||
)
|
||||
|
||||
lazy val getPaymentInitiationAuthorisation : OBPEndpoint = {
|
||||
case payment_service :: payment_product :: paymentid:: "authorisations" :: Nil JsonGet _ => {
|
||||
cc =>
|
||||
for {
|
||||
(Full(u), callContext) <- authorizedAccess(cc, UserNotLoggedIn)
|
||||
} yield {
|
||||
(json.parse("""{
|
||||
"authorisationIds" : ""
|
||||
}"""), callContext)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resourceDocs += ResourceDoc(
|
||||
getPaymentInitiationCancellationAuthorisationInformation,
|
||||
apiVersion,
|
||||
nameOf(getPaymentInitiationCancellationAuthorisationInformation),
|
||||
"GET",
|
||||
"/PAYMENT_SERVICE/PAYMENT_PRODUCT/PAYMENTID/cancellation-authorisations",
|
||||
"Will deliver an array of resource identifications to all generated cancellation authorisation sub-resources.",
|
||||
s"""${mockedDataText(true)}
|
||||
Retrieve a list of all created cancellation authorisation sub-resources.
|
||||
|
||||
""",
|
||||
json.parse(""""""),
|
||||
json.parse(""""""""),
|
||||
List(UserNotLoggedIn, UnknownError),
|
||||
Catalogs(notCore, notPSD2, notOBWG),
|
||||
ApiTag("Payment Initiation Service (PIS)") :: apiTagMockedData :: Nil
|
||||
)
|
||||
|
||||
lazy val getPaymentInitiationCancellationAuthorisationInformation : OBPEndpoint = {
|
||||
case payment_service :: payment_product :: paymentid:: "cancellation-authorisations" :: Nil JsonGet _ => {
|
||||
cc =>
|
||||
for {
|
||||
(Full(u), callContext) <- authorizedAccess(cc, UserNotLoggedIn)
|
||||
} yield {
|
||||
(json.parse(""""""""), callContext)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resourceDocs += ResourceDoc(
|
||||
getPaymentInitiationScaStatus,
|
||||
apiVersion,
|
||||
nameOf(getPaymentInitiationScaStatus),
|
||||
"GET",
|
||||
"/PAYMENT_SERVICE/PAYMENT_PRODUCT/PAYMENTID/authorisations/AUTHORISATIONID",
|
||||
"Read the SCA Status of the payment authorisation",
|
||||
s"""${mockedDataText(true)}
|
||||
This method returns the SCA status of a payment initiation's authorisation sub-resource.
|
||||
|
||||
""",
|
||||
json.parse(""""""),
|
||||
json.parse("""{
|
||||
"scaStatus" : "psuAuthenticated"
|
||||
}"""),
|
||||
List(UserNotLoggedIn, UnknownError),
|
||||
Catalogs(notCore, notPSD2, notOBWG),
|
||||
ApiTag("Payment Initiation Service (PIS)") ::ApiTag("Common Services") :: apiTagMockedData :: Nil
|
||||
)
|
||||
|
||||
lazy val getPaymentInitiationScaStatus : OBPEndpoint = {
|
||||
case payment_service :: payment_product :: paymentid:: "authorisations" :: authorisationid :: Nil JsonGet _ => {
|
||||
cc =>
|
||||
for {
|
||||
(Full(u), callContext) <- authorizedAccess(cc, UserNotLoggedIn)
|
||||
} yield {
|
||||
(json.parse("""{
|
||||
"scaStatus" : "psuAuthenticated"
|
||||
}"""), callContext)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resourceDocs += ResourceDoc(
|
||||
getPaymentInitiationStatus,
|
||||
apiVersion,
|
||||
nameOf(getPaymentInitiationStatus),
|
||||
"GET",
|
||||
"/PAYMENT_SERVICE/PAYMENT_PRODUCT/PAYMENTID/status",
|
||||
"Payment initiation status request",
|
||||
s"""${mockedDataText(true)}
|
||||
Check the transaction status of a payment initiation.
|
||||
|
||||
""",
|
||||
json.parse(""""""),
|
||||
json.parse("""{
|
||||
"transactionStatus" : "ACCP",
|
||||
"fundsAvailable" : { }
|
||||
}"""),
|
||||
List(UserNotLoggedIn, UnknownError),
|
||||
Catalogs(notCore, notPSD2, notOBWG),
|
||||
ApiTag("Payment Initiation Service (PIS)") :: apiTagMockedData :: Nil
|
||||
)
|
||||
|
||||
lazy val getPaymentInitiationStatus : OBPEndpoint = {
|
||||
case payment_service :: payment_product :: paymentid:: "status" :: Nil JsonGet _ => {
|
||||
cc =>
|
||||
for {
|
||||
(Full(u), callContext) <- authorizedAccess(cc, UserNotLoggedIn)
|
||||
} yield {
|
||||
(json.parse("""{
|
||||
"transactionStatus" : "ACCP",
|
||||
"fundsAvailable" : { }
|
||||
}"""), callContext)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resourceDocs += ResourceDoc(
|
||||
initiatePayment,
|
||||
apiVersion,
|
||||
nameOf(initiatePayment),
|
||||
"POST",
|
||||
"/PAYMENT_SERVICE/PAYMENT_PRODUCT",
|
||||
"Payment initiation request",
|
||||
s"""${mockedDataText(true)}
|
||||
This method is used to initiate a payment at the ASPSP. ## Variants of Payment Initiation Requests
|
||||
This method to initiate a payment initiation at the ASPSP can be sent with either a JSON body or an pain.001
|
||||
body depending on the payment product in the path. There are the following
|
||||
**payment products**:
|
||||
- Payment products with payment information in *JSON* format:
|
||||
- ***sepa-credit-transfers***
|
||||
- ***instant-sepa-credit-transfers***
|
||||
- ***target-2-payments***
|
||||
- ***cross-border-credit-transfers***
|
||||
- Payment products with payment information in *pain.001* XML format:
|
||||
- ***pain.001-sepa-credit-transfers***
|
||||
- ***pain.001-instant-sepa-credit-transfers***
|
||||
- ***pain.001-target-2-payments***
|
||||
- ***pain.001-cross-border-credit-transfers*** Furthermore the request body depends on the
|
||||
**payment-service** * ***payments***: A single payment initiation request.
|
||||
* ***bulk-payments***: A collection of several payment iniatiation requests.
|
||||
In case of a *pain.001* message there are more than one payments contained in the *pain.001 message.
|
||||
In case of a *JSON* there are several JSON payment blocks contained in a joining list.
|
||||
* ***periodic-payments***: Create a standing order initiation resource for recurrent
|
||||
i.e. periodic payments addressable under {paymentId} with all data relevant for the corresponding payment
|
||||
product and the execution of the standing order contained in a JSON body. This is the first step in the API
|
||||
to initiate the related recurring/periodic payment. ## Single and mulitilevel SCA Processes The Payment
|
||||
Initiation Requests are independent from the need of one ore multilevel SCA processing, i.e. independent
|
||||
from the number of authorisations needed for the execution of payments. But the response messages are specific
|
||||
to either one SCA processing or multilevel SCA processing. For payment initiation with multilevel SCA,
|
||||
this specification requires an explicit start of the authorisation, i.e. links directly associated with
|
||||
SCA processing like 'scaRedirect' or 'scaOAuth' cannot be contained in the response message of a Payment
|
||||
Initation Request for a payment, where multiple authorisations are needed. Also if any data is needed for
|
||||
the next action, like selecting an SCA method is not supported in the response, since all starts of the
|
||||
multiple authorisations are fully equal. In these cases, first an authorisation sub-resource has to be
|
||||
generated following the 'startAuthorisation' link.
|
||||
|
||||
""",
|
||||
json.parse(""""""),
|
||||
json.parse("""{
|
||||
"challengeData" : {
|
||||
"otpMaxLength" : 0,
|
||||
"additionalInformation" : "additionalInformation",
|
||||
"image" : "image",
|
||||
"imageLink" : "http://example.com/aeiou",
|
||||
"otpFormat" : "characters",
|
||||
"data" : [ "data", "data" ]
|
||||
},
|
||||
"scaMethods" : "",
|
||||
"tppMessages" : [ {
|
||||
"path" : "path",
|
||||
"code" : { },
|
||||
"text" : { },
|
||||
"category" : { }
|
||||
}, {
|
||||
"path" : "path",
|
||||
"code" : { },
|
||||
"text" : { },
|
||||
"category" : { }
|
||||
} ],
|
||||
"_links" : {
|
||||
"scaRedirect" : {
|
||||
"href" : "https://www.testbank.com/asdfasdfasdf"
|
||||
},
|
||||
"self" : {
|
||||
"href" : "/v1/payments/sepa-credit-transfers/1234-wertiq-983"
|
||||
}
|
||||
},
|
||||
"chosenScaMethod" : "",
|
||||
"transactionStatus" : "ACCP",
|
||||
"paymentId" : "1234-wertiq-983",
|
||||
"psuMessage" : { },
|
||||
"transactionFeeIndicator" : { },
|
||||
"transactionFees" : {
|
||||
"amount" : "123",
|
||||
"currency" : "EUR"
|
||||
}
|
||||
}"""),
|
||||
List(UserNotLoggedIn, UnknownError),
|
||||
Catalogs(notCore, notPSD2, notOBWG),
|
||||
ApiTag("Payment Initiation Service (PIS)") :: apiTagMockedData :: Nil
|
||||
)
|
||||
|
||||
lazy val initiatePayment : OBPEndpoint = {
|
||||
case payment_service :: payment_product :: Nil JsonPost _ => {
|
||||
cc =>
|
||||
for {
|
||||
(Full(u), callContext) <- authorizedAccess(cc, UserNotLoggedIn)
|
||||
} yield {
|
||||
(json.parse("""{
|
||||
"challengeData" : {
|
||||
"otpMaxLength" : 0,
|
||||
"additionalInformation" : "additionalInformation",
|
||||
"image" : "image",
|
||||
"imageLink" : "http://example.com/aeiou",
|
||||
"otpFormat" : "characters",
|
||||
"data" : [ "data", "data" ]
|
||||
},
|
||||
"scaMethods" : "",
|
||||
"tppMessages" : [ {
|
||||
"path" : "path",
|
||||
"code" : { },
|
||||
"text" : { },
|
||||
"category" : { }
|
||||
}, {
|
||||
"path" : "path",
|
||||
"code" : { },
|
||||
"text" : { },
|
||||
"category" : { }
|
||||
} ],
|
||||
"_links" : {
|
||||
"scaRedirect" : {
|
||||
"href" : "https://www.testbank.com/asdfasdfasdf"
|
||||
},
|
||||
"self" : {
|
||||
"href" : "/v1/payments/sepa-credit-transfers/1234-wertiq-983"
|
||||
}
|
||||
},
|
||||
"chosenScaMethod" : "",
|
||||
"transactionStatus" : "ACCP",
|
||||
"paymentId" : "1234-wertiq-983",
|
||||
"psuMessage" : { },
|
||||
"transactionFeeIndicator" : { },
|
||||
"transactionFees" : {
|
||||
"amount" : "123",
|
||||
"currency" : "EUR"
|
||||
}
|
||||
}"""), callContext)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resourceDocs += ResourceDoc(
|
||||
startPaymentAuthorisation,
|
||||
apiVersion,
|
||||
nameOf(startPaymentAuthorisation),
|
||||
"POST",
|
||||
"/PAYMENT_SERVICE/PAYMENT_PRODUCT/PAYMENTID/authorisations",
|
||||
"Start the authorisation process for a payment initiation",
|
||||
s"""${mockedDataText(true)}
|
||||
Create an authorisation sub-resource and start the authorisation process. The message might in addition
|
||||
transmit authentication and authorisation related data. This method is iterated n times for a n times
|
||||
SCA authorisation in a corporate context, each creating an own authorisation sub-endpoint for the corresponding
|
||||
PSU authorising the transaction. The ASPSP might make the usage of this access method unnecessary in case of
|
||||
only one SCA process needed, since the related authorisation resource might be automatically created by the
|
||||
ASPSP after the submission of the payment data with the first POST payments/{payment-product} call.
|
||||
The start authorisation process is a process which is needed for creating a new authorisation or cancellation
|
||||
sub-resource. This applies in the following scenarios: * The ASPSP has indicated with an 'startAuthorisation'
|
||||
hyperlink in the preceding Payment Initiation Response that an explicit start of the authorisation process
|
||||
is needed by the TPP. The 'startAuthorisation' hyperlink can transport more information about data which
|
||||
needs to be uploaded by using the extended forms.
|
||||
* 'startAuthorisationWithPsuIdentfication',
|
||||
* 'startAuthorisationWithPsuAuthentication'
|
||||
* 'startAuthorisationWithEncryptedPsuAuthentication'
|
||||
* 'startAuthorisationWithAuthentciationMethodSelection'
|
||||
* The related payment initiation cannot yet be executed since a multilevel SCA is mandated.
|
||||
* The ASPSP has indicated with an 'startAuthorisation' hyperlink in the preceding
|
||||
Payment Cancellation Response that an explicit start of the authorisation process is needed by the TPP.
|
||||
The 'startAuthorisation' hyperlink can transport more information about data which needs to be uploaded
|
||||
by using the extended forms as indicated above. * The related payment cancellation request cannot be
|
||||
applied yet since a multilevel SCA is mandate for executing the cancellation. * The signing basket needs
|
||||
to be authorised yet.
|
||||
|
||||
""",
|
||||
json.parse(""""""),
|
||||
json.parse("""{
|
||||
"authorisationId" : "123auth456",
|
||||
"challengeData" : {
|
||||
"otpMaxLength" : 0,
|
||||
"additionalInformation" : "additionalInformation",
|
||||
"image" : "image",
|
||||
"imageLink" : "http://example.com/aeiou",
|
||||
"otpFormat" : "characters",
|
||||
"data" : [ "data", "data" ]
|
||||
},
|
||||
"scaMethods" : "",
|
||||
"scaStatus" : "psuAuthenticated",
|
||||
"_links" : {
|
||||
"scaStatus" : {
|
||||
"href" : "/v1/payments/sepa-credit-transfers/1234-wertiq-983"
|
||||
},
|
||||
"startAuthorisationWithEncryptedPsuAuthentication" : {
|
||||
"href" : "/v1/payments/sepa-credit-transfers/1234-wertiq-983"
|
||||
},
|
||||
"scaRedirect" : {
|
||||
"href" : "/v1/payments/sepa-credit-transfers/1234-wertiq-983"
|
||||
},
|
||||
"selectAuthenticationMethod" : {
|
||||
"href" : "/v1/payments/sepa-credit-transfers/1234-wertiq-983"
|
||||
},
|
||||
"startAuthorisationWithPsuAuthentication" : {
|
||||
"href" : "/v1/payments/sepa-credit-transfers/1234-wertiq-983"
|
||||
},
|
||||
"authoriseTransaction" : {
|
||||
"href" : "/v1/payments/sepa-credit-transfers/1234-wertiq-983"
|
||||
},
|
||||
"scaOAuth" : {
|
||||
"href" : "/v1/payments/sepa-credit-transfers/1234-wertiq-983"
|
||||
},
|
||||
"updatePsuIdentification" : {
|
||||
"href" : "/v1/payments/sepa-credit-transfers/1234-wertiq-983"
|
||||
}
|
||||
},
|
||||
"chosenScaMethod" : "",
|
||||
"psuMessage" : { }
|
||||
}"""),
|
||||
List(UserNotLoggedIn, UnknownError),
|
||||
Catalogs(notCore, notPSD2, notOBWG),
|
||||
ApiTag("Payment Initiation Service (PIS)") ::ApiTag("Common Services") :: apiTagMockedData :: Nil
|
||||
)
|
||||
|
||||
lazy val startPaymentAuthorisation : OBPEndpoint = {
|
||||
case payment_service :: payment_product :: paymentid:: "authorisations" :: Nil JsonPost _ => {
|
||||
cc =>
|
||||
for {
|
||||
(Full(u), callContext) <- authorizedAccess(cc, UserNotLoggedIn)
|
||||
} yield {
|
||||
(json.parse("""{
|
||||
"authorisationId" : "123auth456",
|
||||
"challengeData" : {
|
||||
"otpMaxLength" : 0,
|
||||
"additionalInformation" : "additionalInformation",
|
||||
"image" : "image",
|
||||
"imageLink" : "http://example.com/aeiou",
|
||||
"otpFormat" : "characters",
|
||||
"data" : [ "data", "data" ]
|
||||
},
|
||||
"scaMethods" : "",
|
||||
"scaStatus" : "psuAuthenticated",
|
||||
"_links" : {
|
||||
"scaStatus" : {
|
||||
"href" : "/v1/payments/sepa-credit-transfers/1234-wertiq-983"
|
||||
},
|
||||
"startAuthorisationWithEncryptedPsuAuthentication" : {
|
||||
"href" : "/v1/payments/sepa-credit-transfers/1234-wertiq-983"
|
||||
},
|
||||
"scaRedirect" : {
|
||||
"href" : "/v1/payments/sepa-credit-transfers/1234-wertiq-983"
|
||||
},
|
||||
"selectAuthenticationMethod" : {
|
||||
"href" : "/v1/payments/sepa-credit-transfers/1234-wertiq-983"
|
||||
},
|
||||
"startAuthorisationWithPsuAuthentication" : {
|
||||
"href" : "/v1/payments/sepa-credit-transfers/1234-wertiq-983"
|
||||
},
|
||||
"authoriseTransaction" : {
|
||||
"href" : "/v1/payments/sepa-credit-transfers/1234-wertiq-983"
|
||||
},
|
||||
"scaOAuth" : {
|
||||
"href" : "/v1/payments/sepa-credit-transfers/1234-wertiq-983"
|
||||
},
|
||||
"updatePsuIdentification" : {
|
||||
"href" : "/v1/payments/sepa-credit-transfers/1234-wertiq-983"
|
||||
}
|
||||
},
|
||||
"chosenScaMethod" : "",
|
||||
"psuMessage" : { }
|
||||
}"""), callContext)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resourceDocs += ResourceDoc(
|
||||
startPaymentInitiationCancellationAuthorisation,
|
||||
apiVersion,
|
||||
nameOf(startPaymentInitiationCancellationAuthorisation),
|
||||
"POST",
|
||||
"/PAYMENT_SERVICE/PAYMENT_PRODUCT/PAYMENTID/cancellation-authorisations",
|
||||
"Start the authorisation process for the cancellation of the addressed payment",
|
||||
s"""${mockedDataText(true)}
|
||||
Creates an authorisation sub-resource and start the authorisation process of the cancellation of the addressed
|
||||
payment. The message might in addition transmit authentication and authorisation related data. This method is
|
||||
iterated n times for a n times SCA authorisation in a corporate context, each creating an own authorisation
|
||||
sub-endpoint for the corresponding PSU authorising the cancellation-authorisation. The ASPSP might make the
|
||||
usage of this access method unnecessary in case of only one SCA process needed, since the related authorisation
|
||||
resource might be automatically created by the ASPSP after the submission of the payment data with the first
|
||||
POST payments/{payment-product} call. The start authorisation process is a process which is needed for
|
||||
creating a new authorisation or cancellation sub-resource. This applies in the following scenarios:
|
||||
* The ASPSP has indicated with an 'startAuthorisation' hyperlink in the preceding Payment Initiation
|
||||
Response that an explicit start of the authorisation process is needed by the TPP.
|
||||
The 'startAuthorisation' hyperlink can transport more information about data which needs to be
|
||||
uploaded by using the extended forms. * 'startAuthorisationWithPsuIdentfication',
|
||||
* 'startAuthorisationWithPsuAuthentication' * 'startAuthorisationWithAuthentciationMethodSelection'
|
||||
* The related payment initiation cannot yet be executed since a multilevel SCA is mandated.
|
||||
* The ASPSP has indicated with an 'startAuthorisation' hyperlink in the preceding Payment Cancellation Response
|
||||
that an explicit start of the authorisation process is needed by the TPP.
|
||||
The 'startAuthorisation' hyperlink can transport more information about data which needs to be uploaded by
|
||||
using the extended forms as indicated above. * The related payment cancellation request cannot be applied
|
||||
yet since a multilevel SCA is mandate for executing the cancellation. * The signing basket needs to be authorised yet.
|
||||
|
||||
""",
|
||||
json.parse(""""""),
|
||||
json.parse("""{
|
||||
"authorisationId" : "123auth456",
|
||||
"challengeData" : {
|
||||
"otpMaxLength" : 0,
|
||||
"additionalInformation" : "additionalInformation",
|
||||
"image" : "image",
|
||||
"imageLink" : "http://example.com/aeiou",
|
||||
"otpFormat" : "characters",
|
||||
"data" : [ "data", "data" ]
|
||||
},
|
||||
"scaMethods" : "",
|
||||
"scaStatus" : "psuAuthenticated",
|
||||
"_links" : {
|
||||
"scaStatus" : {
|
||||
"href" : "/v1/payments/sepa-credit-transfers/1234-wertiq-983"
|
||||
},
|
||||
"startAuthorisationWithEncryptedPsuAuthentication" : {
|
||||
"href" : "/v1/payments/sepa-credit-transfers/1234-wertiq-983"
|
||||
},
|
||||
"scaRedirect" : {
|
||||
"href" : "/v1/payments/sepa-credit-transfers/1234-wertiq-983"
|
||||
},
|
||||
"selectAuthenticationMethod" : {
|
||||
"href" : "/v1/payments/sepa-credit-transfers/1234-wertiq-983"
|
||||
},
|
||||
"startAuthorisationWithPsuAuthentication" : {
|
||||
"href" : "/v1/payments/sepa-credit-transfers/1234-wertiq-983"
|
||||
},
|
||||
"authoriseTransaction" : {
|
||||
"href" : "/v1/payments/sepa-credit-transfers/1234-wertiq-983"
|
||||
},
|
||||
"scaOAuth" : {
|
||||
"href" : "/v1/payments/sepa-credit-transfers/1234-wertiq-983"
|
||||
},
|
||||
"updatePsuIdentification" : {
|
||||
"href" : "/v1/payments/sepa-credit-transfers/1234-wertiq-983"
|
||||
}
|
||||
},
|
||||
"chosenScaMethod" : "",
|
||||
"psuMessage" : { }
|
||||
}"""),
|
||||
List(UserNotLoggedIn, UnknownError),
|
||||
Catalogs(notCore, notPSD2, notOBWG),
|
||||
ApiTag("Payment Initiation Service (PIS)") ::ApiTag("Common Services") :: apiTagMockedData :: Nil
|
||||
)
|
||||
|
||||
lazy val startPaymentInitiationCancellationAuthorisation : OBPEndpoint = {
|
||||
case payment_service :: payment_product :: paymentid:: "cancellation-authorisations" :: Nil JsonPost _ => {
|
||||
cc =>
|
||||
for {
|
||||
(Full(u), callContext) <- authorizedAccess(cc, UserNotLoggedIn)
|
||||
} yield {
|
||||
(json.parse("""{
|
||||
"authorisationId" : "123auth456",
|
||||
"challengeData" : {
|
||||
"otpMaxLength" : 0,
|
||||
"additionalInformation" : "additionalInformation",
|
||||
"image" : "image",
|
||||
"imageLink" : "http://example.com/aeiou",
|
||||
"otpFormat" : "characters",
|
||||
"data" : [ "data", "data" ]
|
||||
},
|
||||
"scaMethods" : "",
|
||||
"scaStatus" : "psuAuthenticated",
|
||||
"_links" : {
|
||||
"scaStatus" : {
|
||||
"href" : "/v1/payments/sepa-credit-transfers/1234-wertiq-983"
|
||||
},
|
||||
"startAuthorisationWithEncryptedPsuAuthentication" : {
|
||||
"href" : "/v1/payments/sepa-credit-transfers/1234-wertiq-983"
|
||||
},
|
||||
"scaRedirect" : {
|
||||
"href" : "/v1/payments/sepa-credit-transfers/1234-wertiq-983"
|
||||
},
|
||||
"selectAuthenticationMethod" : {
|
||||
"href" : "/v1/payments/sepa-credit-transfers/1234-wertiq-983"
|
||||
},
|
||||
"startAuthorisationWithPsuAuthentication" : {
|
||||
"href" : "/v1/payments/sepa-credit-transfers/1234-wertiq-983"
|
||||
},
|
||||
"authoriseTransaction" : {
|
||||
"href" : "/v1/payments/sepa-credit-transfers/1234-wertiq-983"
|
||||
},
|
||||
"scaOAuth" : {
|
||||
"href" : "/v1/payments/sepa-credit-transfers/1234-wertiq-983"
|
||||
},
|
||||
"updatePsuIdentification" : {
|
||||
"href" : "/v1/payments/sepa-credit-transfers/1234-wertiq-983"
|
||||
}
|
||||
},
|
||||
"chosenScaMethod" : "",
|
||||
"psuMessage" : { }
|
||||
}"""), callContext)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resourceDocs += ResourceDoc(
|
||||
updatePaymentCancellationPsuData,
|
||||
apiVersion,
|
||||
nameOf(updatePaymentCancellationPsuData),
|
||||
"PUT",
|
||||
"/PAYMENT_SERVICE/PAYMENT_PRODUCT/PAYMENTID/cancellation-authorisations/CANCELLATIONID",
|
||||
"Update PSU Data for payment initiation cancellation",
|
||||
s"""${mockedDataText(true)}
|
||||
This method updates PSU data on the cancellation authorisation resource if needed. It may authorise a cancellation
|
||||
of the payment within the Embedded SCA Approach where needed. Independently from the SCA Approach it supports
|
||||
e.g. the selection of the authentication method and a non-SCA PSU authentication. This methods updates PSU data
|
||||
on the cancellation authorisation resource if needed. There are several possible Update PSU Data requests in
|
||||
the context of a cancellation authorisation within the payment initiation services needed, which depends on
|
||||
the SCA approach: * Redirect SCA Approach: A specific Update PSU Data Request is applicable for
|
||||
* the selection of authentication methods, before choosing the actual SCA approach.
|
||||
* Decoupled SCA Approach: A specific Update PSU Data Request is only applicable for
|
||||
* adding the PSU Identification, if not provided yet in the Payment Initiation Request or the Account
|
||||
Information Consent Request, or if no OAuth2 access token is used, or
|
||||
* the selection of authentication methods.
|
||||
* Embedded SCA Approach: The Update PSU Data Request might be used
|
||||
* to add credentials as a first factor authentication data of the PSU and * to select the authentication method and
|
||||
* transaction authorisation. The SCA Approach might depend on the chosen SCA method. For that reason, the following
|
||||
possible Update PSU Data request can apply to all SCA approaches: * Select an SCA method in case of several SCA methods
|
||||
are available for the customer. There are the following request types on this access path:
|
||||
* Update PSU Identification
|
||||
* Update PSU Authentication * Select PSU Autorization Method WARNING: This method need a reduced header,
|
||||
therefore many optional elements are not present. Maybe in a later version the access path will change.
|
||||
* Transaction Authorisation WARNING: This method need a reduced header, therefore many optional elements are not present.
|
||||
|
||||
Maybe in a later version the access path will change.
|
||||
|
||||
|
||||
""",
|
||||
json.parse(""""""),
|
||||
json.parse(""""""""),
|
||||
List(UserNotLoggedIn, UnknownError),
|
||||
Catalogs(notCore, notPSD2, notOBWG),
|
||||
ApiTag("Payment Initiation Service (PIS)") ::ApiTag("Common Services") :: apiTagMockedData :: Nil
|
||||
)
|
||||
|
||||
lazy val updatePaymentCancellationPsuData : OBPEndpoint = {
|
||||
case payment_service :: payment_product :: paymentid:: "cancellation-authorisations" :: cancellationid :: Nil JsonPut _ => {
|
||||
cc =>
|
||||
for {
|
||||
(Full(u), callContext) <- authorizedAccess(cc, UserNotLoggedIn)
|
||||
} yield {
|
||||
(json.parse(""""""""), callContext)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resourceDocs += ResourceDoc(
|
||||
updatePaymentPsuData,
|
||||
apiVersion,
|
||||
nameOf(updatePaymentPsuData),
|
||||
"PUT",
|
||||
"/PAYMENT_SERVICE/PAYMENT_PRODUCT/PAYMENTID/authorisations/AUTHORISATIONID",
|
||||
"Update PSU data for payment initiation",
|
||||
s"""${mockedDataText(true)}
|
||||
This methods updates PSU data on the authorisation resource if needed. It may authorise a payment within the
|
||||
Embedded SCA Approach where needed. Independently from the SCA Approach it supports e.g. the selection of
|
||||
the authentication method and a non-SCA PSU authentication. There are several possible Update PSU Data requests
|
||||
in the context of payment initiation services needed, which depends on the SCA approach:
|
||||
* Redirect SCA Approach: A specific Update PSU Data Request is applicable for
|
||||
* the selection of authentication methods, before choosing the actual SCA approach.
|
||||
* Decoupled SCA Approach: A specific Update PSU Data Request is only applicable for
|
||||
* adding the PSU Identification, if not provided yet in the Payment Initiation Request or
|
||||
the Account Information Consent Request, or if no OAuth2 access token is used, or
|
||||
* the selection of authentication methods. * Embedded SCA Approach: The Update PSU
|
||||
Data Request might be used * to add credentials as a first factor authentication data of the PSU and
|
||||
* to select the authentication method and * transaction authorisation.
|
||||
The SCA Approach might depend on the chosen SCA method. For that reason, the following possible Update
|
||||
PSU Data request can apply to all SCA approaches: * Select an SCA method in case of several SCA methods
|
||||
are available for the customer. There are the following request types on this access path:
|
||||
* Update PSU Identification * Update PSU Authentication * Select PSU Autorization Method WARNING:
|
||||
This method need a reduced header, therefore many optional elements are not present. Maybe in a later
|
||||
version the access path will change. * Transaction Authorisation WARNING: This method need a reduced header,
|
||||
therefore many optional elements are not present. Maybe in a later version the access path will change.
|
||||
|
||||
""",
|
||||
json.parse(""""""),
|
||||
json.parse(""""""""),
|
||||
List(UserNotLoggedIn, UnknownError),
|
||||
Catalogs(notCore, notPSD2, notOBWG),
|
||||
ApiTag("Payment Initiation Service (PIS)") ::ApiTag("Common Services") :: apiTagMockedData :: Nil
|
||||
)
|
||||
|
||||
lazy val updatePaymentPsuData : OBPEndpoint = {
|
||||
case payment_service :: payment_product :: paymentid:: "authorisations" :: authorisationid :: Nil JsonPut _ => {
|
||||
cc =>
|
||||
for {
|
||||
(Full(u), callContext) <- authorizedAccess(cc, UserNotLoggedIn)
|
||||
} yield {
|
||||
(json.parse(""""""""), callContext)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -1,614 +0,0 @@
|
||||
package code.api.berlin.group.v1_3_1
|
||||
|
||||
import code.api.APIFailureNewStyle
|
||||
import code.api.berlin.group.v1_3.JvalueCaseClass
|
||||
import net.liftweb.json
|
||||
import net.liftweb.json._
|
||||
import code.api.util.APIUtil.{defaultBankId, _}
|
||||
import code.api.util.{ApiVersion, NewStyle}
|
||||
import code.api.util.ErrorMessages._
|
||||
import code.api.util.ApiTag._
|
||||
import code.api.util.NewStyle.HttpCode
|
||||
import code.bankconnectors.Connector
|
||||
import code.model._
|
||||
import code.util.Helper
|
||||
import code.views.Views
|
||||
import net.liftweb.common.Full
|
||||
import net.liftweb.http.rest.RestHelper
|
||||
import com.github.dwickern.macros.NameOf.nameOf
|
||||
import scala.collection.immutable.Nil
|
||||
import scala.collection.mutable.ArrayBuffer
|
||||
import scala.concurrent.ExecutionContext.Implicits.global
|
||||
import scala.concurrent.Future
|
||||
import code.api.berlin.group.v1_3_1.JSONFactory_BERLIN_GROUP_1_3_3
|
||||
import code.api.util.ApiTag
|
||||
|
||||
object APIMethods_SigningBasketsSBSApi extends RestHelper {
|
||||
val apiVersion = JSONFactory_BERLIN_GROUP_1_3_3.apiVersion
|
||||
val resourceDocs = ArrayBuffer[ResourceDoc]()
|
||||
val apiRelations = ArrayBuffer[ApiRelation]()
|
||||
protected implicit def JvalueToSuper(what: JValue): JvalueCaseClass = JvalueCaseClass(what)
|
||||
|
||||
val endpoints =
|
||||
createSigningBasket ::
|
||||
deleteSigningBasket ::
|
||||
getSigningBasket ::
|
||||
getSigningBasketAuthorisation ::
|
||||
getSigningBasketScaStatus ::
|
||||
getSigningBasketStatus ::
|
||||
startSigningBasketAuthorisation ::
|
||||
updateSigningBasketPsuData ::
|
||||
Nil
|
||||
|
||||
|
||||
resourceDocs += ResourceDoc(
|
||||
createSigningBasket,
|
||||
apiVersion,
|
||||
nameOf(createSigningBasket),
|
||||
"POST",
|
||||
"/signing-baskets",
|
||||
"Create a signing basket resource",
|
||||
s"""${mockedDataText(true)}
|
||||
Create a signing basket resource for authorising several transactions with one SCA method.
|
||||
The resource identifications of these transactions are contained in the payload of this access method
|
||||
|
||||
""",
|
||||
json.parse(""""""),
|
||||
json.parse("""{
|
||||
"basketId" : "1234-basket-567",
|
||||
"challengeData" : {
|
||||
"otpMaxLength" : 0,
|
||||
"additionalInformation" : "additionalInformation",
|
||||
"image" : "image",
|
||||
"imageLink" : "http://example.com/aeiou",
|
||||
"otpFormat" : "characters",
|
||||
"data" : [ "data", "data" ]
|
||||
},
|
||||
"scaMethods" : "",
|
||||
"tppMessages" : [ {
|
||||
"path" : "path",
|
||||
"code" : { },
|
||||
"text" : { },
|
||||
"category" : { }
|
||||
}, {
|
||||
"path" : "path",
|
||||
"code" : { },
|
||||
"text" : { },
|
||||
"category" : { }
|
||||
} ],
|
||||
"_links" : {
|
||||
"scaStatus" : {
|
||||
"href" : "/v1/payments/sepa-credit-transfers/1234-wertiq-983"
|
||||
},
|
||||
"startAuthorisationWithEncryptedPsuAuthentication" : {
|
||||
"href" : "/v1/payments/sepa-credit-transfers/1234-wertiq-983"
|
||||
},
|
||||
"scaRedirect" : {
|
||||
"href" : "/v1/payments/sepa-credit-transfers/1234-wertiq-983"
|
||||
},
|
||||
"startAuthorisationWithAuthenticationMethodSelection" : {
|
||||
"href" : "/v1/payments/sepa-credit-transfers/1234-wertiq-983"
|
||||
},
|
||||
"startAuthorisationWithPsuAuthentication" : {
|
||||
"href" : "/v1/payments/sepa-credit-transfers/1234-wertiq-983"
|
||||
},
|
||||
"scaOAuth" : {
|
||||
"href" : "/v1/payments/sepa-credit-transfers/1234-wertiq-983"
|
||||
},
|
||||
"self" : {
|
||||
"href" : "/v1/payments/sepa-credit-transfers/1234-wertiq-983"
|
||||
},
|
||||
"startAuthorisationWithPsuIdentification" : {
|
||||
"href" : "/v1/payments/sepa-credit-transfers/1234-wertiq-983"
|
||||
},
|
||||
"startAuthorisation" : {
|
||||
"href" : "/v1/payments/sepa-credit-transfers/1234-wertiq-983"
|
||||
},
|
||||
"startAuthorisationWithTransactionAuthorisation" : {
|
||||
"href" : "/v1/payments/sepa-credit-transfers/1234-wertiq-983"
|
||||
},
|
||||
"status" : {
|
||||
"href" : "/v1/payments/sepa-credit-transfers/1234-wertiq-983"
|
||||
}
|
||||
},
|
||||
"chosenScaMethod" : "",
|
||||
"transactionStatus" : "RCVD",
|
||||
"psuMessage" : { }
|
||||
}"""),
|
||||
List(UserNotLoggedIn, UnknownError),
|
||||
Catalogs(notCore, notPSD2, notOBWG),
|
||||
ApiTag("Signing Baskets (SBS)") :: apiTagMockedData :: Nil
|
||||
)
|
||||
|
||||
lazy val createSigningBasket : OBPEndpoint = {
|
||||
case "signing-baskets" :: Nil JsonPost _ => {
|
||||
cc =>
|
||||
for {
|
||||
(Full(u), callContext) <- authorizedAccess(cc, UserNotLoggedIn)
|
||||
} yield {
|
||||
(json.parse("""{
|
||||
"basketId" : "1234-basket-567",
|
||||
"challengeData" : {
|
||||
"otpMaxLength" : 0,
|
||||
"additionalInformation" : "additionalInformation",
|
||||
"image" : "image",
|
||||
"imageLink" : "http://example.com/aeiou",
|
||||
"otpFormat" : "characters",
|
||||
"data" : [ "data", "data" ]
|
||||
},
|
||||
"scaMethods" : "",
|
||||
"tppMessages" : [ {
|
||||
"path" : "path",
|
||||
"code" : { },
|
||||
"text" : { },
|
||||
"category" : { }
|
||||
}, {
|
||||
"path" : "path",
|
||||
"code" : { },
|
||||
"text" : { },
|
||||
"category" : { }
|
||||
} ],
|
||||
"_links" : {
|
||||
"scaStatus" : {
|
||||
"href" : "/v1/payments/sepa-credit-transfers/1234-wertiq-983"
|
||||
},
|
||||
"startAuthorisationWithEncryptedPsuAuthentication" : {
|
||||
"href" : "/v1/payments/sepa-credit-transfers/1234-wertiq-983"
|
||||
},
|
||||
"scaRedirect" : {
|
||||
"href" : "/v1/payments/sepa-credit-transfers/1234-wertiq-983"
|
||||
},
|
||||
"startAuthorisationWithAuthenticationMethodSelection" : {
|
||||
"href" : "/v1/payments/sepa-credit-transfers/1234-wertiq-983"
|
||||
},
|
||||
"startAuthorisationWithPsuAuthentication" : {
|
||||
"href" : "/v1/payments/sepa-credit-transfers/1234-wertiq-983"
|
||||
},
|
||||
"scaOAuth" : {
|
||||
"href" : "/v1/payments/sepa-credit-transfers/1234-wertiq-983"
|
||||
},
|
||||
"self" : {
|
||||
"href" : "/v1/payments/sepa-credit-transfers/1234-wertiq-983"
|
||||
},
|
||||
"startAuthorisationWithPsuIdentification" : {
|
||||
"href" : "/v1/payments/sepa-credit-transfers/1234-wertiq-983"
|
||||
},
|
||||
"startAuthorisation" : {
|
||||
"href" : "/v1/payments/sepa-credit-transfers/1234-wertiq-983"
|
||||
},
|
||||
"startAuthorisationWithTransactionAuthorisation" : {
|
||||
"href" : "/v1/payments/sepa-credit-transfers/1234-wertiq-983"
|
||||
},
|
||||
"status" : {
|
||||
"href" : "/v1/payments/sepa-credit-transfers/1234-wertiq-983"
|
||||
}
|
||||
},
|
||||
"chosenScaMethod" : "",
|
||||
"transactionStatus" : "RCVD",
|
||||
"psuMessage" : { }
|
||||
}"""), callContext)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resourceDocs += ResourceDoc(
|
||||
deleteSigningBasket,
|
||||
apiVersion,
|
||||
nameOf(deleteSigningBasket),
|
||||
"DELETE",
|
||||
"/signing-baskets/BASKETID",
|
||||
"Delete the signing basket",
|
||||
s"""${mockedDataText(true)}
|
||||
Delete the signing basket structure as long as no (partial) authorisation has yet been applied.
|
||||
The undlerying transactions are not affected by this deletion. Remark: The signing basket as such is not
|
||||
deletable after a first (partial) authorisation has been applied. Nevertheless, single transactions might
|
||||
be cancelled on an individual basis on the XS2A interface.
|
||||
|
||||
""",
|
||||
json.parse(""""""),
|
||||
json.parse(""""""),
|
||||
List(UserNotLoggedIn, UnknownError),
|
||||
Catalogs(notCore, notPSD2, notOBWG),
|
||||
ApiTag("Signing Baskets (SBS)") ::ApiTag("Common Services") :: apiTagMockedData :: Nil
|
||||
)
|
||||
|
||||
lazy val deleteSigningBasket : OBPEndpoint = {
|
||||
case "signing-baskets" :: basketid :: Nil JsonDelete _ => {
|
||||
cc =>
|
||||
for {
|
||||
(Full(u), callContext) <- authorizedAccess(cc, UserNotLoggedIn)
|
||||
} yield {
|
||||
(json.parse(""""""), callContext)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resourceDocs += ResourceDoc(
|
||||
getSigningBasket,
|
||||
apiVersion,
|
||||
nameOf(getSigningBasket),
|
||||
"GET",
|
||||
"/signing-baskets/BASKETID",
|
||||
"Returns the content of an signing basket object.",
|
||||
s"""${mockedDataText(true)}
|
||||
Returns the content of an signing basket object.
|
||||
|
||||
""",
|
||||
json.parse(""""""),
|
||||
json.parse("""{
|
||||
"_links" : {
|
||||
"scaStatus" : {
|
||||
"href" : "/v1/payments/sepa-credit-transfers/1234-wertiq-983"
|
||||
},
|
||||
"startAuthorisationWithEncryptedPsuAuthentication" : {
|
||||
"href" : "/v1/payments/sepa-credit-transfers/1234-wertiq-983"
|
||||
},
|
||||
"scaRedirect" : {
|
||||
"href" : "/v1/payments/sepa-credit-transfers/1234-wertiq-983"
|
||||
},
|
||||
"startAuthorisationWithAuthenticationMethodSelection" : {
|
||||
"href" : "/v1/payments/sepa-credit-transfers/1234-wertiq-983"
|
||||
},
|
||||
"startAuthorisationWithPsuAuthentication" : {
|
||||
"href" : "/v1/payments/sepa-credit-transfers/1234-wertiq-983"
|
||||
},
|
||||
"scaOAuth" : {
|
||||
"href" : "/v1/payments/sepa-credit-transfers/1234-wertiq-983"
|
||||
},
|
||||
"self" : {
|
||||
"href" : "/v1/payments/sepa-credit-transfers/1234-wertiq-983"
|
||||
},
|
||||
"startAuthorisationWithPsuIdentification" : {
|
||||
"href" : "/v1/payments/sepa-credit-transfers/1234-wertiq-983"
|
||||
},
|
||||
"startAuthorisation" : {
|
||||
"href" : "/v1/payments/sepa-credit-transfers/1234-wertiq-983"
|
||||
},
|
||||
"startAuthorisationWithTransactionAuthorisation" : {
|
||||
"href" : "/v1/payments/sepa-credit-transfers/1234-wertiq-983"
|
||||
},
|
||||
"status" : {
|
||||
"href" : "/v1/payments/sepa-credit-transfers/1234-wertiq-983"
|
||||
}
|
||||
},
|
||||
"transactionStatus" : "RCVD",
|
||||
"payments" : "",
|
||||
"consents" : ""
|
||||
}"""),
|
||||
List(UserNotLoggedIn, UnknownError),
|
||||
Catalogs(notCore, notPSD2, notOBWG),
|
||||
ApiTag("Signing Baskets (SBS)") :: apiTagMockedData :: Nil
|
||||
)
|
||||
|
||||
lazy val getSigningBasket : OBPEndpoint = {
|
||||
case "signing-baskets" :: basketid :: Nil JsonGet _ => {
|
||||
cc =>
|
||||
for {
|
||||
(Full(u), callContext) <- authorizedAccess(cc, UserNotLoggedIn)
|
||||
} yield {
|
||||
(json.parse("""{
|
||||
"_links" : {
|
||||
"scaStatus" : {
|
||||
"href" : "/v1/payments/sepa-credit-transfers/1234-wertiq-983"
|
||||
},
|
||||
"startAuthorisationWithEncryptedPsuAuthentication" : {
|
||||
"href" : "/v1/payments/sepa-credit-transfers/1234-wertiq-983"
|
||||
},
|
||||
"scaRedirect" : {
|
||||
"href" : "/v1/payments/sepa-credit-transfers/1234-wertiq-983"
|
||||
},
|
||||
"startAuthorisationWithAuthenticationMethodSelection" : {
|
||||
"href" : "/v1/payments/sepa-credit-transfers/1234-wertiq-983"
|
||||
},
|
||||
"startAuthorisationWithPsuAuthentication" : {
|
||||
"href" : "/v1/payments/sepa-credit-transfers/1234-wertiq-983"
|
||||
},
|
||||
"scaOAuth" : {
|
||||
"href" : "/v1/payments/sepa-credit-transfers/1234-wertiq-983"
|
||||
},
|
||||
"self" : {
|
||||
"href" : "/v1/payments/sepa-credit-transfers/1234-wertiq-983"
|
||||
},
|
||||
"startAuthorisationWithPsuIdentification" : {
|
||||
"href" : "/v1/payments/sepa-credit-transfers/1234-wertiq-983"
|
||||
},
|
||||
"startAuthorisation" : {
|
||||
"href" : "/v1/payments/sepa-credit-transfers/1234-wertiq-983"
|
||||
},
|
||||
"startAuthorisationWithTransactionAuthorisation" : {
|
||||
"href" : "/v1/payments/sepa-credit-transfers/1234-wertiq-983"
|
||||
},
|
||||
"status" : {
|
||||
"href" : "/v1/payments/sepa-credit-transfers/1234-wertiq-983"
|
||||
}
|
||||
},
|
||||
"transactionStatus" : "RCVD",
|
||||
"payments" : "",
|
||||
"consents" : ""
|
||||
}"""), callContext)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resourceDocs += ResourceDoc(
|
||||
getSigningBasketAuthorisation,
|
||||
apiVersion,
|
||||
nameOf(getSigningBasketAuthorisation),
|
||||
"GET",
|
||||
"/signing-baskets/BASKETID/authorisations",
|
||||
"Get Signing Basket Authorisation Sub-Resources Request",
|
||||
s"""${mockedDataText(true)}
|
||||
Read a list of all authorisation subresources IDs which have been created. This function returns an array
|
||||
of hyperlinks to all generated authorisation sub-resources.
|
||||
|
||||
""",
|
||||
json.parse(""""""),
|
||||
json.parse("""{
|
||||
"authorisationIds" : ""
|
||||
}"""),
|
||||
List(UserNotLoggedIn, UnknownError),
|
||||
Catalogs(notCore, notPSD2, notOBWG),
|
||||
ApiTag("Signing Baskets (SBS)") ::ApiTag("Common Services") :: apiTagMockedData :: Nil
|
||||
)
|
||||
|
||||
lazy val getSigningBasketAuthorisation : OBPEndpoint = {
|
||||
case "signing-baskets" :: basketid:: "authorisations" :: Nil JsonGet _ => {
|
||||
cc =>
|
||||
for {
|
||||
(Full(u), callContext) <- authorizedAccess(cc, UserNotLoggedIn)
|
||||
} yield {
|
||||
(json.parse("""{
|
||||
"authorisationIds" : ""
|
||||
}"""), callContext)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resourceDocs += ResourceDoc(
|
||||
getSigningBasketScaStatus,
|
||||
apiVersion,
|
||||
nameOf(getSigningBasketScaStatus),
|
||||
"GET",
|
||||
"/signing-baskets/BASKETID/authorisations/AUTHORISATIONID",
|
||||
"Read the SCA status of the signing basket authorisation",
|
||||
s"""${mockedDataText(true)}
|
||||
This method returns the SCA status of a signing basket's authorisation sub-resource.
|
||||
|
||||
""",
|
||||
json.parse(""""""),
|
||||
json.parse("""{
|
||||
"scaStatus" : "psuAuthenticated"
|
||||
}"""),
|
||||
List(UserNotLoggedIn, UnknownError),
|
||||
Catalogs(notCore, notPSD2, notOBWG),
|
||||
ApiTag("Signing Baskets (SBS)") ::ApiTag("Common Services") :: apiTagMockedData :: Nil
|
||||
)
|
||||
|
||||
lazy val getSigningBasketScaStatus : OBPEndpoint = {
|
||||
case "signing-baskets" :: basketid:: "authorisations" :: authorisationid :: Nil JsonGet _ => {
|
||||
cc =>
|
||||
for {
|
||||
(Full(u), callContext) <- authorizedAccess(cc, UserNotLoggedIn)
|
||||
} yield {
|
||||
(json.parse("""{
|
||||
"scaStatus" : "psuAuthenticated"
|
||||
}"""), callContext)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resourceDocs += ResourceDoc(
|
||||
getSigningBasketStatus,
|
||||
apiVersion,
|
||||
nameOf(getSigningBasketStatus),
|
||||
"GET",
|
||||
"/signing-baskets/BASKETID/status",
|
||||
"Read the status of the signing basket",
|
||||
s"""${mockedDataText(true)}
|
||||
Returns the status of a signing basket object.
|
||||
|
||||
""",
|
||||
json.parse(""""""),
|
||||
json.parse("""{
|
||||
"transactionStatus" : "RCVD"
|
||||
}"""),
|
||||
List(UserNotLoggedIn, UnknownError),
|
||||
Catalogs(notCore, notPSD2, notOBWG),
|
||||
ApiTag("Signing Baskets (SBS)") ::ApiTag("Common Services") :: apiTagMockedData :: Nil
|
||||
)
|
||||
|
||||
lazy val getSigningBasketStatus : OBPEndpoint = {
|
||||
case "signing-baskets" :: basketid:: "status" :: Nil JsonGet _ => {
|
||||
cc =>
|
||||
for {
|
||||
(Full(u), callContext) <- authorizedAccess(cc, UserNotLoggedIn)
|
||||
} yield {
|
||||
(json.parse("""{
|
||||
"transactionStatus" : "RCVD"
|
||||
}"""), callContext)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resourceDocs += ResourceDoc(
|
||||
startSigningBasketAuthorisation,
|
||||
apiVersion,
|
||||
nameOf(startSigningBasketAuthorisation),
|
||||
"POST",
|
||||
"/signing-baskets/BASKETID/authorisations",
|
||||
"Start the authorisation process for a signing basket",
|
||||
s"""${mockedDataText(true)}
|
||||
Create an authorisation sub-resource and start the authorisation process of a signing basket. The message
|
||||
might in addition transmit authentication and authorisation related data. This method is iterated n times
|
||||
for a n times SCA authorisation in a corporate context, each creating an own authorisation sub-endpoint for
|
||||
the corresponding PSU authorising the signing-baskets. The ASPSP might make the usage of this access method
|
||||
unnecessary in case of only one SCA process needed, since the related authorisation resource might be
|
||||
automatically created by the ASPSP after the submission of the payment data with the first POST signing
|
||||
basket call. The start authorisation process is a process which is needed for creating a new authorisation
|
||||
or cancellation sub-resource. This applies in the following scenarios: * The ASPSP has indicated with
|
||||
an 'startAuthorisation' hyperlink in the preceding Payment Initiation Response that an explicit start of
|
||||
the authorisation process is needed by the TPP. The 'startAuthorisation' hyperlink can transport more
|
||||
information about data which needs to be uploaded by using the extended forms.
|
||||
* 'startAuthorisationWithPsuIdentfication',
|
||||
* 'startAuthorisationWithPsuAuthentication'
|
||||
* 'startAuthorisationWithEncryptedPsuAuthentication'
|
||||
* 'startAuthorisationWithAuthentciationMethodSelection'
|
||||
*The related payment initiation cannot yet be executed since a multilevel SCA is mandated.
|
||||
* The ASPSP has indicated with an 'startAuthorisation' hyperlink in the preceding Payment Cancellation
|
||||
Response that an explicit start of the authorisation process is needed by the TPP. The 'startAuthorisation'
|
||||
hyperlink can transport more information about data which needs to be uploaded by using the extended forms
|
||||
as indicated above. * The related payment cancellation request cannot be applied yet since a multilevel
|
||||
SCA is mandate for executing the cancellation. * The signing basket needs to be authorised yet.
|
||||
|
||||
""",
|
||||
json.parse(""""""),
|
||||
json.parse("""{
|
||||
"authorisationId" : "123auth456",
|
||||
"challengeData" : {
|
||||
"otpMaxLength" : 0,
|
||||
"additionalInformation" : "additionalInformation",
|
||||
"image" : "image",
|
||||
"imageLink" : "http://example.com/aeiou",
|
||||
"otpFormat" : "characters",
|
||||
"data" : [ "data", "data" ]
|
||||
},
|
||||
"scaMethods" : "",
|
||||
"scaStatus" : "psuAuthenticated",
|
||||
"_links" : {
|
||||
"scaStatus" : {
|
||||
"href" : "/v1/payments/sepa-credit-transfers/1234-wertiq-983"
|
||||
},
|
||||
"startAuthorisationWithEncryptedPsuAuthentication" : {
|
||||
"href" : "/v1/payments/sepa-credit-transfers/1234-wertiq-983"
|
||||
},
|
||||
"scaRedirect" : {
|
||||
"href" : "/v1/payments/sepa-credit-transfers/1234-wertiq-983"
|
||||
},
|
||||
"selectAuthenticationMethod" : {
|
||||
"href" : "/v1/payments/sepa-credit-transfers/1234-wertiq-983"
|
||||
},
|
||||
"startAuthorisationWithPsuAuthentication" : {
|
||||
"href" : "/v1/payments/sepa-credit-transfers/1234-wertiq-983"
|
||||
},
|
||||
"authoriseTransaction" : {
|
||||
"href" : "/v1/payments/sepa-credit-transfers/1234-wertiq-983"
|
||||
},
|
||||
"scaOAuth" : {
|
||||
"href" : "/v1/payments/sepa-credit-transfers/1234-wertiq-983"
|
||||
},
|
||||
"updatePsuIdentification" : {
|
||||
"href" : "/v1/payments/sepa-credit-transfers/1234-wertiq-983"
|
||||
}
|
||||
},
|
||||
"chosenScaMethod" : "",
|
||||
"psuMessage" : { }
|
||||
}"""),
|
||||
List(UserNotLoggedIn, UnknownError),
|
||||
Catalogs(notCore, notPSD2, notOBWG),
|
||||
ApiTag("Signing Baskets (SBS)") ::ApiTag("Common Services") :: apiTagMockedData :: Nil
|
||||
)
|
||||
|
||||
lazy val startSigningBasketAuthorisation : OBPEndpoint = {
|
||||
case "signing-baskets" :: basketid:: "authorisations" :: Nil JsonPost _ => {
|
||||
cc =>
|
||||
for {
|
||||
(Full(u), callContext) <- authorizedAccess(cc, UserNotLoggedIn)
|
||||
} yield {
|
||||
(json.parse("""{
|
||||
"authorisationId" : "123auth456",
|
||||
"challengeData" : {
|
||||
"otpMaxLength" : 0,
|
||||
"additionalInformation" : "additionalInformation",
|
||||
"image" : "image",
|
||||
"imageLink" : "http://example.com/aeiou",
|
||||
"otpFormat" : "characters",
|
||||
"data" : [ "data", "data" ]
|
||||
},
|
||||
"scaMethods" : "",
|
||||
"scaStatus" : "psuAuthenticated",
|
||||
"_links" : {
|
||||
"scaStatus" : {
|
||||
"href" : "/v1/payments/sepa-credit-transfers/1234-wertiq-983"
|
||||
},
|
||||
"startAuthorisationWithEncryptedPsuAuthentication" : {
|
||||
"href" : "/v1/payments/sepa-credit-transfers/1234-wertiq-983"
|
||||
},
|
||||
"scaRedirect" : {
|
||||
"href" : "/v1/payments/sepa-credit-transfers/1234-wertiq-983"
|
||||
},
|
||||
"selectAuthenticationMethod" : {
|
||||
"href" : "/v1/payments/sepa-credit-transfers/1234-wertiq-983"
|
||||
},
|
||||
"startAuthorisationWithPsuAuthentication" : {
|
||||
"href" : "/v1/payments/sepa-credit-transfers/1234-wertiq-983"
|
||||
},
|
||||
"authoriseTransaction" : {
|
||||
"href" : "/v1/payments/sepa-credit-transfers/1234-wertiq-983"
|
||||
},
|
||||
"scaOAuth" : {
|
||||
"href" : "/v1/payments/sepa-credit-transfers/1234-wertiq-983"
|
||||
},
|
||||
"updatePsuIdentification" : {
|
||||
"href" : "/v1/payments/sepa-credit-transfers/1234-wertiq-983"
|
||||
}
|
||||
},
|
||||
"chosenScaMethod" : "",
|
||||
"psuMessage" : { }
|
||||
}"""), callContext)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resourceDocs += ResourceDoc(
|
||||
updateSigningBasketPsuData,
|
||||
apiVersion,
|
||||
nameOf(updateSigningBasketPsuData),
|
||||
"PUT",
|
||||
"/signing-baskets/BASKETID/authorisations/AUTHORISATIONID",
|
||||
"Update PSU Data for signing basket",
|
||||
s"""${mockedDataText(true)}
|
||||
This method update PSU data on the signing basket resource if needed. It may authorise a igning basket within
|
||||
the Embedded SCA Approach where needed. Independently from the SCA Approach it supports e.g. the selection of
|
||||
the authentication method and a non-SCA PSU authentication. This methods updates PSU data on the cancellation
|
||||
authorisation resource if needed. There are several possible Update PSU Data requests in the context of a consent
|
||||
request if needed, which depends on the SCA approach: * Redirect SCA Approach: A specific Update PSU Data Request
|
||||
is applicable for * the selection of authentication methods, before choosing the actual SCA approach.
|
||||
* Decoupled SCA Approach: A specific Update PSU Data Request is only applicable for
|
||||
* adding the PSU Identification, if not provided yet in the Payment Initiation Request or the Account
|
||||
Information Consent Request, or if no OAuth2 access token is used, or
|
||||
* the selection of authentication methods.
|
||||
* Embedded SCA Approach: The Update PSU Data Request might be used
|
||||
* to add credentials as a first factor authentication data of the PSU and
|
||||
* to select the authentication method and * transaction authorisation.
|
||||
The SCA Approach might depend on the chosen SCA method. For that reason,
|
||||
the following possible Update PSU Data request can apply to all SCA approaches:
|
||||
* Select an SCA method in case of several SCA methods are available for the customer.
|
||||
There are the following request types on this access path: * Update PSU Identification
|
||||
* Update PSU Authentication * Select PSU Autorization Method WARNING: This method need a reduced header,
|
||||
therefore many optional elements are not present. Maybe in a later version the access path will change.
|
||||
* Transaction Authorisation WARNING: This method need a reduced header, therefore many optional elements
|
||||
are not present. Maybe in a later version the access path will change.
|
||||
|
||||
""",
|
||||
json.parse(""""""),
|
||||
json.parse(""""""""),
|
||||
List(UserNotLoggedIn, UnknownError),
|
||||
Catalogs(notCore, notPSD2, notOBWG),
|
||||
ApiTag("Signing Baskets (SBS)") ::ApiTag("Common Services") :: apiTagMockedData :: Nil
|
||||
)
|
||||
|
||||
lazy val updateSigningBasketPsuData : OBPEndpoint = {
|
||||
case "signing-baskets" :: basketid:: "authorisations" :: authorisationid :: Nil JsonPut _ => {
|
||||
cc =>
|
||||
for {
|
||||
(Full(u), callContext) <- authorizedAccess(cc, UserNotLoggedIn)
|
||||
} yield {
|
||||
(json.parse(""""""""), callContext)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -2557,9 +2557,11 @@ Returns a string showed to the developer
|
||||
val validatedPem = X509.validate(pem)
|
||||
validatedPem match {
|
||||
case Full(true) =>
|
||||
Full(X509.getRoles(pem).contains(serviceProvider)) match {
|
||||
val roles = X509.extractPsd2Roles(pem).map(_.exists(_ == serviceProvider))
|
||||
roles match {
|
||||
case Full(true) => Full(true)
|
||||
case Full(false) => Failure(X509ActionIsNotAllowed)
|
||||
case _ => roles
|
||||
}
|
||||
case _ =>
|
||||
validatedPem
|
||||
@ -2569,7 +2571,7 @@ Returns a string showed to the developer
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
|
||||
def passesPsd2ServiceProvider(cc: Option[CallContext], serviceProvider: String): OBPReturnType[Box[Boolean]] = {
|
||||
val result = passesPsd2ServiceProviderCommon(cc, serviceProvider)
|
||||
Future(result) map {
|
||||
@ -2577,16 +2579,16 @@ Returns a string showed to the developer
|
||||
}
|
||||
}
|
||||
def passesPsd2Aisp(cc: Option[CallContext]): OBPReturnType[Box[Boolean]] = {
|
||||
passesPsd2ServiceProvider(cc, PemCertificateRole.psp_ai.toString())
|
||||
passesPsd2ServiceProvider(cc, PemCertificateRole.PSP_AI.toString())
|
||||
}
|
||||
def passesPsd2Pisp(cc: Option[CallContext]): OBPReturnType[Box[Boolean]] = {
|
||||
passesPsd2ServiceProvider(cc, PemCertificateRole.psp_pi.toString())
|
||||
passesPsd2ServiceProvider(cc, PemCertificateRole.PSP_PI.toString())
|
||||
}
|
||||
def passesPsd2Icsp(cc: Option[CallContext]): OBPReturnType[Box[Boolean]] = {
|
||||
passesPsd2ServiceProvider(cc, PemCertificateRole.psp_ic.toString())
|
||||
passesPsd2ServiceProvider(cc, PemCertificateRole.PSP_IC.toString())
|
||||
}
|
||||
def passesPsd2Assp(cc: Option[CallContext]): OBPReturnType[Box[Boolean]] = {
|
||||
passesPsd2ServiceProvider(cc, PemCertificateRole.psp_as.toString())
|
||||
passesPsd2ServiceProvider(cc, PemCertificateRole.PSP_AS.toString())
|
||||
}
|
||||
|
||||
|
||||
@ -2594,23 +2596,30 @@ Returns a string showed to the developer
|
||||
passesPsd2ServiceProviderCommon(cc, serviceProvider) ?~! X509GeneralError
|
||||
}
|
||||
def passesPsd2AispOldStyle(cc: Option[CallContext]): Box[Boolean] = {
|
||||
passesPsd2ServiceProviderOldStyle(cc, PemCertificateRole.psp_ai.toString())
|
||||
passesPsd2ServiceProviderOldStyle(cc, PemCertificateRole.PSP_AI.toString())
|
||||
}
|
||||
def passesPsd2PispOldStyle(cc: Option[CallContext]): Box[Boolean] = {
|
||||
passesPsd2ServiceProviderOldStyle(cc, PemCertificateRole.psp_pi.toString())
|
||||
passesPsd2ServiceProviderOldStyle(cc, PemCertificateRole.PSP_PI.toString())
|
||||
}
|
||||
def passesPsd2IcspOldStyle(cc: Option[CallContext]): Box[Boolean] = {
|
||||
passesPsd2ServiceProviderOldStyle(cc, PemCertificateRole.psp_ic.toString())
|
||||
passesPsd2ServiceProviderOldStyle(cc, PemCertificateRole.PSP_IC.toString())
|
||||
}
|
||||
def passesPsd2AsspOldStyle(cc: Option[CallContext]): Box[Boolean] = {
|
||||
passesPsd2ServiceProviderOldStyle(cc, PemCertificateRole.psp_as.toString())
|
||||
passesPsd2ServiceProviderOldStyle(cc, PemCertificateRole.PSP_AS.toString())
|
||||
}
|
||||
|
||||
|
||||
|
||||
def getMaskedPrimaryAccountNumber(accountNumber: String): String = {
|
||||
val (first, second) = accountNumber.splitAt(accountNumber.size/2)
|
||||
first.substring(0, first.size - 3) + "***" + "***" + second.substring(3)
|
||||
if(first.length >=3 && second.length>=3)
|
||||
first.substring(0, first.size - 3) + "***" + "***" + second.substring(3)
|
||||
else if (first.length >=3 && second.length< 3)
|
||||
first.substring(0, first.size - 3) + "***" + "***" + second
|
||||
else if (first.length <3 && second.length>= 3)
|
||||
first + "***" + "***" + second.substring(3)
|
||||
else
|
||||
first+ "***" + "***" + second
|
||||
}
|
||||
|
||||
def getBicFromBankId(bankId: String)= {
|
||||
|
||||
@ -8,8 +8,8 @@ object StrongCustomerAuthentication extends Enumeration {
|
||||
|
||||
object PemCertificateRole extends Enumeration {
|
||||
type ROLE = Value
|
||||
val psp_as = Value
|
||||
val psp_ic = Value
|
||||
val psp_ai = Value
|
||||
val psp_pi = Value
|
||||
val PSP_AS = Value
|
||||
val PSP_IC = Value
|
||||
val PSP_AI = Value
|
||||
val PSP_PI = Value
|
||||
}
|
||||
@ -152,6 +152,7 @@ object ErrorMessages {
|
||||
val X509CannotGetECPublicKey = "OBP-20305: EC public key cannot be found at PEM Encoded Certificate."
|
||||
val X509CannotGetCertificate = "OBP-20306: PEM Encoded Certificate cannot be found at request header."
|
||||
val X509ActionIsNotAllowed = "OBP-20307: PEM Encoded Certificate does not provide the proper role for the action has been taken."
|
||||
val X509ThereAreNoPsd2Roles = "OBP-20308: PEM Encoded Certificate does not contain PSD2 roles."
|
||||
|
||||
// Resource related messages (OBP-30XXX)
|
||||
val BankNotFound = "OBP-30001: Bank not found. Please specify a valid value for BANK_ID."
|
||||
@ -310,6 +311,7 @@ object ErrorMessages {
|
||||
|
||||
//Authorisations
|
||||
val AuthorisationNotFound = "OBP-36001: Authorisation not found. Please specify valid values for PAYMENT_ID and AUTHORISATION_ID. "
|
||||
val InvalidAuthorisationStatus = "OBP-36002: Authorisation Status is Invalid"
|
||||
// General Resource related messages above here
|
||||
|
||||
|
||||
|
||||
@ -3,20 +3,25 @@ package code.api.util
|
||||
import java.security.PublicKey
|
||||
import java.security.cert.{CertificateExpiredException, CertificateNotYetValidException, X509Certificate}
|
||||
import java.security.interfaces.{ECPublicKey, RSAPublicKey}
|
||||
import java.io.ByteArrayInputStream
|
||||
|
||||
import com.github.dwickern.macros.NameOf
|
||||
import com.nimbusds.jose.jwk.RSAKey
|
||||
import com.nimbusds.jose.util.X509CertUtils
|
||||
import net.liftweb.common.{Box, Failure, Full}
|
||||
import org.bouncycastle.asn1.x509.Extension
|
||||
import org.bouncycastle.asn1.{ASN1Encodable, ASN1InputStream, ASN1ObjectIdentifier, ASN1Sequence, DEROctetString}
|
||||
import org.bouncycastle.asn1.x509.qualified.QCStatement
|
||||
|
||||
object X509 {
|
||||
|
||||
|
||||
object OID {
|
||||
lazy val role = "2.5.4.72"
|
||||
lazy val etsiPsd2QcStatement = new ASN1ObjectIdentifier("0.4.0.19495.2")
|
||||
}
|
||||
|
||||
|
||||
case class SubjectAttribute(key: String, value: String)
|
||||
|
||||
|
||||
private def extractSubjectAttributes(encodedCert: String): List[SubjectAttribute] = {
|
||||
// Parse X.509 certificate
|
||||
val cert: X509Certificate = X509CertUtils.parse(encodedCert)
|
||||
@ -24,14 +29,16 @@ object X509 {
|
||||
// Parsing failed
|
||||
Nil
|
||||
} else {
|
||||
cert.getSubjectDN().getName().split(",").toList.map {
|
||||
cert.getSubjectDN().getName().split(",").toList.map {
|
||||
attribute => attribute.trim.split("=").toList match {
|
||||
case key :: value :: Nil => SubjectAttribute(key, value)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
def getRoles(encodedCert: String): String = {
|
||||
extractSubjectAttributes(encodedCert).filter{
|
||||
attribute => attribute.key.contains(OID.role) || attribute.key.contains(NameOf.nameOf(OID.role))
|
||||
@ -40,8 +47,61 @@ object X509 {
|
||||
case _ => ""
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
def extractQcStatements(cert: X509Certificate): ASN1Sequence = {
|
||||
val qcStatementBytes: Array[Byte] = cert.getExtensionValue(Extension.qCStatements.getId)
|
||||
val inputStream = new ASN1InputStream(new ByteArrayInputStream(qcStatementBytes))
|
||||
val dEROctetString = inputStream.readObject().asInstanceOf[DEROctetString]
|
||||
val qcInputStream = new ASN1InputStream(dEROctetString.getOctets)
|
||||
val qcStatements = qcInputStream.readObject().asInstanceOf[ASN1Sequence]
|
||||
qcStatements
|
||||
}
|
||||
|
||||
def extractPsd2QcStatements(qcstatements: ASN1Sequence) = {
|
||||
val encodable: Array[ASN1Encodable] = qcstatements.toArray.filter(QCStatement.getInstance(_).getStatementId.getId.equals(X509.OID.etsiPsd2QcStatement.getId))
|
||||
encodable
|
||||
}
|
||||
|
||||
def getPsd2Roles(asn1encodable: Array[ASN1Encodable]): List[String] = {
|
||||
var psd2Roles: Set[String] = Set()
|
||||
for (i <- asn1encodable.indices) {
|
||||
val psd2Sequence = ASN1Sequence.getInstance(asn1encodable(i))
|
||||
val psd2TypesEncodable: ASN1Encodable = psd2Sequence.getObjectAt(1)
|
||||
val psd2TypesSequence = ASN1Sequence.getInstance(psd2TypesEncodable)
|
||||
val psd2RolesEncodable: ASN1Encodable = psd2TypesSequence.getObjectAt(0)
|
||||
val psd2RolesSequence = ASN1Sequence.getInstance(psd2RolesEncodable)
|
||||
for (y <- 0 until (psd2RolesSequence.size() - 1)){
|
||||
val psd2RoleEncodable = psd2RolesSequence.getObjectAt(y)
|
||||
val psd2RoleSequence = ASN1Sequence.getInstance(psd2RoleEncodable)
|
||||
psd2Roles += (psd2RoleSequence.getObjectAt(1).toASN1Primitive.toString)
|
||||
}
|
||||
}
|
||||
org.scalameta.logger.elem(psd2Roles.toList)
|
||||
psd2Roles.toList
|
||||
}
|
||||
|
||||
def extractPsd2Roles(pem: String): Box[List[String]] = {
|
||||
// Parse X.509 certificate
|
||||
val cert: X509Certificate = X509CertUtils.parse(pem)
|
||||
if (cert == null) {
|
||||
// Parsing failed
|
||||
Failure(ErrorMessages.X509ParsingFailed)
|
||||
} else {
|
||||
try {
|
||||
val qcstatements = extractQcStatements(cert)
|
||||
val asn1encodable = extractPsd2QcStatements(qcstatements)
|
||||
Full(getPsd2Roles(asn1encodable: Array[ASN1Encodable]))
|
||||
}
|
||||
catch {
|
||||
case _ =>
|
||||
Failure(ErrorMessages.X509ThereAreNoPsd2Roles)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* The certificate must be validated before it may be used.
|
||||
@ -67,7 +127,7 @@ object X509 {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* If the certificate passed validation and can be trusted,
|
||||
* you can proceed by extracting the public key (RSA or EC) that comes with it,
|
||||
|
||||
@ -1129,7 +1129,7 @@ trait APIMethods310 {
|
||||
cc =>
|
||||
for {
|
||||
(user, callContext) <- authorizedAccess(cc)
|
||||
_ <- passesPsd2Aisp(callContext)
|
||||
_ <- passesPsd2Pisp(callContext)
|
||||
(_, callContext) <- NewStyle.function.getBank(bankId, callContext)
|
||||
(account, callContext) <- NewStyle.function.checkBankAccountExists(bankId, accountId, callContext)
|
||||
view <- NewStyle.function.view(viewId, BankIdAccountId(account.bankId, account.accountId), callContext)
|
||||
|
||||
@ -1086,6 +1086,29 @@ trait Connector extends MdcLoggable with CustomJsonFormats{
|
||||
}yield{
|
||||
(transactionId,callContext)
|
||||
}
|
||||
case sepa_credit_transfers => for{
|
||||
|
||||
toSepaCreditTransfers <- NewStyle.function.tryons(s"$TransactionRequestDetailsExtractException It can not extract to $TransactionRequestBodySandBoxTanJSON ", 400, callContext){
|
||||
body.to_sepa_credit_transfers.get
|
||||
}
|
||||
toAccountId = toSepaCreditTransfers.debtorAccount.iban
|
||||
(toAccount, callContext) <- NewStyle.function.getBankAccountByIban(toAccountId, callContext)
|
||||
(createdTransactionId, callContext) <- NewStyle.function.makePaymentv210(
|
||||
fromAccount,
|
||||
toAccount,
|
||||
TransactionRequestCommonBodyJSONCommons(
|
||||
toSepaCreditTransfers.instructedAmount,
|
||||
""
|
||||
),
|
||||
BigDecimal(toSepaCreditTransfers.instructedAmount.amount),
|
||||
"", //This is empty for BerlinGroup sepa_credit_transfers type now.
|
||||
TransactionRequestType(transactionRequestType),
|
||||
transactionRequest.charge_policy,
|
||||
callContext
|
||||
)
|
||||
}yield{
|
||||
(createdTransactionId,callContext)
|
||||
}
|
||||
case transactionRequestType => Future((throw new Exception(s"${InvalidTransactionRequestType}: '${transactionRequestType}'. Not supported in this version.")), callContext)
|
||||
}
|
||||
|
||||
|
||||
@ -80,8 +80,8 @@ object MappedAuthorisationProvider extends AuthorisationProvider {
|
||||
case value if value == ScaStatus.received.toString =>
|
||||
val status = if (authorisation.challengeData == challengeData) ScaStatus.finalised.toString else ScaStatus.failed.toString
|
||||
tryo(authorisation.ScaStatus(status).saveMe())
|
||||
case _ =>
|
||||
Full(authorisation)
|
||||
case _ => //make sure, only `reveived` can be processed, all others are invalid .
|
||||
Failure(s"${ErrorMessages.InvalidAuthorisationStatus}.It should be `received`, but now it is `${authorisation.scaStatus}`")
|
||||
}
|
||||
case Empty =>
|
||||
Empty ?~! s"${ErrorMessages.AuthorisationNotFound} Current PAYMENT_ID($paymentId) and AUTHORISATION_ID ($authorizationId),"
|
||||
|
||||
@ -77,7 +77,7 @@ class PaymentOTP extends MdcLoggable {
|
||||
}
|
||||
|
||||
result.map(json.parse(_).extract[StartPaymentAuthorisationJson]) match {
|
||||
case Right(v) if(v.scaStatus == "received")=> {
|
||||
case Right(v) if(v.scaStatus == "finalised")=> {
|
||||
"#form_otp" #> "" &
|
||||
"#otp-validate-success p *" #> "OTP validate success." &
|
||||
"#otp-validate-errors" #> ""
|
||||
|
||||
@ -153,7 +153,7 @@ class WebUI extends MdcLoggable{
|
||||
}
|
||||
|
||||
def sandboxIntroductionLink: CssSel = {
|
||||
"#sandbox-introduction-link [href]" #> scala.xml.Unparsed(s"${getServerUrl}/introduction")
|
||||
"#sandbox-introduction-link [href]" #> scala.xml.Unparsed(getWebUiPropsValue("webui_api_documentation_url",s"${getServerUrl}/introduction"))
|
||||
}
|
||||
|
||||
def apiDocumentation: CssSel = {
|
||||
|
||||
@ -0,0 +1,253 @@
|
||||
package code.api.berlin.group.v1_3
|
||||
|
||||
import code.api.ErrorMessage
|
||||
import code.api.berlin.group.v1_3.JSONFactory_BERLIN_GROUP_1_3._
|
||||
import code.api.builder.AccountInformationServiceAISApi.APIMethods_AccountInformationServiceAISApi
|
||||
import code.api.util.APIUtil.OAuth._
|
||||
import code.api.util.ErrorMessages._
|
||||
import code.setup.{APIResponse, DefaultUsers}
|
||||
import com.github.dwickern.macros.NameOf.nameOf
|
||||
import net.liftweb.json.Serialization.write
|
||||
import org.scalatest.Tag
|
||||
|
||||
class AccountInformationServiceAISApiTest extends BerlinGroupServerSetupV1_3 with DefaultUsers {
|
||||
|
||||
object getAccountList extends Tag(nameOf(APIMethods_AccountInformationServiceAISApi.getAccountList))
|
||||
|
||||
object getBalances extends Tag(nameOf(APIMethods_AccountInformationServiceAISApi.getBalances))
|
||||
|
||||
object getTransactionList extends Tag(nameOf(APIMethods_AccountInformationServiceAISApi.getTransactionList))
|
||||
|
||||
object getCardAccountTransactionList extends Tag(nameOf(APIMethods_AccountInformationServiceAISApi.getCardAccountTransactionList))
|
||||
|
||||
object createConsent extends Tag(nameOf(APIMethods_AccountInformationServiceAISApi.createConsent))
|
||||
|
||||
object deleteConsent extends Tag(nameOf(APIMethods_AccountInformationServiceAISApi.deleteConsent))
|
||||
|
||||
object getConsentInformation extends Tag(nameOf(APIMethods_AccountInformationServiceAISApi.getConsentInformation))
|
||||
|
||||
object getConsentStatus extends Tag(nameOf(APIMethods_AccountInformationServiceAISApi.getConsentStatus))
|
||||
|
||||
object startConsentAuthorisation extends Tag(nameOf(APIMethods_AccountInformationServiceAISApi.startConsentAuthorisation))
|
||||
|
||||
object getConsentAuthorisation extends Tag(nameOf(APIMethods_AccountInformationServiceAISApi.getConsentAuthorisation))
|
||||
|
||||
object getConsentScaStatus extends Tag(nameOf(APIMethods_AccountInformationServiceAISApi.getConsentScaStatus))
|
||||
|
||||
object updateConsentsPsuData extends Tag(nameOf(APIMethods_AccountInformationServiceAISApi.updateConsentsPsuData))
|
||||
|
||||
|
||||
feature(s"BG v1.3 - $getAccountList") {
|
||||
scenario("Not Authentication User, test failed ", BerlinGroupV1_3, getAccountList) {
|
||||
val requestGet = (V1_3_BG / "accounts").GET
|
||||
val response = makeGetRequest(requestGet)
|
||||
|
||||
Then("We should get a 400 ")
|
||||
response.code should equal(400)
|
||||
response.body.extract[ErrorMessage].message should startWith(UserNotLoggedIn)
|
||||
}
|
||||
|
||||
scenario("Authentication User, test succeed", BerlinGroupV1_3, getAccountList) {
|
||||
val requestGet = (V1_3_BG / "accounts").GET <@ (user1)
|
||||
val response = makeGetRequest(requestGet)
|
||||
|
||||
Then("We should get a 200 ")
|
||||
response.code should equal(200)
|
||||
response.body.extract[CoreAccountsJsonV13].accounts.length > 1 should be (true)
|
||||
}
|
||||
}
|
||||
|
||||
feature(s"BG v1.3 - $getBalances") {
|
||||
scenario("Authentication User, test succeed", BerlinGroupV1_3, getBalances) {
|
||||
val testBankId = testAccountId1
|
||||
val requestGet = (V1_3_BG / "accounts" /testBankId.value/ "balances").GET <@ (user1)
|
||||
val response: APIResponse = makeGetRequest(requestGet)
|
||||
|
||||
Then("We should get a 200 ")
|
||||
response.code should equal(200)
|
||||
response.body.extract[AccountBalancesV13].`balances`.length > 0 should be (true)
|
||||
response.body.extract[AccountBalancesV13].account.iban should be ("")
|
||||
}
|
||||
}
|
||||
|
||||
feature(s"BG v1.3 - $getTransactionList") {
|
||||
scenario("Authentication User, test succeed", BerlinGroupV1_3, getTransactionList) {
|
||||
val testBankId = testAccountId1
|
||||
val requestGet = (V1_3_BG / "accounts" /testBankId.value/ "transactions").GET <@ (user1)
|
||||
val response: APIResponse = makeGetRequest(requestGet)
|
||||
|
||||
Then("We should get a 200 ")
|
||||
response.code should equal(200)
|
||||
response.body.extract[TransactionsJsonV13].account.iban should be ("")
|
||||
response.body.extract[TransactionsJsonV13].transactions.booked.length >0 should be (true)
|
||||
response.body.extract[TransactionsJsonV13].transactions.pending.length >0 should be (true)
|
||||
}
|
||||
}
|
||||
|
||||
feature(s"BG v1.3 - $getCardAccountTransactionList") {
|
||||
scenario("Authentication User, test succeed", BerlinGroupV1_3, getCardAccountTransactionList) {
|
||||
val testBankId = testAccountId1
|
||||
val requestGet = (V1_3_BG / "card-accounts" /testBankId.value/ "transactions").GET <@ (user1)
|
||||
val response: APIResponse = makeGetRequest(requestGet)
|
||||
|
||||
Then("We should get a 200 ")
|
||||
response.code should equal(200)
|
||||
response.body.extract[CardTransactionsJsonV13].cardAccount.maskedPan.length >0 should be (true)
|
||||
response.body.extract[CardTransactionsJsonV13].transactions.booked.length >0 should be (true)
|
||||
}
|
||||
}
|
||||
|
||||
feature(s"BG v1.3 - $createConsent") {
|
||||
scenario("Authentication User, test succeed", BerlinGroupV1_3, createConsent) {
|
||||
val testBankId = testAccountId1
|
||||
val postJsonBody = APIMethods_AccountInformationServiceAISApi
|
||||
.resourceDocs
|
||||
.filter( _.partialFunction == APIMethods_AccountInformationServiceAISApi.createConsent)
|
||||
.head.exampleRequestBody.asInstanceOf[JvalueCaseClass] //All the Json String convert to JvalueCaseClass implicitly
|
||||
.jvalueToCaseclass
|
||||
val requestPost = (V1_3_BG / "consents" ).POST <@ (user1)
|
||||
val response: APIResponse = makePostRequest(requestPost, write(postJsonBody))
|
||||
|
||||
Then("We should get a 201 ")
|
||||
response.code should equal(201)
|
||||
response.body.extract[PostConsentResponseJson].consentId should not be (empty)
|
||||
response.body.extract[PostConsentResponseJson].consentStatus should be ("received")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
feature(s"BG v1.3 - $createConsent and $deleteConsent") {
|
||||
scenario("Authentication User, test succeed", BerlinGroupV1_3, createConsent) {
|
||||
val testBankId = testAccountId1
|
||||
val postJsonBody = APIMethods_AccountInformationServiceAISApi
|
||||
.resourceDocs
|
||||
.filter( _.partialFunction == APIMethods_AccountInformationServiceAISApi.createConsent)
|
||||
.head.exampleRequestBody.asInstanceOf[JvalueCaseClass] //All the Json String convert to JvalueCaseClass implicitly
|
||||
.jvalueToCaseclass
|
||||
val requestPost = (V1_3_BG / "consents" ).POST <@ (user1)
|
||||
val response: APIResponse = makePostRequest(requestPost, write(postJsonBody))
|
||||
|
||||
Then("We should get a 201 ")
|
||||
response.code should equal(201)
|
||||
response.body.extract[PostConsentResponseJson].consentId should not be (empty)
|
||||
|
||||
val consentId =response.body.extract[PostConsentResponseJson].consentId
|
||||
|
||||
Then("We test the delete consent ")
|
||||
val requestDelete = (V1_3_BG / "consents"/consentId ).DELETE <@ (user1)
|
||||
val responseDelete = makeDeleteRequest(requestDelete)
|
||||
responseDelete.code should be (204)
|
||||
|
||||
//TODO We can not delete one consent two time, will fix it later.
|
||||
// val responseDeleteSecondTime = makeDeleteRequest(requestDelete)
|
||||
// responseDeleteSecondTime.code should be (400)
|
||||
}
|
||||
}
|
||||
|
||||
feature(s"BG v1.3 - $createConsent and $getConsentInformation and $getConsentStatus") {
|
||||
scenario("Authentication User, test succeed", BerlinGroupV1_3, createConsent) {
|
||||
val testBankId = testAccountId1
|
||||
val postJsonBody = APIMethods_AccountInformationServiceAISApi
|
||||
.resourceDocs
|
||||
.filter( _.partialFunction == APIMethods_AccountInformationServiceAISApi.createConsent)
|
||||
.head.exampleRequestBody.asInstanceOf[JvalueCaseClass] //All the Json String convert to JvalueCaseClass implicitly
|
||||
.jvalueToCaseclass
|
||||
val requestPost = (V1_3_BG / "consents" ).POST <@ (user1)
|
||||
val response: APIResponse = makePostRequest(requestPost, write(postJsonBody))
|
||||
|
||||
Then("We should get a 201 ")
|
||||
response.code should equal(201)
|
||||
response.body.extract[PostConsentResponseJson].consentId should not be (empty)
|
||||
|
||||
val consentId =response.body.extract[PostConsentResponseJson].consentId
|
||||
|
||||
Then(s"We test the $getConsentInformation")
|
||||
val requestGet = (V1_3_BG / "consents"/consentId ).GET <@ (user1)
|
||||
val responseGet = makeGetRequest(requestGet)
|
||||
responseGet.code should be (200)
|
||||
responseGet.body.extract[GetConsentResponseJson].consentStatus should be ("received")
|
||||
|
||||
Then(s"We test the $getConsentStatus")
|
||||
val requestGetStatus = (V1_3_BG / "consents"/consentId /"status" ).GET <@ (user1)
|
||||
val responseGetStatus = makeGetRequest(requestGetStatus)
|
||||
responseGetStatus.code should be (200)
|
||||
responseGetStatus.body.extract[ConsentStatusJsonV13].consentStatus should be ("received")
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
feature(s"BG v1.3 - ${startConsentAuthorisation.name} ") {
|
||||
scenario("Authentication User, test succeed", BerlinGroupV1_3, startConsentAuthorisation) {
|
||||
val postJsonBody = APIMethods_AccountInformationServiceAISApi
|
||||
.resourceDocs
|
||||
.filter( _.partialFunction == APIMethods_AccountInformationServiceAISApi.createConsent)
|
||||
.head.exampleRequestBody.asInstanceOf[JvalueCaseClass] //All the Json String convert to JvalueCaseClass implicitly
|
||||
.jvalueToCaseclass
|
||||
val requestPost = (V1_3_BG / "consents" ).POST <@ (user1)
|
||||
val response: APIResponse = makePostRequest(requestPost, write(postJsonBody))
|
||||
|
||||
Then("We should get a 201 ")
|
||||
response.code should equal(201)
|
||||
response.body.extract[PostConsentResponseJson].consentId should not be (empty)
|
||||
|
||||
val consentId =response.body.extract[PostConsentResponseJson].consentId
|
||||
|
||||
Then(s"We test the $startConsentAuthorisation")
|
||||
val requestStartConsentAuthorisation = (V1_3_BG / "consents"/consentId /"authorisations" ).POST <@ (user1)
|
||||
val responseStartConsentAuthorisation = makePostRequest(requestStartConsentAuthorisation)
|
||||
responseStartConsentAuthorisation.code should be (201)
|
||||
responseStartConsentAuthorisation.body.extract[StartConsentAuthorisationJson].scaStatus should be ("received")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
feature(s"BG v1.3 - ${startConsentAuthorisation.name} and ${getConsentAuthorisation.name} and ${getConsentScaStatus.name} and ${updateConsentsPsuData.name}") {
|
||||
scenario("Authentication User, test succeed", BerlinGroupV1_3, startConsentAuthorisation) {
|
||||
val postJsonBody = APIMethods_AccountInformationServiceAISApi
|
||||
.resourceDocs
|
||||
.filter( _.partialFunction == APIMethods_AccountInformationServiceAISApi.createConsent)
|
||||
.head.exampleRequestBody.asInstanceOf[JvalueCaseClass] //All the Json String convert to JvalueCaseClass implicitly
|
||||
.jvalueToCaseclass
|
||||
val requestPost = (V1_3_BG / "consents" ).POST <@ (user1)
|
||||
val response: APIResponse = makePostRequest(requestPost, write(postJsonBody))
|
||||
|
||||
Then("We should get a 201 ")
|
||||
response.code should equal(201)
|
||||
response.body.extract[PostConsentResponseJson].consentId should not be (empty)
|
||||
|
||||
val consentId =response.body.extract[PostConsentResponseJson].consentId
|
||||
|
||||
Then(s"We test the $startConsentAuthorisation")
|
||||
val requestStartConsentAuthorisation = (V1_3_BG / "consents"/consentId /"authorisations" ).POST <@ (user1)
|
||||
val responseStartConsentAuthorisation = makePostRequest(requestStartConsentAuthorisation)
|
||||
responseStartConsentAuthorisation.code should be (201)
|
||||
responseStartConsentAuthorisation.body.extract[StartConsentAuthorisationJson].scaStatus should be ("received")
|
||||
|
||||
Then(s"We test the $getConsentAuthorisation")
|
||||
val requestGetConsentAuthorisation = (V1_3_BG / "consents"/consentId /"authorisations" ).POST <@ (user1)
|
||||
val responseGetConsentAuthorisation = makeGetRequest(requestGetConsentAuthorisation)
|
||||
responseGetConsentAuthorisation.code should be (200)
|
||||
responseGetConsentAuthorisation.body.extract[AuthorisationJsonV13].authorisationIds.length > 0 should be (true)
|
||||
|
||||
Then(s"We test the $getConsentScaStatus")
|
||||
val authorisationId = responseGetConsentAuthorisation.body.extract[AuthorisationJsonV13].authorisationIds.head
|
||||
val requestGetConsentScaStatus = (V1_3_BG / "consents"/consentId /"authorisations"/authorisationId ).POST <@ (user1)
|
||||
val responseGetConsentScaStatus = makeGetRequest(requestGetConsentScaStatus)
|
||||
responseGetConsentScaStatus.code should be (200)
|
||||
responseGetConsentScaStatus.body.extract[ScaStatusJsonV13].scaStatus should be ("received")
|
||||
|
||||
Then(s"We test the $updateConsentsPsuData")
|
||||
val updateConsentsPsuDataJsonBody = APIMethods_AccountInformationServiceAISApi
|
||||
.resourceDocs
|
||||
.filter( _.partialFunction == APIMethods_AccountInformationServiceAISApi.updateConsentsPsuData)
|
||||
.head.exampleRequestBody.asInstanceOf[JvalueCaseClass] //All the Json String convert to JvalueCaseClass implicitly
|
||||
.jvalueToCaseclass
|
||||
val requestUpdateConsentsPsuData = (V1_3_BG / "consents"/consentId /"authorisations"/ authorisationId).PUT <@ (user1)
|
||||
val responseUpdateConsentsPsuData = makePutRequest(requestUpdateConsentsPsuData, write(updateConsentsPsuDataJsonBody))
|
||||
responseUpdateConsentsPsuData.code should be (200)
|
||||
responseUpdateConsentsPsuData.body.extract[PostConsentResponseJson].consentStatus should be ("received")
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,7 +1,9 @@
|
||||
package code.api.berlin.group.v1_3
|
||||
|
||||
import code.setup.ServerSetupWithTestData
|
||||
import org.scalatest.Tag
|
||||
|
||||
trait BerlinGroupServerSetupV1_3 extends ServerSetupWithTestData {
|
||||
val urpPrefix = baseRequest / "berlin-group" / "v1.3"
|
||||
object BerlinGroupV1_3 extends Tag("BerlinGroup_v1_3")
|
||||
val V1_3_BG = baseRequest / "berlin-group" / "v1.3"
|
||||
}
|
||||
|
||||
@ -1,99 +0,0 @@
|
||||
package code.api.berlin.group.v1_3
|
||||
|
||||
import code.api.ErrorMessage
|
||||
import code.api.util.APIUtil.OAuth._
|
||||
import code.api.util.ErrorMessages._
|
||||
import code.model.dataAccess.MappedBankAccount
|
||||
import code.setup.{APIResponse, DefaultUsers}
|
||||
import code.transactionrequests.TransactionRequests.{PaymentServiceTypes, TransactionRequestTypes}
|
||||
import org.scalatest.Tag
|
||||
|
||||
class BerlinGroupTestsV1_3 extends BerlinGroupServerSetupV1_3 with DefaultUsers {
|
||||
|
||||
object BerlinGroupConcentsV1_3 extends Tag("berlinGroup_concents_v1_3")
|
||||
|
||||
object BerlinGroupPaymentV1_3 extends Tag("berlinGroup_Payment_v1_3")
|
||||
|
||||
val consentJsonForPost =
|
||||
"""{
|
||||
| "access": {
|
||||
| "accounts": [
|
||||
| {
|
||||
| "iban": "FR7612345987650123456789014",
|
||||
| "bban": "BARC12345612345678",
|
||||
| "pan": "5409050000000000",
|
||||
| "maskedPan": "123456xxxxxx1234",
|
||||
| "msisdn": "+49 170 1234567",
|
||||
| "currency": "EUR"
|
||||
| }
|
||||
| ]
|
||||
| },
|
||||
| "recurringIndicator": false,
|
||||
| "validUntil": "2020-12-31",
|
||||
| "frequencyPerDay": 4,
|
||||
| "combinedServiceIndicator": false
|
||||
|}""".stripMargin
|
||||
|
||||
feature("test the BG v1.3 consent endpoints") {
|
||||
scenario("Fail call endpoint createConsent, because accounts is not empty", BerlinGroupConcentsV1_3) {
|
||||
When("Post consent json with no empty accounts")
|
||||
val requestPost = (urpPrefix / "consents").POST <@ (user1)
|
||||
val response: APIResponse = makePostRequest(requestPost, consentJsonForPost)
|
||||
|
||||
Then("We should get a 400 ")
|
||||
response.code should equal(400)
|
||||
response.body.extract[ErrorMessage]
|
||||
.message should startWith(InvalidJsonContent)
|
||||
}
|
||||
|
||||
scenario("Successful call endpoint createConsent", BerlinGroupConcentsV1_3) {
|
||||
When("Post consent json with no empty accounts")
|
||||
val requestPost = (urpPrefix / "consents").POST <@ (user1)
|
||||
val emptyAccountsJson = consentJsonForPost.replaceFirst("""(?s)("accounts"\s*\:\s*\[).*?(\])""", "$1 $2")
|
||||
val response: APIResponse = makePostRequest(requestPost, emptyAccountsJson)
|
||||
|
||||
Then("We should get a 201 ")
|
||||
response.code should equal(201)
|
||||
response.body \ "consentId" should not be null
|
||||
response.body \ "consentStatus" should not be null
|
||||
response.body \ "_links" \ "startAuthorisation" should not be null
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
feature("test the BG v1.3 Payment endpoints") {
|
||||
scenario("Successful call endpoint initiatePayment", BerlinGroupPaymentV1_3) {
|
||||
When("Post empty to call initiatePayment")
|
||||
val accounts = MappedBankAccount.findAll().map(_.accountIban.get).filter(_ != null)
|
||||
val ibanFrom = accounts.head
|
||||
val ibanTo = accounts.last
|
||||
val initiatePaymentJson =
|
||||
s"""{
|
||||
| "debtorAccount": {
|
||||
| "iban": "${ibanFrom}"
|
||||
| },
|
||||
|"instructedAmount": {
|
||||
| "currency": "EUR",
|
||||
| "amount": "1234"
|
||||
|},
|
||||
|"creditorAccount": {
|
||||
| "iban": "${ibanTo}"
|
||||
|},
|
||||
|"creditorName": "70charname"
|
||||
}""".stripMargin
|
||||
val requestPost = (urpPrefix / PaymentServiceTypes.bulk_payments.toString / TransactionRequestTypes.sepa_credit_transfers.toString).POST <@ (user1)
|
||||
val response: APIResponse = makePostRequest(requestPost, initiatePaymentJson)
|
||||
|
||||
Then("We should get a 201 ")
|
||||
response.code should equal(201)
|
||||
response.body \ "transactionStatus" should not be null
|
||||
response.body \ "paymentId" should not be null
|
||||
response.body \ "_links" should not be null
|
||||
response.body \ "_links" \ "scaRedirect" should not be null
|
||||
response.body \ "_links" \ "self" should not be null
|
||||
response.body \ "_links" \ "status" should not be null
|
||||
response.body \ "_links" \ "scaStatus" should not be null
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,63 @@
|
||||
package code.api.berlin.group.v1_3
|
||||
|
||||
import code.api.ErrorMessage
|
||||
import code.api.builder.ConfirmationOfFundsServicePIISApi.APIMethods_ConfirmationOfFundsServicePIISApi
|
||||
import code.api.util.APIUtil.OAuth._
|
||||
import code.api.util.ErrorMessages._
|
||||
import code.setup.{APIResponse, DefaultUsers}
|
||||
import com.github.dwickern.macros.NameOf.nameOf
|
||||
import org.scalatest.Tag
|
||||
|
||||
class ConfirmationOfFundsServicePIISApiTest extends BerlinGroupServerSetupV1_3 with DefaultUsers {
|
||||
|
||||
object PIIS extends Tag("Confirmation of Funds Service (PIIS)")
|
||||
object checkAvailabilityOfFunds extends Tag(nameOf(APIMethods_ConfirmationOfFundsServicePIISApi.checkAvailabilityOfFunds))
|
||||
|
||||
|
||||
val consentJsonForPost =
|
||||
"""{
|
||||
| "access": {
|
||||
| "accounts": [
|
||||
| {
|
||||
| "iban": "FR7612345987650123456789014",
|
||||
| "bban": "BARC12345612345678",
|
||||
| "pan": "5409050000000000",
|
||||
| "maskedPan": "123456xxxxxx1234",
|
||||
| "msisdn": "+49 170 1234567",
|
||||
| "currency": "EUR"
|
||||
| }
|
||||
| ]
|
||||
| },
|
||||
| "recurringIndicator": false,
|
||||
| "validUntil": "2020-12-31",
|
||||
| "frequencyPerDay": 4,
|
||||
| "combinedServiceIndicator": false
|
||||
|}""".stripMargin
|
||||
|
||||
feature("test the BG v1.3 consent endpoints") {
|
||||
scenario("Fail call endpoint createConsent, because accounts is not empty", PIIS) {
|
||||
When("Post consent json with no empty accounts")
|
||||
val requestPost = (V1_3_BG / "consents").POST <@ (user1)
|
||||
val response: APIResponse = makePostRequest(requestPost, consentJsonForPost)
|
||||
|
||||
Then("We should get a 400 ")
|
||||
response.code should equal(400)
|
||||
response.body.extract[ErrorMessage]
|
||||
.message should startWith(InvalidJsonContent)
|
||||
}
|
||||
|
||||
scenario("Successful call endpoint createConsent", PIIS) {
|
||||
When("Post consent json with no empty accounts")
|
||||
val requestPost = (V1_3_BG / "consents").POST <@ (user1)
|
||||
val emptyAccountsJson = consentJsonForPost.replaceFirst("""(?s)("accounts"\s*\:\s*\[).*?(\])""", "$1 $2")
|
||||
val response: APIResponse = makePostRequest(requestPost, emptyAccountsJson)
|
||||
|
||||
Then("We should get a 201 ")
|
||||
response.code should equal(201)
|
||||
response.body \ "consentId" should not be null
|
||||
response.body \ "consentStatus" should not be null
|
||||
response.body \ "_links" \ "startAuthorisation" should not be null
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,145 @@
|
||||
package code.api.berlin.group.v1_3
|
||||
|
||||
import code.api.ErrorMessage
|
||||
import code.api.berlin.group.v1_3.JSONFactory_BERLIN_GROUP_1_3.{InitiatePaymentResponseJson, StartPaymentAuthorisationJson}
|
||||
import code.api.builder.PaymentInitiationServicePISApi.APIMethods_PaymentInitiationServicePISApi
|
||||
import code.api.util.APIUtil.OAuth._
|
||||
import code.api.util.ErrorMessages.{InvalidJsonFormat, NotPositiveAmount}
|
||||
import code.model.dataAccess.MappedBankAccount
|
||||
import code.setup.{APIResponse, DefaultUsers}
|
||||
import code.transactionrequests.TransactionRequests.{PaymentServiceTypes, TransactionRequestTypes}
|
||||
import com.github.dwickern.macros.NameOf.nameOf
|
||||
import com.openbankproject.commons.model.SepaCreditTransfers
|
||||
import org.scalatest.Tag
|
||||
|
||||
class PaymentInitiationServicePISApiTest extends BerlinGroupServerSetupV1_3 with DefaultUsers {
|
||||
|
||||
object PIS extends Tag("Payment Initiation Service (PIS)")
|
||||
object initiatePayment extends Tag(nameOf(APIMethods_PaymentInitiationServicePISApi.initiatePayment))
|
||||
|
||||
object getPaymentCancellationScaStatus extends Tag(nameOf(APIMethods_PaymentInitiationServicePISApi.getPaymentCancellationScaStatus))
|
||||
object getPaymentInitiationAuthorisation extends Tag(nameOf(APIMethods_PaymentInitiationServicePISApi.getPaymentInitiationAuthorisation))
|
||||
object getPaymentInformation extends Tag(nameOf(APIMethods_PaymentInitiationServicePISApi.getPaymentInformation))
|
||||
object getPaymentInitiationCancellationAuthorisationInformation extends Tag(nameOf(APIMethods_PaymentInitiationServicePISApi.getPaymentInitiationCancellationAuthorisationInformation))
|
||||
object getPaymentInitiationScaStatus extends Tag(nameOf(APIMethods_PaymentInitiationServicePISApi.getPaymentInitiationScaStatus))
|
||||
object getPaymentInitiationStatus extends Tag(nameOf(APIMethods_PaymentInitiationServicePISApi.getPaymentInitiationStatus))
|
||||
object startPaymentAuthorisation extends Tag(nameOf(APIMethods_PaymentInitiationServicePISApi.startPaymentAuthorisation))
|
||||
object startPaymentInitiationCancellationAuthorisation extends Tag(nameOf(APIMethods_PaymentInitiationServicePISApi.startPaymentInitiationCancellationAuthorisation))
|
||||
object updatePaymentCancellationPsuData extends Tag(nameOf(APIMethods_PaymentInitiationServicePISApi.updatePaymentCancellationPsuData))
|
||||
object updatePaymentPsuData extends Tag(nameOf(APIMethods_PaymentInitiationServicePISApi.updatePaymentPsuData))
|
||||
|
||||
lazy val accounts = MappedBankAccount.findAll().map(_.accountIban.get).filter(_ != null)
|
||||
lazy val ibanFrom = accounts.head
|
||||
lazy val ibanTo = accounts.last
|
||||
lazy val wrongInitiatePaymentJson =
|
||||
s"""{
|
||||
|"instructedAmount1": {
|
||||
| "currency": "EUR",
|
||||
| "amount": "1234"
|
||||
|},
|
||||
|"creditorAccount": {
|
||||
| "iban": "${ibanTo}"
|
||||
|},
|
||||
|"creditorName": "70charname"
|
||||
}""".stripMargin
|
||||
lazy val initiatePaymentJson =
|
||||
s"""{
|
||||
| "debtorAccount": {
|
||||
| "iban": "${ibanFrom}"
|
||||
| },
|
||||
|"instructedAmount": {
|
||||
| "currency": "EUR",
|
||||
| "amount": "1234"
|
||||
|},
|
||||
|"creditorAccount": {
|
||||
| "iban": "${ibanTo}"
|
||||
|},
|
||||
|"creditorName": "70charname"
|
||||
}""".stripMargin
|
||||
lazy val wrongAmountInitiatePaymentJson =
|
||||
s"""{
|
||||
| "debtorAccount": {
|
||||
| "iban": "${ibanFrom}"
|
||||
| },
|
||||
|"instructedAmount": {
|
||||
| "currency": "EUR",
|
||||
| "amount": "-1234"
|
||||
|},
|
||||
|"creditorAccount": {
|
||||
| "iban": "${ibanTo}"
|
||||
|},
|
||||
|"creditorName": "70charname"
|
||||
}""".stripMargin
|
||||
|
||||
feature("test the BG v1.3 Payment endpoints- wrong json") {
|
||||
scenario("Unsuccessful call endpoint initiatePayment", BerlinGroupV1_3, PIS, initiatePayment) {
|
||||
When("Post empty to call initiatePayment")
|
||||
val requestPost = (V1_3_BG / PaymentServiceTypes.bulk_payments.toString / TransactionRequestTypes.sepa_credit_transfers.toString).POST <@ (user1)
|
||||
val response: APIResponse = makePostRequest(requestPost, wrongInitiatePaymentJson)
|
||||
Then("We should get a 400 ")
|
||||
response.code should equal(400)
|
||||
val error = s"$InvalidJsonFormat The Json body should be the $SepaCreditTransfers "
|
||||
And("error should be " + error)
|
||||
response.body.extract[ErrorMessage].message should equal (error)
|
||||
}
|
||||
scenario("Unsuccessful call endpoint initiatePayment - wrong amount", BerlinGroupV1_3, PIS, initiatePayment) {
|
||||
When("Post empty to call initiatePayment")
|
||||
val requestPost = (V1_3_BG / PaymentServiceTypes.bulk_payments.toString / TransactionRequestTypes.sepa_credit_transfers.toString).POST <@ (user1)
|
||||
val response: APIResponse = makePostRequest(requestPost, wrongAmountInitiatePaymentJson)
|
||||
Then("We should get a 400 ")
|
||||
response.code should equal(400)
|
||||
val error = s"${NotPositiveAmount} Current input is: '-1234'"
|
||||
And("error should be " + error)
|
||||
response.body.extract[ErrorMessage].message should equal (error)
|
||||
}
|
||||
|
||||
scenario("Successful call endpoint initiatePayment", BerlinGroupV1_3, PIS, initiatePayment) {
|
||||
When("Post empty to call initiatePayment")
|
||||
val requestPost = (V1_3_BG / PaymentServiceTypes.bulk_payments.toString / TransactionRequestTypes.sepa_credit_transfers.toString).POST <@ (user1)
|
||||
val response: APIResponse = makePostRequest(requestPost, initiatePaymentJson)
|
||||
Then("We should get a 201 ")
|
||||
response.code should equal(201)
|
||||
val payment = response.body.extract[InitiatePaymentResponseJson]
|
||||
payment.transactionStatus should not be null
|
||||
payment.paymentId should not be null
|
||||
payment._links should not be null
|
||||
payment._links.scaRedirect should not be null
|
||||
payment._links.self should not be null
|
||||
payment._links.status should not be null
|
||||
payment._links.scaStatus should not be null
|
||||
}
|
||||
}
|
||||
|
||||
feature("test the BG v1.3 startPaymentInitiationCancellationAuthorisation") {
|
||||
scenario("Successful call endpoint startPaymentInitiationCancellationAuthorisation", BerlinGroupV1_3, PIS, startPaymentInitiationCancellationAuthorisation) {
|
||||
When("Post empty to call initiatePayment")
|
||||
val requestPost = (V1_3_BG / PaymentServiceTypes.bulk_payments.toString / TransactionRequestTypes.sepa_credit_transfers.toString / "PAYMENT_ID" / "cancellation-authorisations").POST <@ (user1)
|
||||
val response: APIResponse = makePostRequest(requestPost, """""")
|
||||
Then("We should get a 200 ")
|
||||
response.code should equal(200)
|
||||
org.scalameta.logger.elem(response)
|
||||
val payment = response.body.extract[StartPaymentAuthorisationJson]
|
||||
payment.authorisationId should not be null
|
||||
payment.psuMessage should not be null
|
||||
payment.scaStatus should not be null
|
||||
payment._links.scaStatus should not be null
|
||||
}
|
||||
}
|
||||
|
||||
feature("test the BG v1.3 startPaymentAuthorisation") {
|
||||
scenario("Successful call endpoint startPaymentAuthorisation", BerlinGroupV1_3, PIS, startPaymentInitiationCancellationAuthorisation) {
|
||||
When("Post empty to call initiatePayment")
|
||||
val requestPost = (V1_3_BG / PaymentServiceTypes.bulk_payments.toString / TransactionRequestTypes.sepa_credit_transfers.toString / "PAYMENT_ID" / "authorisations").POST <@ (user1)
|
||||
val response: APIResponse = makePostRequest(requestPost, """""")
|
||||
Then("We should get a 200 ")
|
||||
response.code should equal(200)
|
||||
org.scalameta.logger.elem(response)
|
||||
val payment = response.body.extract[StartPaymentAuthorisationJson]
|
||||
payment.authorisationId should not be null
|
||||
payment.psuMessage should not be null
|
||||
payment.scaStatus should not be null
|
||||
payment._links.scaStatus should not be null
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -3,6 +3,9 @@
|
||||
### Most recent changes at top of file
|
||||
```
|
||||
Date Commit Action
|
||||
05/07/2019 7032ce3 Added props: webui_sandbox_introduction, To display the introduction page for sandbox.
|
||||
It supports the markdown format.It will show the introduction OBP-API home page `INTRODUCTION`
|
||||
page and also for Glossary `Sandbox Introduction`.
|
||||
14/06/2019 7a1c453 Added props: sca_phone_api_key and sca_phone_api_secret. We For now, OBP-API use `nexmo` server
|
||||
as the SMS provider. Please check `nexmo` website, and get the api key and value there.
|
||||
03/06/2019 5194b48 The table viewimpl is replaced with a table viewdefinition
|
||||
|
||||
Loading…
Reference in New Issue
Block a user