Skip to content

Commit

Permalink
VRP consent initiation flow implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
kalpanakanagasabai committed Nov 24, 2023
1 parent 1c40fa4 commit 0d2fca3
Show file tree
Hide file tree
Showing 7 changed files with 918 additions and 15 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,11 @@
{% else %}
<FundsConfirmationAPIURL>https://localhost:8243/open-banking/{version}/cbpii/</FundsConfirmationAPIURL>
{% endif %}
{% if open_banking.consent.vrp_consent_self_link is defined %}
<VRPAPIURL>{{open_banking.consent.vrp_consent_self_link}}</VRPAPIURL>
{% else %}
<VRPAPIURL>https://localhost:8243/open-banking/{version}/vrp/</VRPAPIURL>
{% endif %}
<DataRetention>
{% if open_banking.consent.data_retention.enabled is defined %}
<Enabled>{{open_banking.consent.data_retention.enabled}}</Enabled>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,6 @@ public class ErrorConstants {
public static final String PATH_CONSENT_ID = "Data.Initiation.Consent-id";
public static final String PATH_DATA = "Data";
public static final String PATH_INITIATION = "Data.Initiation";
public static final String PATH_RISK = "Data.Risk";
public static final String PATH_URL = "Data.Url";
public static final String PATH_EXPIRATION_DATE = "Data.Expiration-Date";
public static final String MSG_MISSING_DEBTOR_ACC = "Mandatory parameter DebtorAccount is missing in the payload.";
Expand Down Expand Up @@ -207,9 +206,6 @@ public class ErrorConstants {
ErrorConstants.PATH_DATA;
public static final String INITIATION_NOT_FOUND = "Initiation is not found or empty in the request.:" +
ErrorConstants.PATH_INITIATION;
public static final String RISK_MISMATCH = "RISK Does Not Match.:" + ErrorConstants.PATH_RISK;
public static final String RISK_NOT_FOUND = "RISK is not found or empty in the request.:" +
ErrorConstants.PATH_RISK;
public static final String INVALID_URI_ERROR = "Path requested is invalid. :" + ErrorConstants.PATH_URL;
public static final String COF_CONSENT_STATE_INVALID = "Confirmation of Funds validation failed due to invalid" +
" consent state.:" + ErrorConstants.PATH_STATUS;
Expand All @@ -221,9 +217,15 @@ public class ErrorConstants {
" retrieval request";
public static final String INVALID_CONSENT_ID = "Invalid Consent Id found in the request";
public static final String CONSENT_ID_NOT_FOUND = "Consent ID not available in consent data";

public static final String FIELD_INVALID_DATE = "OB.Field.InvalidDate";
public static final String EXPIRED_DATE_ERROR = "The ExpirationDateTime value has to be a future date.";

public static final String PATH_MAXIMUM_INDIVIDUAL_AMOUNT = "Data.ControlParameters.MaximumIndividualAmount.Amount";
public static final String INVALID_MAXIMUM_INDIVIDUAL_AMOUNT = "Invalid value for Amount in MaximumIndividualAmount";
public static final String INVALID_CURRENCY = "Invalid value for currency in MaximumIndividualAmount" ;
public static final String INVALID_PERIOD_ALIGNMENT = "Invalid value for period alignment in PeriodicLimits";
public static final String INVALID_PERIOD_TYPE = "Invalid value for period type in PeriodicLimits";
public static final String PATH_PERIOD_TYPE = "Data.ControlParameters.PeriodicLimits.PeriodType";
public static final String INVALID_VALID_TO_DATE = "Valid to Date specified in the request is invalid";
public static final String PATH_VALID_TO_DATE = "Data.ControlParameters.ValidToDateTime";
}

Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ public class ConsentExtensionConstants {
public static final String HTTP_CODE = "httpCode";
public static final String ERRORS = "errors";
public static final String PAYMENTS = "payments";
public static final String VRP = "vrp";

public static final String DATA = "Data";
public static final String INITIATION = "Initiation";
public static final String STATUS = "Status";
Expand Down Expand Up @@ -108,7 +110,6 @@ public class ConsentExtensionConstants {
public static final String OPENBANKING_INTENT_ID = "openbanking_intent_id";
public static final String VALUE = "value";
public static final String AUTHORIZED_STATUS = "authorised";

public static final String EXPIRATION_DATE = "ExpirationDateTime";
public static final String EXPIRATION_DATE_TITLE = "Expiration Date Time";
public static final String INSTRUCTED_AMOUNT_TITLE = "Instructed Amount";
Expand All @@ -121,8 +122,8 @@ public class ConsentExtensionConstants {
public static final String INSTRUCTION_IDENTIFICATION = "InstructionIdentification";
public static final String REJECTED_STATUS = "rejected";
public static final String OPEN_ENDED_AUTHORIZATION = "Open Ended Authorization Requested";
public static final String DEBTOR_ACC_TITLE = "Debtor Account";
public static final String SCHEME_NAME_TITLE = "Scheme Name";
public static final String DEBTOR_ACC_TITLE = "DebtorAccount";
public static final String SCHEME_NAME_TITLE = "SchemeName";
public static final String IDENTIFICATION_TITLE = "Identification";
public static final String NAME_TITLE = "Name";
public static final String SECONDARY_IDENTIFICATION_TITLE = "Secondary Identification";
Expand Down Expand Up @@ -153,19 +154,38 @@ public class ConsentExtensionConstants {
public static final String ACCOUNTS_SELF_LINK = "Consent.AccountAPIURL";
public static final String PAYMENT_SELF_LINK = "Consent.PaymentAPIURL";
public static final String COF_SELF_LINK = "Consent.FundsConfirmationAPIURL";
public static final String VRP_SELF_LINK = "Consent.VRPAPIURL";
public static final String REVOKED_STATUS = "revoked";

public static final String DISPLAY_NAME = "display_name";
public static final String ACCOUNT_DATA = "account_data";
public static final String SELECTED_ACCOUNT = "selectedAccount";
public static final String PAYMENT_COF_PATH = "funds-confirmation";

public static final String AWAITING_UPLOAD_STATUS = "awaitingUpload";

public static final String OB_REVOKED_STATUS = "Revoked";
public static final String OB_REJECTED_STATUS = "Rejected";
public static final String OB_AUTHORIZED_STATUS = "Authorised";
public static final String OB_AWAITING_AUTH_STATUS = "AwaitingAuthorisation";
public static final String OB_AWAITING_UPLOAD_STATUS = "AwaitingUpload";

public static final String VRP_CONSENT_PATH = "domestic-vrp-consents";
public static final String VRP_PAYMENT = "vrp-payment";
public static final String PAID_AMOUNT = "paid-amount";
public static final String LAST_PAYMENT_DATE = "last-payment-date";
public static final String AUTH_TYPE_AUTHORIZATION = "authorization";
public static final String CONTROL_PARAMETERS = "ControlParameters";
public static final String MAXIMUM_INDIVIDUAL_AMOUNT = "MaximumIndividualAmount";
public static final String PERIOD_ALIGNMENT = "PeriodicAlignment";
public static final String PERIODIC_LIMITS = "PeriodicLimits";
public static final String PERIOD_TYPE = "PeriodType";
public static final String PERIOD_AMOUNT_LIMIT = "Amount";
public static final String CONSENT = "consent-periodicAlignment";
public static final String CALENDER = "calender-periodicAlignment";
public static final String DAY = "Day";
public static final String WEEK = "Week";
public static final String FORTNIGHT = "Fortnight";
public static final String MONTH = "Month";
public static final String HALF_YEAR = "Half-year";
public static final String YEAR = "Year";
public static final String VALID_TO_DATE_TIME = "ValidToDateTime";
public static final String VALID_FROM_DATE_TIME = "ValidFromDateTime";
public static final String VRP_RESPONSE_PROCESS_PATH = "vrp-response-process";
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
import com.wso2.openbanking.accelerator.consent.extensions.manage.impl.CofConsentRequestHandler;
import com.wso2.openbanking.accelerator.consent.extensions.manage.impl.ConsentManageRequestHandler;
import com.wso2.openbanking.accelerator.consent.extensions.manage.impl.PaymentConsentRequestHandler;
import com.wso2.openbanking.accelerator.consent.extensions.manage.impl.VRPConsentRequestHandler;

/**
* Factory class to get the class based in request type.
Expand All @@ -55,6 +56,10 @@ public static ConsentManageRequestHandler getConsentManageRequestValidator(Strin
case ConsentExtensionConstants.PAYMENT_CONSENT_PATH:
consentManageRequestHandler = new PaymentConsentRequestHandler();
break;
case ConsentExtensionConstants.VRP_CONSENT_PATH:
case ConsentExtensionConstants.VRP_RESPONSE_PROCESS_PATH:
consentManageRequestHandler = new VRPConsentRequestHandler();
break;
default:
return null;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,192 @@
/**
* Copyright (c) 2021-2022, WSO2 LLC. (https://www.wso2.com). All Rights Reserved.
* This software is the property of WSO2 LLC. and its suppliers, if any.
* Dissemination of any information or reproduction of any material contained
* herein in any form is strictly forbidden, unless permitted by WSO2 expressly.
* You may not alter or remove any copyright or other notice from copies of this content.
*/

package com.wso2.openbanking.accelerator.consent.extensions.manage.impl;

import com.wso2.openbanking.accelerator.common.exception.ConsentManagementException;
import com.wso2.openbanking.accelerator.common.util.ErrorConstants;
import com.wso2.openbanking.accelerator.consent.extensions.common.ConsentException;
import com.wso2.openbanking.accelerator.consent.extensions.common.ConsentExtensionConstants;
import com.wso2.openbanking.accelerator.consent.extensions.common.ConsentExtensionUtils;
import com.wso2.openbanking.accelerator.consent.extensions.common.ConsentServiceUtil;
import com.wso2.openbanking.accelerator.consent.extensions.common.ResponseStatus;
import com.wso2.openbanking.accelerator.consent.extensions.internal.ConsentExtensionsDataHolder;
import com.wso2.openbanking.accelerator.consent.extensions.manage.model.ConsentManageData;
import com.wso2.openbanking.accelerator.consent.extensions.manage.validator.VRPConsentRequestValidator;
import com.wso2.openbanking.accelerator.consent.extensions.util.ConsentManageUtil;
import com.wso2.openbanking.accelerator.consent.mgt.dao.models.ConsentResource;
import com.wso2.openbanking.accelerator.consent.mgt.dao.models.DetailedConsentResource;
import net.minidev.json.JSONArray;
import net.minidev.json.JSONObject;
import net.minidev.json.parser.JSONParser;
import net.minidev.json.parser.ParseException;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import java.util.HashMap;
import java.util.Map;

import static com.wso2.openbanking.accelerator.consent.extensions.common.ConsentExtensionConstants.AUTH_TYPE_AUTHORIZATION;
import static com.wso2.openbanking.accelerator.consent.extensions.common.ConsentExtensionConstants.CREATED_STATUS;

/**
* Consent Manage request handler class for VRP Payment Request Validation.
*/
public class VRPConsentRequestHandler implements ConsentManageRequestHandler {

private static final Log log = LogFactory.getLog(VRPConsentRequestHandler.class);

/**
* Method to handle Variable Recurring Payment Consent Manage Post Request.
*
* @param consentManageData Object containing request details
*/
@Override
public void handleConsentManagePost(ConsentManageData consentManageData) {

try {
//Validate cutoff datetime
if (ConsentExtensionUtils.shouldInitiationRequestBeRejected()) {
log.error(ErrorConstants.MSG_ELAPSED_CUT_OFF_DATE_TIME);
throw new ConsentException(ResponseStatus.BAD_REQUEST, ErrorConstants.PAYMENT_INITIATION_HANDLE_ERROR);
}

//Get the request payload from the ConsentManageData
Object request = consentManageData.getPayload();
if (!(request instanceof JSONObject)) {
log.error(ErrorConstants.PAYLOAD_FORMAT_ERROR);
throw new ConsentException(ResponseStatus.BAD_REQUEST, ErrorConstants.INVALID_REQ_PAYLOAD);
}

JSONObject requestObject = (JSONObject) request;

//Set request object to the response
JSONObject response = requestObject;

//Check Idempotency key exists
if (StringUtils.isEmpty(consentManageData.getHeaders()
.get(ConsentExtensionConstants.X_IDEMPOTENCY_KEY))) {
throw new ConsentException(ResponseStatus.BAD_REQUEST, ErrorConstants.IDEMPOTENCY_KEY_NOT_FOUND);
}

//Handle payment initiation flows
handlePaymentPost(consentManageData, requestObject, response);

} catch (ConsentManagementException e) {
log.error(e.getMessage());
throw new ConsentException(ResponseStatus.INTERNAL_SERVER_ERROR,
ErrorConstants.PAYMENT_INITIATION_HANDLE_ERROR);
}
}


@Override
public void handleConsentManageGet(ConsentManageData consentManageData) {

String consentId = consentManageData.getRequestPath().split("/")[1];
if (ConsentManageUtil.isConsentIdValid(consentId)) {
try {
ConsentResource consent = ConsentServiceUtil.getConsentService().getConsent(consentId,
false);
if (consent == null) {
throw new ConsentException(ResponseStatus.BAD_REQUEST, ErrorConstants.RESOURCE_CONSENT_MISMATCH);
}
// Check whether the client id is matching
if (!consent.getClientID().equals(consentManageData.getClientId())) {
//Throwing same error as null scenario since client will not be able to identify if consent
// exists if consent does not belong to them
throw new ConsentException(ResponseStatus.BAD_REQUEST,
ErrorConstants.NO_CONSENT_FOR_CLIENT_ERROR);
}
JSONObject receiptJSON = (JSONObject) new JSONParser(JSONParser.MODE_PERMISSIVE).
parse(consent.getReceipt());
consentManageData.setResponsePayload(ConsentManageUtil
.getInitiationRetrievalResponse(receiptJSON, consent, consentManageData,
ConsentExtensionConstants.VRP));
consentManageData.setResponseStatus(ResponseStatus.OK);
} catch (ConsentManagementException | ParseException e) {
throw new ConsentException(ResponseStatus.INTERNAL_SERVER_ERROR,
ErrorConstants.ACC_INITIATION_RETRIEVAL_ERROR);
}
} else {
throw new ConsentException(ResponseStatus.BAD_REQUEST, ErrorConstants.INVALID_CONSENT_ID);
}
}

@Override
public void handleConsentManageDelete(ConsentManageData consentManageData) {

ConsentManageUtil.handleConsentManageDelete(consentManageData);
}

/**
* Method to handle the Variable Recurring Payment POST requests.
*
* @param consentManageData Object containing request details
* @param requestObject Request payload
* @param response Response
*/
private void handlePaymentPost(ConsentManageData consentManageData, JSONObject requestObject, JSONObject response)
throws ConsentManagementException {

DetailedConsentResource createdConsent;

//Validate Payment Initiation request
JSONObject validationResponse = VRPConsentRequestValidator.validatePaymentInitiation(requestObject);

//Throw an error if the initiation payload is not valid
if (!((boolean) validationResponse.get(ConsentExtensionConstants.IS_VALID))) {

log.error(ErrorConstants.PAYLOAD_INVALID);
throw new ConsentException((ResponseStatus) validationResponse
.get(ConsentExtensionConstants.HTTP_CODE),
String.valueOf(validationResponse.get(ConsentExtensionConstants.ERRORS)));
}

ConsentResource requestedConsent = new ConsentResource(consentManageData.getClientId(),
requestObject.toJSONString(), ConsentExtensionConstants.VRP,
ConsentExtensionConstants.AWAITING_AUTH_STATUS);

createdConsent = ConsentExtensionsDataHolder.getInstance().getConsentCoreService()
.createAuthorizableConsent(requestedConsent, null,
CREATED_STATUS, AUTH_TYPE_AUTHORIZATION, true);

//Set consent attributes for storing
Map<String, String> consentAttributes = new HashMap();
consentAttributes.put(ConsentExtensionConstants.IDEMPOTENCY_KEY, consentManageData.getHeaders()
.get(ConsentExtensionConstants.X_IDEMPOTENCY_KEY));
//Store consent attributes
ConsentServiceUtil.getConsentService().storeConsentAttributes(createdConsent.getConsentID(),
consentAttributes);
consentManageData.setResponsePayload(ConsentManageUtil.getInitiationResponse(response, createdConsent,
consentManageData, ConsentExtensionConstants.VRP_PAYMENT));

//Set Control Parameters as consent attributes to store
JSONObject controlParameters = (JSONObject) ((JSONObject) ((JSONObject) consentManageData.getPayload())
.get(ConsentExtensionConstants.DATA)).get(ConsentExtensionConstants.CONTROL_PARAMETERS);
consentAttributes.put(ConsentExtensionConstants.MAXIMUM_INDIVIDUAL_AMOUNT, ((JSONObject) (controlParameters)
.get(ConsentExtensionConstants.MAXIMUM_INDIVIDUAL_AMOUNT)).get(ConsentExtensionConstants.AMOUNT)
.toString());
consentAttributes.put(ConsentExtensionConstants.PERIOD_TYPE, ((JSONObject) ((JSONArray) (controlParameters)
.get(ConsentExtensionConstants.PERIODIC_LIMITS)).get(0)).get(ConsentExtensionConstants.PERIOD_TYPE)
.toString());
consentAttributes.put(ConsentExtensionConstants.PERIOD_AMOUNT_LIMIT, ((JSONObject)
((JSONArray) (controlParameters).get(ConsentExtensionConstants.PERIODIC_LIMITS)).get(0))
.get(ConsentExtensionConstants.PERIOD_AMOUNT_LIMIT).toString());
consentAttributes.put(ConsentExtensionConstants.PAID_AMOUNT, "0");
consentAttributes.put(ConsentExtensionConstants.LAST_PAYMENT_DATE, "0");

Map<String, String> headers = consentManageData.getHeaders();
//Setting response headers
//Setting created time and idempotency to headers to handle idempotency in Gateway
consentManageData.setResponseHeader(ConsentExtensionConstants.X_IDEMPOTENCY_KEY,
headers.get(ConsentExtensionConstants.X_IDEMPOTENCY_KEY));
consentManageData.setResponseStatus(ResponseStatus.CREATED);
}
}
Loading

0 comments on commit 0d2fca3

Please sign in to comment.