headers = fsApiResponseContext.getMsgInfo().getHeaders();
headers.put(GatewayConstants.CONTENT_TYPE_TAG, GatewayConstants.JSON_CONTENT_TYPE);
- fsapiResponseContext.getMsgInfo().setHeaders(headers);
+ fsApiResponseContext.getMsgInfo().setHeaders(headers);
extensionResponseDTO.setHeaders(headers);
- if (fsapiResponseContext.getContextProps().containsKey(GatewayConstants.MODIFIED_STATUS)) {
- extensionResponseDTO.setStatusCode((Integer.parseInt(fsapiResponseContext.getContextProps()
+ if (fsApiResponseContext.getContextProps().containsKey(GatewayConstants.MODIFIED_STATUS)) {
+ extensionResponseDTO.setStatusCode((Integer.parseInt(fsApiResponseContext.getContextProps()
.get(GatewayConstants.MODIFIED_STATUS).toString())));
}
extensionResponseDTO.setResponseStatus(ExtensionResponseStatus.RETURN_ERROR.toString());
@@ -201,13 +201,13 @@ protected ExtensionResponseDTO getResponseDTOForResponse(FSAPIResponseContext fs
extensionResponseDTO.setResponseStatus(ExtensionResponseStatus.CONTINUE.toString());
}
- String modifiedPayload = fsapiResponseContext.getModifiedPayload();
+ String modifiedPayload = fsApiResponseContext.getModifiedPayload();
if (modifiedPayload != null) {
extensionResponseDTO.setPayload(new ByteArrayInputStream(modifiedPayload.getBytes(StandardCharsets.UTF_8)));
}
- setHeadersToResponse(extensionResponseDTO, fsapiResponseContext.getAddedHeaders(),
- fsapiResponseContext.getMsgInfo().getHeaders());
+ setHeadersToResponse(extensionResponseDTO, fsApiResponseContext.getAddedHeaders(),
+ fsApiResponseContext.getMsgInfo().getHeaders());
return extensionResponseDTO;
}
diff --git a/financial-services-accelerator/components/org.wso2.financial.services.accelerator.gateway/src/main/java/org/wso2/financial/services/accelerator/gateway/executor/impl/consent/ConsentEnforcementExecutor.java b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.gateway/src/main/java/org/wso2/financial/services/accelerator/gateway/executor/impl/consent/ConsentEnforcementExecutor.java
new file mode 100644
index 00000000..88be3af0
--- /dev/null
+++ b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.gateway/src/main/java/org/wso2/financial/services/accelerator/gateway/executor/impl/consent/ConsentEnforcementExecutor.java
@@ -0,0 +1,318 @@
+/**
+ * Copyright (c) 2024, WSO2 LLC. (https://www.wso2.com).
+ *
+ * WSO2 LLC. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.wso2.financial.services.accelerator.gateway.executor.impl.consent;
+
+import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
+import io.jsonwebtoken.Jwts;
+import io.jsonwebtoken.SignatureAlgorithm;
+import org.apache.commons.io.IOUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.entity.StringEntity;
+import org.json.JSONObject;
+import org.wso2.financial.services.accelerator.common.constant.FinancialServicesConstants;
+import org.wso2.financial.services.accelerator.common.constant.FinancialServicesErrorCodes;
+import org.wso2.financial.services.accelerator.common.exception.FinancialServicesException;
+import org.wso2.financial.services.accelerator.common.util.Generated;
+import org.wso2.financial.services.accelerator.common.util.HTTPClientUtils;
+import org.wso2.financial.services.accelerator.gateway.executor.core.FinancialServicesGatewayExecutor;
+import org.wso2.financial.services.accelerator.gateway.executor.model.FSAPIRequestContext;
+import org.wso2.financial.services.accelerator.gateway.executor.model.FSAPIResponseContext;
+import org.wso2.financial.services.accelerator.gateway.executor.model.FSExecutorError;
+import org.wso2.financial.services.accelerator.gateway.internal.GatewayDataHolder;
+import org.wso2.financial.services.accelerator.gateway.util.GatewayConstants;
+import org.wso2.financial.services.accelerator.gateway.util.GatewayUtils;
+
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
+import java.security.Key;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.UnrecoverableKeyException;
+import java.security.cert.CertificateException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Consent Enforcement executor.
+ */
+public class ConsentEnforcementExecutor implements FinancialServicesGatewayExecutor {
+
+ protected static final String ERROR_TITLE = "Consent Enforcement Error";
+ protected static final String HEADERS_TAG = "headers";
+ protected static final String BODY_TAG = "body";
+ protected static final String CONTEXT_TAG = "context";
+ protected static final String RESOURCE_TAG = "resource";
+ protected static final String ELECTED_RESOURCE_TAG = "electedResource";
+ protected static final String HTTP_METHOD = "httpMethod";
+ protected static final String CONSENT_ID_TAG = "consentId";
+ protected static final String USER_ID_TAG = "userId";
+ protected static final String CLIENT_ID_TAG = "clientId";
+ protected static final String RESOURCE_PARAMS = "resourceParams";
+ private static final Log log = LogFactory.getLog(ConsentEnforcementExecutor.class);
+ private static final GatewayDataHolder dataHolder = GatewayDataHolder.getInstance();
+ private static final String INFO_HEADER_TAG = "Account-Request-Information";
+ private static final String IS_VALID = "isValid";
+ private static final String ERROR_CODE = "errorCode";
+ private static final String ERROR_MESSAGE = "errorMessage";
+ private static final String HTTP_CODE = "httpCode";
+ private static final String MODIFIED_PAYLOAD = "modifiedPayload";
+ private static final String CONSENT_INFO = "consentInformation";
+ private static volatile String consentValidationEndpoint;
+ private static volatile Key key;
+
+ /**
+ * Method to handle request.
+ *
+ * @param fsApiRequestContext FS request context object
+ */
+ @Generated(message = "Unit testable components are covered")
+ @Override
+ public void preProcessRequest(FSAPIRequestContext fsApiRequestContext) {
+
+ }
+
+ /**
+ * Method to handle post request.
+ *
+ * @param fsApiRequestContext FS request context object
+ */
+ @Override
+ public void postProcessRequest(FSAPIRequestContext fsApiRequestContext) {
+ // Consent ID is required for consent enforcement. If the consent ID is null, we are assume this is a
+ // pre-consent creation call. Therefore consent enforcement is not required.
+ if (fsApiRequestContext.isError() || fsApiRequestContext.getConsentId() == null) {
+ return;
+ }
+
+ Map requestHeaders = fsApiRequestContext.getMsgInfo().getHeaders();
+ Map additionalParams = new HashMap<>();
+ additionalParams.put(ELECTED_RESOURCE_TAG, fsApiRequestContext.getMsgInfo().getElectedResource());
+ additionalParams.put(CONSENT_ID_TAG, fsApiRequestContext.getConsentId());
+ additionalParams.put(USER_ID_TAG, fsApiRequestContext.getApiRequestInfo().getUsername());
+ additionalParams.put(CLIENT_ID_TAG, fsApiRequestContext.getApiRequestInfo().getConsumerKey());
+ additionalParams.put(RESOURCE_PARAMS, getResourceParamMap(fsApiRequestContext));
+
+ JSONObject validationRequest;
+ if (StringUtils.isNotBlank(fsApiRequestContext.getModifiedPayload())) {
+ validationRequest = createValidationRequestPayload(requestHeaders,
+ fsApiRequestContext.getModifiedPayload(), additionalParams);
+ } else {
+ validationRequest = createValidationRequestPayload(requestHeaders,
+ fsApiRequestContext.getRequestPayload(), additionalParams);
+ }
+ String enforcementJWTPayload = generateJWT(validationRequest.toString());
+ JSONObject jsonResponse;
+ try {
+ String response = invokeConsentValidationService(enforcementJWTPayload);
+ jsonResponse = new JSONObject(response);
+ } catch (IOException | FinancialServicesException e) {
+ handleError(fsApiRequestContext, FinancialServicesErrorCodes.CONSENT_VALIDATION_REQUEST_FAILURE,
+ e.getMessage(), FinancialServicesErrorCodes.SERVER_ERROR_CODE);
+ return;
+ }
+
+ boolean isValid = jsonResponse.getBoolean(IS_VALID);
+ if (!isValid) {
+ String errorCode = jsonResponse.get(ERROR_CODE).toString();
+ String errorMessage = jsonResponse.get(ERROR_MESSAGE).toString();
+ String httpCode = jsonResponse.get(HTTP_CODE).toString();
+ handleError(fsApiRequestContext, errorCode, errorMessage, httpCode);
+ return;
+ } else if (!jsonResponse.isNull(MODIFIED_PAYLOAD)) {
+ Object modifiedPayloadObj = jsonResponse.get(MODIFIED_PAYLOAD);
+ if (modifiedPayloadObj != null) {
+ fsApiRequestContext.setModifiedPayload(modifiedPayloadObj.toString());
+ }
+ } else if (!jsonResponse.isNull(CONSENT_INFO)) {
+ Object consentInformationObj = jsonResponse.get(CONSENT_INFO);
+ if (consentInformationObj != null) {
+ requestHeaders.put(INFO_HEADER_TAG, consentInformationObj.toString());
+ fsApiRequestContext.setAddedHeaders(requestHeaders);
+ }
+ }
+ }
+
+ /**
+ * Method to handle response.
+ *
+ * @param fsApiResponseContext FS response context object
+ */
+ @Override
+ public void preProcessResponse(FSAPIResponseContext fsApiResponseContext) {
+
+ }
+
+ /**
+ * Method to handle post response.
+ *
+ * @param fsApiResponseContext FS response context object
+ */
+ @Override
+ public void postProcessResponse(FSAPIResponseContext fsApiResponseContext) {
+
+ }
+
+ private static String getValidationEndpoint() {
+
+ if (consentValidationEndpoint == null) {
+ synchronized (ConsentEnforcementExecutor.class) {
+ if (consentValidationEndpoint == null) {
+ consentValidationEndpoint = dataHolder
+ .getFinancialServicesConfigurationService().getConfigurations()
+ .get(FinancialServicesConstants.CONSENT_VALIDATION_ENDPOINT).toString();
+ }
+ }
+ }
+ return consentValidationEndpoint;
+
+ }
+
+ /**
+ * Method to obtain signing key.
+ *
+ * @return Key as an Object.
+ */
+ @SuppressFBWarnings("PATH_TRAVERSAL_IN")
+ // Suppressed content - dataHolder.getKeyStoreLocation()
+ // Suppression reason - False Positive : Keystore location is obtained from deployment.toml. So it can be marked
+ // as a trusted filepath
+ // Suppressed warning count - 1
+ protected static Key getJWTSigningKey() {
+
+ if (key == null) {
+ synchronized (ConsentEnforcementExecutor.class) {
+ if (key == null) {
+ try (FileInputStream is = new FileInputStream(dataHolder.getKeyStoreLocation())) {
+ KeyStore keystore = KeyStore.getInstance(KeyStore.getDefaultType());
+ keystore.load(is, dataHolder.getKeyStorePassword());
+ key = keystore.getKey(dataHolder.getKeyAlias(), dataHolder.getKeyPassword().toCharArray());
+ } catch (IOException | CertificateException | KeyStoreException | NoSuchAlgorithmException
+ | UnrecoverableKeyException e) {
+ log.error("Error occurred while retrieving private key from keystore ", e);
+ }
+ }
+ }
+ }
+ return key;
+ }
+
+ /**
+ * Method to generate JWT.
+ * @param payload Payload to be signed
+ * @return Signed JWT
+ */
+ protected String generateJWT(String payload) {
+
+ return Jwts.builder()
+ .setPayload(payload)
+ .signWith(SignatureAlgorithm.RS512, getJWTSigningKey())
+ .compact();
+ }
+
+ /**
+ * Method to invoke consent validation service when the JWT payload is provided.
+ *
+ * @param enforcementJWTPayload JWT Payload
+ * @return Response as a String
+ * @throws IOException When failed to invoke the validation endpoint or failed to parse the response.
+ */
+ @Generated(message = "Ignoring from unit tests since this method require calling external component to function")
+ private String invokeConsentValidationService(String enforcementJWTPayload) throws IOException,
+ FinancialServicesException {
+
+ HttpPost httpPost = new HttpPost(getValidationEndpoint());
+ StringEntity params;
+ params = new StringEntity(enforcementJWTPayload);
+ httpPost.setEntity(params);
+ httpPost.setHeader(GatewayConstants.CONTENT_TYPE_TAG, GatewayConstants.JWT_CONTENT_TYPE);
+ String userName = GatewayUtils.getAPIMgtConfig(GatewayConstants.API_KEY_VALIDATOR_USERNAME);
+ String password = GatewayUtils.getAPIMgtConfig(GatewayConstants.API_KEY_VALIDATOR_PASSWORD);
+ httpPost.setHeader(GatewayConstants.AUTH_HEADER, GatewayUtils.getBasicAuthHeader(userName, password));
+ CloseableHttpResponse response = HTTPClientUtils.getHttpsClient().execute(httpPost);
+ InputStream in = response.getEntity().getContent();
+ return IOUtils.toString(in, String.valueOf(StandardCharsets.UTF_8));
+ }
+
+ /**
+ * Method to handle errors.
+ *
+ * @param fsApiRequestContext API Context
+ * @param errorCode Error Code
+ * @param errorMessage Error Message
+ * @param httpCode HTTP status code ( in 4XX range)
+ */
+ protected void handleError(FSAPIRequestContext fsApiRequestContext, String errorCode, String errorMessage,
+ String httpCode) {
+
+ fsApiRequestContext.setError(true);
+ ArrayList errors = fsApiRequestContext.getErrors();
+ errors.add(new FSExecutorError(errorCode, ERROR_TITLE, errorMessage, httpCode));
+ fsApiRequestContext.setErrors(errors);
+ fsApiRequestContext.addContextProperty(GatewayConstants.ERROR_STATUS_PROP, httpCode);
+ }
+
+ /**
+ * Method to create validation payload.
+ *
+ * @param requestHeaders Request headers of original request
+ * @param requestPayload Request payload of original request
+ * @return JSON Object with added attributes.
+ */
+ protected JSONObject createValidationRequestPayload(Map requestHeaders, String requestPayload,
+ Map additionalParams) {
+
+ JSONObject validationRequest = new JSONObject();
+ JSONObject headers = new JSONObject();
+ requestHeaders.forEach(headers::put);
+ validationRequest.put(HEADERS_TAG, headers);
+ /*requestContextDTO.getMsgInfo().getPayloadHandler().consumeAsString() method sets the request payload as a
+ null string, hence adding string null check to the validation*/
+ if (requestPayload != null && !requestPayload.isEmpty() && !requestPayload.equals("null")) {
+ //This assumes all input payloads are in Content-Type : Application/JSON
+ validationRequest.put(BODY_TAG, new JSONObject(requestPayload));
+ }
+ additionalParams.forEach(validationRequest::put);
+ return validationRequest;
+ }
+
+ /**
+ * Method to construct resource parameter map to invoke the validation service.
+ *
+ * @param fsApiRequestContext FS request context object
+ * @return A Map containing resource path(ex: /aisp/accounts/{AccountId}?queryParam=urlEncodedQueryParamValue),
+ * http method and context(ex: /open-banking/v3.1/aisp)
+ */
+ private Map getResourceParamMap(FSAPIRequestContext fsApiRequestContext) {
+
+ Map resourceMap = new HashMap<>();
+ resourceMap.put(RESOURCE_TAG, fsApiRequestContext.getMsgInfo().getResource());
+ resourceMap.put(HTTP_METHOD, fsApiRequestContext.getMsgInfo().getHttpMethod());
+ resourceMap.put(CONTEXT_TAG, fsApiRequestContext.getApiRequestInfo().getContext());
+
+ return resourceMap;
+ }
+}
diff --git a/financial-services-accelerator/components/org.wso2.financial.services.accelerator.gateway/src/main/java/org/wso2/financial/services/accelerator/gateway/executor/impl/error/handling/DefaultErrorHandlingExecutor.java b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.gateway/src/main/java/org/wso2/financial/services/accelerator/gateway/executor/impl/error/handling/DefaultErrorHandlingExecutor.java
new file mode 100644
index 00000000..205f6d8c
--- /dev/null
+++ b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.gateway/src/main/java/org/wso2/financial/services/accelerator/gateway/executor/impl/error/handling/DefaultErrorHandlingExecutor.java
@@ -0,0 +1,177 @@
+/**
+ * Copyright (c) 2024, WSO2 LLC. (https://www.wso2.com).
+ *
+ * WSO2 LLC. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.wso2.financial.services.accelerator.gateway.executor.impl.error.handling;
+
+import org.apache.http.HttpStatus;
+import org.json.JSONArray;
+import org.json.JSONObject;
+import org.wso2.financial.services.accelerator.gateway.executor.core.FinancialServicesGatewayExecutor;
+import org.wso2.financial.services.accelerator.gateway.executor.model.FSAPIRequestContext;
+import org.wso2.financial.services.accelerator.gateway.executor.model.FSAPIResponseContext;
+import org.wso2.financial.services.accelerator.gateway.executor.model.FSExecutorError;
+import org.wso2.financial.services.accelerator.gateway.util.GatewayConstants;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Default Executor to handle gateway errors.
+ */
+public class DefaultErrorHandlingExecutor implements FinancialServicesGatewayExecutor {
+
+ private static final String ERRORS_TAG = "errors";
+
+ /**
+ * Method to handle pre request.
+ *
+ * @param fsApiRequestContext FS request context object
+ */
+ @Override
+ public void preProcessRequest(FSAPIRequestContext fsApiRequestContext) {
+
+ handleRequestError(fsApiRequestContext);
+
+ }
+
+ /**
+ * Method to handle post request.
+ *
+ * @param fsApiRequestContext FS request context object
+ */
+ @Override
+ public void postProcessRequest(FSAPIRequestContext fsApiRequestContext) {
+
+ handleRequestError(fsApiRequestContext);
+ }
+
+ /**
+ * Method to handle pre response.
+ *
+ * @param fsApiResponseContext FS response context object
+ */
+ @Override
+ public void preProcessResponse(FSAPIResponseContext fsApiResponseContext) {
+
+ handleResponseError(fsApiResponseContext);
+ }
+
+ /**
+ * Method to handle post response.
+ *
+ * @param fsApiResponseContext FS response context object
+ */
+ @Override
+ public void postProcessResponse(FSAPIResponseContext fsApiResponseContext) {
+
+ handleResponseError(fsApiResponseContext);
+ }
+
+ private void handleRequestError(FSAPIRequestContext fsApiRequestContext) {
+
+ if (!fsApiRequestContext.isError()) {
+ return;
+ }
+ JSONObject payload = new JSONObject();
+ ArrayList errors = fsApiRequestContext.getErrors();
+ JSONArray errorList = getErrorJSON(errors);
+ HashSet statusCodes = new HashSet<>();
+
+ for (FSExecutorError error : errors) {
+ statusCodes.add(error.getHttpStatusCode());
+ }
+
+ payload.put(ERRORS_TAG, errorList);
+ if (!errorList.isEmpty()) {
+ fsApiRequestContext.setModifiedPayload(payload.toString());
+ Map addedHeaders = fsApiRequestContext.getAddedHeaders();
+ addedHeaders.put(GatewayConstants.CONTENT_TYPE_TAG, GatewayConstants.JSON_CONTENT_TYPE);
+ fsApiRequestContext.setAddedHeaders(addedHeaders);
+ }
+ int statusCode;
+ if (fsApiRequestContext.getContextProps().containsKey(GatewayConstants.ERROR_STATUS_PROP)) {
+ statusCode = Integer.parseInt(fsApiRequestContext
+ .getContextProperty(GatewayConstants.ERROR_STATUS_PROP).toString());
+ } else if (isAnyClientErrors(statusCodes)) {
+ statusCode = HttpStatus.SC_BAD_REQUEST;
+ } else {
+ statusCode = HttpStatus.SC_INTERNAL_SERVER_ERROR;
+ }
+ fsApiRequestContext.addContextProperty(GatewayConstants.ERROR_STATUS_PROP,
+ String.valueOf(statusCode));
+ }
+
+ private void handleResponseError(FSAPIResponseContext fsApiResponseContext) {
+
+ if (!fsApiResponseContext.isError()) {
+ return;
+ }
+ JSONObject payload = new JSONObject();
+ ArrayList errors = fsApiResponseContext.getErrors();
+ JSONArray errorList = getErrorJSON(errors);
+ HashSet statusCodes = new HashSet<>();
+
+ for (FSExecutorError error : errors) {
+ statusCodes.add(error.getHttpStatusCode());
+ }
+
+ payload.put(ERRORS_TAG, errorList);
+ fsApiResponseContext.setModifiedPayload(payload.toString());
+ Map addedHeaders = fsApiResponseContext.getAddedHeaders();
+ addedHeaders.put(GatewayConstants.CONTENT_TYPE_TAG, GatewayConstants.JSON_CONTENT_TYPE);
+ fsApiResponseContext.setAddedHeaders(addedHeaders);
+ int statusCode;
+ if (fsApiResponseContext.getContextProps().containsKey(GatewayConstants.ERROR_STATUS_PROP)) {
+ statusCode = Integer.parseInt(fsApiResponseContext
+ .getContextProperty(GatewayConstants.ERROR_STATUS_PROP).toString());
+ } else if (isAnyClientErrors(statusCodes)) {
+ statusCode = HttpStatus.SC_BAD_REQUEST;
+ } else {
+ statusCode = HttpStatus.SC_INTERNAL_SERVER_ERROR;
+ }
+ fsApiResponseContext.addContextProperty(GatewayConstants.ERROR_STATUS_PROP,
+ String.valueOf(statusCode));
+ }
+
+ private JSONArray getErrorJSON(List errors) {
+
+ JSONArray errorList = new JSONArray();
+ for (FSExecutorError error : errors) {
+ JSONObject errorObj = new JSONObject();
+ errorObj.put(GatewayConstants.CODE, error.getCode());
+ errorObj.put(GatewayConstants.MESSAGE, error.getTitle());
+ errorObj.put(GatewayConstants.DESCRIPTION, error.getMessage());
+ Map links = error.getLinks();
+ if (links != null && !links.isEmpty()) {
+ JSONObject linksObj = new JSONObject();
+ links.forEach(linksObj::put);
+ errorObj.put(GatewayConstants.LINKS, linksObj);
+ }
+ errorList.put(errorObj);
+ }
+ return errorList;
+ }
+
+ private boolean isAnyClientErrors(Set statusCodes) {
+
+ return statusCodes.stream().anyMatch(statusCode -> statusCode.startsWith("4"));
+ }
+}
diff --git a/financial-services-accelerator/components/org.wso2.financial.services.accelerator.gateway/src/main/java/org/wso2/financial/services/accelerator/gateway/internal/GatewayDataHolder.java b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.gateway/src/main/java/org/wso2/financial/services/accelerator/gateway/internal/GatewayDataHolder.java
index e3b7b1b4..fdd17b93 100644
--- a/financial-services-accelerator/components/org.wso2.financial.services.accelerator.gateway/src/main/java/org/wso2/financial/services/accelerator/gateway/internal/GatewayDataHolder.java
+++ b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.gateway/src/main/java/org/wso2/financial/services/accelerator/gateway/internal/GatewayDataHolder.java
@@ -20,6 +20,7 @@
import org.apache.http.impl.client.CloseableHttpClient;
import org.wso2.carbon.apimgt.impl.APIManagerConfigurationService;
+import org.wso2.carbon.base.ServerConfiguration;
import org.wso2.financial.services.accelerator.common.config.FinancialServicesConfigurationService;
import org.wso2.financial.services.accelerator.common.constant.FinancialServicesConstants;
import org.wso2.financial.services.accelerator.common.exception.FinancialServicesException;
@@ -28,6 +29,7 @@
import org.wso2.financial.services.accelerator.gateway.cache.GatewayCache;
import org.wso2.financial.services.accelerator.gateway.executor.core.AbstractRequestRouter;
+import java.util.Arrays;
import java.util.Map;
/**
@@ -43,6 +45,10 @@ public class GatewayDataHolder {
private int gatewayCacheModifiedExpiry;
private APIManagerConfigurationService apiManagerConfigurationService;
private AbstractRequestRouter requestRouter;
+ private String keyStoreLocation;
+ private char[] keyStorePassword;
+ private String keyAlias;
+ private String keyPassword;
private GatewayDataHolder() {
@@ -135,6 +141,55 @@ public void setGatewayCacheModifiedExpiry(String expTime) {
this.gatewayCacheModifiedExpiry = expTime == null ? 60 : Integer.parseInt(expTime);
}
+ public String getKeyStoreLocation() {
+
+ return keyStoreLocation == null ? ServerConfiguration.getInstance()
+ .getFirstProperty(FinancialServicesConstants.KEYSTORE_LOCATION_TAG) : keyStoreLocation;
+ }
+
+ public void setKeyStoreLocation(String keyStoreLocation) {
+
+ this.keyStoreLocation = keyStoreLocation;
+ }
+
+ public char[] getKeyStorePassword() {
+
+ if (this.keyStorePassword == null) {
+ this.keyStorePassword = ServerConfiguration.getInstance()
+ .getFirstProperty(FinancialServicesConstants.KEYSTORE_PASSWORD_TAG).toCharArray();
+ }
+ return Arrays.copyOf(this.keyStorePassword, this.keyStorePassword.length);
+ }
+
+ public void setKeyStorePassword(char[] keyStorePassword) {
+
+ if (keyStorePassword != null) {
+ this.keyStorePassword = Arrays.copyOf(keyStorePassword, keyStorePassword.length);
+ }
+ }
+
+ public String getKeyAlias() {
+
+ return keyAlias == null ? ServerConfiguration.getInstance()
+ .getFirstProperty(FinancialServicesConstants.SIGNING_ALIAS_TAG) : keyAlias;
+ }
+
+ public void setKeyAlias(String keyAlias) {
+
+ this.keyAlias = keyAlias;
+ }
+
+ public String getKeyPassword() {
+
+ return keyPassword == null ? ServerConfiguration.getInstance()
+ .getFirstProperty(FinancialServicesConstants.SIGNING_KEY_PASSWORD) : keyPassword;
+ }
+
+ public void setKeyPassword(String keyPassword) {
+
+ this.keyPassword = keyPassword;
+ }
+
public void setApiManagerConfiguration(APIManagerConfigurationService apiManagerConfigurationService) {
this.apiManagerConfigurationService = apiManagerConfigurationService;
diff --git a/financial-services-accelerator/components/org.wso2.financial.services.accelerator.gateway/src/main/java/org/wso2/financial/services/accelerator/gateway/util/GatewayConstants.java b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.gateway/src/main/java/org/wso2/financial/services/accelerator/gateway/util/GatewayConstants.java
index 39159bbf..0575c608 100644
--- a/financial-services-accelerator/components/org.wso2.financial.services.accelerator.gateway/src/main/java/org/wso2/financial/services/accelerator/gateway/util/GatewayConstants.java
+++ b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.gateway/src/main/java/org/wso2/financial/services/accelerator/gateway/util/GatewayConstants.java
@@ -59,4 +59,8 @@ public class GatewayConstants {
public static final String ERROR_STATUS_PROP = "errorStatusCode";
public static final String IS_RETURN_RESPONSE = "isReturnResponse";
public static final String MODIFIED_STATUS = "ModifiedStatus";
+ public static final String CODE = "code";
+ public static final String MESSAGE = "message";
+ public static final String DESCRIPTION = "description";
+ public static final String LINKS = "links";
}
diff --git a/financial-services-accelerator/components/org.wso2.financial.services.accelerator.gateway/src/test/java/org/wso2/financial/services/accelerator/gateway/GatewayTestConstants.java b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.gateway/src/test/java/org/wso2/financial/services/accelerator/gateway/GatewayTestConstants.java
index 4629ba3c..1697dfbf 100644
--- a/financial-services-accelerator/components/org.wso2.financial.services.accelerator.gateway/src/test/java/org/wso2/financial/services/accelerator/gateway/GatewayTestConstants.java
+++ b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.gateway/src/test/java/org/wso2/financial/services/accelerator/gateway/GatewayTestConstants.java
@@ -29,7 +29,7 @@
public class GatewayTestConstants {
public static final String VALID_EXECUTOR_CLASS =
- "org.wso2.financial.services.accelerator.gateway.executor.core.MockOBExecutor";
+ "org.wso2.financial.services.accelerator.gateway.executor.core.MockFSExecutor";
public static final Map VALID_EXECUTOR_MAP = Stream.of(
new AbstractMap.SimpleImmutableEntry<>(1, VALID_EXECUTOR_CLASS))
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
diff --git a/financial-services-accelerator/components/org.wso2.financial.services.accelerator.gateway/src/test/java/org/wso2/financial/services/accelerator/gateway/executor/core/FSExtensionImplTest.java b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.gateway/src/test/java/org/wso2/financial/services/accelerator/gateway/executor/core/FSExtensionImplTest.java
index 589cbe12..d576d328 100644
--- a/financial-services-accelerator/components/org.wso2.financial.services.accelerator.gateway/src/test/java/org/wso2/financial/services/accelerator/gateway/executor/core/FSExtensionImplTest.java
+++ b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.gateway/src/test/java/org/wso2/financial/services/accelerator/gateway/executor/core/FSExtensionImplTest.java
@@ -36,7 +36,7 @@
import java.util.Map;
/**
- * Test for open Banking extension implementation.
+ * Test for FS extension implementation.
*/
public class FSExtensionImplTest {
diff --git a/financial-services-accelerator/components/org.wso2.financial.services.accelerator.gateway/src/test/java/org/wso2/financial/services/accelerator/gateway/executor/core/MockOBExecutor.java b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.gateway/src/test/java/org/wso2/financial/services/accelerator/gateway/executor/core/MockFSExecutor.java
similarity index 94%
rename from financial-services-accelerator/components/org.wso2.financial.services.accelerator.gateway/src/test/java/org/wso2/financial/services/accelerator/gateway/executor/core/MockOBExecutor.java
rename to financial-services-accelerator/components/org.wso2.financial.services.accelerator.gateway/src/test/java/org/wso2/financial/services/accelerator/gateway/executor/core/MockFSExecutor.java
index 55cc2eb7..8122dca0 100644
--- a/financial-services-accelerator/components/org.wso2.financial.services.accelerator.gateway/src/test/java/org/wso2/financial/services/accelerator/gateway/executor/core/MockOBExecutor.java
+++ b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.gateway/src/test/java/org/wso2/financial/services/accelerator/gateway/executor/core/MockFSExecutor.java
@@ -23,9 +23,9 @@
import org.wso2.financial.services.accelerator.gateway.executor.model.FSAPIResponseContext;
/**
- * Mock Open banking executor for testing.
+ * Mock FS executor for testing.
*/
-public class MockOBExecutor implements FinancialServicesGatewayExecutor {
+public class MockFSExecutor implements FinancialServicesGatewayExecutor {
@Override
public void preProcessRequest(FSAPIRequestContext fsapiRequestContext) {
diff --git a/financial-services-accelerator/components/org.wso2.financial.services.accelerator.gateway/src/test/java/org/wso2/financial/services/accelerator/gateway/executor/impl/consent/ConsentEnforcementExecutorTest.java b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.gateway/src/test/java/org/wso2/financial/services/accelerator/gateway/executor/impl/consent/ConsentEnforcementExecutorTest.java
new file mode 100644
index 00000000..79464dd7
--- /dev/null
+++ b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.gateway/src/test/java/org/wso2/financial/services/accelerator/gateway/executor/impl/consent/ConsentEnforcementExecutorTest.java
@@ -0,0 +1,186 @@
+/**
+ * Copyright (c) 2024, WSO2 LLC. (https://www.wso2.com).
+ *
+ * WSO2 LLC. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.wso2.financial.services.accelerator.gateway.executor.impl.consent;
+
+import org.apache.commons.io.FileUtils;
+import org.apache.http.HttpEntity;
+import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.json.JSONObject;
+import org.mockito.MockedStatic;
+import org.mockito.Mockito;
+import org.testng.Assert;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+import org.wso2.carbon.apimgt.common.gateway.dto.APIRequestInfoDTO;
+import org.wso2.carbon.apimgt.common.gateway.dto.MsgInfoDTO;
+import org.wso2.carbon.apimgt.impl.APIManagerConfiguration;
+import org.wso2.carbon.apimgt.impl.APIManagerConfigurationService;
+import org.wso2.financial.services.accelerator.common.config.FinancialServicesConfigurationService;
+import org.wso2.financial.services.accelerator.common.constant.FinancialServicesConstants;
+import org.wso2.financial.services.accelerator.common.util.HTTPClientUtils;
+import org.wso2.financial.services.accelerator.gateway.GatewayTestConstants;
+import org.wso2.financial.services.accelerator.gateway.executor.model.FSAPIRequestContext;
+import org.wso2.financial.services.accelerator.gateway.executor.model.FSExecutorError;
+import org.wso2.financial.services.accelerator.gateway.internal.GatewayDataHolder;
+import org.wso2.financial.services.accelerator.gateway.util.GatewayUtils;
+
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.UnsupportedEncodingException;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.UUID;
+
+/**
+ * Test for enforcement executor.
+ */
+public class ConsentEnforcementExecutorTest {
+
+ private static ConsentEnforcementExecutor consentEnforcementExecutor;
+ private static MockedStatic httpClientUtilsMockedStatic;
+
+ @BeforeClass
+ public static void beforeClass() throws IOException {
+
+ GatewayDataHolder dataHolder = GatewayDataHolder.getInstance();
+ String path = "src/test/resources";
+ File file = new File(path);
+ String absolutePathForTestResources = file.getAbsolutePath();
+ dataHolder.setKeyStoreLocation(absolutePathForTestResources + "/wso2carbon.jks");
+ dataHolder.setKeyAlias("wso2carbon");
+ dataHolder.setKeyPassword("wso2carbon");
+ dataHolder.setKeyStorePassword("wso2carbon".toCharArray());
+
+ Map configs = new HashMap<>();
+ configs.put(FinancialServicesConstants.CONSENT_VALIDATION_ENDPOINT, "http://localhost:8080");
+ configs.put(FinancialServicesConstants.REQUEST_ROUTER,
+ "org.wso2.financial.services.accelerator.gateway.executor.core.DefaultRequestRouter");
+ FinancialServicesConfigurationService financialServicesConfigurationService =
+ Mockito.mock(FinancialServicesConfigurationService.class);
+ Mockito.when(financialServicesConfigurationService.getConfigurations()).thenReturn(configs);
+ dataHolder.setFinancialServicesConfigurationService(financialServicesConfigurationService);
+
+ APIManagerConfiguration apiManagerConfiguration = Mockito.mock(APIManagerConfiguration.class);
+ Mockito.when(apiManagerConfiguration.getFirstProperty(Mockito.anyString())).thenReturn("admin");
+ APIManagerConfigurationService apimConfigurationService = Mockito.mock(APIManagerConfigurationService.class);
+ Mockito.when(apimConfigurationService.getAPIManagerConfiguration()).thenReturn(apiManagerConfiguration);
+ dataHolder.setApiManagerConfiguration(apimConfigurationService);
+
+ File responseFile = new File("src/test/resources/test-validation-response.json");
+ byte[] crlBytes = FileUtils.readFileToString(responseFile, String.valueOf(StandardCharsets.UTF_8))
+ .getBytes(StandardCharsets.UTF_8);
+ InputStream inStream = new ByteArrayInputStream(crlBytes);
+
+ HttpEntity httpEntityMock = Mockito.mock(HttpEntity.class);
+ Mockito.doReturn(inStream).when(httpEntityMock).getContent();
+
+ CloseableHttpClient httpClient = Mockito.mock(CloseableHttpClient.class);
+ CloseableHttpResponse httpResponse = Mockito.mock(CloseableHttpResponse.class);
+ Mockito.doReturn(httpEntityMock).when(httpResponse).getEntity();
+ Mockito.doReturn(httpResponse).when(httpClient).execute(Mockito.any());
+
+ httpClientUtilsMockedStatic = Mockito.mockStatic(HTTPClientUtils.class);
+ httpClientUtilsMockedStatic.when(() -> HTTPClientUtils.getHttpsClient()).thenReturn(httpClient);
+
+ consentEnforcementExecutor = new ConsentEnforcementExecutor();
+ }
+
+ @AfterClass
+ public static void afterClass() {
+ httpClientUtilsMockedStatic.close();
+ }
+
+ @Test(priority = 1)
+ public void testSigningKeyRetrieval() {
+
+ Assert.assertNotNull(consentEnforcementExecutor.getJWTSigningKey());
+ }
+
+ @Test(priority = 2)
+ public void testJWTGeneration() {
+
+ String jwtToken = consentEnforcementExecutor.generateJWT(GatewayTestConstants.CUSTOM_PAYLOAD);
+ Assert.assertNotNull(jwtToken);
+ String[] parts = jwtToken.split("\\.");
+ Assert.assertEquals(parts.length, 3);
+ }
+
+ @Test(priority = 2)
+ public void testValidationPayloadCreation() {
+
+ Map headers = new HashMap<>();
+ headers.put("customHeader", "headerValue");
+ headers.put("customHeader2", "headerValue2");
+ JSONObject jsonObject =
+ consentEnforcementExecutor.createValidationRequestPayload(headers,
+ GatewayTestConstants.CUSTOM_PAYLOAD, new HashMap<>());
+ Assert.assertNotNull(jsonObject);
+ Assert.assertEquals(((JSONObject) jsonObject.get(ConsentEnforcementExecutor.HEADERS_TAG)).get("customHeader"),
+ "headerValue");
+ Assert.assertEquals(((JSONObject) jsonObject.get(ConsentEnforcementExecutor.BODY_TAG)).get("custom"),
+ "payload");
+ }
+
+ @Test(priority = 3)
+ public void testB64Decoder() throws UnsupportedEncodingException {
+
+ String jwtToken = "eyJjdXN0b20iOiJwYXlsb2FkIn0";
+ JSONObject jsonObject = GatewayUtils.decodeBase64(jwtToken);
+ Assert.assertEquals(jsonObject.get("custom").toString(), "payload");
+ }
+
+ @Test
+ public void testHandlerError() {
+ FSAPIRequestContext fsapiRequestContext = Mockito.mock(FSAPIRequestContext.class);
+ ArrayList errors = new ArrayList<>();
+ Mockito.when(fsapiRequestContext.getErrors()).thenReturn(errors);
+ consentEnforcementExecutor.handleError(fsapiRequestContext, "Error", "Error",
+ "400");
+ }
+
+ @Test
+ public void testPostProcessRequest() {
+ String consentID = String.valueOf(UUID.randomUUID());
+
+ MsgInfoDTO msgInfoDTOMock = Mockito.mock(MsgInfoDTO.class);
+ Mockito.doReturn("/accounts").when(msgInfoDTOMock).getElectedResource();
+ Mockito.doReturn("/accounts").when(msgInfoDTOMock).getResource();
+ Mockito.doReturn("GET").when(msgInfoDTOMock).getHttpMethod();
+
+ APIRequestInfoDTO apiRequestInfoDTOMock = Mockito.mock(APIRequestInfoDTO.class);
+ Mockito.doReturn("admin@wso2.com").when(apiRequestInfoDTOMock).getUsername();
+ Mockito.doReturn("test-client-id").when(apiRequestInfoDTOMock).getConsumerKey();
+ Mockito.doReturn("/open-banking/v3.1/aisp").when(apiRequestInfoDTOMock).getContext();
+
+ FSAPIRequestContext fsapiRequestContext = Mockito.mock(FSAPIRequestContext.class);
+ Mockito.doReturn(false).when(fsapiRequestContext).isError();
+ Mockito.doReturn(consentID).when(fsapiRequestContext).getConsentId();
+ Mockito.doReturn(apiRequestInfoDTOMock).when(fsapiRequestContext).getApiRequestInfo();
+ Mockito.doReturn(msgInfoDTOMock).when(fsapiRequestContext).getMsgInfo();
+
+ consentEnforcementExecutor.postProcessRequest(fsapiRequestContext);
+ }
+
+}
diff --git a/financial-services-accelerator/components/org.wso2.financial.services.accelerator.gateway/src/test/java/org/wso2/financial/services/accelerator/gateway/executor/impl/error/handling/DefaultErrorHandlingExecutorTest.java b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.gateway/src/test/java/org/wso2/financial/services/accelerator/gateway/executor/impl/error/handling/DefaultErrorHandlingExecutorTest.java
new file mode 100644
index 00000000..150abfdc
--- /dev/null
+++ b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.gateway/src/test/java/org/wso2/financial/services/accelerator/gateway/executor/impl/error/handling/DefaultErrorHandlingExecutorTest.java
@@ -0,0 +1,102 @@
+/**
+ * Copyright (c) 2023, WSO2 LLC. (https://www.wso2.com).
+ *
+ * WSO2 LLC. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.wso2.financial.services.accelerator.gateway.executor.impl.error.handling;
+
+import org.mockito.Mockito;
+import org.testng.annotations.Test;
+import org.wso2.financial.services.accelerator.gateway.executor.model.FSAPIRequestContext;
+import org.wso2.financial.services.accelerator.gateway.executor.model.FSAPIResponseContext;
+import org.wso2.financial.services.accelerator.gateway.executor.model.FSExecutorError;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+/**
+ * Test class for OBDefaultErrorHandler.
+ */
+public class DefaultErrorHandlingExecutorTest {
+
+ Map contextProps = new HashMap<>();
+
+ @Test
+ public void testPreRequestFlow() {
+
+ FSAPIRequestContext fsapiRequestContext = Mockito.mock(FSAPIRequestContext.class);
+ Mockito.when(fsapiRequestContext.isError()).thenReturn(true);
+ Mockito.when(fsapiRequestContext.getErrors()).thenReturn(getErrorList());
+ Mockito.when(fsapiRequestContext.getContextProps()).thenReturn(contextProps);
+
+ DefaultErrorHandlingExecutor errorHandlingExecutor = Mockito.spy(DefaultErrorHandlingExecutor.class);
+ errorHandlingExecutor.preProcessRequest(fsapiRequestContext);
+ verify(fsapiRequestContext, times(0)).setError(false);
+ }
+
+ @Test
+ public void testPostRequestFlow() {
+
+ FSAPIRequestContext fsapiRequestContext = Mockito.mock(FSAPIRequestContext.class);
+ Mockito.when(fsapiRequestContext.isError()).thenReturn(true);
+ Mockito.when(fsapiRequestContext.getErrors()).thenReturn(getErrorList());
+ Mockito.when(fsapiRequestContext.getContextProps()).thenReturn(contextProps);
+
+ DefaultErrorHandlingExecutor errorHandlingExecutor = Mockito.spy(DefaultErrorHandlingExecutor.class);
+ errorHandlingExecutor.postProcessRequest(fsapiRequestContext);
+ verify(fsapiRequestContext, times(0)).setError(false);
+ }
+
+ @Test
+ public void testPreResponseFlow() {
+
+ FSAPIResponseContext fsapiResponseContext = Mockito.mock(FSAPIResponseContext.class);
+ Mockito.when(fsapiResponseContext.isError()).thenReturn(true);
+ Mockito.when(fsapiResponseContext.getErrors()).thenReturn(getErrorList());
+ Mockito.when(fsapiResponseContext.getContextProps()).thenReturn(contextProps);
+
+ DefaultErrorHandlingExecutor errorHandlingExecutor = Mockito.spy(DefaultErrorHandlingExecutor.class);
+ errorHandlingExecutor.preProcessResponse(fsapiResponseContext);
+ verify(fsapiResponseContext, times(0)).setError(false);
+ }
+
+ @Test
+ public void testPostResponseFlow() {
+
+ FSAPIResponseContext fsapiResponseContext = Mockito.mock(FSAPIResponseContext.class);
+ Mockito.when(fsapiResponseContext.isError()).thenReturn(true);
+ Mockito.when(fsapiResponseContext.getErrors()).thenReturn(getErrorList());
+ Mockito.when(fsapiResponseContext.getContextProps()).thenReturn(contextProps);
+
+ DefaultErrorHandlingExecutor errorHandlingExecutor = Mockito.spy(DefaultErrorHandlingExecutor.class);
+ errorHandlingExecutor.postProcessResponse(fsapiResponseContext);
+ verify(fsapiResponseContext, times(0)).setError(false);
+ }
+
+ private ArrayList getErrorList() {
+
+ FSExecutorError error = new FSExecutorError("400", "Invalid Request",
+ "Mandatory parameter is missing", "400");
+
+ ArrayList errors = new ArrayList<>();
+ errors.add(error);
+ return errors;
+ }
+}
diff --git a/financial-services-accelerator/components/org.wso2.financial.services.accelerator.gateway/src/test/resources/test-validation-response.json b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.gateway/src/test/resources/test-validation-response.json
new file mode 100644
index 00000000..a0ba4412
--- /dev/null
+++ b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.gateway/src/test/resources/test-validation-response.json
@@ -0,0 +1,12 @@
+{
+ "isValid": true,
+ "errorCode": "",
+ "errorMessage": "",
+ "httpCode": "",
+ "modifiedPayload": {
+ "key": "value"
+ },
+ "consentInformation": {
+ "key": "value"
+ }
+}
diff --git a/financial-services-accelerator/components/org.wso2.financial.services.accelerator.gateway/src/test/resources/testng.xml b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.gateway/src/test/resources/testng.xml
index 8e4cd5f5..b5603e04 100644
--- a/financial-services-accelerator/components/org.wso2.financial.services.accelerator.gateway/src/test/resources/testng.xml
+++ b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.gateway/src/test/resources/testng.xml
@@ -22,6 +22,8 @@
+
+
diff --git a/financial-services-accelerator/components/org.wso2.financial.services.accelerator.gateway/src/test/resources/wso2carbon.jks b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.gateway/src/test/resources/wso2carbon.jks
new file mode 100644
index 00000000..c8775783
Binary files /dev/null and b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.gateway/src/test/resources/wso2carbon.jks differ
diff --git a/pom.xml b/pom.xml
index 7a9cc35d..07ea9463 100644
--- a/pom.xml
+++ b/pom.xml
@@ -454,9 +454,14 @@
${oltu.version}