diff --git a/financial-services-accelerator/components/org.wso2.financial.services.accelerator.common/src/main/java/org/wso2/financial/services/accelerator/common/constant/FinancialServicesConstants.java b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.common/src/main/java/org/wso2/financial/services/accelerator/common/constant/FinancialServicesConstants.java index 0d2591c4..ccc7707d 100644 --- a/financial-services-accelerator/components/org.wso2.financial.services.accelerator.common/src/main/java/org/wso2/financial/services/accelerator/common/constant/FinancialServicesConstants.java +++ b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.common/src/main/java/org/wso2/financial/services/accelerator/common/constant/FinancialServicesConstants.java @@ -82,5 +82,9 @@ public class FinancialServicesConstants { "Identity.TokenSubject.RemoveUserStoreDomainFromSubject"; public static final String REMOVE_TENANT_DOMAIN_FROM_SUBJECT = "Identity.TokenSubject.RemoveTenantDomainFromSubject"; + public static final String PUBLISHER_HOSTNAME = "PublisherURL"; + public static final String REQUEST_ROUTER = "Gateway.RequestRouter"; + public static final String GATEWAY_CACHE_EXPIRY = "Gateway.Cache.GatewayCache.CacheAccessExpiry"; + public static final String GATEWAY_CACHE_MODIFIED_EXPIRY = "Gateway.Cache.GatewayCache.CacheModifiedExpiry"; } diff --git a/financial-services-accelerator/components/org.wso2.financial.services.accelerator.gateway/pom.xml b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.gateway/pom.xml new file mode 100644 index 00000000..86ea23cf --- /dev/null +++ b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.gateway/pom.xml @@ -0,0 +1,230 @@ + + + + 4.0.0 + + + financial-services-accelerator + org.wso2.financial.services.accelerator + 4.0.0-SNAPSHOT + ../../pom.xml + + + org.wso2.financial.services.accelerator.gateway + WSO2 Financial Services - Gateway Module + WSO2 Financial Services - Gateway Module + http://maven.apache.org + bundle + + + + commons-logging + commons-logging + + + org.apache.commons + commons-lang3 + + + io.swagger.parser.v3 + swagger-parser + + + commons-io.wso2 + commons-io + + + org.wso2.carbon.apimgt + org.wso2.carbon.apimgt.impl + + + org.wso2.carbon.apimgt + org.wso2.carbon.apimgt.common.gateway + + + org.wso2.financial.services.accelerator + org.wso2.financial.services.accelerator.common + + + + org.testng + testng + test + + + org.mockito + mockito-core + test + + + org.mockito + mockito-testng + test + + + + + + + com.github.spotbugs + spotbugs-maven-plugin + + Max + Low + true + true + ${project.build.directory}/spotbugs + ${project.basedir}/src/main/resources/findbugs-exclude.xml + ${project.basedir}/src/main/resources/findbugs-include.xml + + + com.h3xstream.findsecbugs + findsecbugs-plugin + ${com.h3xstream.findsecbugs.version} + + + + + + analyze-compile + compile + + check + + + + + + org.apache.maven.plugins + maven-surefire-plugin + + + src/test/resources/testng.xml + + + target/jacoco.exec + + true + + + + org.jacoco + jacoco-maven-plugin + ${jacoco.version} + + + + **/*Constants.class + **/*Component.class + **/*DataHolder.class + **/*Cache.class + **/*CacheKey.class + **/*APIRequestContext.class + **/*APIResponseContext.class + **/*ExecutorError.class + + + + + default-prepare-agent + + prepare-agent + + + + default-prepare-agent-integration + + prepare-agent-integration + + + + default-report + + report + + + + default-report-integration + + report-integration + + + + default-check + + check + + + + + BUNDLE + + + INSTRUCTION + COVEREDRATIO + 0.8 + + + + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + + org.apache.felix + maven-bundle-plugin + true + + + + ${project.artifactId} + + + org.wso2.financial.services.accelerator.gateway.internal + + + org.osgi.framework; version="${osgi.framework.imp.pkg.version.range}", + org.osgi.service.component; version="${osgi.service.component.imp.pkg.version.range}", + org.apache.commons.io;version="${org.apache.commons.io.version.range}", + io.swagger.parser.*;version="${swagger.parser.version}", + org.apache.commons.logging;version="${commons.logging.version}", + org.apache.http.*;version="${orbit.httpcore.version}", + org.json;version="${org.json.version.range}", + org.wso2.carbon.apimgt.common.gateway.*;version="${org.wso2.carbon.apimgt.version.range}", + org.wso2.carbon.apimgt.impl;version="${org.wso2.carbon.apimgt.version.range}", + org.wso2.financial.services.accelerator.common.*;version="${project.version}" + + + !org.wso2.financial.services.accelerator.gateway.internal, + org.wso2.financial.services.accelerator.gateway.*;version="${project.version}", + + <_dsannotations>* + + + + + + + diff --git a/financial-services-accelerator/components/org.wso2.financial.services.accelerator.gateway/src/main/java/org/wso2/financial/services/accelerator/gateway/cache/GatewayCache.java b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.gateway/src/main/java/org/wso2/financial/services/accelerator/gateway/cache/GatewayCache.java new file mode 100644 index 00000000..7bffb01f --- /dev/null +++ b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.gateway/src/main/java/org/wso2/financial/services/accelerator/gateway/cache/GatewayCache.java @@ -0,0 +1,65 @@ +/** + * 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.cache; + +import org.wso2.financial.services.accelerator.common.caching.FinancialServicesBaseCache; +import org.wso2.financial.services.accelerator.gateway.internal.GatewayDataHolder; + +/** + * Cache definition to store API Resource Security Schemes + */ +public class GatewayCache extends FinancialServicesBaseCache { + + private static final String cacheName = "FINANCIAL_SERVICES_GATEWAY_CACHE"; + + private final Integer accessExpiryMinutes; + private final Integer modifiedExpiryMinutes; + + /** + * Initialize with unique cache name. + */ + public GatewayCache() { + + super(cacheName); + this.accessExpiryMinutes = setAccessExpiryMinutes(); + this.modifiedExpiryMinutes = setModifiedExpiryMinutes(); + } + + @Override + public int getCacheAccessExpiryMinutes() { + + return accessExpiryMinutes; + } + + @Override + public int getCacheModifiedExpiryMinutes() { + + return modifiedExpiryMinutes; + } + + public int setAccessExpiryMinutes() { + + return GatewayDataHolder.getInstance().getGatewayCacheAccessExpiry(); + } + + public int setModifiedExpiryMinutes() { + + return GatewayDataHolder.getInstance().getGatewayCacheModifiedExpiry(); + } +} diff --git a/financial-services-accelerator/components/org.wso2.financial.services.accelerator.gateway/src/main/java/org/wso2/financial/services/accelerator/gateway/cache/GatewayCacheKey.java b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.gateway/src/main/java/org/wso2/financial/services/accelerator/gateway/cache/GatewayCacheKey.java new file mode 100644 index 00000000..e8df4485 --- /dev/null +++ b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.gateway/src/main/java/org/wso2/financial/services/accelerator/gateway/cache/GatewayCacheKey.java @@ -0,0 +1,63 @@ +/** + * 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.cache; + + +import org.wso2.financial.services.accelerator.common.caching.FinancialServicesBaseCacheKey; + +import java.io.Serializable; +import java.util.Objects; + +/** + * Cache Key for Financial Services Gateway cache. + */ +public class GatewayCacheKey extends FinancialServicesBaseCacheKey implements Serializable { + + private static final long serialVersionUID = 883027070771592120L; + public String gatewayCacheKey; + + public GatewayCacheKey(String gatewayCacheKey) { + + this.gatewayCacheKey = gatewayCacheKey; + } + + public static GatewayCacheKey of(String gatewayCacheKey) { + + return new GatewayCacheKey(gatewayCacheKey); + } + + @Override + public boolean equals(Object o) { + + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + GatewayCacheKey that = (GatewayCacheKey) o; + return Objects.equals(gatewayCacheKey, that.gatewayCacheKey); + } + + @Override + public int hashCode() { + + return Objects.hash(gatewayCacheKey); + } +} diff --git a/financial-services-accelerator/components/org.wso2.financial.services.accelerator.gateway/src/main/java/org/wso2/financial/services/accelerator/gateway/executor/core/AbstractRequestRouter.java b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.gateway/src/main/java/org/wso2/financial/services/accelerator/gateway/executor/core/AbstractRequestRouter.java new file mode 100644 index 00000000..aef8ca76 --- /dev/null +++ b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.gateway/src/main/java/org/wso2/financial/services/accelerator/gateway/executor/core/AbstractRequestRouter.java @@ -0,0 +1,85 @@ +/** + * 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.core; + + +import org.wso2.financial.services.accelerator.common.util.FinancialServicesUtils; +import org.wso2.financial.services.accelerator.common.util.Generated; +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.internal.GatewayDataHolder; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +/** + * Financial Services abstract Request Router. + */ +public abstract class AbstractRequestRouter { + + private Map> executorMap = new HashMap<>(); + + /** + * Initiation method of the Router + */ + @Generated(message = "Ignoring since the method require OSGi services to function. This functionality is tested " + + "in other services") + public void build() { + + Map> executorConfig = + GatewayDataHolder.getInstance().getFinancialServicesConfigurationService().getExecutors(); + executorConfig.keySet().forEach(consentType -> { + Map integerStringMap = executorConfig.get(consentType); + List executorList = integerStringMap.keySet().stream() + .map(integer -> (FinancialServicesGatewayExecutor) FinancialServicesUtils + .getClassInstanceFromFQN(integerStringMap.get(integer))).collect(Collectors.toList()); + executorMap.put(consentType, executorList); + }); + } + + /** + * Method to obtain correct executors for the given request context. ( Expected to be implemented at toolkit) + * + * @param requestContext FS Request context + * @return List of executors + */ + public abstract List getExecutorsForRequest(FSAPIRequestContext requestContext); + + /** + * Method to obtain correct executors for the given response context. ( Expected to be implemented at toolkit) + * + * @param requestContext FS Response context + * @return List of executors + */ + public abstract List getExecutorsForResponse(FSAPIResponseContext requestContext); + + public Map> getExecutorMap() { + + return executorMap; + } + + public void setExecutorMap( + Map> executorMap) { + + this.executorMap = executorMap; + } + +} diff --git a/financial-services-accelerator/components/org.wso2.financial.services.accelerator.gateway/src/main/java/org/wso2/financial/services/accelerator/gateway/executor/core/DefaultRequestRouter.java b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.gateway/src/main/java/org/wso2/financial/services/accelerator/gateway/executor/core/DefaultRequestRouter.java new file mode 100644 index 00000000..21d957d5 --- /dev/null +++ b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.gateway/src/main/java/org/wso2/financial/services/accelerator/gateway/executor/core/DefaultRequestRouter.java @@ -0,0 +1,74 @@ +/** + * 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.core; + +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.util.GatewayConstants; + +import java.util.ArrayList; +import java.util.List; + +/** + * Financial Services Default Request Router. + */ +public class DefaultRequestRouter extends AbstractRequestRouter { + + private static final List EMPTY_LIST = new ArrayList<>(); + + @Override + public List getExecutorsForRequest(FSAPIRequestContext requestContext) { + if (GatewayConstants.API_TYPE_NON_REGULATORY + .equals(requestContext.getOpenAPI().getExtensions().get(GatewayConstants.API_TYPE_CUSTOM_PROP))) { + requestContext.addContextProperty(GatewayConstants.API_TYPE_CUSTOM_PROP, + GatewayConstants.API_TYPE_NON_REGULATORY); + return EMPTY_LIST; + } else if (GatewayConstants.API_TYPE_CONSENT + .equals(requestContext.getOpenAPI().getExtensions().get(GatewayConstants.API_TYPE_CUSTOM_PROP))) { + //add support for consent management portal APIs + requestContext.addContextProperty(GatewayConstants.API_TYPE_CUSTOM_PROP, + GatewayConstants.API_TYPE_CONSENT); + return this.getExecutorMap().get(GatewayConstants.EXECUTOR_TYPE_CONSENT); + } else if (requestContext.getMsgInfo().getResource().contains(GatewayConstants.DCR_PATH)) { + return this.getExecutorMap().get(GatewayConstants.EXECUTOR_TYPE_DCR); + } else { + return this.getExecutorMap().get(GatewayConstants.EXECUTOR_TYPE_DEFAULT); + } + } + + @Override + public List getExecutorsForResponse(FSAPIResponseContext responseContext) { + + if (responseContext.getContextProps().containsKey(GatewayConstants.API_TYPE_CUSTOM_PROP)) { + if (GatewayConstants.API_TYPE_NON_REGULATORY + .equals(responseContext.getContextProps().get(GatewayConstants.API_TYPE_CUSTOM_PROP))) { + return EMPTY_LIST; + } else if (GatewayConstants.API_TYPE_CONSENT + .equals(responseContext.getContextProps().get(GatewayConstants.API_TYPE_CUSTOM_PROP))) { + return this.getExecutorMap().get(GatewayConstants.EXECUTOR_TYPE_CONSENT); + } + } + + if (responseContext.getMsgInfo().getResource().contains(GatewayConstants.DCR_PATH)) { + return this.getExecutorMap().get(GatewayConstants.EXECUTOR_TYPE_DCR); + } else { + return this.getExecutorMap().get(GatewayConstants.EXECUTOR_TYPE_DEFAULT); + } + } +} diff --git a/financial-services-accelerator/components/org.wso2.financial.services.accelerator.gateway/src/main/java/org/wso2/financial/services/accelerator/gateway/executor/core/FSExtensionListenerImpl.java b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.gateway/src/main/java/org/wso2/financial/services/accelerator/gateway/executor/core/FSExtensionListenerImpl.java new file mode 100644 index 00000000..4c1b03cc --- /dev/null +++ b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.gateway/src/main/java/org/wso2/financial/services/accelerator/gateway/executor/core/FSExtensionListenerImpl.java @@ -0,0 +1,267 @@ +/** + * 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.core; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.http.HttpStatus; +import org.wso2.carbon.apimgt.common.gateway.dto.ExtensionResponseDTO; +import org.wso2.carbon.apimgt.common.gateway.dto.ExtensionResponseStatus; +import org.wso2.carbon.apimgt.common.gateway.dto.RequestContextDTO; +import org.wso2.carbon.apimgt.common.gateway.dto.ResponseContextDTO; +import org.wso2.carbon.apimgt.common.gateway.extensionlistener.ExtensionListener; +import org.wso2.financial.services.accelerator.common.util.Generated; +import org.wso2.financial.services.accelerator.gateway.cache.GatewayCacheKey; +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.internal.GatewayDataHolder; +import org.wso2.financial.services.accelerator.gateway.util.GatewayConstants; + +import java.io.ByteArrayInputStream; +import java.nio.charset.StandardCharsets; +import java.util.HashMap; +import java.util.Map; + +/** + * Financial Services implementation for Extension listener. + */ +public class FSExtensionListenerImpl implements ExtensionListener { + + private static final Log log = LogFactory.getLog(FSExtensionListenerImpl.class); + + @Override + @Generated(message = "Ignoring since the method has covered in other tests") + public ExtensionResponseDTO preProcessRequest(RequestContextDTO requestContextDTO) { + + FSAPIRequestContext fsapiRequestContext = new FSAPIRequestContext(requestContextDTO, new HashMap<>()); + for (FinancialServicesGatewayExecutor gatewayExecutor : + GatewayDataHolder.getInstance().getRequestRouter().getExecutorsForRequest(fsapiRequestContext)) { + if (log.isDebugEnabled()) { + log.debug("Executing preProcessRequest for executor: " + gatewayExecutor.getClass().getName()); + } + gatewayExecutor.preProcessRequest(fsapiRequestContext); + } + + if (!fsapiRequestContext.isError()) { + setPropertiesToCache(requestContextDTO.getMsgInfo().getMessageId(), fsapiRequestContext.getContextProps()); + } + return getResponseDTOForRequest(fsapiRequestContext); + } + + @Override + @Generated(message = "Ignoring since the method has covered in other tests") + public ExtensionResponseDTO postProcessRequest(RequestContextDTO requestContextDTO) { + + Map contextProps = getPropertiesFromCache(requestContextDTO.getMsgInfo().getMessageId() + + GatewayConstants.CONTEXT_PROP_CACHE_KEY); + + FSAPIRequestContext fsapiRequestContext = new FSAPIRequestContext(requestContextDTO, contextProps); + for (FinancialServicesGatewayExecutor gatewayExecutor : + GatewayDataHolder.getInstance().getRequestRouter().getExecutorsForRequest(fsapiRequestContext)) { + if (log.isDebugEnabled()) { + log.debug("Executing postProcessRequest for executor: " + gatewayExecutor.getClass().getName()); + } + gatewayExecutor.postProcessRequest(fsapiRequestContext); + } + + if (!fsapiRequestContext.isError()) { + setPropertiesToCache(requestContextDTO.getMsgInfo().getMessageId() + + GatewayConstants.CONTEXT_PROP_CACHE_KEY, fsapiRequestContext.getContextProps()); + } + return getResponseDTOForRequest(fsapiRequestContext); + } + + @Override + @Generated(message = "Ignoring since the method has covered in other tests") + public ExtensionResponseDTO preProcessResponse(ResponseContextDTO responseContextDTO) { + + Map contextProps = getPropertiesFromCache(responseContextDTO.getMsgInfo().getMessageId() + + GatewayConstants.CONTEXT_PROP_CACHE_KEY); + FSAPIResponseContext fsapiResponseContext = new FSAPIResponseContext(responseContextDTO, contextProps); + for (FinancialServicesGatewayExecutor gatewayExecutor : + GatewayDataHolder.getInstance().getRequestRouter().getExecutorsForResponse(fsapiResponseContext)) { + if (log.isDebugEnabled()) { + log.debug("Executing preProcessResponse for executor: " + gatewayExecutor.getClass().getName()); + } + gatewayExecutor.preProcessResponse(fsapiResponseContext); + } + + if (!fsapiResponseContext.isError()) { + setPropertiesToCache(responseContextDTO.getMsgInfo().getMessageId() + + GatewayConstants.CONTEXT_PROP_CACHE_KEY, fsapiResponseContext.getContextProps()); + } + return getResponseDTOForResponse(fsapiResponseContext); + } + + @Override + @Generated(message = "Ignoring since the method has covered in other tests") + public ExtensionResponseDTO postProcessResponse(ResponseContextDTO responseContextDTO) { + + Map contextProps = getPropertiesFromCache(responseContextDTO.getMsgInfo().getMessageId() + + GatewayConstants.CONTEXT_PROP_CACHE_KEY); + FSAPIResponseContext fsapiResponseContext = new FSAPIResponseContext(responseContextDTO, contextProps); + for (FinancialServicesGatewayExecutor gatewayExecutor : + GatewayDataHolder.getInstance().getRequestRouter().getExecutorsForResponse(fsapiResponseContext)) { + if (log.isDebugEnabled()) { + log.debug("Executing postProcessResponse for executor: " + gatewayExecutor.getClass().getName()); + } + gatewayExecutor.postProcessResponse(fsapiResponseContext); + } + ExtensionResponseDTO responseDTOForResponse = getResponseDTOForResponse(fsapiResponseContext); + removePropertiesFromCache(responseContextDTO.getMsgInfo().getMessageId() + + GatewayConstants.CONTEXT_PROP_CACHE_KEY); + return responseDTOForResponse; + } + + /** + * Method to get response DTO for request path. + * + * @param fsapiRequestContext API Request Context + * @return ExtensionResponseDTO Extension Response DTO + */ + protected ExtensionResponseDTO getResponseDTOForRequest(FSAPIRequestContext fsapiRequestContext) { + + ExtensionResponseDTO extensionResponseDTO = new ExtensionResponseDTO(); + if (fsapiRequestContext.isError()) { + int statusCode = (!fsapiRequestContext.getContextProps().containsKey(GatewayConstants.ERROR_STATUS_PROP)) ? + HttpStatus.SC_INTERNAL_SERVER_ERROR : + (int) (fsapiRequestContext.getContextProperty(GatewayConstants.ERROR_STATUS_PROP)); + extensionResponseDTO.setStatusCode(statusCode); + extensionResponseDTO.setResponseStatus(ExtensionResponseStatus.RETURN_ERROR.toString()); + } else if (fsapiRequestContext.getContextProps().containsKey(GatewayConstants.IS_RETURN_RESPONSE) && + Boolean.parseBoolean(fsapiRequestContext.getContextProps() + .get(GatewayConstants.IS_RETURN_RESPONSE).toString())) { + Map headers = fsapiRequestContext.getMsgInfo().getHeaders(); + headers.put(GatewayConstants.CONTENT_TYPE_TAG, GatewayConstants.JSON_CONTENT_TYPE); + fsapiRequestContext.getMsgInfo().setHeaders(headers); + extensionResponseDTO.setHeaders(headers); + if (fsapiRequestContext.getContextProps().containsKey(GatewayConstants.MODIFIED_STATUS)) { + extensionResponseDTO.setStatusCode(Integer.parseInt(fsapiRequestContext.getContextProps() + .get(GatewayConstants.MODIFIED_STATUS).toString())); + } + extensionResponseDTO.setResponseStatus(ExtensionResponseStatus.RETURN_ERROR.toString()); + } else { + extensionResponseDTO.setResponseStatus(ExtensionResponseStatus.CONTINUE.toString()); + } + + String modifiedPayload = fsapiRequestContext.getModifiedPayload(); + if (modifiedPayload != null) { + extensionResponseDTO.setPayload(new ByteArrayInputStream(modifiedPayload.getBytes(StandardCharsets.UTF_8))); + } + + setHeadersToResponse(extensionResponseDTO, fsapiRequestContext.getAddedHeaders(), + fsapiRequestContext.getMsgInfo().getHeaders()); + return extensionResponseDTO; + } + + /** + * Method to get response DTO for response path. + * + * @param fsapiResponseContext API Response Context + * @return ExtensionResponseDTO Extension Response DTO + */ + protected ExtensionResponseDTO getResponseDTOForResponse(FSAPIResponseContext fsapiResponseContext) { + + ExtensionResponseDTO extensionResponseDTO = new ExtensionResponseDTO(); + if (fsapiResponseContext.isError()) { + int statusCode = (!fsapiResponseContext.getContextProps().containsKey(GatewayConstants.ERROR_STATUS_PROP)) ? + HttpStatus.SC_INTERNAL_SERVER_ERROR : + (int) (fsapiResponseContext.getContextProperty(GatewayConstants.ERROR_STATUS_PROP)); + extensionResponseDTO.setStatusCode(statusCode); + extensionResponseDTO.setResponseStatus(ExtensionResponseStatus.RETURN_ERROR.toString()); + } else if (fsapiResponseContext.getContextProps().containsKey(GatewayConstants.IS_RETURN_RESPONSE) && + Boolean.parseBoolean(fsapiResponseContext.getContextProps() + .get(GatewayConstants.IS_RETURN_RESPONSE).toString())) { + Map headers = fsapiResponseContext.getMsgInfo().getHeaders(); + headers.put(GatewayConstants.CONTENT_TYPE_TAG, GatewayConstants.JSON_CONTENT_TYPE); + fsapiResponseContext.getMsgInfo().setHeaders(headers); + extensionResponseDTO.setHeaders(headers); + if (fsapiResponseContext.getContextProps().containsKey(GatewayConstants.MODIFIED_STATUS)) { + extensionResponseDTO.setStatusCode((Integer.parseInt(fsapiResponseContext.getContextProps() + .get(GatewayConstants.MODIFIED_STATUS).toString()))); + } + extensionResponseDTO.setResponseStatus(ExtensionResponseStatus.RETURN_ERROR.toString()); + } else { + extensionResponseDTO.setResponseStatus(ExtensionResponseStatus.CONTINUE.toString()); + } + + String modifiedPayload = fsapiResponseContext.getModifiedPayload(); + if (modifiedPayload != null) { + extensionResponseDTO.setPayload(new ByteArrayInputStream(modifiedPayload.getBytes(StandardCharsets.UTF_8))); + } + + setHeadersToResponse(extensionResponseDTO, fsapiResponseContext.getAddedHeaders(), + fsapiResponseContext.getMsgInfo().getHeaders()); + return extensionResponseDTO; + } + + @Override + public String getType() { + + return null; + } + + /** + * Method to store properties to cache + * + * @param key unique cache key + * @param contextProps properties to store + */ + private void setPropertiesToCache(String key, Map contextProps) { + + GatewayDataHolder.getGatewayCache().addToCache(GatewayCacheKey.of(key), contextProps); + } + + /** + * Method to retrieve context properties from cache. + * + * @param key unique cache key + * @return context properties + */ + private Map getPropertiesFromCache(String key) { + Object cachedObject = GatewayDataHolder.getGatewayCache().getFromCache(GatewayCacheKey.of(key)); + return cachedObject == null ? new HashMap<>() : (Map) cachedObject; + } + + /** + * Method to remove context properties from cache. + * + * @param key unique cache key + */ + private void removePropertiesFromCache(String key) { + GatewayDataHolder.getGatewayCache().removeFromCache(GatewayCacheKey.of(key)); + } + + /** + * Method to add headers to the response. + * + * @param extensionResponseDTO Extension response DTO + * @param addedHeaders Added headers + * @param requestHeaders Request headers + */ + private void setHeadersToResponse(ExtensionResponseDTO extensionResponseDTO, Map addedHeaders, + Map requestHeaders) { + if (addedHeaders.size() != 0) { + HashMap headers = new HashMap<>(); + headers.putAll(requestHeaders); + headers.putAll(addedHeaders); + extensionResponseDTO.setHeaders(headers); + } + } +} diff --git a/financial-services-accelerator/components/org.wso2.financial.services.accelerator.gateway/src/main/java/org/wso2/financial/services/accelerator/gateway/executor/core/FinancialServicesGatewayExecutor.java b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.gateway/src/main/java/org/wso2/financial/services/accelerator/gateway/executor/core/FinancialServicesGatewayExecutor.java new file mode 100644 index 00000000..8e1cfe95 --- /dev/null +++ b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.gateway/src/main/java/org/wso2/financial/services/accelerator/gateway/executor/core/FinancialServicesGatewayExecutor.java @@ -0,0 +1,56 @@ +/** + * 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.core; + +import org.wso2.financial.services.accelerator.gateway.executor.model.FSAPIRequestContext; +import org.wso2.financial.services.accelerator.gateway.executor.model.FSAPIResponseContext; + +/** + * Financial Services executor interface. + */ +public interface FinancialServicesGatewayExecutor { + + /** + * Method to handle pre request + * + * @param fsapiRequestContext FS request context object + */ + public void preProcessRequest(FSAPIRequestContext fsapiRequestContext); + + /** + * Method to handle post request + * + * @param fsapiRequestContext FS request context object + */ + public void postProcessRequest(FSAPIRequestContext fsapiRequestContext); + + /** + * Method to handle pre response + * + * @param fsapiResponseContext FS response context object + */ + public void preProcessResponse(FSAPIResponseContext fsapiResponseContext); + + /** + * Method to handle post response + * + * @param fsapiResponseContext FS response context object + */ + public void postProcessResponse(FSAPIResponseContext fsapiResponseContext); +} diff --git a/financial-services-accelerator/components/org.wso2.financial.services.accelerator.gateway/src/main/java/org/wso2/financial/services/accelerator/gateway/executor/model/FSAPIRequestContext.java b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.gateway/src/main/java/org/wso2/financial/services/accelerator/gateway/executor/model/FSAPIRequestContext.java new file mode 100644 index 00000000..5cc58b9e --- /dev/null +++ b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.gateway/src/main/java/org/wso2/financial/services/accelerator/gateway/executor/model/FSAPIRequestContext.java @@ -0,0 +1,263 @@ +/** + * 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.model; + +import io.swagger.parser.OpenAPIParser; +import io.swagger.v3.oas.models.OpenAPI; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.json.JSONException; +import org.json.JSONObject; +import org.wso2.carbon.apimgt.common.gateway.dto.APIRequestInfoDTO; +import org.wso2.carbon.apimgt.common.gateway.dto.MsgInfoDTO; +import org.wso2.carbon.apimgt.common.gateway.dto.RequestContextDTO; +import org.wso2.financial.services.accelerator.common.constant.FinancialServicesConstants; +import org.wso2.financial.services.accelerator.common.constant.FinancialServicesErrorCodes; +import org.wso2.financial.services.accelerator.gateway.cache.GatewayCacheKey; +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.UnsupportedEncodingException; +import java.security.cert.Certificate; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; + + +/** + * Financial services executor request context. + */ +public class FSAPIRequestContext extends RequestContextDTO { + + private static final Log log = LogFactory.getLog(FSAPIRequestContext.class); + private final RequestContextDTO requestContextDTO; + private Map contextProps; + private String modifiedPayload; + private String requestPayload; + private Map addedHeaders; + private boolean isError; + private ArrayList errors; + private String consentId; + private OpenAPI openAPI; + + public FSAPIRequestContext(RequestContextDTO requestContextDTO, Map contextProps) { + + this.requestContextDTO = requestContextDTO; + this.contextProps = contextProps; + this.addedHeaders = new HashMap<>(); + this.errors = new ArrayList<>(); + + this.consentId = extractConsentID(requestContextDTO); + this.openAPI = retrieveOpenAPI(requestContextDTO); + + if (requestContextDTO.getMsgInfo().getHeaders().get(GatewayConstants.CONTENT_TYPE_TAG) != null) { + String contentType = requestContextDTO.getMsgInfo().getHeaders().get(GatewayConstants.CONTENT_TYPE_TAG); + String httpMethod = requestContextDTO.getMsgInfo().getHttpMethod(); + String errorMessage = "Request Content-Type header does not match any allowed types"; + if (contentType.startsWith(GatewayConstants.JWT_CONTENT_TYPE) || contentType.startsWith(GatewayConstants + .JOSE_CONTENT_TYPE)) { + try { + this.requestPayload = GatewayUtils.getTextPayload(requestContextDTO.getMsgInfo().getPayloadHandler() + .consumeAsString()); + } catch (Exception e) { + log.error(String.format("Failed to read the text payload from request. %s", + e.getMessage().replaceAll("\n\r", ""))); + handleContentTypeErrors(errorMessage); + } + } else if (GatewayUtils.isEligibleRequest(contentType, httpMethod)) { + try { + this.requestPayload = requestContextDTO.getMsgInfo().getPayloadHandler().consumeAsString(); + } catch (Exception e) { + log.error(String.format("Failed to read the payload from request. %s", + e.getMessage().replaceAll("\n\r", ""))); + handleContentTypeErrors(errorMessage); + } + } else { + this.requestPayload = null; + } + } + } + + public String getModifiedPayload() { + + return modifiedPayload; + } + + public void setModifiedPayload(String modifiedPayload) { + + this.modifiedPayload = modifiedPayload; + } + + public Map getAddedHeaders() { + + return addedHeaders; + } + + public void setAddedHeaders(Map addedHeaders) { + + this.addedHeaders = addedHeaders; + } + + public Map getContextProps() { + + return contextProps; + } + + public void setContextProps(Map contextProps) { + + this.contextProps = contextProps; + } + + public void addContextProperty(String key, String value) { + + this.contextProps.put(key, value); + } + + public Object getContextProperty(String key) { + + return this.contextProps.get(key); + } + + public boolean isError() { + + return isError; + } + + public void setError(boolean error) { + + isError = error; + } + + public ArrayList getErrors() { + + return errors; + } + + public void setErrors( + ArrayList errors) { + + this.errors = errors; + } + + public String getConsentId() { + + return consentId; + } + + public void setConsentId(String consentId) { + + this.consentId = consentId; + } + + public OpenAPI getOpenAPI() { + + return openAPI; + } + + public void setOpenAPI(OpenAPI openAPI) { + + this.openAPI = openAPI; + } + + @Override + public MsgInfoDTO getMsgInfo() { + + return requestContextDTO.getMsgInfo(); + } + + @Override + public APIRequestInfoDTO getApiRequestInfo() { + + return requestContextDTO.getApiRequestInfo(); + } + + + @Override + public Certificate[] getClientCertsLatest() { + return requestContextDTO.getClientCertsLatest(); + } + + public String getRequestPayload() { + + return requestPayload; + } + + /** + * Extract consent ID from the Auth header in the request context. + * + * @param requestContextDTO Request context DTO + * @return consent ID + */ + private String extractConsentID(RequestContextDTO requestContextDTO) { + + Map headers = requestContextDTO.getMsgInfo().getHeaders(); + String authHeader = headers.get(GatewayConstants.AUTH_HEADER); + if (authHeader != null && !authHeader.isEmpty() && + GatewayUtils.isValidJWTToken(authHeader.replace(GatewayConstants.BEARER_TAG, ""))) { + String consentIdClaim = null; + try { + if (!authHeader.contains(GatewayConstants.BASIC_TAG)) { + authHeader = authHeader.replace(GatewayConstants.BEARER_TAG, ""); + JSONObject jwtClaims = GatewayUtils.decodeBase64(GatewayUtils.getPayloadFromJWT(authHeader)); + String consentIdClaimName = GatewayDataHolder.getInstance() + .getFinancialServicesConfigurationService().getConfigurations() + .get(FinancialServicesConstants.CONSENT_ID_CLAIM_NAME).toString(); + if (!jwtClaims.isNull(consentIdClaimName) && + !jwtClaims.getString(consentIdClaimName).isEmpty()) { + consentIdClaim = jwtClaims.getString(consentIdClaimName); + } + } + } catch (UnsupportedEncodingException | JSONException | IllegalArgumentException e) { + log.error("Failed to retrieve the consent ID from JWT claims. %s", e); + } + return consentIdClaim; + } + return null; + } + + /** + * Retrieve OpenAPI definition from the cache or from the publisher API. + * + * @param requestContextDTO Request context DTO + * @return OpenAPI definition + */ + private OpenAPI retrieveOpenAPI(RequestContextDTO requestContextDTO) { + + String apiId = requestContextDTO.getApiRequestInfo().getApiId(); + Object cacheObject = GatewayDataHolder.getGatewayCache() + .getFromCache(GatewayCacheKey.of(apiId)); + if (cacheObject == null) { + String swaggerDefinition = GatewayUtils.getSwaggerDefinition(apiId); + OpenAPIParser parser = new OpenAPIParser(); + OpenAPI openAPIDefinition = parser.readContents(swaggerDefinition, null, null).getOpenAPI(); + GatewayDataHolder.getGatewayCache().addToCache(GatewayCacheKey.of(apiId), openAPIDefinition); + return openAPIDefinition; + } + return (OpenAPI) cacheObject; + } + + private void handleContentTypeErrors(String errorMessage) { + FSExecutorError error = new FSExecutorError(FinancialServicesErrorCodes.INVALID_CONTENT_TYPE, errorMessage, + errorMessage, FinancialServicesErrorCodes.UNSUPPORTED_MEDIA_TYPE_CODE); + + this.isError = true; + this.errors.add(error); + } +} diff --git a/financial-services-accelerator/components/org.wso2.financial.services.accelerator.gateway/src/main/java/org/wso2/financial/services/accelerator/gateway/executor/model/FSAPIResponseContext.java b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.gateway/src/main/java/org/wso2/financial/services/accelerator/gateway/executor/model/FSAPIResponseContext.java new file mode 100644 index 00000000..f7c4a809 --- /dev/null +++ b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.gateway/src/main/java/org/wso2/financial/services/accelerator/gateway/executor/model/FSAPIResponseContext.java @@ -0,0 +1,190 @@ +/** + * 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.model; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.http.HttpStatus; +import org.json.JSONObject; +import org.json.XML; +import org.wso2.carbon.apimgt.common.gateway.dto.APIRequestInfoDTO; +import org.wso2.carbon.apimgt.common.gateway.dto.MsgInfoDTO; +import org.wso2.carbon.apimgt.common.gateway.dto.ResponseContextDTO; +import org.wso2.financial.services.accelerator.common.constant.FinancialServicesErrorCodes; +import org.wso2.financial.services.accelerator.gateway.util.GatewayConstants; +import org.wso2.financial.services.accelerator.gateway.util.GatewayUtils; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; + +/** + * Financial services executor response context. + */ +public class FSAPIResponseContext extends ResponseContextDTO { + + private static final Log log = LogFactory.getLog(FSAPIResponseContext.class); + private ResponseContextDTO responseContextDTO; + private Map contextProps; + private String responsePayload; + private String modifiedPayload; + private Map addedHeaders; + private boolean isError; + private ArrayList errors; + + public FSAPIResponseContext(ResponseContextDTO responseContextDTO, Map contextProps) { + + this.responseContextDTO = responseContextDTO; + this.contextProps = contextProps; + this.errors = new ArrayList<>(); + this.addedHeaders = new HashMap<>(); + + if (responseContextDTO.getMsgInfo().getHeaders().get(GatewayConstants.CONTENT_TYPE_TAG) != null) { + String contentType = responseContextDTO.getMsgInfo().getHeaders().get(GatewayConstants.CONTENT_TYPE_TAG); + String httpMethod = responseContextDTO.getMsgInfo().getHttpMethod(); + String errorMessage = "Request Content-Type header does not match any allowed types"; + if (contentType.startsWith(GatewayConstants.JWT_CONTENT_TYPE) || contentType.startsWith(GatewayConstants + .JOSE_CONTENT_TYPE)) { + try { + this.responsePayload = GatewayUtils.getTextPayload(responseContextDTO.getMsgInfo() + .getPayloadHandler().consumeAsString()); + } catch (Exception e) { + log.error(String.format("Failed to read the text payload from response. %s", + e.getMessage().replaceAll("\n\r", ""))); + handleContentTypeErrors(errorMessage); + } + } else if (GatewayUtils.isEligibleResponse(contentType, httpMethod) && + HttpStatus.SC_NO_CONTENT != responseContextDTO.getStatusCode()) { + try { + this.responsePayload = responseContextDTO.getMsgInfo().getPayloadHandler().consumeAsString(); + if (contentType.contains(GatewayConstants.JSON_CONTENT_TYPE) && + this.responsePayload.contains(GatewayConstants.SOAP_BODY)) { + JSONObject soapPayload = XML.toJSONObject(responseContextDTO.getMsgInfo().getPayloadHandler() + .consumeAsString()).getJSONObject(GatewayConstants.SOAP_BODY); + if (soapPayload.has(GatewayConstants.SOAP_JSON_OBJECT)) { + this.responsePayload = soapPayload.getJSONObject(GatewayConstants.SOAP_JSON_OBJECT) + .toString(); + } else { + this.responsePayload = null; + } + } + } catch (Exception e) { + log.error(String.format("Failed to read the payload from response. %s", + e.getMessage().replaceAll("\n\r", ""))); + handleContentTypeErrors(errorMessage); + } + } else { + this.responsePayload = null; + } + } + } + + public String getModifiedPayload() { + + return modifiedPayload; + } + + public void setModifiedPayload(String modifiedPayload) { + + this.modifiedPayload = modifiedPayload; + } + + public Map getAddedHeaders() { + + return addedHeaders; + } + + public void setAddedHeaders(Map addedHeaders) { + + this.addedHeaders = addedHeaders; + } + + public Map getContextProps() { + + return contextProps; + } + + public void setContextProps(Map contextProps) { + + this.contextProps = contextProps; + } + + public boolean isError() { + + return isError; + } + + public void setError(boolean error) { + + isError = error; + } + + public ArrayList getErrors() { + + return errors; + } + + public void setErrors( + ArrayList errors) { + + this.errors = errors; + } + + @Override + public APIRequestInfoDTO getApiRequestInfo() { + + return this.responseContextDTO.getApiRequestInfo(); + } + + @Override + public int getStatusCode() { + + return responseContextDTO.getStatusCode(); + } + + @Override + public MsgInfoDTO getMsgInfo() { + + return responseContextDTO.getMsgInfo(); + } + + public String getResponsePayload() { + + return responsePayload; + } + + public void addContextProperty(String key, String value) { + + this.contextProps.put(key, value); + } + + public Object getContextProperty(String key) { + + return this.contextProps.get(key); + } + + private void handleContentTypeErrors(String errorMessage) { + FSExecutorError error = new FSExecutorError(FinancialServicesErrorCodes.INVALID_CONTENT_TYPE, errorMessage, + errorMessage, FinancialServicesErrorCodes.UNSUPPORTED_MEDIA_TYPE_CODE); + + this.isError = true; + this.errors.add(error); + } + +} diff --git a/financial-services-accelerator/components/org.wso2.financial.services.accelerator.gateway/src/main/java/org/wso2/financial/services/accelerator/gateway/executor/model/FSExecutorError.java b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.gateway/src/main/java/org/wso2/financial/services/accelerator/gateway/executor/model/FSExecutorError.java new file mode 100644 index 00000000..96219a26 --- /dev/null +++ b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.gateway/src/main/java/org/wso2/financial/services/accelerator/gateway/executor/model/FSExecutorError.java @@ -0,0 +1,106 @@ +/** + * 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.model; + +import java.util.Map; + +/** + * Error model for Financial Services executors. + */ +public class FSExecutorError { + + private String code; + private String title; + private String message; + private String httpStatusCode; + private Map links; + + public FSExecutorError() {} + + public FSExecutorError(String errorCode) { + this.code = errorCode; + } + + + public FSExecutorError(String code, String title, String message, String httpStatusCode) { + this.code = code; + this.title = title; + this.message = message; + this.httpStatusCode = httpStatusCode; + } + + public FSExecutorError(String code, String title, String message, String httpStatusCode, + Map links) { + this.code = code; + this.title = title; + this.message = message; + this.httpStatusCode = httpStatusCode; + this.links = links; + } + + public String getCode() { + + return code; + } + + public void setCode(String code) { + + this.code = code; + } + + public String getTitle() { + + return title; + } + + public void setTitle(String title) { + + this.title = title; + } + + public String getMessage() { + + return message; + } + + public void setMessage(String message) { + + this.message = message; + } + + public String getHttpStatusCode() { + + return httpStatusCode; + } + + public void setHttpStatusCode(String httpStatusCode) { + + this.httpStatusCode = httpStatusCode; + } + + public Map getLinks() { + + return links; + } + + public void setLinks(Map links) { + + this.links = links; + } +} 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 new file mode 100644 index 00000000..e3b7b1b4 --- /dev/null +++ b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.gateway/src/main/java/org/wso2/financial/services/accelerator/gateway/internal/GatewayDataHolder.java @@ -0,0 +1,147 @@ +/** + * 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.internal; + +import org.apache.http.impl.client.CloseableHttpClient; +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.exception.FinancialServicesException; +import org.wso2.financial.services.accelerator.common.util.FinancialServicesUtils; +import org.wso2.financial.services.accelerator.common.util.HTTPClientUtils; +import org.wso2.financial.services.accelerator.gateway.cache.GatewayCache; +import org.wso2.financial.services.accelerator.gateway.executor.core.AbstractRequestRouter; + +import java.util.Map; + +/** + * Data holder for executor core + */ +public class GatewayDataHolder { + + private static volatile GatewayDataHolder instance; + private static volatile CloseableHttpClient httpClient; + private static volatile GatewayCache gatewayCache; + private FinancialServicesConfigurationService financialServicesConfigurationService; + private int gatewayCacheAccessExpiry; + private int gatewayCacheModifiedExpiry; + private APIManagerConfigurationService apiManagerConfigurationService; + private AbstractRequestRouter requestRouter; + + private GatewayDataHolder() { + + } + + public static GatewayDataHolder getInstance() { + + if (instance == null) { + synchronized (GatewayDataHolder.class) { + if (instance == null) { + instance = new GatewayDataHolder(); + } + } + } + return instance; + } + + public static CloseableHttpClient getHttpClient() throws FinancialServicesException { + + if (httpClient == null) { + synchronized (GatewayDataHolder.class) { + if (httpClient == null) { + httpClient = HTTPClientUtils.getHttpsClient(); + } + } + } + return httpClient; + } + + public static GatewayCache getGatewayCache() { + + if (gatewayCache == null) { + synchronized (GatewayDataHolder.class) { + if (gatewayCache == null) { + gatewayCache = new GatewayCache(); + } + } + } + return gatewayCache; + } + + public FinancialServicesConfigurationService getFinancialServicesConfigurationService() { + + return financialServicesConfigurationService; + } + + public void setFinancialServicesConfigurationService( + FinancialServicesConfigurationService financialServicesConfigurationService) { + + this.financialServicesConfigurationService = financialServicesConfigurationService; + if (financialServicesConfigurationService != null) { + Map configurations = financialServicesConfigurationService.getConfigurations(); + setGatewayCacheAccessExpiry((String) configurations.get(FinancialServicesConstants.GATEWAY_CACHE_EXPIRY)); + setGatewayCacheModifiedExpiry((String) configurations + .get(FinancialServicesConstants.GATEWAY_CACHE_MODIFIED_EXPIRY)); + AbstractRequestRouter configuredRequestRouter = (AbstractRequestRouter) FinancialServicesUtils + .getClassInstanceFromFQN(configurations.get(FinancialServicesConstants.REQUEST_ROUTER).toString()); + configuredRequestRouter.build(); + this.setRequestRouter(configuredRequestRouter); + } + } + + public AbstractRequestRouter getRequestRouter() { + + return requestRouter; + } + + public void setRequestRouter(AbstractRequestRouter requestRouter) { + + this.requestRouter = requestRouter; + } + + public int getGatewayCacheAccessExpiry() { + + return gatewayCacheAccessExpiry; + } + + public void setGatewayCacheAccessExpiry(String expTime) { + + this.gatewayCacheAccessExpiry = expTime == null ? 60 : Integer.parseInt(expTime); + } + + public int getGatewayCacheModifiedExpiry() { + + return gatewayCacheModifiedExpiry; + } + + public void setGatewayCacheModifiedExpiry(String expTime) { + + this.gatewayCacheModifiedExpiry = expTime == null ? 60 : Integer.parseInt(expTime); + } + + public void setApiManagerConfiguration(APIManagerConfigurationService apiManagerConfigurationService) { + + this.apiManagerConfigurationService = apiManagerConfigurationService; + } + + public APIManagerConfigurationService getApiManagerConfigurationService() { + + return apiManagerConfigurationService; + } +} diff --git a/financial-services-accelerator/components/org.wso2.financial.services.accelerator.gateway/src/main/java/org/wso2/financial/services/accelerator/gateway/internal/GatewayServiceComponent.java b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.gateway/src/main/java/org/wso2/financial/services/accelerator/gateway/internal/GatewayServiceComponent.java new file mode 100644 index 00000000..52171c5b --- /dev/null +++ b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.gateway/src/main/java/org/wso2/financial/services/accelerator/gateway/internal/GatewayServiceComponent.java @@ -0,0 +1,87 @@ +/** + * 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.internal; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.osgi.service.component.ComponentContext; +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Deactivate; +import org.osgi.service.component.annotations.Reference; +import org.osgi.service.component.annotations.ReferenceCardinality; +import org.osgi.service.component.annotations.ReferencePolicy; +import org.wso2.carbon.apimgt.impl.APIManagerConfigurationService; +import org.wso2.financial.services.accelerator.common.config.FinancialServicesConfigurationService; + +/** + * Service class for executor core + */ +@Component( + name = "org.wso2.financial.services.accelerator.gateway.internal.GatewayServiceComponent", + immediate = true +) +public class GatewayServiceComponent { + + private static final Log log = LogFactory.getLog(GatewayServiceComponent.class); + + @Activate + protected void activate(ComponentContext context) { + + log.debug("Financial services gateway component is activated "); + } + + @Deactivate + protected void deactivate(ComponentContext context) { + + log.debug("Financial services gateway component is deactivated "); + } + + @Reference( + service = FinancialServicesConfigurationService.class, + cardinality = ReferenceCardinality.MANDATORY, + policy = ReferencePolicy.DYNAMIC, + unbind = "unsetConfigService" + ) + public void setConfigService(FinancialServicesConfigurationService configurationService) { + + GatewayDataHolder.getInstance().setFinancialServicesConfigurationService(configurationService); + } + + public void unsetConfigService(FinancialServicesConfigurationService configurationService) { + + GatewayDataHolder.getInstance().setFinancialServicesConfigurationService(null); + } + + @Reference( + service = APIManagerConfigurationService.class, + cardinality = ReferenceCardinality.MANDATORY, + policy = ReferencePolicy.DYNAMIC, + unbind = "unSetAPIMConfigs" + ) + public void setAPIMConfig(APIManagerConfigurationService apManagerConfigurationService) { + + GatewayDataHolder.getInstance().setApiManagerConfiguration(apManagerConfigurationService); + } + + public void unSetAPIMConfigs(APIManagerConfigurationService apManagerConfigurationService) { + + GatewayDataHolder.getInstance().setApiManagerConfiguration(apManagerConfigurationService); + } +} 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 new file mode 100644 index 00000000..39159bbf --- /dev/null +++ b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.gateway/src/main/java/org/wso2/financial/services/accelerator/gateway/util/GatewayConstants.java @@ -0,0 +1,62 @@ +/** + * 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.util; + +/** + * Class containing the constants for Financial Services Gateway module. + */ +public class GatewayConstants { + + public static final String AUTH_HEADER = "Authorization"; + public static final String BEARER_TAG = "Bearer "; + public static final String BASIC_TAG = "Basic "; + public static final String CONTENT_TYPE_TAG = "Content-Type"; + public static final String JWT_CONTENT_TYPE = "application/jwt"; + public static final String JSON_CONTENT_TYPE = "application/json"; + public static final String JOSE_CONTENT_TYPE = "application/jose"; + public static final String APPLICATION_XML_CONTENT_TYPE = "application/xml"; + public static final String TEXT_XML_CONTENT_TYPE = "text/xml"; + public static final String SOAP_BODY = "soapenv:Body"; + public static final String SOAP_BODY_TEXT = "text"; + public static final String SOAP_BODY_CONTENT = "content"; + public static final String SOAP_JSON_OBJECT = "jsonObject"; + public static final String COLON = ":"; + public static final String SLASH = "/"; + public static final String POST_HTTP_METHOD = "POST"; + public static final String PUT_HTTP_METHOD = "PUT"; + public static final String GET_HTTP_METHOD = "GET"; + public static final String PATCH_HTTP_METHOD = "PATCH"; + public static final String DELETE_HTTP_METHOD = "DELETE"; + public static final String PUBLISHER_API_PATH = "api/am/publisher/apis/"; + public static final String SWAGGER_ENDPOINT = "/swagger"; + public static final String API_KEY_VALIDATOR_USERNAME = "APIKeyValidator.Username"; + public static final String API_KEY_VALIDATOR_PASSWORD = "APIKeyValidator.Password"; + public static final String API_TYPE_CONSENT = "consent"; + public static final String API_TYPE_NON_REGULATORY = "non-regulatory"; + public static final String API_TYPE_CUSTOM_PROP = "x-wso2-api-type"; + public static final String EXECUTOR_TYPE_CONSENT = "Consent"; + public static final String EXECUTOR_TYPE_DCR = "DCR"; + public static final String EXECUTOR_TYPE_DEFAULT = "Default"; + public static final String DCR_PATH = "/register"; + public static final String CONTEXT_PROP_CACHE_KEY = "_contextProp"; + public static final String ANALYTICS_PROP_CACHE_KEY = "_analyticsData"; + public static final String ERROR_STATUS_PROP = "errorStatusCode"; + public static final String IS_RETURN_RESPONSE = "isReturnResponse"; + public static final String MODIFIED_STATUS = "ModifiedStatus"; +} diff --git a/financial-services-accelerator/components/org.wso2.financial.services.accelerator.gateway/src/main/java/org/wso2/financial/services/accelerator/gateway/util/GatewayUtils.java b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.gateway/src/main/java/org/wso2/financial/services/accelerator/gateway/util/GatewayUtils.java new file mode 100644 index 00000000..9c7ddc3b --- /dev/null +++ b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.gateway/src/main/java/org/wso2/financial/services/accelerator/gateway/util/GatewayUtils.java @@ -0,0 +1,191 @@ +/** + * 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.util; + +import org.apache.commons.io.IOUtils; +import org.apache.http.HttpResponse; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.utils.URIBuilder; +import org.json.JSONException; +import org.json.JSONObject; +import org.json.XML; +import org.wso2.financial.services.accelerator.common.constant.FinancialServicesConstants; +import org.wso2.financial.services.accelerator.common.exception.FinancialServicesException; +import org.wso2.financial.services.accelerator.common.exception.FinancialServicesRuntimeException; +import org.wso2.financial.services.accelerator.common.util.Generated; +import org.wso2.financial.services.accelerator.gateway.internal.GatewayDataHolder; + +import java.io.IOException; +import java.io.InputStream; +import java.io.UnsupportedEncodingException; +import java.net.URISyntaxException; +import java.nio.charset.StandardCharsets; +import java.util.Base64; + +/** + * Utility methods used in gateway modules. + */ +public class GatewayUtils { + + /** + * Method to check whether the given string is a valid JWT token. + * + * @param jwtString JWT token string + * @return true if the given string is a valid JWT token, false otherwise + */ + public static boolean isValidJWTToken(String jwtString) { + + String[] jwtPart = jwtString.split("\\."); + if (jwtPart.length != 3) { + return false; + } + try { + decodeBase64(jwtPart[0]); + decodeBase64(jwtPart[1]); + } catch (UnsupportedEncodingException | JSONException | IllegalArgumentException e) { + return false; + } + return true; + } + + /** + * Method to decode the base64 encoded JSON payload. + * + * @param payload base64 encoded payload + * @return Decoded JSON Object + * @throws UnsupportedEncodingException When encoding is not UTF-8 + */ + public static JSONObject decodeBase64(String payload) throws UnsupportedEncodingException { + + return new JSONObject(new String(Base64.getDecoder().decode(payload), + String.valueOf(StandardCharsets.UTF_8))); + } + + /** + * Method to obtain swagger definition from publisher API. + * + * @param apiId ID of the API + * @return String of swagger definition + */ + @Generated(message = "Cannot test without running APIM. Integration test will be written for this") + public static String getSwaggerDefinition(String apiId) { + + String publisherHostName = + GatewayDataHolder.getInstance().getFinancialServicesConfigurationService() + .getConfigurations() + .get(FinancialServicesConstants.PUBLISHER_HOSTNAME).toString(); + + String publisherAPIURL = publisherHostName.endsWith(GatewayConstants.SLASH) ? + publisherHostName + GatewayConstants.PUBLISHER_API_PATH + apiId + GatewayConstants.SWAGGER_ENDPOINT : + publisherHostName + GatewayConstants.SLASH + GatewayConstants.PUBLISHER_API_PATH + apiId + + GatewayConstants.SWAGGER_ENDPOINT; + try { + URIBuilder uriBuilder = new URIBuilder(publisherAPIURL); + HttpGet httpGet = new HttpGet(uriBuilder.build().toString()); + String userName = getAPIMgtConfig(GatewayConstants.API_KEY_VALIDATOR_USERNAME); + String password = getAPIMgtConfig(GatewayConstants.API_KEY_VALIDATOR_PASSWORD); + + httpGet.setHeader(GatewayConstants.AUTH_HEADER, GatewayUtils.getBasicAuthHeader(userName, password)); + HttpResponse response = null; + response = GatewayDataHolder.getHttpClient().execute(httpGet); + InputStream in = response.getEntity().getContent(); + return IOUtils.toString(in, String.valueOf(StandardCharsets.UTF_8)); + } catch (IOException | FinancialServicesException | URISyntaxException e) { + throw new FinancialServicesRuntimeException("Failed to retrieve swagger definition from API", e); + } + } + + /** + * Method to read API mgt configs when key is given. + * + * @param key config key + * @return config value + */ + public static String getAPIMgtConfig(String key) { + + return GatewayDataHolder.getInstance().getApiManagerConfigurationService() + .getAPIManagerConfiguration().getFirstProperty(key); + } + + /** + * Method to obtain basic auth header. + * + * @param username Username of Auth header + * @param password Password of Auth header + * @return basic auth header + */ + public static String getBasicAuthHeader(String username, String password) { + + byte[] authHeader = Base64.getEncoder().encode((username + GatewayConstants.COLON + password) + .getBytes(StandardCharsets.UTF_8)); + return GatewayConstants.BASIC_TAG + new String(authHeader, StandardCharsets.UTF_8); + } + + public static String getTextPayload(String payload) { + + return XML.toJSONObject(payload).getJSONObject(GatewayConstants.SOAP_BODY) + .getJSONObject(GatewayConstants.SOAP_BODY_TEXT).getString(GatewayConstants.SOAP_BODY_CONTENT); + + } + + /** + * Check the content type and http method of the request. + * + * @param contentType - contentType + * @param httpMethod - httpMethod + * @return true if the request is eligible + */ + public static boolean isEligibleRequest(String contentType, String httpMethod) { + + return (contentType.startsWith(GatewayConstants.JSON_CONTENT_TYPE) || + contentType.startsWith(GatewayConstants.APPLICATION_XML_CONTENT_TYPE) || + contentType.startsWith(GatewayConstants.TEXT_XML_CONTENT_TYPE)) && + (GatewayConstants.POST_HTTP_METHOD.equals(httpMethod) || GatewayConstants.PUT_HTTP_METHOD + .equals(httpMethod)); + } + + /** + * Check the content type and http method of the response. + * + * @param contentType - contentType + * @param httpMethod - httpMethod + * @return true if the response is eligible + */ + public static boolean isEligibleResponse(String contentType, String httpMethod) { + + return (contentType.startsWith(GatewayConstants.JSON_CONTENT_TYPE) || + contentType.startsWith(GatewayConstants.APPLICATION_XML_CONTENT_TYPE) || + contentType.startsWith(GatewayConstants.TEXT_XML_CONTENT_TYPE)) && + (GatewayConstants.GET_HTTP_METHOD.equals(httpMethod) || GatewayConstants. + POST_HTTP_METHOD.equals(httpMethod) || GatewayConstants.PUT_HTTP_METHOD.equals(httpMethod) + || GatewayConstants.PATCH_HTTP_METHOD.equals(httpMethod) || GatewayConstants. + DELETE_HTTP_METHOD.equals(httpMethod)); + } + + /** + * Method to extract JWT payload section as a string. + * + * @param jwtString full JWT + * @return Payload section of JWT + */ + public static String getPayloadFromJWT(String jwtString) { + + return jwtString.split("\\.")[1]; + } +} diff --git a/financial-services-accelerator/components/org.wso2.financial.services.accelerator.gateway/src/main/resources/findbugs-exclude.xml b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.gateway/src/main/resources/findbugs-exclude.xml new file mode 100644 index 00000000..9fa42f18 --- /dev/null +++ b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.gateway/src/main/resources/findbugs-exclude.xml @@ -0,0 +1,21 @@ + + + + + diff --git a/financial-services-accelerator/components/org.wso2.financial.services.accelerator.gateway/src/main/resources/findbugs-include.xml b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.gateway/src/main/resources/findbugs-include.xml new file mode 100644 index 00000000..c6b932b1 --- /dev/null +++ b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.gateway/src/main/resources/findbugs-include.xml @@ -0,0 +1,22 @@ + + + + + + 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 new file mode 100644 index 00000000..4629ba3c --- /dev/null +++ b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.gateway/src/test/java/org/wso2/financial/services/accelerator/gateway/GatewayTestConstants.java @@ -0,0 +1,49 @@ +/** +* 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; + +import java.util.AbstractMap; +import java.util.Map; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +/** + * Constants for Gateway test cases. + */ +public class GatewayTestConstants { + + public static final String VALID_EXECUTOR_CLASS = + "org.wso2.financial.services.accelerator.gateway.executor.core.MockOBExecutor"; + 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)); + public static final Map> FULL_VALIDATOR_MAP = Stream.of( + new AbstractMap.SimpleImmutableEntry<>("Default", VALID_EXECUTOR_MAP), + new AbstractMap.SimpleImmutableEntry<>("DCR", VALID_EXECUTOR_MAP)) + .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); + public static final String CUSTOM_PAYLOAD = "{\"custom\":\"payload\"}"; + public static final String B64_PAYLOAD = "eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6Ikpva" + + "G4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ"; + public static final String TEST_JWT = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwI" + + "iwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"; + public static final String XML_PAYLOAD = "" + + "Test Content2024-09-30" + + ""; +} diff --git a/financial-services-accelerator/components/org.wso2.financial.services.accelerator.gateway/src/test/java/org/wso2/financial/services/accelerator/gateway/executor/core/DefaultRequestRouterTest.java b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.gateway/src/test/java/org/wso2/financial/services/accelerator/gateway/executor/core/DefaultRequestRouterTest.java new file mode 100644 index 00000000..872da972 --- /dev/null +++ b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.gateway/src/test/java/org/wso2/financial/services/accelerator/gateway/executor/core/DefaultRequestRouterTest.java @@ -0,0 +1,141 @@ +/** + * 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.core; + +import io.swagger.v3.oas.models.OpenAPI; +import org.mockito.Mockito; +import org.testng.Assert; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; +import org.wso2.carbon.apimgt.common.gateway.dto.MsgInfoDTO; +import org.wso2.financial.services.accelerator.common.util.FinancialServicesUtils; +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.FSAPIResponseContext; +import org.wso2.financial.services.accelerator.gateway.util.GatewayConstants; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Test for default request router. + */ +public class DefaultRequestRouterTest { + + DefaultRequestRouter defaultRequestRouter; + OpenAPI openAPI; + + @BeforeClass + public void beforeClass() { + + defaultRequestRouter = new DefaultRequestRouter(); + defaultRequestRouter.setExecutorMap(initExecutors()); + openAPI = new OpenAPI(); + openAPI.setExtensions(new HashMap<>()); + } + + @Test(priority = 1) + public void testDCRRequestsForRouter() { + + FSAPIRequestContext obapiRequestContext = Mockito.mock(FSAPIRequestContext.class); + FSAPIResponseContext obapiResponseContext = Mockito.mock(FSAPIResponseContext.class); + MsgInfoDTO msgInfoDTO = new MsgInfoDTO(); + msgInfoDTO.setResource("/anyAPIcall/register"); + Mockito.when(obapiRequestContext.getMsgInfo()).thenReturn(msgInfoDTO); + Mockito.when(obapiRequestContext.getOpenAPI()).thenReturn(openAPI); + Mockito.when(obapiResponseContext.getMsgInfo()).thenReturn(msgInfoDTO); + Assert.assertNotNull(defaultRequestRouter.getExecutorsForRequest(obapiRequestContext)); + Assert.assertNotNull(defaultRequestRouter.getExecutorsForResponse(obapiResponseContext)); + + } + + @Test(priority = 1) + public void testAccountRequestsForRouter() { + + FSAPIRequestContext obapiRequestContext = Mockito.mock(FSAPIRequestContext.class); + FSAPIResponseContext obapiResponseContext = Mockito.mock(FSAPIResponseContext.class); + MsgInfoDTO msgInfoDTO = new MsgInfoDTO(); + msgInfoDTO.setResource("/anyAPIcall"); + Mockito.when(obapiRequestContext.getOpenAPI()).thenReturn(openAPI); + Mockito.when(obapiRequestContext.getMsgInfo()).thenReturn(msgInfoDTO); + Mockito.when(obapiResponseContext.getMsgInfo()).thenReturn(msgInfoDTO); + Assert.assertNotNull(defaultRequestRouter.getExecutorsForRequest(obapiRequestContext)); + Assert.assertNotNull(defaultRequestRouter.getExecutorsForResponse(obapiResponseContext)); + } + + @Test(priority = 2) + public void testNonRegulatoryAPIcall() { + + FSAPIRequestContext obapiRequestContext = Mockito.mock(FSAPIRequestContext.class); + FSAPIResponseContext obapiResponseContext = Mockito.mock(FSAPIResponseContext.class); + MsgInfoDTO msgInfoDTO = new MsgInfoDTO(); + msgInfoDTO.setResource("/anyAPIcall"); + Map extensions = new HashMap<>(); + Map contextProps = new HashMap<>(); + extensions.put(GatewayConstants.API_TYPE_CUSTOM_PROP, GatewayConstants.API_TYPE_NON_REGULATORY); + contextProps.put(GatewayConstants.API_TYPE_CUSTOM_PROP, GatewayConstants.API_TYPE_NON_REGULATORY); + openAPI.setExtensions(extensions); + Mockito.when(obapiRequestContext.getOpenAPI()).thenReturn(openAPI); + Mockito.when(obapiRequestContext.getMsgInfo()).thenReturn(msgInfoDTO); + Mockito.when(obapiResponseContext.getMsgInfo()).thenReturn(msgInfoDTO); + Mockito.when(obapiResponseContext.getContextProps()).thenReturn(contextProps); + Assert.assertEquals(defaultRequestRouter.getExecutorsForRequest(obapiRequestContext).size(), 0); + Assert.assertEquals(defaultRequestRouter.getExecutorsForResponse(obapiResponseContext).size(), 0); + } + + @Test(priority = 2) + public void testRegulatoryAPIcall() { + + FSAPIRequestContext obapiRequestContext = Mockito.mock(FSAPIRequestContext.class); + FSAPIResponseContext obapiResponseContext = Mockito.mock(FSAPIResponseContext.class); + MsgInfoDTO msgInfoDTO = new MsgInfoDTO(); + msgInfoDTO.setResource("/anyAPIcall"); + Map extensions = new HashMap<>(); + Map contextProps = new HashMap<>(); + extensions.put(GatewayConstants.API_TYPE_CUSTOM_PROP, GatewayConstants.API_TYPE_NON_REGULATORY); + contextProps.put(GatewayConstants.API_TYPE_CUSTOM_PROP, "regulatory"); + openAPI.setExtensions(extensions); + Mockito.when(obapiRequestContext.getOpenAPI()).thenReturn(openAPI); + Mockito.when(obapiRequestContext.getMsgInfo()).thenReturn(msgInfoDTO); + Mockito.when(obapiResponseContext.getMsgInfo()).thenReturn(msgInfoDTO); + Mockito.when(obapiResponseContext.getContextProps()).thenReturn(contextProps); + Assert.assertNotNull(defaultRequestRouter.getExecutorsForRequest(obapiRequestContext)); + Assert.assertNotNull(defaultRequestRouter.getExecutorsForResponse(obapiResponseContext)); + } + + public static Map> initExecutors() { + + Map> executors = new HashMap<>(); + Map> fullValidatorMap = GatewayTestConstants.FULL_VALIDATOR_MAP; + for (Map.Entry> stringMapEntry : fullValidatorMap.entrySet()) { + List executorList = new ArrayList<>(); + Map executorNames = stringMapEntry.getValue(); + for (Map.Entry executorEntity : executorNames.entrySet()) { + FinancialServicesGatewayExecutor object = (FinancialServicesGatewayExecutor) + FinancialServicesUtils.getClassInstanceFromFQN(executorEntity.getValue()); + executorList.add(object); + } + executors.put(stringMapEntry.getKey(), executorList); + } + return executors; + + } +} 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 new file mode 100644 index 00000000..589cbe12 --- /dev/null +++ b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.gateway/src/test/java/org/wso2/financial/services/accelerator/gateway/executor/core/FSExtensionImplTest.java @@ -0,0 +1,233 @@ +/** + * 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.core; + +import org.apache.http.HttpStatus; +import org.json.JSONObject; +import org.mockito.Mockito; +import org.testng.Assert; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; +import org.wso2.carbon.apimgt.common.gateway.dto.ExtensionResponseDTO; +import org.wso2.carbon.apimgt.common.gateway.dto.ExtensionResponseStatus; +import org.wso2.carbon.apimgt.common.gateway.dto.MsgInfoDTO; +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.FSAPIResponseContext; +import org.wso2.financial.services.accelerator.gateway.util.GatewayConstants; + +import java.util.HashMap; +import java.util.Map; + +/** + * Test for open Banking extension implementation. + */ +public class FSExtensionImplTest { + + private static FSAPIRequestContext fsapiRequestContext; + private static FSAPIResponseContext fsapiResponseContext; + private static final FSExtensionListenerImpl fsExtensionListener = new FSExtensionListenerImpl(); + + @BeforeClass + public static void beforeClass() { + + } + + @Test(priority = 1) + public void testMinimumFlow() { + + MsgInfoDTO msgInfoDTO = new MsgInfoDTO(); + msgInfoDTO.setHeaders(new HashMap<>()); + + fsapiRequestContext = Mockito.mock(FSAPIRequestContext.class); + Mockito.when(fsapiRequestContext.isError()).thenReturn(false); + Mockito.when(fsapiRequestContext.getModifiedPayload()).thenReturn(null); + Mockito.when(fsapiRequestContext.getAddedHeaders()).thenReturn(new HashMap<>()); + Mockito.when(fsapiRequestContext.getMsgInfo()).thenReturn(msgInfoDTO); + + fsapiResponseContext = Mockito.mock(FSAPIResponseContext.class); + Mockito.when(fsapiResponseContext.isError()).thenReturn(false); + Mockito.when(fsapiResponseContext.getModifiedPayload()).thenReturn(null); + Mockito.when(fsapiResponseContext.getAddedHeaders()).thenReturn(new HashMap<>()); + Mockito.when(fsapiResponseContext.getMsgInfo()).thenReturn(msgInfoDTO); + + ExtensionResponseDTO responseDTOForRequest = fsExtensionListener.getResponseDTOForRequest(fsapiRequestContext); + Assert.assertEquals(responseDTOForRequest.getResponseStatus(), ExtensionResponseStatus.CONTINUE.toString()); + Assert.assertNull(responseDTOForRequest.getHeaders()); + Assert.assertNull(responseDTOForRequest.getPayload()); + Assert.assertNull(responseDTOForRequest.getCustomProperty()); + Assert.assertEquals(responseDTOForRequest.getStatusCode(), 0); + + ExtensionResponseDTO responseDTOForResponse = + fsExtensionListener.getResponseDTOForResponse(fsapiResponseContext); + + Assert.assertEquals(responseDTOForResponse.getResponseStatus(), ExtensionResponseStatus.CONTINUE.toString()); + Assert.assertNull(responseDTOForResponse.getHeaders()); + Assert.assertNull(responseDTOForResponse.getPayload()); + Assert.assertNull(responseDTOForResponse.getCustomProperty()); + Assert.assertEquals(responseDTOForResponse.getStatusCode(), 0); + + } + + @Test(priority = 1) + public void testAddedHeaders() { + + fsapiRequestContext = Mockito.mock(FSAPIRequestContext.class); + fsapiResponseContext = Mockito.mock(FSAPIResponseContext.class); + Mockito.when(fsapiRequestContext.isError()).thenReturn(false); + Mockito.when(fsapiRequestContext.getModifiedPayload()).thenReturn(null); + MsgInfoDTO msgInfoDTO = new MsgInfoDTO(); + msgInfoDTO.setHeaders(new HashMap<>()); + Mockito.when(fsapiRequestContext.getMsgInfo()).thenReturn(msgInfoDTO); + Map addedHeaders = new HashMap<>(); + addedHeaders.put("custom", "header"); + Mockito.when(fsapiRequestContext.getAddedHeaders()).thenReturn(addedHeaders); + + ExtensionResponseDTO responseDTOForRequest = fsExtensionListener.getResponseDTOForRequest(fsapiRequestContext); + Assert.assertEquals(responseDTOForRequest.getResponseStatus(), ExtensionResponseStatus.CONTINUE.toString()); + Assert.assertEquals(responseDTOForRequest.getHeaders().get("custom"), "header"); + Assert.assertNull(responseDTOForRequest.getPayload()); + Assert.assertNull(responseDTOForRequest.getCustomProperty()); + Assert.assertEquals(responseDTOForRequest.getStatusCode(), 0); + + Mockito.when(fsapiResponseContext.isError()).thenReturn(false); + Mockito.when(fsapiResponseContext.getModifiedPayload()).thenReturn(null); + Mockito.when(fsapiResponseContext.getMsgInfo()).thenReturn(msgInfoDTO); + Mockito.when(fsapiResponseContext.getAddedHeaders()).thenReturn(addedHeaders); + + ExtensionResponseDTO responseDTOForResponse = + fsExtensionListener.getResponseDTOForResponse(fsapiResponseContext); + Assert.assertEquals(responseDTOForResponse.getResponseStatus(), ExtensionResponseStatus.CONTINUE.toString()); + Assert.assertEquals(responseDTOForResponse.getHeaders().get("custom"), "header"); + Assert.assertNull(responseDTOForResponse.getPayload()); + Assert.assertNull(responseDTOForResponse.getCustomProperty()); + Assert.assertEquals(responseDTOForResponse.getStatusCode(), 0); + + } + + @Test(priority = 1) + public void testModifiedPayload() { + + MsgInfoDTO msgInfoDTO = new MsgInfoDTO(); + msgInfoDTO.setHeaders(new HashMap<>()); + + fsapiRequestContext = Mockito.mock(FSAPIRequestContext.class); + fsapiResponseContext = Mockito.mock(FSAPIResponseContext.class); + Mockito.when(fsapiRequestContext.isError()).thenReturn(false); + Mockito.when(fsapiRequestContext.getModifiedPayload()).thenReturn(GatewayTestConstants.CUSTOM_PAYLOAD); + Mockito.when(fsapiRequestContext.getAddedHeaders()).thenReturn(new HashMap<>()); + Mockito.when(fsapiRequestContext.getMsgInfo()).thenReturn(msgInfoDTO); + + ExtensionResponseDTO responseDTOForRequest = fsExtensionListener.getResponseDTOForRequest(fsapiRequestContext); + Assert.assertEquals(responseDTOForRequest.getResponseStatus(), ExtensionResponseStatus.CONTINUE.toString()); + Assert.assertNull(responseDTOForRequest.getHeaders()); + Assert.assertNotNull(responseDTOForRequest.getPayload()); + Assert.assertNull(responseDTOForRequest.getCustomProperty()); + Assert.assertEquals(responseDTOForRequest.getStatusCode(), 0); + + Mockito.when(fsapiResponseContext.isError()).thenReturn(false); + Mockito.when(fsapiResponseContext.getModifiedPayload()).thenReturn(GatewayTestConstants.CUSTOM_PAYLOAD); + Mockito.when(fsapiResponseContext.getAddedHeaders()).thenReturn(new HashMap<>()); + Mockito.when(fsapiResponseContext.getMsgInfo()).thenReturn(msgInfoDTO); + + ExtensionResponseDTO responseDTOForResponse = + fsExtensionListener.getResponseDTOForResponse(fsapiResponseContext); + Assert.assertEquals(responseDTOForResponse.getResponseStatus(), ExtensionResponseStatus.CONTINUE.toString()); + Assert.assertNull(responseDTOForResponse.getHeaders()); + Assert.assertNotNull(responseDTOForResponse.getPayload()); + Assert.assertNull(responseDTOForResponse.getCustomProperty()); + Assert.assertEquals(responseDTOForResponse.getStatusCode(), 0); + } + + @Test(priority = 1) + public void testErrorFlow() { + + MsgInfoDTO msgInfoDTO = new MsgInfoDTO(); + msgInfoDTO.setHeaders(new HashMap<>()); + + fsapiRequestContext = Mockito.mock(FSAPIRequestContext.class); + Mockito.when(fsapiRequestContext.isError()).thenReturn(true); + JSONObject errorJSON = new JSONObject(); + errorJSON.put("error", true); + Mockito.when(fsapiRequestContext.getModifiedPayload()).thenReturn(errorJSON.toString()); + Mockito.when(fsapiRequestContext.getAddedHeaders()).thenReturn(new HashMap<>()); + Mockito.when(fsapiRequestContext.getMsgInfo()).thenReturn(msgInfoDTO); + + fsapiResponseContext = Mockito.mock(FSAPIResponseContext.class); + Mockito.when(fsapiResponseContext.isError()).thenReturn(true); + Mockito.when(fsapiResponseContext.getModifiedPayload()).thenReturn(errorJSON.toString()); + Mockito.when(fsapiResponseContext.getAddedHeaders()).thenReturn(new HashMap<>()); + Mockito.when(fsapiResponseContext.getMsgInfo()).thenReturn(msgInfoDTO); + + ExtensionResponseDTO responseDTOForRequest = fsExtensionListener.getResponseDTOForRequest(fsapiRequestContext); + Assert.assertEquals(responseDTOForRequest.getResponseStatus(), ExtensionResponseStatus.RETURN_ERROR.toString()); + Assert.assertNull(responseDTOForRequest.getHeaders()); + Assert.assertNotNull(responseDTOForRequest.getPayload()); + Assert.assertNull(responseDTOForRequest.getCustomProperty()); + Assert.assertEquals(responseDTOForRequest.getStatusCode(), 500); + + ExtensionResponseDTO responseDTOForResponse = + fsExtensionListener.getResponseDTOForResponse(fsapiResponseContext); + + Assert.assertEquals(responseDTOForResponse.getResponseStatus(), + ExtensionResponseStatus.RETURN_ERROR.toString()); + Assert.assertNull(responseDTOForResponse.getHeaders()); + Assert.assertNotNull(responseDTOForResponse.getPayload()); + Assert.assertNull(responseDTOForResponse.getCustomProperty()); + Assert.assertEquals(responseDTOForResponse.getStatusCode(), 500); + + } + + @Test(priority = 1) + public void testFlowWithReturnResponseTrue() { + + Map contextProps = new HashMap<>(); + contextProps.put(GatewayConstants.IS_RETURN_RESPONSE, "true"); + contextProps.put(GatewayConstants.MODIFIED_STATUS, String.valueOf(HttpStatus.SC_CREATED)); + MsgInfoDTO msgInfoDTO = new MsgInfoDTO(); + msgInfoDTO.setHeaders(new HashMap<>()); + + fsapiRequestContext = Mockito.mock(FSAPIRequestContext.class); + Mockito.when(fsapiRequestContext.isError()).thenReturn(false); + Mockito.when(fsapiRequestContext.getModifiedPayload()).thenReturn(null); + Mockito.when(fsapiRequestContext.getAddedHeaders()).thenReturn(new HashMap<>()); + Mockito.when(fsapiRequestContext.getMsgInfo()).thenReturn(msgInfoDTO); + Mockito.when(fsapiRequestContext.getContextProps()).thenReturn(contextProps); + + fsapiResponseContext = Mockito.mock(FSAPIResponseContext.class); + Mockito.when(fsapiResponseContext.isError()).thenReturn(false); + Mockito.when(fsapiResponseContext.getModifiedPayload()).thenReturn(null); + Mockito.when(fsapiResponseContext.getAddedHeaders()).thenReturn(new HashMap<>()); + Mockito.when(fsapiResponseContext.getMsgInfo()).thenReturn(msgInfoDTO); + Mockito.when(fsapiResponseContext.getContextProps()).thenReturn(contextProps); + + ExtensionResponseDTO responseDTOForRequest = fsExtensionListener.getResponseDTOForRequest(fsapiRequestContext); + Assert.assertEquals(responseDTOForRequest.getResponseStatus(), ExtensionResponseStatus.RETURN_ERROR.toString()); + Assert.assertEquals(responseDTOForRequest.getStatusCode(), HttpStatus.SC_CREATED); + + ExtensionResponseDTO responseDTOForResponse = + fsExtensionListener.getResponseDTOForResponse(fsapiResponseContext); + + Assert.assertEquals(responseDTOForResponse.getResponseStatus(), + ExtensionResponseStatus.RETURN_ERROR.toString()); + Assert.assertEquals(responseDTOForResponse.getStatusCode(), HttpStatus.SC_CREATED); + + } + +} 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/MockOBExecutor.java new file mode 100644 index 00000000..55cc2eb7 --- /dev/null +++ b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.gateway/src/test/java/org/wso2/financial/services/accelerator/gateway/executor/core/MockOBExecutor.java @@ -0,0 +1,67 @@ +/** + * 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.core; + + +import org.wso2.financial.services.accelerator.gateway.executor.model.FSAPIRequestContext; +import org.wso2.financial.services.accelerator.gateway.executor.model.FSAPIResponseContext; + +/** + * Mock Open banking executor for testing. + */ +public class MockOBExecutor implements FinancialServicesGatewayExecutor { + + @Override + public void preProcessRequest(FSAPIRequestContext fsapiRequestContext) { + + fsapiRequestContext.setModifiedPayload("{}"); + } + + /** + * Method to handle post request. + * + * @param fsapiRequestContext FS request context object + */ + @Override + public void postProcessRequest(FSAPIRequestContext fsapiRequestContext) { + + } + + + /** + * Method to handle pre 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) { + + } + +} diff --git a/financial-services-accelerator/components/org.wso2.financial.services.accelerator.gateway/src/test/java/org/wso2/financial/services/accelerator/gateway/util/GatewayUtilsTest.java b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.gateway/src/test/java/org/wso2/financial/services/accelerator/gateway/util/GatewayUtilsTest.java new file mode 100644 index 00000000..bf07c177 --- /dev/null +++ b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.gateway/src/test/java/org/wso2/financial/services/accelerator/gateway/util/GatewayUtilsTest.java @@ -0,0 +1,108 @@ +/** + * 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.util; + +import org.json.JSONObject; +import org.testng.Assert; +import org.testng.annotations.Test; +import org.wso2.financial.services.accelerator.gateway.GatewayTestConstants; + +import java.io.UnsupportedEncodingException; + +/** + * Test class for Gateway utility methods. + */ +public class GatewayUtilsTest { + + @Test(priority = 1) + public void testIsValidJWTToken() { + + Assert.assertTrue(GatewayUtils.isValidJWTToken(GatewayTestConstants.TEST_JWT)); + } + + @Test(priority = 2) + public void testB64Encode() throws UnsupportedEncodingException { + + JSONObject payload = GatewayUtils.decodeBase64(GatewayTestConstants.B64_PAYLOAD); + Assert.assertEquals(payload.getString("sub"), "1234567890"); + Assert.assertEquals(payload.getString("name"), "John Doe"); + Assert.assertEquals(payload.getInt("iat"), 1516239022); + } + + @Test(priority = 3) + public void testBasicAuthHeader() { + + Assert.assertEquals(GatewayUtils.getBasicAuthHeader("admin", "admin"), + "Basic YWRtaW46YWRtaW4="); + } + + @Test(priority = 4) + public void testGetTextPayload() { + + Assert.assertEquals(GatewayUtils.getTextPayload(GatewayTestConstants.XML_PAYLOAD), "Test Content"); + } + + @Test (priority = 5) + public void testIsEligibleRequest() { + + Assert.assertTrue(GatewayUtils.isEligibleRequest(GatewayConstants.JSON_CONTENT_TYPE, + GatewayConstants.POST_HTTP_METHOD)); + Assert.assertTrue(GatewayUtils.isEligibleRequest(GatewayConstants.APPLICATION_XML_CONTENT_TYPE, + GatewayConstants.POST_HTTP_METHOD)); + Assert.assertTrue(GatewayUtils.isEligibleRequest(GatewayConstants.TEXT_XML_CONTENT_TYPE, + GatewayConstants.POST_HTTP_METHOD)); + Assert.assertTrue(GatewayUtils.isEligibleRequest(GatewayConstants.JSON_CONTENT_TYPE, + GatewayConstants.PUT_HTTP_METHOD)); + Assert.assertTrue(GatewayUtils.isEligibleRequest(GatewayConstants.APPLICATION_XML_CONTENT_TYPE, + GatewayConstants.PUT_HTTP_METHOD)); + Assert.assertTrue(GatewayUtils.isEligibleRequest(GatewayConstants.TEXT_XML_CONTENT_TYPE, + GatewayConstants.PUT_HTTP_METHOD)); + } + + @Test (priority = 6) + public void testIsEligibleResponse() { + + Assert.assertTrue(GatewayUtils.isEligibleResponse(GatewayConstants.JSON_CONTENT_TYPE, + GatewayConstants.POST_HTTP_METHOD)); + Assert.assertTrue(GatewayUtils.isEligibleResponse(GatewayConstants.APPLICATION_XML_CONTENT_TYPE, + GatewayConstants.POST_HTTP_METHOD)); + Assert.assertTrue(GatewayUtils.isEligibleResponse(GatewayConstants.TEXT_XML_CONTENT_TYPE, + GatewayConstants.POST_HTTP_METHOD)); + Assert.assertTrue(GatewayUtils.isEligibleResponse(GatewayConstants.JSON_CONTENT_TYPE, + GatewayConstants.PUT_HTTP_METHOD)); + Assert.assertTrue(GatewayUtils.isEligibleResponse(GatewayConstants.APPLICATION_XML_CONTENT_TYPE, + GatewayConstants.PUT_HTTP_METHOD)); + Assert.assertTrue(GatewayUtils.isEligibleResponse(GatewayConstants.TEXT_XML_CONTENT_TYPE, + GatewayConstants.PUT_HTTP_METHOD)); + Assert.assertTrue(GatewayUtils.isEligibleResponse(GatewayConstants.JSON_CONTENT_TYPE, + GatewayConstants.GET_HTTP_METHOD)); + Assert.assertTrue(GatewayUtils.isEligibleResponse(GatewayConstants.APPLICATION_XML_CONTENT_TYPE, + GatewayConstants.GET_HTTP_METHOD)); + Assert.assertTrue(GatewayUtils.isEligibleResponse(GatewayConstants.TEXT_XML_CONTENT_TYPE, + GatewayConstants.GET_HTTP_METHOD)); + } + + @Test(priority = 7) + public void testJWTPayloadLoad() { + + Assert.assertEquals(GatewayUtils.getPayloadFromJWT(GatewayTestConstants.TEST_JWT), + GatewayTestConstants.B64_PAYLOAD); + } + +} 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 new file mode 100644 index 00000000..8e4cd5f5 --- /dev/null +++ b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.gateway/src/test/resources/testng.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + + diff --git a/financial-services-accelerator/internal-webapps/org.wso2.financial.services.accelerator.authentication.endpoint/pom.xml b/financial-services-accelerator/internal-webapps/org.wso2.financial.services.accelerator.authentication.endpoint/pom.xml index f91fab52..7dd3caa6 100644 --- a/financial-services-accelerator/internal-webapps/org.wso2.financial.services.accelerator.authentication.endpoint/pom.xml +++ b/financial-services-accelerator/internal-webapps/org.wso2.financial.services.accelerator.authentication.endpoint/pom.xml @@ -75,7 +75,7 @@ provided - commons-io + commons-io.wso2 commons-io provided diff --git a/financial-services-accelerator/pom.xml b/financial-services-accelerator/pom.xml index 56da9ca6..c2b8ba0d 100644 --- a/financial-services-accelerator/pom.xml +++ b/financial-services-accelerator/pom.xml @@ -38,6 +38,7 @@ components/org.wso2.financial.services.accelerator.consent.mgt.service components/org.wso2.financial.services.accelerator.consent.mgt.extensions components/org.wso2.financial.services.accelerator.identity.extensions + components/org.wso2.financial.services.accelerator.gateway internal-webapps/org.wso2.financial.services.accelerator.consent.mgt.endpoint internal-webapps/org.wso2.financial.services.accelerator.authentication.endpoint diff --git a/pom.xml b/pom.xml index d8a07f73..9b0ef11f 100644 --- a/pom.xml +++ b/pom.xml @@ -424,7 +424,7 @@ ${equinox.javax.servlet.version} - commons-io + commons-io.wso2 commons-io ${commons.io.version} @@ -438,6 +438,11 @@ oltu ${oltu.version} + + io.swagger.parser.v3 + swagger-parser + ${swagger.parser.version} + org.wso2.carbon @@ -464,6 +469,22 @@ org.wso2.carbon.identity.core ${carbon.identity.framework.version} + + org.wso2.carbon.apimgt + org.wso2.carbon.apimgt.impl + ${org.wso2.carbon.apimgt.version} + + + javassist + javassist + + + + + org.wso2.carbon.apimgt + org.wso2.carbon.apimgt.common.gateway + ${org.wso2.carbon.apimgt.version} + org.wso2.financial.services.accelerator @@ -567,16 +588,19 @@ 3.0.0.v201112011016 4.5.13.wso2v1 4.3.3.wso2v1 - 2.7 + 2.15.1.wso2v1 1.2.5 9.0.11 2.0.1.Final + 2.0.24 7.0.75 [7.0.75, 8.0.0) 7.0.26 - [7.0.26, 7.0.62) + [6.13.0, 7.0.62) 2.5.10 + 9.29.120 + [9.29.120, 9.29.121) 0.8.6 5.3.1 @@ -585,12 +609,14 @@ 1.4 1.2.140.wso2v3 - [1.7.0, 2.0.0) - [1.2.0, 2.0.0) + [1.7.0, 4.0.0) + [1.2.0, 4.0.0) [2.6.0, 3.0.0) [2.9,3) [4.4.0, 5.0.0) [1.2.11, 2.0.0) - [7.9.0, 8.0) + [7.9.0, 10.0) + [2.15.1, 2.16.0) + [3.0.0, 4.0.0)